1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)nfs_serv.c 8.8 (Berkeley) 7/31/95 33 * $FreeBSD: src/sys/nfs/nfs_serv.c,v 1.93.2.6 2002/12/29 18:19:53 dillon Exp $ 34 */ 35 36 /* 37 * nfs version 2 and 3 server calls to vnode ops 38 * - these routines generally have 3 phases 39 * 1 - break down and validate rpc request in mbuf list 40 * 2 - do the vnode ops for the request 41 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c) 42 * 3 - build the rpc reply in an mbuf list 43 * nb: 44 * - do not mix the phases, since the nfsm_?? macros can return failures 45 * on a bad rpc or similar and do not do any vrele() or vput()'s 46 * 47 * - the nfsm_reply() macro generates an nfs rpc reply with the nfs 48 * error number iff error != 0 whereas 49 * returning an error from the server function implies a fatal error 50 * such as a badly constructed rpc request that should be dropped without 51 * a reply. 52 * For Version 3, nfsm_reply() does not return for the error case, since 53 * most version 3 rpcs return more than the status for error cases. 54 * 55 * Other notes: 56 * Warning: always pay careful attention to resource cleanup on return 57 * and note that nfsm_*() macros can terminate a procedure on certain 58 * errors. 59 */ 60 61 #include <sys/param.h> 62 #include <sys/systm.h> 63 #include <sys/proc.h> 64 #include <sys/priv.h> 65 #include <sys/nlookup.h> 66 #include <sys/namei.h> 67 #include <sys/unistd.h> 68 #include <sys/vnode.h> 69 #include <sys/mount.h> 70 #include <sys/socket.h> 71 #include <sys/socketvar.h> 72 #include <sys/malloc.h> 73 #include <sys/mbuf.h> 74 #include <sys/dirent.h> 75 #include <sys/stat.h> 76 #include <sys/kernel.h> 77 #include <sys/sysctl.h> 78 #include <sys/buf.h> 79 80 #include <vm/vm.h> 81 #include <vm/vm_extern.h> 82 #include <vm/vm_object.h> 83 84 #include <sys/buf2.h> 85 86 #include <sys/thread2.h> 87 88 #include "nfsproto.h" 89 #include "rpcv2.h" 90 #include "nfs.h" 91 #include "xdr_subs.h" 92 #include "nfsm_subs.h" 93 94 #ifdef NFSRV_DEBUG 95 #define nfsdbprintf(info) kprintf info 96 #else 97 #define nfsdbprintf(info) 98 #endif 99 100 #define MAX_REORDERED_RPC (16) 101 #define MAX_COMMIT_COUNT (1024 * 1024) 102 103 #define NUM_HEURISTIC 1031 104 #define NHUSE_INIT 64 105 #define NHUSE_INC 16 106 #define NHUSE_MAX 2048 107 108 static struct nfsheur { 109 struct vnode *nh_vp; /* vp to match (unreferenced pointer) */ 110 off_t nh_nextoff; /* next offset for sequential detection */ 111 int nh_use; /* use count for selection */ 112 int nh_seqcount; /* heuristic */ 113 } nfsheur[NUM_HEURISTIC]; 114 115 nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, 116 NFFIFO, NFNON }; 117 #ifndef NFS_NOSERVER 118 nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, 119 NFCHR, NFNON }; 120 121 int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000; 122 int nfsrvw_procrastinate_v3 = 0; 123 124 static struct timespec nfsver; 125 126 SYSCTL_DECL(_vfs_nfs); 127 128 int nfs_async; 129 SYSCTL_INT(_vfs_nfs, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0, 130 "Enable unstable and fast writes"); 131 static int nfs_commit_blks; 132 static int nfs_commit_miss; 133 SYSCTL_INT(_vfs_nfs, OID_AUTO, commit_blks, CTLFLAG_RW, &nfs_commit_blks, 0, 134 "Number of committed blocks"); 135 SYSCTL_INT(_vfs_nfs, OID_AUTO, commit_miss, CTLFLAG_RW, &nfs_commit_miss, 0, 136 "Number of nfs blocks committed from dirty buffers"); 137 138 static int nfsrv_access (struct mount *, struct vnode *, int, 139 struct ucred *, int, struct thread *, int); 140 static void nfsrvw_coalesce (struct nfsrv_descript *, 141 struct nfsrv_descript *); 142 143 /* 144 * Heuristic to detect sequential operation. 145 */ 146 static struct nfsheur * 147 nfsrv_sequential_heuristic(struct uio *uio, struct vnode *vp, int writeop) 148 { 149 struct nfsheur *nh; 150 int hi, try; 151 152 /* Locate best candidate */ 153 try = 32; 154 hi = ((int)(vm_offset_t) vp / sizeof(struct vnode)) % NUM_HEURISTIC; 155 nh = &nfsheur[hi]; 156 157 while (try--) { 158 if (nfsheur[hi].nh_vp == vp) { 159 nh = &nfsheur[hi]; 160 break; 161 } 162 if (nfsheur[hi].nh_use > 0) 163 --nfsheur[hi].nh_use; 164 hi = (hi + 1) % NUM_HEURISTIC; 165 if (nfsheur[hi].nh_use < nh->nh_use) 166 nh = &nfsheur[hi]; 167 } 168 169 /* Initialize hint if this is a new file */ 170 if (nh->nh_vp != vp) { 171 nh->nh_vp = vp; 172 nh->nh_nextoff = uio->uio_offset; 173 nh->nh_use = NHUSE_INIT; 174 if (uio->uio_offset == 0) 175 nh->nh_seqcount = 4; 176 else 177 nh->nh_seqcount = 1; 178 } 179 180 /* 181 * Calculate heuristic 182 * 183 * See vfs_vnops.c:sequential_heuristic(). 184 */ 185 if ((uio->uio_offset == 0 && nh->nh_seqcount > 0) || 186 uio->uio_offset == nh->nh_nextoff) { 187 nh->nh_seqcount += howmany(uio->uio_resid, 16384); 188 if (nh->nh_seqcount > IO_SEQMAX) 189 nh->nh_seqcount = IO_SEQMAX; 190 } else if (qabs(uio->uio_offset - nh->nh_nextoff) <= MAX_REORDERED_RPC * 191 imax(vp->v_mount->mnt_stat.f_iosize, uio->uio_resid)) { 192 /* Probably a reordered RPC, leave seqcount alone. */ 193 } else if (nh->nh_seqcount > 1) { 194 nh->nh_seqcount /= 2; 195 } else { 196 nh->nh_seqcount = 0; 197 } 198 nh->nh_use += NHUSE_INC; 199 if (nh->nh_use > NHUSE_MAX) 200 nh->nh_use = NHUSE_MAX; 201 return (nh); 202 } 203 204 /* 205 * nfs v3 access service 206 */ 207 int 208 nfsrv3_access(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 209 struct thread *td, struct mbuf **mrq) 210 { 211 struct sockaddr *nam = nfsd->nd_nam; 212 struct ucred *cred = &nfsd->nd_cr; 213 struct vnode *vp = NULL; 214 struct mount *mp = NULL; 215 nfsfh_t nfh; 216 fhandle_t *fhp; 217 int error = 0, rdonly, getret; 218 struct vattr vattr, *vap = &vattr; 219 u_long testmode, nfsmode; 220 struct nfsm_info info; 221 u_int32_t *tl; 222 223 info.dpos = nfsd->nd_dpos; 224 info.md = nfsd->nd_md; 225 info.mrep = nfsd->nd_mrep; 226 info.mreq = NULL; 227 228 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 229 fhp = &nfh.fh_generic; 230 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 231 NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED)); 232 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, &rdonly, 233 (nfsd->nd_flag & ND_KERBAUTH), TRUE); 234 if (error) { 235 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error)); 236 nfsm_srvpostop_attr(&info, nfsd, 1, NULL); 237 error = 0; 238 goto nfsmout; 239 } 240 nfsmode = fxdr_unsigned(u_int32_t, *tl); 241 if ((nfsmode & NFSV3ACCESS_READ) && 242 nfsrv_access(mp, vp, VREAD, cred, rdonly, td, 0)) 243 nfsmode &= ~NFSV3ACCESS_READ; 244 if (vp->v_type == VDIR) 245 testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND | 246 NFSV3ACCESS_DELETE); 247 else 248 testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND); 249 if ((nfsmode & testmode) && 250 nfsrv_access(mp, vp, VWRITE, cred, rdonly, td, 0)) 251 nfsmode &= ~testmode; 252 if (vp->v_type == VDIR) 253 testmode = NFSV3ACCESS_LOOKUP; 254 else 255 testmode = NFSV3ACCESS_EXECUTE; 256 if ((nfsmode & testmode) && 257 nfsrv_access(mp, vp, VEXEC, cred, rdonly, td, 0)) 258 nfsmode &= ~testmode; 259 getret = VOP_GETATTR(vp, vap); 260 vput(vp); 261 vp = NULL; 262 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 263 NFSX_POSTOPATTR(1) + NFSX_UNSIGNED, &error)); 264 nfsm_srvpostop_attr(&info, nfsd, getret, vap); 265 tl = nfsm_build(&info, NFSX_UNSIGNED); 266 *tl = txdr_unsigned(nfsmode); 267 nfsmout: 268 *mrq = info.mreq; 269 if (vp) 270 vput(vp); 271 return(error); 272 } 273 274 /* 275 * nfs getattr service 276 */ 277 int 278 nfsrv_getattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 279 struct thread *td, struct mbuf **mrq) 280 { 281 struct sockaddr *nam = nfsd->nd_nam; 282 struct ucred *cred = &nfsd->nd_cr; 283 struct nfs_fattr *fp; 284 struct vattr va; 285 struct vattr *vap = &va; 286 struct vnode *vp = NULL; 287 struct mount *mp = NULL; 288 nfsfh_t nfh; 289 fhandle_t *fhp; 290 int error = 0, rdonly; 291 struct nfsm_info info; 292 293 info.mrep = nfsd->nd_mrep; 294 info.md = nfsd->nd_md; 295 info.dpos = nfsd->nd_dpos; 296 info.mreq = NULL; 297 298 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 299 fhp = &nfh.fh_generic; 300 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 301 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 302 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 303 if (error) { 304 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 0, &error)); 305 error = 0; 306 goto nfsmout; 307 } 308 error = VOP_GETATTR(vp, vap); 309 vput(vp); 310 vp = NULL; 311 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 312 NFSX_FATTR(nfsd->nd_flag & ND_NFSV3), &error)); 313 if (error) { 314 error = 0; 315 goto nfsmout; 316 } 317 fp = nfsm_build(&info, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3)); 318 nfsm_srvfattr(nfsd, vap, fp); 319 /* fall through */ 320 321 nfsmout: 322 *mrq = info.mreq; 323 if (vp) 324 vput(vp); 325 return(error); 326 } 327 328 /* 329 * nfs setattr service 330 */ 331 int 332 nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 333 struct thread *td, struct mbuf **mrq) 334 { 335 struct sockaddr *nam = nfsd->nd_nam; 336 struct ucred *cred = &nfsd->nd_cr; 337 struct vattr va, preat; 338 struct vattr *vap = &va; 339 struct nfsv2_sattr *sp; 340 struct nfs_fattr *fp; 341 struct vnode *vp = NULL; 342 struct mount *mp = NULL; 343 nfsfh_t nfh; 344 fhandle_t *fhp; 345 u_int32_t *tl; 346 int error = 0, rdonly, preat_ret = 1, postat_ret = 1; 347 int gcheck = 0; 348 struct timespec guard; 349 struct nfsm_info info; 350 351 info.mrep = nfsd->nd_mrep; 352 info.mreq = NULL; 353 info.md = nfsd->nd_md; 354 info.dpos = nfsd->nd_dpos; 355 info.v3 = (nfsd->nd_flag & ND_NFSV3); 356 357 guard.tv_sec = 0; /* fix compiler warning */ 358 guard.tv_nsec = 0; 359 360 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 361 fhp = &nfh.fh_generic; 362 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 363 VATTR_NULL(vap); 364 if (info.v3) { 365 ERROROUT(nfsm_srvsattr(&info, vap)); 366 NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED)); 367 gcheck = fxdr_unsigned(int, *tl); 368 if (gcheck) { 369 NULLOUT(tl = nfsm_dissect(&info, 2 * NFSX_UNSIGNED)); 370 fxdr_nfsv3time(tl, &guard); 371 } 372 } else { 373 NULLOUT(sp = nfsm_dissect(&info, NFSX_V2SATTR)); 374 /* 375 * Nah nah nah nah na nah 376 * There is a bug in the Sun client that puts 0xffff in the mode 377 * field of sattr when it should put in 0xffffffff. The u_short 378 * doesn't sign extend. 379 * --> check the low order 2 bytes for 0xffff 380 */ 381 if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) 382 vap->va_mode = nfstov_mode(sp->sa_mode); 383 if (sp->sa_uid != nfs_xdrneg1) 384 vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid); 385 if (sp->sa_gid != nfs_xdrneg1) 386 vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid); 387 if (sp->sa_size != nfs_xdrneg1) 388 vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_size); 389 if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) { 390 #ifdef notyet 391 fxdr_nfsv2time(&sp->sa_atime, &vap->va_atime); 392 #else 393 vap->va_atime.tv_sec = 394 fxdr_unsigned(int32_t, sp->sa_atime.nfsv2_sec); 395 vap->va_atime.tv_nsec = 0; 396 #endif 397 } 398 if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1) 399 fxdr_nfsv2time(&sp->sa_mtime, &vap->va_mtime); 400 401 } 402 403 /* 404 * Now that we have all the fields, lets do it. 405 */ 406 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, &rdonly, 407 (nfsd->nd_flag & ND_KERBAUTH), TRUE); 408 if (error) { 409 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 410 2 * NFSX_UNSIGNED, &error)); 411 nfsm_srvwcc_data(&info, nfsd, preat_ret, &preat, 412 postat_ret, vap); 413 error = 0; 414 goto nfsmout; 415 } 416 417 /* 418 * vp now an active resource, pay careful attention to cleanup 419 */ 420 421 if (info.v3) { 422 error = preat_ret = VOP_GETATTR(vp, &preat); 423 if (!error && gcheck && 424 (preat.va_ctime.tv_sec != guard.tv_sec || 425 preat.va_ctime.tv_nsec != guard.tv_nsec)) 426 error = NFSERR_NOT_SYNC; 427 if (error) { 428 vput(vp); 429 vp = NULL; 430 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 431 NFSX_WCCDATA(info.v3), &error)); 432 nfsm_srvwcc_data(&info, nfsd, preat_ret, &preat, 433 postat_ret, vap); 434 error = 0; 435 goto nfsmout; 436 } 437 } 438 439 /* 440 * If the size is being changed write acces is required, otherwise 441 * just check for a read only file system. 442 */ 443 if (vap->va_size == ((u_quad_t)((quad_t) -1))) { 444 if (rdonly || (mp->mnt_flag & MNT_RDONLY)) { 445 error = EROFS; 446 goto out; 447 } 448 } else { 449 if (vp->v_type == VDIR) { 450 error = EISDIR; 451 goto out; 452 } else if ((error = nfsrv_access(mp, vp, VWRITE, cred, rdonly, 453 td, 0)) != 0){ 454 goto out; 455 } 456 } 457 error = VOP_SETATTR(vp, vap, cred); 458 postat_ret = VOP_GETATTR(vp, vap); 459 if (!error) 460 error = postat_ret; 461 out: 462 vput(vp); 463 vp = NULL; 464 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 465 NFSX_WCCORFATTR(info.v3), &error)); 466 if (info.v3) { 467 nfsm_srvwcc_data(&info, nfsd, preat_ret, &preat, 468 postat_ret, vap); 469 error = 0; 470 goto nfsmout; 471 } 472 fp = nfsm_build(&info, NFSX_V2FATTR); 473 nfsm_srvfattr(nfsd, vap, fp); 474 /* fall through */ 475 476 nfsmout: 477 *mrq = info.mreq; 478 if (vp) 479 vput(vp); 480 return(error); 481 } 482 483 /* 484 * nfs lookup rpc 485 */ 486 int 487 nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 488 struct thread *td, struct mbuf **mrq) 489 { 490 struct sockaddr *nam = nfsd->nd_nam; 491 struct ucred *cred = &nfsd->nd_cr; 492 struct nfs_fattr *fp; 493 struct nlookupdata nd; 494 struct vnode *vp; 495 struct vnode *dirp; 496 struct nchandle nch; 497 nfsfh_t nfh; 498 fhandle_t *fhp; 499 int error = 0, len, dirattr_ret = 1; 500 int pubflag; 501 struct vattr va, dirattr, *vap = &va; 502 struct nfsm_info info; 503 504 info.mrep = nfsd->nd_mrep; 505 info.mreq = NULL; 506 info.md = nfsd->nd_md; 507 info.dpos = nfsd->nd_dpos; 508 info.v3 = (nfsd->nd_flag & ND_NFSV3); 509 510 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 511 nlookup_zero(&nd); 512 dirp = NULL; 513 vp = NULL; 514 515 fhp = &nfh.fh_generic; 516 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 517 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 518 519 pubflag = nfs_ispublicfh(fhp); 520 521 error = nfs_namei(&nd, cred, 0, NULL, &vp, 522 fhp, len, slp, nam, &info.md, &info.dpos, 523 &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), pubflag); 524 525 /* 526 * namei failure, only dirp to cleanup. Clear out garbarge from 527 * structure in case macros jump to nfsmout. 528 */ 529 530 if (error) { 531 if (dirp) { 532 if (info.v3) 533 dirattr_ret = VOP_GETATTR(dirp, &dirattr); 534 vrele(dirp); 535 dirp = NULL; 536 } 537 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 538 NFSX_POSTOPATTR(info.v3), &error)); 539 nfsm_srvpostop_attr(&info, nfsd, dirattr_ret, &dirattr); 540 error = 0; 541 goto nfsmout; 542 } 543 544 /* 545 * Locate index file for public filehandle 546 * 547 * error is 0 on entry and 0 on exit from this block. 548 */ 549 550 if (pubflag) { 551 if (vp->v_type == VDIR && nfs_pub.np_index != NULL) { 552 /* 553 * Setup call to lookup() to see if we can find 554 * the index file. Arguably, this doesn't belong 555 * in a kernel.. Ugh. If an error occurs, do not 556 * try to install an index file and then clear the 557 * error. 558 * 559 * When we replace nd with ind and redirect ndp, 560 * maintenance of ni_startdir and ni_vp shift to 561 * ind and we have to clean them up in the old nd. 562 * However, the cnd resource continues to be maintained 563 * via the original nd. Confused? You aren't alone! 564 */ 565 vn_unlock(vp); 566 cache_copy(&nd.nl_nch, &nch); 567 nlookup_done(&nd); 568 error = nlookup_init_raw(&nd, nfs_pub.np_index, 569 UIO_SYSSPACE, 0, cred, &nch); 570 cache_drop(&nch); 571 if (error == 0) 572 error = nlookup(&nd); 573 574 if (error == 0) { 575 /* 576 * Found an index file. Get rid of 577 * the old references. transfer vp and 578 * load up the new vp. Fortunately we do 579 * not have to deal with dvp, that would be 580 * a huge mess. 581 */ 582 if (dirp) 583 vrele(dirp); 584 dirp = vp; 585 vp = NULL; 586 error = cache_vget(&nd.nl_nch, nd.nl_cred, 587 LK_EXCLUSIVE, &vp); 588 KKASSERT(error == 0); 589 } 590 error = 0; 591 } 592 /* 593 * If the public filehandle was used, check that this lookup 594 * didn't result in a filehandle outside the publicly exported 595 * filesystem. We clear the poor vp here to avoid lockups due 596 * to NFS I/O. 597 */ 598 599 if (vp->v_mount != nfs_pub.np_mount) { 600 vput(vp); 601 vp = NULL; 602 error = EPERM; 603 } 604 } 605 606 if (dirp) { 607 if (info.v3) 608 dirattr_ret = VOP_GETATTR(dirp, &dirattr); 609 vrele(dirp); 610 dirp = NULL; 611 } 612 613 /* 614 * Resources at this point: 615 * ndp->ni_vp may not be NULL 616 * 617 */ 618 619 if (error) { 620 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 621 NFSX_POSTOPATTR(info.v3), &error)); 622 nfsm_srvpostop_attr(&info, nfsd, dirattr_ret, &dirattr); 623 error = 0; 624 goto nfsmout; 625 } 626 627 /* 628 * Clear out some resources prior to potentially blocking. This 629 * is not as critical as ni_dvp resources in other routines, but 630 * it helps. 631 */ 632 nlookup_done(&nd); 633 634 /* 635 * Get underlying attribute, then release remaining resources ( for 636 * the same potential blocking reason ) and reply. 637 */ 638 bzero(&fhp->fh_fid, sizeof(fhp->fh_fid)); 639 error = VFS_VPTOFH(vp, &fhp->fh_fid); 640 if (!error) 641 error = VOP_GETATTR(vp, vap); 642 643 vput(vp); 644 vp = NULL; 645 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 646 NFSX_SRVFH(info.v3) + 647 NFSX_POSTOPORFATTR(info.v3) + 648 NFSX_POSTOPATTR(info.v3), 649 &error)); 650 if (error) { 651 nfsm_srvpostop_attr(&info, nfsd, dirattr_ret, &dirattr); 652 error = 0; 653 goto nfsmout; 654 } 655 nfsm_srvfhtom(&info, fhp); 656 if (info.v3) { 657 nfsm_srvpostop_attr(&info, nfsd, 0, vap); 658 nfsm_srvpostop_attr(&info, nfsd, dirattr_ret, &dirattr); 659 } else { 660 fp = nfsm_build(&info, NFSX_V2FATTR); 661 nfsm_srvfattr(nfsd, vap, fp); 662 } 663 664 nfsmout: 665 *mrq = info.mreq; 666 if (dirp) 667 vrele(dirp); 668 nlookup_done(&nd); /* may be called twice */ 669 if (vp) 670 vput(vp); 671 return (error); 672 } 673 674 /* 675 * nfs readlink service 676 */ 677 int 678 nfsrv_readlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 679 struct thread *td, struct mbuf **mrq) 680 { 681 struct sockaddr *nam = nfsd->nd_nam; 682 struct ucred *cred = &nfsd->nd_cr; 683 struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; 684 struct iovec *ivp = iv; 685 u_int32_t *tl; 686 int error = 0, rdonly, i, tlen, len, getret; 687 struct mbuf *mp1, *mp2, *mp3; 688 struct vnode *vp = NULL; 689 struct mount *mp = NULL; 690 struct vattr attr; 691 nfsfh_t nfh; 692 fhandle_t *fhp; 693 struct uio io, *uiop = &io; 694 struct nfsm_info info; 695 696 info.mrep = nfsd->nd_mrep; 697 info.mreq = NULL; 698 info.md = nfsd->nd_md; 699 info.dpos = nfsd->nd_dpos; 700 info.v3 = (nfsd->nd_flag & ND_NFSV3); 701 702 bzero(&io, sizeof(struct uio)); 703 704 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 705 #ifndef nolint 706 mp2 = NULL; 707 #endif 708 mp3 = NULL; 709 fhp = &nfh.fh_generic; 710 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 711 len = 0; 712 i = 0; 713 while (len < NFS_MAXPATHLEN) { 714 mp1 = m_getcl(M_WAITOK, MT_DATA, 0); 715 mp1->m_len = MCLBYTES; 716 if (len == 0) 717 mp3 = mp2 = mp1; 718 else { 719 mp2->m_next = mp1; 720 mp2 = mp1; 721 } 722 if ((len + mp1->m_len) > NFS_MAXPATHLEN) { 723 mp1->m_len = NFS_MAXPATHLEN-len; 724 len = NFS_MAXPATHLEN; 725 } else 726 len += mp1->m_len; 727 ivp->iov_base = mtod(mp1, caddr_t); 728 ivp->iov_len = mp1->m_len; 729 i++; 730 ivp++; 731 } 732 uiop->uio_iov = iv; 733 uiop->uio_iovcnt = i; 734 uiop->uio_offset = 0; 735 uiop->uio_resid = len; 736 uiop->uio_rw = UIO_READ; 737 uiop->uio_segflg = UIO_SYSSPACE; 738 uiop->uio_td = NULL; 739 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 740 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 741 if (error) { 742 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 743 2 * NFSX_UNSIGNED, &error)); 744 nfsm_srvpostop_attr(&info, nfsd, 1, NULL); 745 error = 0; 746 goto nfsmout; 747 } 748 if (vp->v_type != VLNK) { 749 if (info.v3) 750 error = EINVAL; 751 else 752 error = ENXIO; 753 goto out; 754 } 755 error = VOP_READLINK(vp, uiop, cred); 756 out: 757 getret = VOP_GETATTR(vp, &attr); 758 vput(vp); 759 vp = NULL; 760 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 761 NFSX_POSTOPATTR(info.v3) + NFSX_UNSIGNED, 762 &error)); 763 if (info.v3) { 764 nfsm_srvpostop_attr(&info, nfsd, getret, &attr); 765 if (error) { 766 error = 0; 767 goto nfsmout; 768 } 769 } 770 if (uiop->uio_resid > 0) { 771 len -= uiop->uio_resid; 772 tlen = nfsm_rndup(len); 773 nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len); 774 } 775 tl = nfsm_build(&info, NFSX_UNSIGNED); 776 *tl = txdr_unsigned(len); 777 info.mb->m_next = mp3; 778 mp3 = NULL; 779 nfsmout: 780 *mrq = info.mreq; 781 if (mp3) 782 m_freem(mp3); 783 if (vp) 784 vput(vp); 785 return(error); 786 } 787 788 /* 789 * nfs read service 790 */ 791 int 792 nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 793 struct thread *td, struct mbuf **mrq) 794 { 795 struct nfsm_info info; 796 struct sockaddr *nam = nfsd->nd_nam; 797 struct ucred *cred = &nfsd->nd_cr; 798 struct iovec *iv; 799 struct iovec *iv2; 800 struct mbuf *m; 801 struct nfs_fattr *fp; 802 u_int32_t *tl; 803 int i; 804 int reqlen; 805 int error = 0, rdonly, cnt, len, left, siz, tlen, getret; 806 struct mbuf *m2; 807 struct vnode *vp = NULL; 808 struct mount *mp = NULL; 809 nfsfh_t nfh; 810 fhandle_t *fhp; 811 struct uio io, *uiop = &io; 812 struct vattr va, *vap = &va; 813 struct nfsheur *nh; 814 off_t off; 815 int ioflag = 0; 816 817 info.mrep = nfsd->nd_mrep; 818 info.mreq = NULL; 819 info.md = nfsd->nd_md; 820 info.dpos = nfsd->nd_dpos; 821 info.v3 = (nfsd->nd_flag & ND_NFSV3); 822 823 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 824 fhp = &nfh.fh_generic; 825 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 826 if (info.v3) { 827 NULLOUT(tl = nfsm_dissect(&info, 2 * NFSX_UNSIGNED)); 828 off = fxdr_hyper(tl); 829 } else { 830 NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED)); 831 off = (off_t)fxdr_unsigned(u_int32_t, *tl); 832 } 833 NEGREPLYOUT(reqlen = nfsm_srvstrsiz(&info, 834 NFS_SRVMAXDATA(nfsd), &error)); 835 836 /* 837 * Reference vp. If an error occurs, vp will be invalid, but we 838 * have to NULL it just in case. The macros might goto nfsmout 839 * as well. 840 */ 841 842 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 843 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 844 if (error) { 845 vp = NULL; 846 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 847 2 * NFSX_UNSIGNED, &error)); 848 nfsm_srvpostop_attr(&info, nfsd, 1, NULL); 849 error = 0; 850 goto nfsmout; 851 } 852 853 if (vp->v_type != VREG) { 854 if (info.v3) 855 error = EINVAL; 856 else 857 error = (vp->v_type == VDIR) ? EISDIR : EACCES; 858 } 859 if (!error) { 860 if ((error = nfsrv_access(mp, vp, VREAD, cred, rdonly, td, 1)) != 0) 861 error = nfsrv_access(mp, vp, VEXEC, cred, rdonly, td, 1); 862 } 863 getret = VOP_GETATTR(vp, vap); 864 if (!error) 865 error = getret; 866 if (error) { 867 vput(vp); 868 vp = NULL; 869 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 870 NFSX_POSTOPATTR(info.v3), &error)); 871 nfsm_srvpostop_attr(&info, nfsd, getret, vap); 872 error = 0; 873 goto nfsmout; 874 } 875 876 /* 877 * Calculate byte count to read 878 */ 879 880 if (off >= vap->va_size) 881 cnt = 0; 882 else if ((off + reqlen) > vap->va_size) 883 cnt = vap->va_size - off; 884 else 885 cnt = reqlen; 886 887 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 888 NFSX_POSTOPORFATTR(info.v3) + 889 3 * NFSX_UNSIGNED + nfsm_rndup(cnt), 890 &error)); 891 if (info.v3) { 892 tl = nfsm_build(&info, NFSX_V3FATTR + 4 * NFSX_UNSIGNED); 893 *tl++ = nfs_true; 894 fp = (struct nfs_fattr *)tl; 895 tl += (NFSX_V3FATTR / sizeof (u_int32_t)); 896 } else { 897 tl = nfsm_build(&info, NFSX_V2FATTR + NFSX_UNSIGNED); 898 fp = (struct nfs_fattr *)tl; 899 tl += (NFSX_V2FATTR / sizeof (u_int32_t)); 900 } 901 len = left = nfsm_rndup(cnt); 902 if (cnt > 0) { 903 /* 904 * Generate the mbuf list with the uio_iov ref. to it. 905 */ 906 i = 0; 907 m = m2 = info.mb; 908 while (left > 0) { 909 siz = min(M_TRAILINGSPACE(m), left); 910 if (siz > 0) { 911 left -= siz; 912 i++; 913 } 914 if (left > 0) { 915 m = m_getcl(M_WAITOK, MT_DATA, 0); 916 m->m_len = 0; 917 m2->m_next = m; 918 m2 = m; 919 } 920 } 921 iv = kmalloc(i * sizeof(struct iovec), M_TEMP, M_WAITOK); 922 uiop->uio_iov = iv2 = iv; 923 m = info.mb; 924 left = len; 925 i = 0; 926 while (left > 0) { 927 if (m == NULL) 928 panic("nfsrv_read iov"); 929 siz = min(M_TRAILINGSPACE(m), left); 930 if (siz > 0) { 931 iv->iov_base = mtod(m, caddr_t) + m->m_len; 932 iv->iov_len = siz; 933 m->m_len += siz; 934 left -= siz; 935 iv++; 936 i++; 937 } 938 m = m->m_next; 939 } 940 uiop->uio_iovcnt = i; 941 uiop->uio_offset = off; 942 uiop->uio_resid = len; 943 uiop->uio_rw = UIO_READ; 944 uiop->uio_segflg = UIO_SYSSPACE; 945 nh = nfsrv_sequential_heuristic(uiop, vp, 0); 946 ioflag |= nh->nh_seqcount << IO_SEQSHIFT; 947 error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred); 948 if (error == 0) { 949 off = uiop->uio_offset; 950 nh->nh_nextoff = off; 951 } 952 kfree((caddr_t)iv2, M_TEMP); 953 if (error || (getret = VOP_GETATTR(vp, vap))) { 954 if (!error) 955 error = getret; 956 m_freem(info.mreq); 957 info.mreq = NULL; 958 vput(vp); 959 vp = NULL; 960 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 961 NFSX_POSTOPATTR(info.v3), 962 &error)); 963 nfsm_srvpostop_attr(&info, nfsd, getret, vap); 964 error = 0; 965 goto nfsmout; 966 } 967 } else { 968 uiop->uio_resid = 0; 969 } 970 vput(vp); 971 vp = NULL; 972 nfsm_srvfattr(nfsd, vap, fp); 973 tlen = len - uiop->uio_resid; 974 cnt = cnt < tlen ? cnt : tlen; 975 tlen = nfsm_rndup(cnt); 976 if (len != tlen || tlen != cnt) 977 nfsm_adj(info.mb, len - tlen, tlen - cnt); 978 if (info.v3) { 979 *tl++ = txdr_unsigned(cnt); 980 if (cnt < reqlen) 981 *tl++ = nfs_true; 982 else 983 *tl++ = nfs_false; 984 } 985 *tl = txdr_unsigned(cnt); 986 nfsmout: 987 *mrq = info.mreq; 988 if (vp) 989 vput(vp); 990 return(error); 991 } 992 993 /* 994 * nfs write service 995 */ 996 int 997 nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 998 struct thread *td, struct mbuf **mrq) 999 { 1000 struct sockaddr *nam = nfsd->nd_nam; 1001 struct ucred *cred = &nfsd->nd_cr; 1002 struct iovec *ivp; 1003 int i, cnt; 1004 struct mbuf *mp1; 1005 struct nfs_fattr *fp; 1006 struct iovec *iv; 1007 struct vattr va, forat; 1008 struct vattr *vap = &va; 1009 u_int32_t *tl; 1010 int error = 0, rdonly, len, forat_ret = 1; 1011 int ioflags, aftat_ret = 1, retlen, zeroing, adjust; 1012 int stable = NFSV3WRITE_FILESYNC; 1013 struct vnode *vp = NULL; 1014 struct mount *mp = NULL; 1015 struct nfsheur *nh; 1016 nfsfh_t nfh; 1017 fhandle_t *fhp; 1018 struct uio io, *uiop = &io; 1019 struct nfsm_info info; 1020 off_t off; 1021 1022 info.mrep = nfsd->nd_mrep; 1023 info.mreq = NULL; 1024 info.md = nfsd->nd_md; 1025 info.dpos = nfsd->nd_dpos; 1026 info.v3 = (nfsd->nd_flag & ND_NFSV3); 1027 1028 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 1029 if (info.mrep == NULL) { 1030 error = 0; 1031 goto nfsmout; 1032 } 1033 fhp = &nfh.fh_generic; 1034 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 1035 if (info.v3) { 1036 NULLOUT(tl = nfsm_dissect(&info, 5 * NFSX_UNSIGNED)); 1037 off = fxdr_hyper(tl); 1038 tl += 3; 1039 stable = fxdr_unsigned(int, *tl++); 1040 } else { 1041 NULLOUT(tl = nfsm_dissect(&info, 4 * NFSX_UNSIGNED)); 1042 off = (off_t)fxdr_unsigned(u_int32_t, *++tl); 1043 tl += 2; 1044 if (nfs_async) 1045 stable = NFSV3WRITE_UNSTABLE; 1046 } 1047 retlen = len = fxdr_unsigned(int32_t, *tl); 1048 cnt = i = 0; 1049 1050 /* 1051 * For NFS Version 2, it is not obvious what a write of zero length 1052 * should do, but I might as well be consistent with Version 3, 1053 * which is to return ok so long as there are no permission problems. 1054 */ 1055 if (len > 0) { 1056 zeroing = 1; 1057 mp1 = info.mrep; 1058 while (mp1) { 1059 if (mp1 == info.md) { 1060 zeroing = 0; 1061 adjust = info.dpos - mtod(mp1, caddr_t); 1062 mp1->m_len -= adjust; 1063 if (mp1->m_len > 0 && adjust > 0) 1064 mp1->m_data += adjust; 1065 } 1066 if (zeroing) 1067 mp1->m_len = 0; 1068 else if (mp1->m_len > 0) { 1069 i += mp1->m_len; 1070 if (i > len) { 1071 mp1->m_len -= (i - len); 1072 zeroing = 1; 1073 } 1074 if (mp1->m_len > 0) 1075 cnt++; 1076 } 1077 mp1 = mp1->m_next; 1078 } 1079 } 1080 if (len > NFS_MAXDATA || len < 0 || i < len) { 1081 error = EIO; 1082 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 1083 2 * NFSX_UNSIGNED, &error)); 1084 nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat, 1085 aftat_ret, vap); 1086 error = 0; 1087 goto nfsmout; 1088 } 1089 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 1090 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 1091 if (error) { 1092 vp = NULL; 1093 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 1094 2 * NFSX_UNSIGNED, &error)); 1095 nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat, 1096 aftat_ret, vap); 1097 error = 0; 1098 goto nfsmout; 1099 } 1100 if (info.v3) 1101 forat_ret = VOP_GETATTR(vp, &forat); 1102 if (vp->v_type != VREG) { 1103 if (info.v3) 1104 error = EINVAL; 1105 else 1106 error = (vp->v_type == VDIR) ? EISDIR : EACCES; 1107 } 1108 if (!error) { 1109 error = nfsrv_access(mp, vp, VWRITE, cred, rdonly, td, 1); 1110 } 1111 if (error) { 1112 vput(vp); 1113 vp = NULL; 1114 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 1115 NFSX_WCCDATA(info.v3), &error)); 1116 nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat, 1117 aftat_ret, vap); 1118 error = 0; 1119 goto nfsmout; 1120 } 1121 1122 if (len > 0) { 1123 ivp = kmalloc(cnt * sizeof(struct iovec), M_TEMP, M_WAITOK); 1124 uiop->uio_iov = iv = ivp; 1125 uiop->uio_iovcnt = cnt; 1126 mp1 = info.mrep; 1127 while (mp1) { 1128 if (mp1->m_len > 0) { 1129 ivp->iov_base = mtod(mp1, caddr_t); 1130 ivp->iov_len = mp1->m_len; 1131 ivp++; 1132 } 1133 mp1 = mp1->m_next; 1134 } 1135 1136 /* 1137 * XXX 1138 * The IO_METASYNC flag indicates that all metadata (and not just 1139 * enough to ensure data integrity) mus be written to stable storage 1140 * synchronously. 1141 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.) 1142 */ 1143 if (stable == NFSV3WRITE_UNSTABLE) 1144 ioflags = IO_NODELOCKED; 1145 else if (stable == NFSV3WRITE_DATASYNC) 1146 ioflags = (IO_SYNC | IO_NODELOCKED); 1147 else 1148 ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED); 1149 uiop->uio_resid = len; 1150 uiop->uio_rw = UIO_WRITE; 1151 uiop->uio_segflg = UIO_SYSSPACE; 1152 uiop->uio_td = NULL; 1153 uiop->uio_offset = off; 1154 nh = nfsrv_sequential_heuristic(uiop, vp, 1); 1155 ioflags |= nh->nh_seqcount << IO_SEQSHIFT; 1156 error = VOP_WRITE(vp, uiop, ioflags, cred); 1157 if (error == 0) 1158 nh->nh_nextoff = uiop->uio_offset; 1159 nfsstats.srvvop_writes++; 1160 kfree((caddr_t)iv, M_TEMP); 1161 } 1162 aftat_ret = VOP_GETATTR(vp, vap); 1163 vput(vp); 1164 vp = NULL; 1165 if (!error) 1166 error = aftat_ret; 1167 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 1168 NFSX_PREOPATTR(info.v3) + 1169 NFSX_POSTOPORFATTR(info.v3) + 1170 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(info.v3), 1171 &error)); 1172 if (info.v3) { 1173 nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat, 1174 aftat_ret, vap); 1175 if (error) { 1176 error = 0; 1177 goto nfsmout; 1178 } 1179 tl = nfsm_build(&info, 4 * NFSX_UNSIGNED); 1180 *tl++ = txdr_unsigned(retlen); 1181 /* 1182 * If nfs_async is set, then pretend the write was FILESYNC. 1183 */ 1184 if (stable == NFSV3WRITE_UNSTABLE && !nfs_async) 1185 *tl++ = txdr_unsigned(stable); 1186 else 1187 *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC); 1188 /* 1189 * Actually, there is no need to txdr these fields, 1190 * but it may make the values more human readable, 1191 * for debugging purposes. 1192 */ 1193 if (nfsver.tv_sec == 0) 1194 nfsver = boottime; 1195 *tl++ = txdr_unsigned(nfsver.tv_sec); 1196 *tl = txdr_unsigned(nfsver.tv_nsec / 1000); 1197 } else { 1198 fp = nfsm_build(&info, NFSX_V2FATTR); 1199 nfsm_srvfattr(nfsd, vap, fp); 1200 } 1201 nfsmout: 1202 *mrq = info.mreq; 1203 if (vp) 1204 vput(vp); 1205 return(error); 1206 } 1207 1208 /* 1209 * NFS write service with write gathering support. Called when 1210 * nfsrvw_procrastinate > 0. 1211 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server", 1212 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco, 1213 * Jan. 1994. 1214 */ 1215 int 1216 nfsrv_writegather(struct nfsrv_descript **ndp, struct nfssvc_sock *slp, 1217 struct thread *td, struct mbuf **mrq) 1218 { 1219 struct iovec *ivp; 1220 struct nfsrv_descript *wp, *nfsd, *owp, *swp; 1221 struct nfs_fattr *fp; 1222 int i; 1223 struct iovec *iov; 1224 struct nfsrvw_delayhash *wpp; 1225 struct ucred *cred; 1226 struct vattr va, forat; 1227 u_int32_t *tl; 1228 int error = 0, rdonly, len, forat_ret = 1; 1229 int ioflags, aftat_ret = 1, adjust, zeroing; 1230 struct mbuf *mp1; 1231 struct vnode *vp = NULL; 1232 struct mount *mp = NULL; 1233 struct uio io, *uiop = &io; 1234 u_quad_t cur_usec; 1235 struct nfsm_info info; 1236 1237 info.mreq = NULL; 1238 1239 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 1240 #ifndef nolint 1241 i = 0; 1242 len = 0; 1243 #endif 1244 if (*ndp) { 1245 nfsd = *ndp; 1246 *ndp = NULL; 1247 info.mrep = nfsd->nd_mrep; 1248 info.mreq = NULL; 1249 info.md = nfsd->nd_md; 1250 info.dpos = nfsd->nd_dpos; 1251 info.v3 = (nfsd->nd_flag & ND_NFSV3); 1252 cred = &nfsd->nd_cr; 1253 LIST_INIT(&nfsd->nd_coalesce); 1254 nfsd->nd_mreq = NULL; 1255 nfsd->nd_stable = NFSV3WRITE_FILESYNC; 1256 cur_usec = nfs_curusec(); 1257 nfsd->nd_time = cur_usec + 1258 (info.v3 ? nfsrvw_procrastinate_v3 : nfsrvw_procrastinate); 1259 1260 /* 1261 * Now, get the write header.. 1262 */ 1263 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, &nfsd->nd_fh, &error)); 1264 if (info.v3) { 1265 NULLOUT(tl = nfsm_dissect(&info, 5 * NFSX_UNSIGNED)); 1266 nfsd->nd_off = fxdr_hyper(tl); 1267 tl += 3; 1268 nfsd->nd_stable = fxdr_unsigned(int, *tl++); 1269 } else { 1270 NULLOUT(tl = nfsm_dissect(&info, 4 * NFSX_UNSIGNED)); 1271 nfsd->nd_off = (off_t)fxdr_unsigned(u_int32_t, *++tl); 1272 tl += 2; 1273 if (nfs_async) 1274 nfsd->nd_stable = NFSV3WRITE_UNSTABLE; 1275 } 1276 len = fxdr_unsigned(int32_t, *tl); 1277 nfsd->nd_len = len; 1278 nfsd->nd_eoff = nfsd->nd_off + len; 1279 1280 /* 1281 * Trim the header out of the mbuf list and trim off any trailing 1282 * junk so that the mbuf list has only the write data. 1283 */ 1284 zeroing = 1; 1285 i = 0; 1286 mp1 = info.mrep; 1287 while (mp1) { 1288 if (mp1 == info.md) { 1289 zeroing = 0; 1290 adjust = info.dpos - mtod(mp1, caddr_t); 1291 mp1->m_len -= adjust; 1292 if (mp1->m_len > 0 && adjust > 0) 1293 mp1->m_data += adjust; 1294 } 1295 if (zeroing) 1296 mp1->m_len = 0; 1297 else { 1298 i += mp1->m_len; 1299 if (i > len) { 1300 mp1->m_len -= (i - len); 1301 zeroing = 1; 1302 } 1303 } 1304 mp1 = mp1->m_next; 1305 } 1306 if (len > NFS_MAXDATA || len < 0 || i < len) { 1307 nfsmout: 1308 m_freem(info.mrep); 1309 info.mrep = NULL; 1310 error = EIO; 1311 nfsm_writereply(&info, nfsd, slp, error, 2 * NFSX_UNSIGNED); 1312 if (info.v3) { 1313 nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat, 1314 aftat_ret, &va); 1315 } 1316 nfsd->nd_mreq = info.mreq; 1317 nfsd->nd_mrep = NULL; 1318 nfsd->nd_time = 0; 1319 } 1320 1321 /* 1322 * Add this entry to the hash and time queues. 1323 */ 1324 owp = NULL; 1325 wp = slp->ns_tq.lh_first; 1326 while (wp && wp->nd_time < nfsd->nd_time) { 1327 owp = wp; 1328 wp = wp->nd_tq.le_next; 1329 } 1330 NFS_DPF(WG, ("Q%03x", nfsd->nd_retxid & 0xfff)); 1331 if (owp) { 1332 LIST_INSERT_AFTER(owp, nfsd, nd_tq); 1333 } else { 1334 LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq); 1335 } 1336 if (nfsd->nd_mrep) { 1337 wpp = NWDELAYHASH(slp, nfsd->nd_fh.fh_fid.fid_data); 1338 owp = NULL; 1339 wp = wpp->lh_first; 1340 while (wp && 1341 bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) { 1342 owp = wp; 1343 wp = wp->nd_hash.le_next; 1344 } 1345 while (wp && wp->nd_off < nfsd->nd_off && 1346 !bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) { 1347 owp = wp; 1348 wp = wp->nd_hash.le_next; 1349 } 1350 if (owp) { 1351 LIST_INSERT_AFTER(owp, nfsd, nd_hash); 1352 1353 /* 1354 * Search the hash list for overlapping entries and 1355 * coalesce. 1356 */ 1357 for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) { 1358 wp = nfsd->nd_hash.le_next; 1359 if (NFSW_SAMECRED(owp, nfsd)) 1360 nfsrvw_coalesce(owp, nfsd); 1361 } 1362 } else { 1363 LIST_INSERT_HEAD(wpp, nfsd, nd_hash); 1364 } 1365 } 1366 } 1367 1368 /* 1369 * Now, do VOP_WRITE()s for any one(s) that need to be done now 1370 * and generate the associated reply mbuf list(s). 1371 */ 1372 loop1: 1373 cur_usec = nfs_curusec(); 1374 for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = owp) { 1375 owp = nfsd->nd_tq.le_next; 1376 if (nfsd->nd_time > cur_usec) 1377 break; 1378 if (nfsd->nd_mreq) 1379 continue; 1380 NFS_DPF(WG, ("P%03x", nfsd->nd_retxid & 0xfff)); 1381 LIST_REMOVE(nfsd, nd_tq); 1382 LIST_REMOVE(nfsd, nd_hash); 1383 info.mrep = nfsd->nd_mrep; 1384 info.mreq = NULL; 1385 info.v3 = (nfsd->nd_flag & ND_NFSV3); 1386 nfsd->nd_mrep = NULL; 1387 cred = &nfsd->nd_cr; 1388 forat_ret = aftat_ret = 1; 1389 error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &mp, &vp, cred, slp, 1390 nfsd->nd_nam, &rdonly, 1391 (nfsd->nd_flag & ND_KERBAUTH), TRUE); 1392 if (!error) { 1393 if (info.v3) 1394 forat_ret = VOP_GETATTR(vp, &forat); 1395 if (vp->v_type != VREG) { 1396 if (info.v3) 1397 error = EINVAL; 1398 else 1399 error = (vp->v_type == VDIR) ? EISDIR : EACCES; 1400 } 1401 } else { 1402 vp = NULL; 1403 } 1404 if (!error) { 1405 error = nfsrv_access(mp, vp, VWRITE, cred, rdonly, td, 1); 1406 } 1407 1408 if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE) 1409 ioflags = IO_NODELOCKED; 1410 else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC) 1411 ioflags = (IO_SYNC | IO_NODELOCKED); 1412 else 1413 ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED); 1414 uiop->uio_rw = UIO_WRITE; 1415 uiop->uio_segflg = UIO_SYSSPACE; 1416 uiop->uio_td = NULL; 1417 uiop->uio_offset = nfsd->nd_off; 1418 uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off; 1419 if (uiop->uio_resid > 0) { 1420 mp1 = info.mrep; 1421 i = 0; 1422 while (mp1) { 1423 if (mp1->m_len > 0) 1424 i++; 1425 mp1 = mp1->m_next; 1426 } 1427 uiop->uio_iovcnt = i; 1428 iov = kmalloc(i * sizeof(struct iovec), M_TEMP, M_WAITOK); 1429 uiop->uio_iov = ivp = iov; 1430 mp1 = info.mrep; 1431 while (mp1) { 1432 if (mp1->m_len > 0) { 1433 ivp->iov_base = mtod(mp1, caddr_t); 1434 ivp->iov_len = mp1->m_len; 1435 ivp++; 1436 } 1437 mp1 = mp1->m_next; 1438 } 1439 if (!error) { 1440 error = VOP_WRITE(vp, uiop, ioflags, cred); 1441 nfsstats.srvvop_writes++; 1442 } 1443 kfree((caddr_t)iov, M_TEMP); 1444 } 1445 m_freem(info.mrep); 1446 info.mrep = NULL; 1447 if (vp) { 1448 aftat_ret = VOP_GETATTR(vp, &va); 1449 vput(vp); 1450 vp = NULL; 1451 } 1452 1453 /* 1454 * Loop around generating replies for all write rpcs that have 1455 * now been completed. 1456 */ 1457 swp = nfsd; 1458 do { 1459 NFS_DPF(WG, ("R%03x", nfsd->nd_retxid & 0xfff)); 1460 if (error) { 1461 nfsm_writereply(&info, nfsd, slp, error, 1462 NFSX_WCCDATA(info.v3)); 1463 if (info.v3) { 1464 nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat, 1465 aftat_ret, &va); 1466 } 1467 } else { 1468 nfsm_writereply(&info, nfsd, slp, error, 1469 NFSX_PREOPATTR(info.v3) + 1470 NFSX_POSTOPORFATTR(info.v3) + 1471 2 * NFSX_UNSIGNED + 1472 NFSX_WRITEVERF(info.v3)); 1473 if (info.v3) { 1474 nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat, 1475 aftat_ret, &va); 1476 tl = nfsm_build(&info, 4 * NFSX_UNSIGNED); 1477 *tl++ = txdr_unsigned(nfsd->nd_len); 1478 *tl++ = txdr_unsigned(swp->nd_stable); 1479 /* 1480 * Actually, there is no need to txdr these fields, 1481 * but it may make the values more human readable, 1482 * for debugging purposes. 1483 */ 1484 if (nfsver.tv_sec == 0) 1485 nfsver = boottime; 1486 *tl++ = txdr_unsigned(nfsver.tv_sec); 1487 *tl = txdr_unsigned(nfsver.tv_nsec / 1000); 1488 } else { 1489 fp = nfsm_build(&info, NFSX_V2FATTR); 1490 nfsm_srvfattr(nfsd, &va, fp); 1491 } 1492 } 1493 nfsd->nd_mreq = info.mreq; 1494 if (nfsd->nd_mrep) 1495 panic("nfsrv_write: nd_mrep not free"); 1496 1497 /* 1498 * Done. Put it at the head of the timer queue so that 1499 * the final phase can return the reply. 1500 */ 1501 if (nfsd != swp) { 1502 nfsd->nd_time = 0; 1503 LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq); 1504 } 1505 nfsd = swp->nd_coalesce.lh_first; 1506 if (nfsd) { 1507 LIST_REMOVE(nfsd, nd_tq); 1508 } 1509 } while (nfsd); 1510 swp->nd_time = 0; 1511 LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq); 1512 goto loop1; 1513 } 1514 1515 /* 1516 * Search for a reply to return. 1517 */ 1518 for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next) { 1519 if (nfsd->nd_mreq) { 1520 NFS_DPF(WG, ("X%03x", nfsd->nd_retxid & 0xfff)); 1521 LIST_REMOVE(nfsd, nd_tq); 1522 break; 1523 } 1524 } 1525 if (nfsd) { 1526 *ndp = nfsd; 1527 *mrq = nfsd->nd_mreq; 1528 } else { 1529 *ndp = NULL; 1530 *mrq = NULL; 1531 } 1532 return (0); 1533 } 1534 1535 /* 1536 * Coalesce the write request nfsd into owp. To do this we must: 1537 * - remove nfsd from the queues 1538 * - merge nfsd->nd_mrep into owp->nd_mrep 1539 * - update the nd_eoff and nd_stable for owp 1540 * - put nfsd on owp's nd_coalesce list 1541 * NB: Must be called at splsoftclock(). 1542 */ 1543 static void 1544 nfsrvw_coalesce(struct nfsrv_descript *owp, struct nfsrv_descript *nfsd) 1545 { 1546 int overlap; 1547 struct mbuf *mp1; 1548 struct nfsrv_descript *p; 1549 1550 NFS_DPF(WG, ("C%03x-%03x", 1551 nfsd->nd_retxid & 0xfff, owp->nd_retxid & 0xfff)); 1552 LIST_REMOVE(nfsd, nd_hash); 1553 LIST_REMOVE(nfsd, nd_tq); 1554 if (owp->nd_eoff < nfsd->nd_eoff) { 1555 overlap = owp->nd_eoff - nfsd->nd_off; 1556 if (overlap < 0) 1557 panic("nfsrv_coalesce: bad off"); 1558 if (overlap > 0) 1559 m_adj(nfsd->nd_mrep, overlap); 1560 mp1 = owp->nd_mrep; 1561 while (mp1->m_next) 1562 mp1 = mp1->m_next; 1563 mp1->m_next = nfsd->nd_mrep; 1564 owp->nd_eoff = nfsd->nd_eoff; 1565 } else 1566 m_freem(nfsd->nd_mrep); 1567 nfsd->nd_mrep = NULL; 1568 if (nfsd->nd_stable == NFSV3WRITE_FILESYNC) 1569 owp->nd_stable = NFSV3WRITE_FILESYNC; 1570 else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC && 1571 owp->nd_stable == NFSV3WRITE_UNSTABLE) 1572 owp->nd_stable = NFSV3WRITE_DATASYNC; 1573 LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq); 1574 1575 /* 1576 * If nfsd had anything else coalesced into it, transfer them 1577 * to owp, otherwise their replies will never get sent. 1578 */ 1579 for (p = nfsd->nd_coalesce.lh_first; p; 1580 p = nfsd->nd_coalesce.lh_first) { 1581 LIST_REMOVE(p, nd_tq); 1582 LIST_INSERT_HEAD(&owp->nd_coalesce, p, nd_tq); 1583 } 1584 } 1585 1586 /* 1587 * nfs create service 1588 * now does a truncate to 0 length via. setattr if it already exists 1589 */ 1590 int 1591 nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1592 struct thread *td, struct mbuf **mrq) 1593 { 1594 struct sockaddr *nam = nfsd->nd_nam; 1595 struct ucred *cred = &nfsd->nd_cr; 1596 struct nfs_fattr *fp; 1597 struct vattr va, dirfor, diraft; 1598 struct vattr *vap = &va; 1599 struct nfsv2_sattr *sp; 1600 u_int32_t *tl; 1601 struct nlookupdata nd; 1602 int error = 0, len, tsize, dirfor_ret = 1, diraft_ret = 1; 1603 dev_t rdev = NOUDEV; 1604 caddr_t cp; 1605 int how, exclusive_flag = 0; 1606 struct vnode *dirp; 1607 struct vnode *dvp; 1608 struct vnode *vp; 1609 struct mount *mp = NULL; 1610 nfsfh_t nfh; 1611 fhandle_t *fhp; 1612 u_quad_t tempsize; 1613 u_char cverf[NFSX_V3CREATEVERF]; 1614 struct nfsm_info info; 1615 1616 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 1617 nlookup_zero(&nd); 1618 dirp = NULL; 1619 dvp = NULL; 1620 vp = NULL; 1621 1622 info.mrep = nfsd->nd_mrep; 1623 info.mreq = NULL; 1624 info.md = nfsd->nd_md; 1625 info.dpos = nfsd->nd_dpos; 1626 info.v3 = (nfsd->nd_flag & ND_NFSV3); 1627 1628 fhp = &nfh.fh_generic; 1629 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 1630 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 1631 1632 /* 1633 * Call namei and do initial cleanup to get a few things 1634 * out of the way. If we get an initial error we cleanup 1635 * and return here to avoid special-casing the invalid nd 1636 * structure through the rest of the case. dirp may be 1637 * set even if an error occurs, but the nd structure will not 1638 * be valid at all if an error occurs so we have to invalidate it 1639 * prior to calling nfsm_reply ( which might goto nfsmout ). 1640 */ 1641 error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp, 1642 fhp, len, slp, nam, &info.md, &info.dpos, &dirp, 1643 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 1644 mp = vfs_getvfs(&fhp->fh_fsid); 1645 1646 if (dirp) { 1647 if (info.v3) { 1648 dirfor_ret = VOP_GETATTR(dirp, &dirfor); 1649 } else { 1650 vrele(dirp); 1651 dirp = NULL; 1652 } 1653 } 1654 if (error) { 1655 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 1656 NFSX_WCCDATA(info.v3), &error)); 1657 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 1658 diraft_ret, &diraft); 1659 error = 0; 1660 goto nfsmout; 1661 } 1662 1663 /* 1664 * No error. Continue. State: 1665 * 1666 * dirp may be valid 1667 * vp may be valid or NULL if the target does not 1668 * exist. 1669 * dvp is valid 1670 * 1671 * The error state is set through the code and we may also do some 1672 * opportunistic releasing of vnodes to avoid holding locks through 1673 * NFS I/O. The cleanup at the end is a catch-all 1674 */ 1675 1676 VATTR_NULL(vap); 1677 if (info.v3) { 1678 NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED)); 1679 how = fxdr_unsigned(int, *tl); 1680 switch (how) { 1681 case NFSV3CREATE_GUARDED: 1682 if (vp) { 1683 error = EEXIST; 1684 break; 1685 } 1686 /* fall through */ 1687 case NFSV3CREATE_UNCHECKED: 1688 ERROROUT(nfsm_srvsattr(&info, vap)); 1689 break; 1690 case NFSV3CREATE_EXCLUSIVE: 1691 NULLOUT(cp = nfsm_dissect(&info, NFSX_V3CREATEVERF)); 1692 bcopy(cp, cverf, NFSX_V3CREATEVERF); 1693 exclusive_flag = 1; 1694 break; 1695 } 1696 vap->va_type = VREG; 1697 } else { 1698 NULLOUT(sp = nfsm_dissect(&info, NFSX_V2SATTR)); 1699 vap->va_type = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode)); 1700 if (vap->va_type == VNON) 1701 vap->va_type = VREG; 1702 vap->va_mode = nfstov_mode(sp->sa_mode); 1703 switch (vap->va_type) { 1704 case VREG: 1705 tsize = fxdr_unsigned(int32_t, sp->sa_size); 1706 if (tsize != -1) 1707 vap->va_size = (u_quad_t)tsize; 1708 break; 1709 case VCHR: 1710 case VBLK: 1711 case VFIFO: 1712 rdev = fxdr_unsigned(long, sp->sa_size); 1713 break; 1714 default: 1715 break; 1716 } 1717 } 1718 1719 /* 1720 * Iff doesn't exist, create it 1721 * otherwise just truncate to 0 length 1722 * should I set the mode too ? 1723 * 1724 * The only possible error we can have at this point is EEXIST. 1725 * nd.ni_vp will also be non-NULL in that case. 1726 */ 1727 if (vp == NULL) { 1728 if (vap->va_mode == (mode_t)VNOVAL) 1729 vap->va_mode = 0; 1730 if (vap->va_type == VREG || vap->va_type == VSOCK) { 1731 vn_unlock(dvp); 1732 error = VOP_NCREATE(&nd.nl_nch, dvp, &vp, 1733 nd.nl_cred, vap); 1734 vrele(dvp); 1735 dvp = NULL; 1736 if (error == 0) { 1737 if (exclusive_flag) { 1738 exclusive_flag = 0; 1739 VATTR_NULL(vap); 1740 bcopy(cverf, (caddr_t)&vap->va_atime, 1741 NFSX_V3CREATEVERF); 1742 error = VOP_SETATTR(vp, vap, cred); 1743 } 1744 } 1745 } else if ( 1746 vap->va_type == VCHR || 1747 vap->va_type == VBLK || 1748 vap->va_type == VFIFO 1749 ) { 1750 /* 1751 * Handle SysV FIFO node special cases. All other 1752 * devices require super user to access. 1753 */ 1754 if (vap->va_type == VCHR && rdev == 0xffffffff) 1755 vap->va_type = VFIFO; 1756 if (vap->va_type != VFIFO && 1757 (error = priv_check_cred(cred, PRIV_ROOT, 0))) { 1758 goto nfsmreply0; 1759 } 1760 vap->va_rmajor = umajor(rdev); 1761 vap->va_rminor = uminor(rdev); 1762 1763 vn_unlock(dvp); 1764 error = VOP_NMKNOD(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap); 1765 vrele(dvp); 1766 dvp = NULL; 1767 if (error) 1768 goto nfsmreply0; 1769 #if 0 1770 /* 1771 * XXX what is this junk supposed to do ? 1772 */ 1773 1774 vput(vp); 1775 vp = NULL; 1776 1777 /* 1778 * release dvp prior to lookup 1779 */ 1780 vput(dvp); 1781 dvp = NULL; 1782 1783 /* 1784 * Setup for lookup. 1785 * 1786 * Even though LOCKPARENT was cleared, ni_dvp may 1787 * be garbage. 1788 */ 1789 nd.ni_cnd.cn_nameiop = NAMEI_LOOKUP; 1790 nd.ni_cnd.cn_flags &= ~(CNP_LOCKPARENT); 1791 nd.ni_cnd.cn_td = td; 1792 nd.ni_cnd.cn_cred = cred; 1793 1794 error = lookup(&nd); 1795 nd.ni_dvp = NULL; 1796 1797 if (error != 0) { 1798 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 1799 0, &error)); 1800 /* fall through on certain errors */ 1801 } 1802 nfsrv_object_create(nd.ni_vp); 1803 if (nd.ni_cnd.cn_flags & CNP_ISSYMLINK) { 1804 error = EINVAL; 1805 goto nfsmreply0; 1806 } 1807 #endif 1808 } else { 1809 error = ENXIO; 1810 } 1811 } else { 1812 if (vap->va_size != -1) { 1813 error = nfsrv_access(mp, vp, VWRITE, cred, 1814 (nd.nl_flags & NLC_NFS_RDONLY), td, 0); 1815 if (!error) { 1816 tempsize = vap->va_size; 1817 VATTR_NULL(vap); 1818 vap->va_size = tempsize; 1819 error = VOP_SETATTR(vp, vap, cred); 1820 } 1821 } 1822 } 1823 1824 if (!error) { 1825 bzero(&fhp->fh_fid, sizeof(fhp->fh_fid)); 1826 error = VFS_VPTOFH(vp, &fhp->fh_fid); 1827 if (!error) 1828 error = VOP_GETATTR(vp, vap); 1829 } 1830 if (info.v3) { 1831 if (exclusive_flag && !error && 1832 bcmp(cverf, (caddr_t)&vap->va_atime, NFSX_V3CREATEVERF)) 1833 error = EEXIST; 1834 diraft_ret = VOP_GETATTR(dirp, &diraft); 1835 vrele(dirp); 1836 dirp = NULL; 1837 } 1838 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 1839 NFSX_SRVFH(info.v3) + NFSX_FATTR(info.v3) + 1840 NFSX_WCCDATA(info.v3), 1841 &error)); 1842 if (info.v3) { 1843 if (!error) { 1844 nfsm_srvpostop_fh(&info, fhp); 1845 nfsm_srvpostop_attr(&info, nfsd, 0, vap); 1846 } 1847 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 1848 diraft_ret, &diraft); 1849 error = 0; 1850 } else { 1851 nfsm_srvfhtom(&info, fhp); 1852 fp = nfsm_build(&info, NFSX_V2FATTR); 1853 nfsm_srvfattr(nfsd, vap, fp); 1854 } 1855 goto nfsmout; 1856 1857 nfsmreply0: 1858 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 0, &error)); 1859 error = 0; 1860 /* fall through */ 1861 1862 nfsmout: 1863 *mrq = info.mreq; 1864 if (dirp) 1865 vrele(dirp); 1866 nlookup_done(&nd); 1867 if (dvp) { 1868 if (dvp == vp) 1869 vrele(dvp); 1870 else 1871 vput(dvp); 1872 } 1873 if (vp) 1874 vput(vp); 1875 if (mp) 1876 mount_drop(mp); 1877 return (error); 1878 } 1879 1880 /* 1881 * nfs v3 mknod service 1882 */ 1883 int 1884 nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1885 struct thread *td, struct mbuf **mrq) 1886 { 1887 struct sockaddr *nam = nfsd->nd_nam; 1888 struct ucred *cred = &nfsd->nd_cr; 1889 struct vattr va, dirfor, diraft; 1890 struct vattr *vap = &va; 1891 u_int32_t *tl; 1892 struct nlookupdata nd; 1893 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 1894 enum vtype vtyp; 1895 struct vnode *dirp; 1896 struct vnode *dvp; 1897 struct vnode *vp; 1898 nfsfh_t nfh; 1899 fhandle_t *fhp; 1900 struct nfsm_info info; 1901 1902 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 1903 nlookup_zero(&nd); 1904 dirp = NULL; 1905 dvp = NULL; 1906 vp = NULL; 1907 1908 info.mrep = nfsd->nd_mrep; 1909 info.mreq = NULL; 1910 info.md = nfsd->nd_md; 1911 info.dpos = nfsd->nd_dpos; 1912 1913 fhp = &nfh.fh_generic; 1914 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 1915 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 1916 1917 /* 1918 * Handle nfs_namei() call. If an error occurs, the nd structure 1919 * is not valid. However, nfsm_*() routines may still jump to 1920 * nfsmout. 1921 */ 1922 1923 error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp, 1924 fhp, len, slp, nam, &info.md, &info.dpos, &dirp, 1925 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 1926 if (dirp) 1927 dirfor_ret = VOP_GETATTR(dirp, &dirfor); 1928 if (error) { 1929 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 1930 NFSX_WCCDATA(1), &error)); 1931 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 1932 diraft_ret, &diraft); 1933 error = 0; 1934 goto nfsmout; 1935 } 1936 NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED)); 1937 vtyp = nfsv3tov_type(*tl); 1938 if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) { 1939 error = NFSERR_BADTYPE; 1940 goto out; 1941 } 1942 VATTR_NULL(vap); 1943 ERROROUT(nfsm_srvsattr(&info, vap)); 1944 if (vtyp == VCHR || vtyp == VBLK) { 1945 NULLOUT(tl = nfsm_dissect(&info, 2 * NFSX_UNSIGNED)); 1946 vap->va_rmajor = fxdr_unsigned(u_int32_t, *tl++); 1947 vap->va_rminor = fxdr_unsigned(u_int32_t, *tl); 1948 } 1949 1950 /* 1951 * Iff doesn't exist, create it. 1952 */ 1953 if (vp) { 1954 error = EEXIST; 1955 goto out; 1956 } 1957 vap->va_type = vtyp; 1958 if (vap->va_mode == (mode_t)VNOVAL) 1959 vap->va_mode = 0; 1960 if (vtyp == VSOCK) { 1961 vn_unlock(dvp); 1962 error = VOP_NCREATE(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap); 1963 vrele(dvp); 1964 dvp = NULL; 1965 } else { 1966 if (vtyp != VFIFO && (error = priv_check_cred(cred, PRIV_ROOT, 0))) 1967 goto out; 1968 1969 vn_unlock(dvp); 1970 error = VOP_NMKNOD(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap); 1971 vrele(dvp); 1972 dvp = NULL; 1973 if (error) 1974 goto out; 1975 } 1976 1977 /* 1978 * send response, cleanup, return. 1979 */ 1980 out: 1981 nlookup_done(&nd); 1982 if (dvp) { 1983 if (dvp == vp) 1984 vrele(dvp); 1985 else 1986 vput(dvp); 1987 dvp = NULL; 1988 } 1989 if (!error) { 1990 bzero(&fhp->fh_fid, sizeof(fhp->fh_fid)); 1991 error = VFS_VPTOFH(vp, &fhp->fh_fid); 1992 if (!error) 1993 error = VOP_GETATTR(vp, vap); 1994 } 1995 if (vp) { 1996 vput(vp); 1997 vp = NULL; 1998 } 1999 diraft_ret = VOP_GETATTR(dirp, &diraft); 2000 if (dirp) { 2001 vrele(dirp); 2002 dirp = NULL; 2003 } 2004 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2005 NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + 2006 NFSX_WCCDATA(1), &error)); 2007 if (!error) { 2008 nfsm_srvpostop_fh(&info, fhp); 2009 nfsm_srvpostop_attr(&info, nfsd, 0, vap); 2010 } 2011 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2012 diraft_ret, &diraft); 2013 *mrq = info.mreq; 2014 return (0); 2015 nfsmout: 2016 *mrq = info.mreq; 2017 if (dirp) 2018 vrele(dirp); 2019 nlookup_done(&nd); 2020 if (dvp) { 2021 if (dvp == vp) 2022 vrele(dvp); 2023 else 2024 vput(dvp); 2025 } 2026 if (vp) 2027 vput(vp); 2028 return (error); 2029 } 2030 2031 /* 2032 * nfs remove service 2033 */ 2034 int 2035 nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2036 struct thread *td, struct mbuf **mrq) 2037 { 2038 struct sockaddr *nam = nfsd->nd_nam; 2039 struct ucred *cred = &nfsd->nd_cr; 2040 struct nlookupdata nd; 2041 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 2042 struct vnode *dirp; 2043 struct vnode *dvp; 2044 struct vnode *vp; 2045 struct vattr dirfor, diraft; 2046 nfsfh_t nfh; 2047 fhandle_t *fhp; 2048 struct nfsm_info info; 2049 2050 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 2051 nlookup_zero(&nd); 2052 dirp = NULL; 2053 dvp = NULL; 2054 vp = NULL; 2055 2056 info.mrep = nfsd->nd_mrep; 2057 info.mreq = NULL; 2058 info.md = nfsd->nd_md; 2059 info.dpos = nfsd->nd_dpos; 2060 info.v3 = (nfsd->nd_flag & ND_NFSV3); 2061 2062 fhp = &nfh.fh_generic; 2063 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 2064 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 2065 2066 error = nfs_namei(&nd, cred, NLC_DELETE, &dvp, &vp, 2067 fhp, len, slp, nam, &info.md, &info.dpos, &dirp, 2068 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2069 if (dirp) { 2070 if (info.v3) 2071 dirfor_ret = VOP_GETATTR(dirp, &dirfor); 2072 } 2073 if (error == 0) { 2074 if (vp->v_type == VDIR) { 2075 error = EPERM; /* POSIX */ 2076 goto out; 2077 } 2078 /* 2079 * The root of a mounted filesystem cannot be deleted. 2080 */ 2081 if (vp->v_flag & VROOT) { 2082 error = EBUSY; 2083 goto out; 2084 } 2085 out: 2086 if (!error) { 2087 if (dvp != vp) 2088 vn_unlock(dvp); 2089 if (vp) { 2090 vput(vp); 2091 vp = NULL; 2092 } 2093 error = VOP_NREMOVE(&nd.nl_nch, dvp, nd.nl_cred); 2094 vrele(dvp); 2095 dvp = NULL; 2096 } 2097 } 2098 if (dirp && info.v3) 2099 diraft_ret = VOP_GETATTR(dirp, &diraft); 2100 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_WCCDATA(info.v3), &error)); 2101 if (info.v3) { 2102 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2103 diraft_ret, &diraft); 2104 error = 0; 2105 } 2106 nfsmout: 2107 *mrq = info.mreq; 2108 nlookup_done(&nd); 2109 if (dirp) 2110 vrele(dirp); 2111 if (dvp) { 2112 if (dvp == vp) 2113 vrele(dvp); 2114 else 2115 vput(dvp); 2116 } 2117 if (vp) 2118 vput(vp); 2119 return(error); 2120 } 2121 2122 /* 2123 * nfs rename service 2124 */ 2125 int 2126 nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2127 struct thread *td, struct mbuf **mrq) 2128 { 2129 struct sockaddr *nam = nfsd->nd_nam; 2130 struct ucred *cred = &nfsd->nd_cr; 2131 int error = 0, len, len2, fdirfor_ret = 1, fdiraft_ret = 1; 2132 int tdirfor_ret = 1, tdiraft_ret = 1; 2133 struct nlookupdata fromnd, tond; 2134 struct nchandle fnchd; 2135 struct nchandle tnchd; 2136 struct vnode *fvp, *fdirp, *fdvp; 2137 struct vnode *tvp, *tdirp, *tdvp; 2138 struct namecache *ncp; 2139 struct vattr fdirfor, fdiraft, tdirfor, tdiraft; 2140 int fnchd_status = 0; 2141 int tnchd_status = 0; 2142 nfsfh_t fnfh, tnfh; 2143 fhandle_t *ffhp, *tfhp; 2144 uid_t saved_uid; 2145 struct nfsm_info info; 2146 2147 info.mrep = nfsd->nd_mrep; 2148 info.mreq = NULL; 2149 info.md = nfsd->nd_md; 2150 info.dpos = nfsd->nd_dpos; 2151 info.v3 = (nfsd->nd_flag & ND_NFSV3); 2152 2153 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 2154 #ifndef nolint 2155 fvp = NULL; 2156 #endif 2157 ffhp = &fnfh.fh_generic; 2158 tfhp = &tnfh.fh_generic; 2159 2160 /* 2161 * Clear fields incase goto nfsmout occurs from macro. 2162 */ 2163 2164 nlookup_zero(&fromnd); 2165 nlookup_zero(&tond); 2166 fdirp = NULL; 2167 tdirp = NULL; 2168 2169 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, ffhp, &error)); 2170 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 2171 2172 /* 2173 * Remember our original uid so that we can reset cr_uid before 2174 * the second nfs_namei() call, in case it is remapped. 2175 * 2176 * NOTE! If nfs_namei() is called twice on the same nd, it assumes 2177 * a retry and does not try to reparse the path. 2178 */ 2179 saved_uid = cred->cr_uid; 2180 again: 2181 error = nfs_namei(&fromnd, cred, NLC_RENAME_SRC, 2182 NULL, NULL, 2183 ffhp, len, slp, nam, &info.md, &info.dpos, &fdirp, 2184 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2185 if (fdirp) { 2186 if (info.v3) 2187 fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor); 2188 } 2189 if (error) { 2190 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2191 2 * NFSX_WCCDATA(info.v3), &error)); 2192 nfsm_srvwcc_data(&info, nfsd, fdirfor_ret, &fdirfor, 2193 fdiraft_ret, &fdiraft); 2194 nfsm_srvwcc_data(&info, nfsd, tdirfor_ret, &tdirfor, 2195 tdiraft_ret, &tdiraft); 2196 error = 0; 2197 goto nfsmout; 2198 } 2199 2200 fnchd.mount = fromnd.nl_nch.mount; 2201 fnchd.ncp = fromnd.nl_nch.ncp->nc_parent; 2202 if (fnchd.ncp == NULL) { 2203 error = ENOENT; 2204 goto nfsmout; 2205 } 2206 cache_hold(&fnchd); 2207 fnchd_status = 1; 2208 2209 /* 2210 * We have to unlock the from ncp before we can safely lookup 2211 * the target ncp. 2212 */ 2213 KKASSERT(fromnd.nl_flags & NLC_NCPISLOCKED); 2214 cache_unlock(&fromnd.nl_nch); 2215 fromnd.nl_flags &= ~NLC_NCPISLOCKED; 2216 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, tfhp, &error)); 2217 NEGATIVEOUT(len2 = nfsm_strsiz(&info, NFS_MAXNAMLEN)); 2218 cred->cr_uid = saved_uid; 2219 2220 error = nfs_namei(&tond, cred, NLC_RENAME_DST, NULL, NULL, 2221 tfhp, len2, slp, nam, &info.md, &info.dpos, &tdirp, 2222 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2223 if (tdirp) { 2224 if (info.v3) 2225 tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor); 2226 } 2227 if (error) 2228 goto out1; 2229 tnchd.mount = tond.nl_nch.mount; 2230 tnchd.ncp = tond.nl_nch.ncp->nc_parent; 2231 if (tnchd.ncp == NULL) { 2232 error = ENOENT; 2233 goto nfsmout; 2234 } 2235 cache_hold(&tnchd); 2236 tnchd_status = 1; 2237 2238 cache_lock4_tondlocked(&fnchd, &fromnd.nl_nch, 2239 &tnchd, &tond.nl_nch, 2240 fromnd.nl_cred, tond.nl_cred); 2241 fromnd.nl_flags |= NLC_NCPISLOCKED; 2242 fnchd_status = 2; 2243 tnchd_status = 2; 2244 2245 /* 2246 * Revalidate namecache records and retry the lookups if necessary. 2247 */ 2248 if (fnchd.ncp != fromnd.nl_nch.ncp->nc_parent || 2249 tnchd.ncp != tond.nl_nch.ncp->nc_parent || 2250 (fromnd.nl_nch.ncp->nc_flag & (NCF_DESTROYED | NCF_UNRESOLVED)) || 2251 fromnd.nl_nch.ncp->nc_vp == NULL || 2252 (tond.nl_nch.ncp->nc_flag & (NCF_DESTROYED | NCF_UNRESOLVED))) { 2253 cache_put(&fnchd); 2254 cache_put(&tnchd); 2255 if (tdirp) 2256 vrele(tdirp); 2257 if (fdirp) 2258 vrele(fdirp); 2259 kprintf("nfs - retry rename %s to %s\n", 2260 fromnd.nl_path, tond.nl_path); 2261 goto again; 2262 } 2263 2264 /* 2265 * Source and target vnodes (tvp might be NULL) 2266 */ 2267 fvp = fromnd.nl_nch.ncp->nc_vp; 2268 tvp = tond.nl_nch.ncp->nc_vp; 2269 2270 /* 2271 * Set fdvp and tdvp. We haven't done all the topology checks 2272 * so these can wind up NULL (e.g. if either fvp or tvp is a mount 2273 * point). If we get through the checks these will be guarenteed 2274 * to be non-NULL. 2275 * 2276 * Holding the children ncp's should be sufficient to prevent 2277 * fdvp and tdvp ripouts. 2278 */ 2279 fdvp = fromnd.nl_nch.ncp->nc_parent->nc_vp; 2280 tdvp = tond.nl_nch.ncp->nc_parent->nc_vp; 2281 2282 if (tvp != NULL) { 2283 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 2284 if (info.v3) 2285 error = EEXIST; 2286 else 2287 error = EISDIR; 2288 goto out; 2289 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 2290 if (info.v3) 2291 error = EEXIST; 2292 else 2293 error = ENOTDIR; 2294 goto out; 2295 } 2296 if (tvp->v_type == VDIR && (tond.nl_nch.ncp->nc_flag & NCF_ISMOUNTPT)) { 2297 if (info.v3) 2298 error = EXDEV; 2299 else 2300 error = ENOTEMPTY; 2301 goto out; 2302 } 2303 } 2304 if (fvp->v_type == VDIR && (fromnd.nl_nch.ncp->nc_flag & NCF_ISMOUNTPT)) { 2305 if (info.v3) 2306 error = EXDEV; 2307 else 2308 error = ENOTEMPTY; 2309 goto out; 2310 } 2311 if (fromnd.nl_nch.mount != tond.nl_nch.mount) { 2312 if (info.v3) 2313 error = EXDEV; 2314 else 2315 error = ENOTEMPTY; 2316 goto out; 2317 } 2318 if (fromnd.nl_nch.ncp == tond.nl_nch.ncp->nc_parent) { 2319 if (info.v3) 2320 error = EINVAL; 2321 else 2322 error = ENOTEMPTY; 2323 } 2324 2325 /* 2326 * You cannot rename a source into itself or a subdirectory of itself. 2327 * We check this by travsering the target directory upwards looking 2328 * for a match against the source. 2329 */ 2330 if (error == 0) { 2331 for (ncp = tond.nl_nch.ncp; ncp; ncp = ncp->nc_parent) { 2332 if (fromnd.nl_nch.ncp == ncp) { 2333 error = EINVAL; 2334 break; 2335 } 2336 } 2337 } 2338 2339 /* 2340 * If source is the same as the destination (that is the 2341 * same vnode with the same name in the same directory), 2342 * then there is nothing to do. 2343 */ 2344 if (fromnd.nl_nch.ncp == tond.nl_nch.ncp) 2345 error = -1; 2346 out: 2347 if (!error) { 2348 /* 2349 * The VOP_NRENAME function releases all vnode references & 2350 * locks prior to returning so we need to clear the pointers 2351 * to bypass cleanup code later on. 2352 */ 2353 error = VOP_NRENAME(&fromnd.nl_nch, &tond.nl_nch, 2354 fdvp, tdvp, tond.nl_cred); 2355 } else { 2356 if (error == -1) 2357 error = 0; 2358 } 2359 /* fall through */ 2360 2361 out1: 2362 if (fdirp) 2363 fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft); 2364 if (tdirp) 2365 tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft); 2366 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2367 2 * NFSX_WCCDATA(info.v3), &error)); 2368 if (info.v3) { 2369 nfsm_srvwcc_data(&info, nfsd, fdirfor_ret, &fdirfor, 2370 fdiraft_ret, &fdiraft); 2371 nfsm_srvwcc_data(&info, nfsd, tdirfor_ret, &tdirfor, 2372 tdiraft_ret, &tdiraft); 2373 } 2374 error = 0; 2375 /* fall through */ 2376 2377 nfsmout: 2378 if (fnchd_status > 1) 2379 cache_unlock(&fnchd); 2380 if (fnchd_status > 0) 2381 cache_drop(&fnchd); 2382 if (tnchd_status > 1) 2383 cache_unlock(&tnchd); 2384 if (tnchd_status > 0) 2385 cache_drop(&tnchd); 2386 2387 *mrq = info.mreq; 2388 if (tdirp) 2389 vrele(tdirp); 2390 nlookup_done(&tond); 2391 if (fdirp) 2392 vrele(fdirp); 2393 nlookup_done(&fromnd); 2394 return (error); 2395 } 2396 2397 /* 2398 * nfs link service 2399 */ 2400 int 2401 nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2402 struct thread *td, struct mbuf **mrq) 2403 { 2404 struct sockaddr *nam = nfsd->nd_nam; 2405 struct ucred *cred = &nfsd->nd_cr; 2406 struct nlookupdata nd; 2407 int error = 0, rdonly, len, dirfor_ret = 1, diraft_ret = 1; 2408 int getret = 1; 2409 struct vnode *dirp; 2410 struct vnode *dvp; 2411 struct vnode *vp; 2412 struct vnode *xp; 2413 struct mount *xmp; 2414 struct vattr dirfor, diraft, at; 2415 nfsfh_t nfh, dnfh; 2416 fhandle_t *fhp, *dfhp; 2417 struct nfsm_info info; 2418 2419 info.mrep = nfsd->nd_mrep; 2420 info.mreq = NULL; 2421 info.md = nfsd->nd_md; 2422 info.dpos = nfsd->nd_dpos; 2423 info.v3 = (nfsd->nd_flag & ND_NFSV3); 2424 2425 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 2426 nlookup_zero(&nd); 2427 dirp = dvp = vp = xp = NULL; 2428 xmp = NULL; 2429 2430 fhp = &nfh.fh_generic; 2431 dfhp = &dnfh.fh_generic; 2432 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 2433 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, dfhp, &error)); 2434 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 2435 2436 error = nfsrv_fhtovp(fhp, FALSE, &xmp, &xp, cred, slp, nam, 2437 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 2438 if (error) { 2439 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2440 NFSX_POSTOPATTR(info.v3) + 2441 NFSX_WCCDATA(info.v3), 2442 &error)); 2443 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 2444 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2445 diraft_ret, &diraft); 2446 xp = NULL; 2447 error = 0; 2448 goto nfsmout; 2449 } 2450 if (xp->v_type == VDIR) { 2451 error = EPERM; /* POSIX */ 2452 goto out1; 2453 } 2454 2455 error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp, 2456 dfhp, len, slp, nam, &info.md, &info.dpos, &dirp, 2457 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2458 if (dirp) { 2459 if (info.v3) 2460 dirfor_ret = VOP_GETATTR(dirp, &dirfor); 2461 } 2462 if (error) 2463 goto out1; 2464 2465 if (vp != NULL) { 2466 error = EEXIST; 2467 goto out; 2468 } 2469 if (xp->v_mount != dvp->v_mount) 2470 error = EXDEV; 2471 out: 2472 if (!error) { 2473 vn_unlock(dvp); 2474 error = VOP_NLINK(&nd.nl_nch, dvp, xp, nd.nl_cred); 2475 vrele(dvp); 2476 dvp = NULL; 2477 } 2478 /* fall through */ 2479 2480 out1: 2481 if (info.v3) 2482 getret = VOP_GETATTR(xp, &at); 2483 if (dirp) 2484 diraft_ret = VOP_GETATTR(dirp, &diraft); 2485 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2486 NFSX_POSTOPATTR(info.v3) + NFSX_WCCDATA(info.v3), 2487 &error)); 2488 if (info.v3) { 2489 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 2490 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2491 diraft_ret, &diraft); 2492 error = 0; 2493 } 2494 /* fall through */ 2495 2496 nfsmout: 2497 *mrq = info.mreq; 2498 nlookup_done(&nd); 2499 if (dirp) 2500 vrele(dirp); 2501 if (xp) 2502 vrele(xp); 2503 if (dvp) { 2504 if (dvp == vp) 2505 vrele(dvp); 2506 else 2507 vput(dvp); 2508 } 2509 if (vp) 2510 vput(vp); 2511 return(error); 2512 } 2513 2514 /* 2515 * nfs symbolic link service 2516 */ 2517 int 2518 nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2519 struct thread *td, struct mbuf **mrq) 2520 { 2521 struct sockaddr *nam = nfsd->nd_nam; 2522 struct ucred *cred = &nfsd->nd_cr; 2523 struct vattr va, dirfor, diraft; 2524 struct nlookupdata nd; 2525 struct vattr *vap = &va; 2526 struct nfsv2_sattr *sp; 2527 char *pathcp = NULL; 2528 struct uio io; 2529 struct iovec iv; 2530 int error = 0, len, len2, dirfor_ret = 1, diraft_ret = 1; 2531 struct vnode *dirp; 2532 struct vnode *vp; 2533 struct vnode *dvp; 2534 nfsfh_t nfh; 2535 fhandle_t *fhp; 2536 struct nfsm_info info; 2537 2538 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 2539 nlookup_zero(&nd); 2540 dirp = NULL; 2541 dvp = NULL; 2542 vp = NULL; 2543 2544 info.mrep = nfsd->nd_mrep; 2545 info.mreq = NULL; 2546 info.md = nfsd->nd_md; 2547 info.dpos = nfsd->nd_dpos; 2548 info.v3 = (nfsd->nd_flag & ND_NFSV3); 2549 2550 fhp = &nfh.fh_generic; 2551 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 2552 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 2553 2554 error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp, 2555 fhp, len, slp, nam, &info.md, &info.dpos, &dirp, 2556 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2557 if (dirp) { 2558 if (info.v3) 2559 dirfor_ret = VOP_GETATTR(dirp, &dirfor); 2560 } 2561 if (error) 2562 goto out; 2563 2564 VATTR_NULL(vap); 2565 if (info.v3) { 2566 ERROROUT(nfsm_srvsattr(&info, vap)); 2567 } 2568 NEGATIVEOUT(len2 = nfsm_strsiz(&info, NFS_MAXPATHLEN)); 2569 pathcp = kmalloc(len2 + 1, M_TEMP, M_WAITOK); 2570 iv.iov_base = pathcp; 2571 iv.iov_len = len2; 2572 io.uio_resid = len2; 2573 io.uio_offset = 0; 2574 io.uio_iov = &iv; 2575 io.uio_iovcnt = 1; 2576 io.uio_segflg = UIO_SYSSPACE; 2577 io.uio_rw = UIO_READ; 2578 io.uio_td = NULL; 2579 ERROROUT(nfsm_mtouio(&info, &io, len2)); 2580 if (info.v3 == 0) { 2581 NULLOUT(sp = nfsm_dissect(&info, NFSX_V2SATTR)); 2582 vap->va_mode = nfstov_mode(sp->sa_mode); 2583 } 2584 *(pathcp + len2) = '\0'; 2585 if (vp) { 2586 error = EEXIST; 2587 goto out; 2588 } 2589 2590 if (vap->va_mode == (mode_t)VNOVAL) 2591 vap->va_mode = 0; 2592 if (dvp != vp) 2593 vn_unlock(dvp); 2594 error = VOP_NSYMLINK(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap, pathcp); 2595 vrele(dvp); 2596 dvp = NULL; 2597 if (error == 0) { 2598 bzero(&fhp->fh_fid, sizeof(fhp->fh_fid)); 2599 error = VFS_VPTOFH(vp, &fhp->fh_fid); 2600 if (!error) 2601 error = VOP_GETATTR(vp, vap); 2602 } 2603 2604 out: 2605 if (dvp) { 2606 if (dvp == vp) 2607 vrele(dvp); 2608 else 2609 vput(dvp); 2610 } 2611 if (vp) { 2612 vput(vp); 2613 vp = NULL; 2614 } 2615 if (pathcp) { 2616 kfree(pathcp, M_TEMP); 2617 pathcp = NULL; 2618 } 2619 if (dirp) { 2620 diraft_ret = VOP_GETATTR(dirp, &diraft); 2621 vrele(dirp); 2622 dirp = NULL; 2623 } 2624 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2625 NFSX_SRVFH(info.v3) + NFSX_POSTOPATTR(info.v3) + 2626 NFSX_WCCDATA(info.v3), 2627 &error)); 2628 if (info.v3) { 2629 if (!error) { 2630 nfsm_srvpostop_fh(&info, fhp); 2631 nfsm_srvpostop_attr(&info, nfsd, 0, vap); 2632 } 2633 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2634 diraft_ret, &diraft); 2635 } 2636 error = 0; 2637 /* fall through */ 2638 2639 nfsmout: 2640 *mrq = info.mreq; 2641 nlookup_done(&nd); 2642 if (vp) 2643 vput(vp); 2644 if (dirp) 2645 vrele(dirp); 2646 if (pathcp) 2647 kfree(pathcp, M_TEMP); 2648 return (error); 2649 } 2650 2651 /* 2652 * nfs mkdir service 2653 */ 2654 int 2655 nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2656 struct thread *td, struct mbuf **mrq) 2657 { 2658 struct sockaddr *nam = nfsd->nd_nam; 2659 struct ucred *cred = &nfsd->nd_cr; 2660 struct vattr va, dirfor, diraft; 2661 struct vattr *vap = &va; 2662 struct nfs_fattr *fp; 2663 struct nlookupdata nd; 2664 u_int32_t *tl; 2665 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 2666 struct vnode *dirp; 2667 struct vnode *dvp; 2668 struct vnode *vp; 2669 nfsfh_t nfh; 2670 fhandle_t *fhp; 2671 struct nfsm_info info; 2672 2673 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 2674 nlookup_zero(&nd); 2675 dirp = NULL; 2676 dvp = NULL; 2677 vp = NULL; 2678 2679 info.dpos = nfsd->nd_dpos; 2680 info.mrep = nfsd->nd_mrep; 2681 info.mreq = NULL; 2682 info.md = nfsd->nd_md; 2683 info.v3 = (nfsd->nd_flag & ND_NFSV3); 2684 2685 fhp = &nfh.fh_generic; 2686 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 2687 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 2688 2689 error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp, 2690 fhp, len, slp, nam, &info.md, &info.dpos, &dirp, 2691 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2692 if (dirp) { 2693 if (info.v3) 2694 dirfor_ret = VOP_GETATTR(dirp, &dirfor); 2695 } 2696 if (error) { 2697 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2698 NFSX_WCCDATA(info.v3), &error)); 2699 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2700 diraft_ret, &diraft); 2701 error = 0; 2702 goto nfsmout; 2703 } 2704 VATTR_NULL(vap); 2705 if (info.v3) { 2706 ERROROUT(nfsm_srvsattr(&info, vap)); 2707 } else { 2708 NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED)); 2709 vap->va_mode = nfstov_mode(*tl++); 2710 } 2711 2712 /* 2713 * At this point nd.ni_dvp is referenced and exclusively locked and 2714 * nd.ni_vp, if it exists, is referenced but not locked. 2715 */ 2716 2717 vap->va_type = VDIR; 2718 if (vp != NULL) { 2719 error = EEXIST; 2720 goto out; 2721 } 2722 2723 /* 2724 * Issue mkdir op. Since SAVESTART is not set, the pathname 2725 * component is freed by the VOP call. This will fill-in 2726 * nd.ni_vp, reference, and exclusively lock it. 2727 */ 2728 if (vap->va_mode == (mode_t)VNOVAL) 2729 vap->va_mode = 0; 2730 vn_unlock(dvp); 2731 error = VOP_NMKDIR(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap); 2732 vrele(dvp); 2733 dvp = NULL; 2734 2735 if (error == 0) { 2736 bzero(&fhp->fh_fid, sizeof(fhp->fh_fid)); 2737 error = VFS_VPTOFH(vp, &fhp->fh_fid); 2738 if (error == 0) 2739 error = VOP_GETATTR(vp, vap); 2740 } 2741 out: 2742 if (dirp) 2743 diraft_ret = VOP_GETATTR(dirp, &diraft); 2744 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2745 NFSX_SRVFH(info.v3) + NFSX_POSTOPATTR(info.v3) + 2746 NFSX_WCCDATA(info.v3), 2747 &error)); 2748 if (info.v3) { 2749 if (!error) { 2750 nfsm_srvpostop_fh(&info, fhp); 2751 nfsm_srvpostop_attr(&info, nfsd, 0, vap); 2752 } 2753 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2754 diraft_ret, &diraft); 2755 } else { 2756 nfsm_srvfhtom(&info, fhp); 2757 fp = nfsm_build(&info, NFSX_V2FATTR); 2758 nfsm_srvfattr(nfsd, vap, fp); 2759 } 2760 error = 0; 2761 /* fall through */ 2762 2763 nfsmout: 2764 *mrq = info.mreq; 2765 nlookup_done(&nd); 2766 if (dirp) 2767 vrele(dirp); 2768 if (dvp) { 2769 if (dvp == vp) 2770 vrele(dvp); 2771 else 2772 vput(dvp); 2773 } 2774 if (vp) 2775 vput(vp); 2776 return (error); 2777 } 2778 2779 /* 2780 * nfs rmdir service 2781 */ 2782 int 2783 nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2784 struct thread *td, struct mbuf **mrq) 2785 { 2786 struct sockaddr *nam = nfsd->nd_nam; 2787 struct ucred *cred = &nfsd->nd_cr; 2788 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 2789 struct vnode *dirp; 2790 struct vnode *dvp; 2791 struct vnode *vp; 2792 struct vattr dirfor, diraft; 2793 nfsfh_t nfh; 2794 fhandle_t *fhp; 2795 struct nlookupdata nd; 2796 struct nfsm_info info; 2797 2798 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 2799 nlookup_zero(&nd); 2800 dirp = NULL; 2801 dvp = NULL; 2802 vp = NULL; 2803 2804 info.mrep = nfsd->nd_mrep; 2805 info.mreq = NULL; 2806 info.md = nfsd->nd_md; 2807 info.dpos = nfsd->nd_dpos; 2808 info.v3 = (nfsd->nd_flag & ND_NFSV3); 2809 2810 fhp = &nfh.fh_generic; 2811 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 2812 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 2813 2814 error = nfs_namei(&nd, cred, NLC_DELETE, &dvp, &vp, 2815 fhp, len, slp, nam, &info.md, &info.dpos, &dirp, 2816 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2817 if (dirp) { 2818 if (info.v3) 2819 dirfor_ret = VOP_GETATTR(dirp, &dirfor); 2820 } 2821 if (error) { 2822 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2823 NFSX_WCCDATA(info.v3), &error)); 2824 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2825 diraft_ret, &diraft); 2826 error = 0; 2827 goto nfsmout; 2828 } 2829 if (vp->v_type != VDIR) { 2830 error = ENOTDIR; 2831 goto out; 2832 } 2833 2834 /* 2835 * The root of a mounted filesystem cannot be deleted. 2836 */ 2837 if (vp->v_flag & VROOT) 2838 error = EBUSY; 2839 out: 2840 /* 2841 * Issue or abort op. Since SAVESTART is not set, path name 2842 * component is freed by the VOP after either. 2843 */ 2844 if (!error) { 2845 if (dvp != vp) 2846 vn_unlock(dvp); 2847 vput(vp); 2848 vp = NULL; 2849 error = VOP_NRMDIR(&nd.nl_nch, dvp, nd.nl_cred); 2850 vrele(dvp); 2851 dvp = NULL; 2852 } 2853 nlookup_done(&nd); 2854 2855 if (dirp) 2856 diraft_ret = VOP_GETATTR(dirp, &diraft); 2857 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_WCCDATA(info.v3), &error)); 2858 if (info.v3) { 2859 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2860 diraft_ret, &diraft); 2861 error = 0; 2862 } 2863 /* fall through */ 2864 2865 nfsmout: 2866 *mrq = info.mreq; 2867 if (dvp) { 2868 if (dvp == vp) 2869 vrele(dvp); 2870 else 2871 vput(dvp); 2872 } 2873 nlookup_done(&nd); 2874 if (dirp) 2875 vrele(dirp); 2876 if (vp) 2877 vput(vp); 2878 return(error); 2879 } 2880 2881 /* 2882 * nfs readdir service 2883 * - mallocs what it thinks is enough to read 2884 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 2885 * - calls VOP_READDIR() 2886 * - loops around building the reply 2887 * if the output generated exceeds count break out of loop 2888 * The nfsm_clget macro is used here so that the reply will be packed 2889 * tightly in mbuf clusters. 2890 * - it only knows that it has encountered eof when the VOP_READDIR() 2891 * reads nothing 2892 * - as such one readdir rpc will return eof false although you are there 2893 * and then the next will return eof 2894 * - it trims out records with d_fileno == 0 2895 * this doesn't matter for Unix clients, but they might confuse clients 2896 * for other os'. 2897 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 2898 * than requested, but this may not apply to all filesystems. For 2899 * example, client NFS does not { although it is never remote mounted 2900 * anyhow } 2901 * The alternate call nfsrv_readdirplus() does lookups as well. 2902 * PS: The NFS protocol spec. does not clarify what the "count" byte 2903 * argument is a count of.. just name strings and file id's or the 2904 * entire reply rpc or ... 2905 * I tried just file name and id sizes and it confused the Sun client, 2906 * so I am using the full rpc size now. The "paranoia.." comment refers 2907 * to including the status longwords that are not a part of the dir. 2908 * "entry" structures, but are in the rpc. 2909 */ 2910 struct flrep { 2911 nfsuint64 fl_off; 2912 u_int32_t fl_postopok; 2913 u_int32_t fl_fattr[NFSX_V3FATTR / sizeof (u_int32_t)]; 2914 u_int32_t fl_fhok; 2915 u_int32_t fl_fhsize; 2916 u_int32_t fl_nfh[NFSX_V3FH / sizeof (u_int32_t)]; 2917 }; 2918 2919 int 2920 nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2921 struct thread *td, struct mbuf **mrq) 2922 { 2923 struct sockaddr *nam = nfsd->nd_nam; 2924 struct ucred *cred = &nfsd->nd_cr; 2925 char *bp, *be; 2926 struct dirent *dp; 2927 caddr_t cp; 2928 u_int32_t *tl; 2929 struct mbuf *mp1, *mp2; 2930 char *cpos, *cend, *rbuf; 2931 struct vnode *vp = NULL; 2932 struct mount *mp = NULL; 2933 struct vattr at; 2934 nfsfh_t nfh; 2935 fhandle_t *fhp; 2936 struct uio io; 2937 struct iovec iv; 2938 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1; 2939 int siz, cnt, fullsiz, eofflag, rdonly, ncookies; 2940 u_quad_t off, toff; 2941 #if 0 2942 u_quad_t verf; 2943 #endif 2944 off_t *cookies = NULL, *cookiep; 2945 struct nfsm_info info; 2946 2947 info.mrep = nfsd->nd_mrep; 2948 info.mreq = NULL; 2949 info.md = nfsd->nd_md; 2950 info.dpos = nfsd->nd_dpos; 2951 info.v3 = (nfsd->nd_flag & ND_NFSV3); 2952 2953 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 2954 fhp = &nfh.fh_generic; 2955 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 2956 if (info.v3) { 2957 NULLOUT(tl = nfsm_dissect(&info, 5 * NFSX_UNSIGNED)); 2958 toff = fxdr_hyper(tl); 2959 tl += 2; 2960 #if 0 2961 verf = fxdr_hyper(tl); 2962 #endif 2963 tl += 2; 2964 } else { 2965 NULLOUT(tl = nfsm_dissect(&info, 2 * NFSX_UNSIGNED)); 2966 toff = fxdr_unsigned(u_quad_t, *tl++); 2967 #if 0 2968 verf = 0; /* shut up gcc */ 2969 #endif 2970 } 2971 off = toff; 2972 cnt = fxdr_unsigned(int, *tl); 2973 siz = roundup2(cnt, DIRBLKSIZ); 2974 xfer = NFS_SRVMAXDATA(nfsd); 2975 if ((unsigned)cnt > xfer) 2976 cnt = xfer; 2977 if ((unsigned)siz > xfer) 2978 siz = xfer; 2979 fullsiz = siz; 2980 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 2981 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 2982 if (!error && vp->v_type != VDIR) { 2983 error = ENOTDIR; 2984 vput(vp); 2985 vp = NULL; 2986 } 2987 if (error) { 2988 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error)); 2989 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 2990 error = 0; 2991 goto nfsmout; 2992 } 2993 2994 /* 2995 * Obtain lock on vnode for this section of the code 2996 */ 2997 2998 if (info.v3) { 2999 error = getret = VOP_GETATTR(vp, &at); 3000 #if 0 3001 /* 3002 * XXX This check may be too strict for Solaris 2.5 clients. 3003 */ 3004 if (!error && toff && verf && verf != at.va_filerev) 3005 error = NFSERR_BAD_COOKIE; 3006 #endif 3007 } 3008 if (!error) 3009 error = nfsrv_access(mp, vp, VEXEC, cred, rdonly, td, 0); 3010 if (error) { 3011 vput(vp); 3012 vp = NULL; 3013 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3014 NFSX_POSTOPATTR(info.v3), &error)); 3015 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3016 error = 0; 3017 goto nfsmout; 3018 } 3019 vn_unlock(vp); 3020 3021 /* 3022 * end section. Allocate rbuf and continue 3023 */ 3024 rbuf = kmalloc(siz, M_TEMP, M_WAITOK); 3025 again: 3026 iv.iov_base = rbuf; 3027 iv.iov_len = fullsiz; 3028 io.uio_iov = &iv; 3029 io.uio_iovcnt = 1; 3030 io.uio_offset = (off_t)off; 3031 io.uio_resid = fullsiz; 3032 io.uio_segflg = UIO_SYSSPACE; 3033 io.uio_rw = UIO_READ; 3034 io.uio_td = NULL; 3035 eofflag = 0; 3036 if (cookies) { 3037 kfree((caddr_t)cookies, M_TEMP); 3038 cookies = NULL; 3039 } 3040 error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies); 3041 off = (off_t)io.uio_offset; 3042 if (!cookies && !error) 3043 error = NFSERR_PERM; 3044 if (info.v3) { 3045 getret = VOP_GETATTR(vp, &at); 3046 if (!error) 3047 error = getret; 3048 } 3049 if (error) { 3050 vrele(vp); 3051 vp = NULL; 3052 kfree((caddr_t)rbuf, M_TEMP); 3053 if (cookies) 3054 kfree((caddr_t)cookies, M_TEMP); 3055 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3056 NFSX_POSTOPATTR(info.v3), &error)); 3057 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3058 error = 0; 3059 goto nfsmout; 3060 } 3061 if (io.uio_resid) { 3062 siz -= io.uio_resid; 3063 3064 /* 3065 * If nothing read, return eof 3066 * rpc reply 3067 */ 3068 if (siz == 0) { 3069 vrele(vp); 3070 vp = NULL; 3071 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3072 NFSX_POSTOPATTR(info.v3) + 3073 NFSX_COOKIEVERF(info.v3) + 3074 2 * NFSX_UNSIGNED, 3075 &error)); 3076 if (info.v3) { 3077 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3078 tl = nfsm_build(&info, 4 * NFSX_UNSIGNED); 3079 txdr_hyper(at.va_filerev, tl); 3080 tl += 2; 3081 } else 3082 tl = nfsm_build(&info, 2 * NFSX_UNSIGNED); 3083 *tl++ = nfs_false; 3084 *tl = nfs_true; 3085 kfree((caddr_t)rbuf, M_TEMP); 3086 kfree((caddr_t)cookies, M_TEMP); 3087 error = 0; 3088 goto nfsmout; 3089 } 3090 } 3091 3092 /* 3093 * Check for degenerate cases of nothing useful read. 3094 * If so go try again 3095 */ 3096 cpos = rbuf; 3097 cend = rbuf + siz; 3098 dp = (struct dirent *)cpos; 3099 cookiep = cookies; 3100 /* 3101 * For some reason FreeBSD's ufs_readdir() chooses to back the 3102 * directory offset up to a block boundary, so it is necessary to 3103 * skip over the records that preceed the requested offset. This 3104 * requires the assumption that file offset cookies monotonically 3105 * increase. 3106 */ 3107 while (cpos < cend && ncookies > 0 && 3108 (dp->d_ino == 0 || dp->d_type == DT_WHT || 3109 ((u_quad_t)(*cookiep)) <= toff)) { 3110 dp = _DIRENT_NEXT(dp); 3111 cpos = (char *)dp; 3112 cookiep++; 3113 ncookies--; 3114 } 3115 if (cpos >= cend || ncookies == 0) { 3116 toff = off; 3117 siz = fullsiz; 3118 goto again; 3119 } 3120 3121 len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 3122 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3123 NFSX_POSTOPATTR(info.v3) + 3124 NFSX_COOKIEVERF(info.v3) + siz, 3125 &error)); 3126 if (info.v3) { 3127 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3128 tl = nfsm_build(&info, 2 * NFSX_UNSIGNED); 3129 txdr_hyper(at.va_filerev, tl); 3130 } 3131 mp1 = mp2 = info.mb; 3132 bp = info.bpos; 3133 be = bp + M_TRAILINGSPACE(mp1); 3134 3135 /* Loop through the records and build reply */ 3136 while (cpos < cend && ncookies > 0) { 3137 if (dp->d_ino != 0 && dp->d_type != DT_WHT) { 3138 nlen = dp->d_namlen; 3139 rem = nfsm_rndup(nlen) - nlen; 3140 len += (4 * NFSX_UNSIGNED + nlen + rem); 3141 if (info.v3) 3142 len += 2 * NFSX_UNSIGNED; 3143 if (len > cnt) { 3144 eofflag = 0; 3145 break; 3146 } 3147 /* 3148 * Build the directory record xdr from 3149 * the dirent entry. 3150 */ 3151 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3152 *tl = nfs_true; 3153 bp += NFSX_UNSIGNED; 3154 if (info.v3) { 3155 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3156 *tl = txdr_unsigned(dp->d_ino >> 32); 3157 bp += NFSX_UNSIGNED; 3158 } 3159 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3160 *tl = txdr_unsigned(dp->d_ino); 3161 bp += NFSX_UNSIGNED; 3162 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3163 *tl = txdr_unsigned(nlen); 3164 bp += NFSX_UNSIGNED; 3165 3166 /* And loop around copying the name */ 3167 xfer = nlen; 3168 cp = dp->d_name; 3169 while (xfer > 0) { 3170 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3171 if ((bp+xfer) > be) 3172 tsiz = be-bp; 3173 else 3174 tsiz = xfer; 3175 bcopy(cp, bp, tsiz); 3176 bp += tsiz; 3177 xfer -= tsiz; 3178 if (xfer > 0) 3179 cp += tsiz; 3180 } 3181 /* And null pad to a int32_t boundary */ 3182 for (i = 0; i < rem; i++) 3183 *bp++ = '\0'; 3184 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3185 3186 /* Finish off the record */ 3187 if (info.v3) { 3188 *tl = txdr_unsigned(*cookiep >> 32); 3189 bp += NFSX_UNSIGNED; 3190 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3191 } 3192 *tl = txdr_unsigned(*cookiep); 3193 bp += NFSX_UNSIGNED; 3194 } 3195 dp = _DIRENT_NEXT(dp); 3196 cpos = (char *)dp; 3197 cookiep++; 3198 ncookies--; 3199 } 3200 vrele(vp); 3201 vp = NULL; 3202 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3203 *tl = nfs_false; 3204 bp += NFSX_UNSIGNED; 3205 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3206 if (eofflag) 3207 *tl = nfs_true; 3208 else 3209 *tl = nfs_false; 3210 bp += NFSX_UNSIGNED; 3211 if (mp1 != info.mb) { 3212 if (bp < be) 3213 mp1->m_len = bp - mtod(mp1, caddr_t); 3214 } else 3215 mp1->m_len += bp - info.bpos; 3216 kfree((caddr_t)rbuf, M_TEMP); 3217 kfree((caddr_t)cookies, M_TEMP); 3218 3219 nfsmout: 3220 *mrq = info.mreq; 3221 if (vp) 3222 vrele(vp); 3223 return(error); 3224 } 3225 3226 int 3227 nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3228 struct thread *td, struct mbuf **mrq) 3229 { 3230 struct sockaddr *nam = nfsd->nd_nam; 3231 struct ucred *cred = &nfsd->nd_cr; 3232 char *bp, *be; 3233 struct dirent *dp; 3234 caddr_t cp; 3235 u_int32_t *tl; 3236 struct mbuf *mp1, *mp2; 3237 char *cpos, *cend, *rbuf; 3238 struct vnode *vp = NULL, *nvp; 3239 struct mount *mp = NULL; 3240 struct flrep fl; 3241 nfsfh_t nfh; 3242 fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh; 3243 struct uio io; 3244 struct iovec iv; 3245 struct vattr va, at, *vap = &va; 3246 struct nfs_fattr *fp; 3247 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1; 3248 int siz, cnt, fullsiz, eofflag, rdonly, dirlen, ncookies; 3249 u_quad_t off, toff; 3250 #if 0 3251 u_quad_t verf; 3252 #endif 3253 off_t *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */ 3254 struct nfsm_info info; 3255 3256 info.mrep = nfsd->nd_mrep; 3257 info.mreq = NULL; 3258 info.md = nfsd->nd_md; 3259 info.dpos = nfsd->nd_dpos; 3260 info.v3 = (nfsd->nd_flag & ND_NFSV3); 3261 3262 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3263 fhp = &nfh.fh_generic; 3264 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 3265 NULLOUT(tl = nfsm_dissect(&info, 6 * NFSX_UNSIGNED)); 3266 toff = fxdr_hyper(tl); 3267 tl += 2; 3268 #if 0 3269 verf = fxdr_hyper(tl); 3270 #endif 3271 tl += 2; 3272 siz = fxdr_unsigned(int, *tl++); 3273 cnt = fxdr_unsigned(int, *tl); 3274 off = toff; 3275 siz = roundup2(siz, DIRBLKSIZ); 3276 xfer = NFS_SRVMAXDATA(nfsd); 3277 if ((unsigned)cnt > xfer) 3278 cnt = xfer; 3279 if ((unsigned)siz > xfer) 3280 siz = xfer; 3281 fullsiz = siz; 3282 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 3283 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 3284 if (!error && vp->v_type != VDIR) { 3285 error = ENOTDIR; 3286 vput(vp); 3287 vp = NULL; 3288 } 3289 if (error) { 3290 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error)); 3291 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3292 error = 0; 3293 goto nfsmout; 3294 } 3295 error = getret = VOP_GETATTR(vp, &at); 3296 #if 0 3297 /* 3298 * XXX This check may be too strict for Solaris 2.5 clients. 3299 */ 3300 if (!error && toff && verf && verf != at.va_filerev) 3301 error = NFSERR_BAD_COOKIE; 3302 #endif 3303 if (!error) { 3304 error = nfsrv_access(mp, vp, VEXEC, cred, rdonly, td, 0); 3305 } 3306 if (error) { 3307 vput(vp); 3308 vp = NULL; 3309 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3310 NFSX_V3POSTOPATTR, &error)); 3311 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3312 error = 0; 3313 goto nfsmout; 3314 } 3315 vn_unlock(vp); 3316 rbuf = kmalloc(siz, M_TEMP, M_WAITOK); 3317 again: 3318 iv.iov_base = rbuf; 3319 iv.iov_len = fullsiz; 3320 io.uio_iov = &iv; 3321 io.uio_iovcnt = 1; 3322 io.uio_offset = (off_t)off; 3323 io.uio_resid = fullsiz; 3324 io.uio_segflg = UIO_SYSSPACE; 3325 io.uio_rw = UIO_READ; 3326 io.uio_td = NULL; 3327 eofflag = 0; 3328 if (cookies) { 3329 kfree((caddr_t)cookies, M_TEMP); 3330 cookies = NULL; 3331 } 3332 error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies); 3333 off = (u_quad_t)io.uio_offset; 3334 getret = VOP_GETATTR(vp, &at); 3335 if (!cookies && !error) 3336 error = NFSERR_PERM; 3337 if (!error) 3338 error = getret; 3339 if (error) { 3340 vrele(vp); 3341 vp = NULL; 3342 if (cookies) 3343 kfree((caddr_t)cookies, M_TEMP); 3344 kfree((caddr_t)rbuf, M_TEMP); 3345 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3346 NFSX_V3POSTOPATTR, &error)); 3347 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3348 error = 0; 3349 goto nfsmout; 3350 } 3351 if (io.uio_resid) { 3352 siz -= io.uio_resid; 3353 3354 /* 3355 * If nothing read, return eof 3356 * rpc reply 3357 */ 3358 if (siz == 0) { 3359 vrele(vp); 3360 vp = NULL; 3361 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3362 NFSX_V3POSTOPATTR + 3363 NFSX_V3COOKIEVERF + 3364 2 * NFSX_UNSIGNED, 3365 &error)); 3366 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3367 tl = nfsm_build(&info, 4 * NFSX_UNSIGNED); 3368 txdr_hyper(at.va_filerev, tl); 3369 tl += 2; 3370 *tl++ = nfs_false; 3371 *tl = nfs_true; 3372 kfree((caddr_t)cookies, M_TEMP); 3373 kfree((caddr_t)rbuf, M_TEMP); 3374 error = 0; 3375 goto nfsmout; 3376 } 3377 } 3378 3379 /* 3380 * Check for degenerate cases of nothing useful read. 3381 * If so go try again 3382 */ 3383 cpos = rbuf; 3384 cend = rbuf + siz; 3385 dp = (struct dirent *)cpos; 3386 cookiep = cookies; 3387 /* 3388 * For some reason FreeBSD's ufs_readdir() chooses to back the 3389 * directory offset up to a block boundary, so it is necessary to 3390 * skip over the records that preceed the requested offset. This 3391 * requires the assumption that file offset cookies monotonically 3392 * increase. 3393 */ 3394 while (cpos < cend && ncookies > 0 && 3395 (dp->d_ino == 0 || dp->d_type == DT_WHT || 3396 ((u_quad_t)(*cookiep)) <= toff)) { 3397 dp = _DIRENT_NEXT(dp); 3398 cpos = (char *)dp; 3399 cookiep++; 3400 ncookies--; 3401 } 3402 if (cpos >= cend || ncookies == 0) { 3403 toff = off; 3404 siz = fullsiz; 3405 goto again; 3406 } 3407 3408 /* 3409 * Probe one of the directory entries to see if the filesystem 3410 * supports VGET. 3411 */ 3412 if (VFS_VGET(vp->v_mount, vp, dp->d_ino, &nvp) == EOPNOTSUPP) { 3413 error = NFSERR_NOTSUPP; 3414 vrele(vp); 3415 vp = NULL; 3416 kfree((caddr_t)cookies, M_TEMP); 3417 kfree((caddr_t)rbuf, M_TEMP); 3418 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3419 NFSX_V3POSTOPATTR, &error)); 3420 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3421 error = 0; 3422 goto nfsmout; 3423 } 3424 if (nvp) { 3425 vput(nvp); 3426 nvp = NULL; 3427 } 3428 3429 dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 3430 2 * NFSX_UNSIGNED; 3431 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, cnt, &error)); 3432 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3433 tl = nfsm_build(&info, 2 * NFSX_UNSIGNED); 3434 txdr_hyper(at.va_filerev, tl); 3435 mp1 = mp2 = info.mb; 3436 bp = info.bpos; 3437 be = bp + M_TRAILINGSPACE(mp1); 3438 3439 /* Loop through the records and build reply */ 3440 while (cpos < cend && ncookies > 0) { 3441 if (dp->d_ino != 0 && dp->d_type != DT_WHT) { 3442 nlen = dp->d_namlen; 3443 rem = nfsm_rndup(nlen) - nlen; 3444 3445 /* 3446 * For readdir_and_lookup get the vnode using 3447 * the file number. 3448 */ 3449 if (VFS_VGET(vp->v_mount, vp, dp->d_ino, &nvp)) 3450 goto invalid; 3451 bzero((caddr_t)nfhp, NFSX_V3FH); 3452 nfhp->fh_fsid = fhp->fh_fsid; 3453 if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) { 3454 vput(nvp); 3455 nvp = NULL; 3456 goto invalid; 3457 } 3458 if (VOP_GETATTR(nvp, vap)) { 3459 vput(nvp); 3460 nvp = NULL; 3461 goto invalid; 3462 } 3463 vput(nvp); 3464 nvp = NULL; 3465 3466 /* 3467 * If either the dircount or maxcount will be 3468 * exceeded, get out now. Both of these lengths 3469 * are calculated conservatively, including all 3470 * XDR overheads. 3471 */ 3472 len += (8 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH + 3473 NFSX_V3POSTOPATTR); 3474 dirlen += (6 * NFSX_UNSIGNED + nlen + rem); 3475 if (len > cnt || dirlen > fullsiz) { 3476 eofflag = 0; 3477 break; 3478 } 3479 3480 /* 3481 * Build the directory record xdr from 3482 * the dirent entry. 3483 */ 3484 fp = (struct nfs_fattr *)&fl.fl_fattr; 3485 nfsm_srvfattr(nfsd, vap, fp); 3486 fl.fl_off.nfsuquad[0] = txdr_unsigned(*cookiep >> 32); 3487 fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep); 3488 fl.fl_postopok = nfs_true; 3489 fl.fl_fhok = nfs_true; 3490 fl.fl_fhsize = txdr_unsigned(NFSX_V3FH); 3491 3492 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3493 *tl = nfs_true; 3494 bp += NFSX_UNSIGNED; 3495 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3496 *tl = txdr_unsigned(dp->d_ino >> 32); 3497 bp += NFSX_UNSIGNED; 3498 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3499 *tl = txdr_unsigned(dp->d_ino); 3500 bp += NFSX_UNSIGNED; 3501 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3502 *tl = txdr_unsigned(nlen); 3503 bp += NFSX_UNSIGNED; 3504 3505 /* And loop around copying the name */ 3506 xfer = nlen; 3507 cp = dp->d_name; 3508 while (xfer > 0) { 3509 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3510 if ((bp + xfer) > be) 3511 tsiz = be - bp; 3512 else 3513 tsiz = xfer; 3514 bcopy(cp, bp, tsiz); 3515 bp += tsiz; 3516 xfer -= tsiz; 3517 cp += tsiz; 3518 } 3519 /* And null pad to a int32_t boundary */ 3520 for (i = 0; i < rem; i++) 3521 *bp++ = '\0'; 3522 3523 /* 3524 * Now copy the flrep structure out. 3525 */ 3526 xfer = sizeof (struct flrep); 3527 cp = (caddr_t)&fl; 3528 while (xfer > 0) { 3529 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3530 if ((bp + xfer) > be) 3531 tsiz = be - bp; 3532 else 3533 tsiz = xfer; 3534 bcopy(cp, bp, tsiz); 3535 bp += tsiz; 3536 xfer -= tsiz; 3537 cp += tsiz; 3538 } 3539 } 3540 invalid: 3541 dp = _DIRENT_NEXT(dp); 3542 cpos = (char *)dp; 3543 cookiep++; 3544 ncookies--; 3545 } 3546 vrele(vp); 3547 vp = NULL; 3548 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3549 *tl = nfs_false; 3550 bp += NFSX_UNSIGNED; 3551 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3552 if (eofflag) 3553 *tl = nfs_true; 3554 else 3555 *tl = nfs_false; 3556 bp += NFSX_UNSIGNED; 3557 if (mp1 != info.mb) { 3558 if (bp < be) 3559 mp1->m_len = bp - mtod(mp1, caddr_t); 3560 } else 3561 mp1->m_len += bp - info.bpos; 3562 kfree((caddr_t)cookies, M_TEMP); 3563 kfree((caddr_t)rbuf, M_TEMP); 3564 nfsmout: 3565 *mrq = info.mreq; 3566 if (vp) 3567 vrele(vp); 3568 return(error); 3569 } 3570 3571 /* 3572 * nfs commit service 3573 */ 3574 int 3575 nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3576 struct thread *td, struct mbuf **mrq) 3577 { 3578 struct sockaddr *nam = nfsd->nd_nam; 3579 struct ucred *cred = &nfsd->nd_cr; 3580 struct vattr bfor, aft; 3581 struct vnode *vp = NULL; 3582 struct mount *mp = NULL; 3583 nfsfh_t nfh; 3584 fhandle_t *fhp; 3585 u_int32_t *tl; 3586 int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt; 3587 u_quad_t off; 3588 struct nfsm_info info; 3589 3590 info.mrep = nfsd->nd_mrep; 3591 info.mreq = NULL; 3592 info.md = nfsd->nd_md; 3593 info.dpos = nfsd->nd_dpos; 3594 3595 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3596 fhp = &nfh.fh_generic; 3597 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 3598 NULLOUT(tl = nfsm_dissect(&info, 3 * NFSX_UNSIGNED)); 3599 3600 /* 3601 * XXX At this time VOP_FSYNC() does not accept offset and byte 3602 * count parameters, so these arguments are useless (someday maybe). 3603 */ 3604 off = fxdr_hyper(tl); 3605 tl += 2; 3606 cnt = fxdr_unsigned(int, *tl); 3607 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 3608 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 3609 if (error) { 3610 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3611 2 * NFSX_UNSIGNED, &error)); 3612 nfsm_srvwcc_data(&info, nfsd, for_ret, &bfor, 3613 aft_ret, &aft); 3614 error = 0; 3615 goto nfsmout; 3616 } 3617 for_ret = VOP_GETATTR(vp, &bfor); 3618 3619 /* 3620 * RFC 1813 3.3.21: If count is 0, a flush from offset to the end of 3621 * file is done. At this time VOP_FSYNC does not accept offset and 3622 * byte count parameters, so call VOP_FSYNC the whole file for now. 3623 */ 3624 if (cnt == 0 || cnt > MAX_COMMIT_COUNT) { 3625 /* 3626 * Give up and do the whole thing 3627 */ 3628 if (vp->v_object && 3629 (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) { 3630 vm_object_page_clean(vp->v_object, 0, 0, OBJPC_SYNC); 3631 } 3632 error = VOP_FSYNC(vp, MNT_WAIT, 0); 3633 } else { 3634 /* 3635 * Locate and synchronously write any buffers that fall 3636 * into the requested range. Note: we are assuming that 3637 * f_iosize is a power of 2. 3638 */ 3639 int iosize = vp->v_mount->mnt_stat.f_iosize; 3640 int iomask = iosize - 1; 3641 off_t loffset; 3642 3643 /* 3644 * Align to iosize boundry, super-align to page boundry. 3645 */ 3646 if (off & iomask) { 3647 cnt += off & iomask; 3648 off &= ~(u_quad_t)iomask; 3649 } 3650 if (off & PAGE_MASK) { 3651 cnt += off & PAGE_MASK; 3652 off &= ~(u_quad_t)PAGE_MASK; 3653 } 3654 loffset = off; 3655 3656 if (vp->v_object && 3657 (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) { 3658 vm_object_page_clean(vp->v_object, off / PAGE_SIZE, 3659 (cnt + PAGE_MASK) / PAGE_SIZE, OBJPC_SYNC); 3660 } 3661 3662 crit_enter(); 3663 while (error == 0 || cnt > 0) { 3664 struct buf *bp; 3665 3666 /* 3667 * If we have a buffer and it is marked B_DELWRI we 3668 * have to lock and write it. Otherwise the prior 3669 * write is assumed to have already been committed. 3670 * 3671 * WARNING: FINDBLK_TEST buffers represent stable 3672 * storage but not necessarily stable 3673 * content. It is ok in this case. 3674 */ 3675 if ((bp = findblk(vp, loffset, FINDBLK_TEST)) != NULL) { 3676 if (bp->b_flags & B_DELWRI) 3677 bp = findblk(vp, loffset, 0); 3678 else 3679 bp = NULL; 3680 } 3681 if (bp) { 3682 if (bp->b_flags & B_DELWRI) { 3683 bremfree(bp); 3684 error = bwrite(bp); 3685 ++nfs_commit_miss; 3686 } else { 3687 BUF_UNLOCK(bp); 3688 } 3689 } 3690 ++nfs_commit_blks; 3691 if (cnt < iosize) 3692 break; 3693 cnt -= iosize; 3694 loffset += iosize; 3695 } 3696 crit_exit(); 3697 } 3698 3699 aft_ret = VOP_GETATTR(vp, &aft); 3700 vput(vp); 3701 vp = NULL; 3702 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3703 NFSX_V3WCCDATA + NFSX_V3WRITEVERF, 3704 &error)); 3705 nfsm_srvwcc_data(&info, nfsd, for_ret, &bfor, 3706 aft_ret, &aft); 3707 if (!error) { 3708 tl = nfsm_build(&info, NFSX_V3WRITEVERF); 3709 if (nfsver.tv_sec == 0) 3710 nfsver = boottime; 3711 *tl++ = txdr_unsigned(nfsver.tv_sec); 3712 *tl = txdr_unsigned(nfsver.tv_nsec / 1000); 3713 } else { 3714 error = 0; 3715 } 3716 nfsmout: 3717 *mrq = info.mreq; 3718 if (vp) 3719 vput(vp); 3720 return(error); 3721 } 3722 3723 /* 3724 * nfs statfs service 3725 */ 3726 int 3727 nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3728 struct thread *td, struct mbuf **mrq) 3729 { 3730 struct sockaddr *nam = nfsd->nd_nam; 3731 struct ucred *cred = &nfsd->nd_cr; 3732 struct statfs *sf; 3733 struct nfs_statfs *sfp; 3734 int error = 0, rdonly, getret = 1; 3735 struct vnode *vp = NULL; 3736 struct mount *mp = NULL; 3737 struct vattr at; 3738 nfsfh_t nfh; 3739 fhandle_t *fhp; 3740 struct statfs statfs; 3741 u_quad_t tval; 3742 struct nfsm_info info; 3743 3744 info.mrep = nfsd->nd_mrep; 3745 info.mreq = NULL; 3746 info.md = nfsd->nd_md; 3747 info.dpos = nfsd->nd_dpos; 3748 info.v3 = (nfsd->nd_flag & ND_NFSV3); 3749 3750 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3751 fhp = &nfh.fh_generic; 3752 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 3753 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 3754 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 3755 if (error) { 3756 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error)); 3757 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3758 error = 0; 3759 goto nfsmout; 3760 } 3761 sf = &statfs; 3762 error = VFS_STATFS(vp->v_mount, sf, proc0.p_ucred); 3763 getret = VOP_GETATTR(vp, &at); 3764 vput(vp); 3765 vp = NULL; 3766 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3767 NFSX_POSTOPATTR(info.v3) + NFSX_STATFS(info.v3), 3768 &error)); 3769 if (info.v3) 3770 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3771 if (error) { 3772 error = 0; 3773 goto nfsmout; 3774 } 3775 sfp = nfsm_build(&info, NFSX_STATFS(info.v3)); 3776 if (info.v3) { 3777 tval = (u_quad_t)sf->f_blocks; 3778 tval *= (u_quad_t)sf->f_bsize; 3779 txdr_hyper(tval, &sfp->sf_tbytes); 3780 tval = (u_quad_t)sf->f_bfree; 3781 tval *= (u_quad_t)sf->f_bsize; 3782 txdr_hyper(tval, &sfp->sf_fbytes); 3783 tval = (u_quad_t)sf->f_bavail; 3784 tval *= (u_quad_t)sf->f_bsize; 3785 txdr_hyper(tval, &sfp->sf_abytes); 3786 sfp->sf_tfiles.nfsuquad[0] = 0; 3787 sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files); 3788 sfp->sf_ffiles.nfsuquad[0] = 0; 3789 sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree); 3790 sfp->sf_afiles.nfsuquad[0] = 0; 3791 sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree); 3792 sfp->sf_invarsec = 0; 3793 } else { 3794 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 3795 sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 3796 sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 3797 sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 3798 sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 3799 } 3800 nfsmout: 3801 *mrq = info.mreq; 3802 if (vp) 3803 vput(vp); 3804 return(error); 3805 } 3806 3807 /* 3808 * nfs fsinfo service 3809 */ 3810 int 3811 nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3812 struct thread *td, struct mbuf **mrq) 3813 { 3814 struct sockaddr *nam = nfsd->nd_nam; 3815 struct ucred *cred = &nfsd->nd_cr; 3816 struct nfsv3_fsinfo *sip; 3817 int error = 0, rdonly, getret = 1, pref; 3818 struct vnode *vp = NULL; 3819 struct mount *mp = NULL; 3820 struct vattr at; 3821 nfsfh_t nfh; 3822 fhandle_t *fhp; 3823 u_quad_t maxfsize; 3824 struct statfs sb; 3825 struct nfsm_info info; 3826 3827 info.mrep = nfsd->nd_mrep; 3828 info.mreq = NULL; 3829 info.md = nfsd->nd_md; 3830 info.dpos = nfsd->nd_dpos; 3831 3832 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3833 fhp = &nfh.fh_generic; 3834 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 3835 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 3836 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 3837 if (error) { 3838 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error)); 3839 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3840 error = 0; 3841 goto nfsmout; 3842 } 3843 3844 /* XXX Try to make a guess on the max file size. */ 3845 VFS_STATFS(vp->v_mount, &sb, proc0.p_ucred); 3846 maxfsize = (u_quad_t)0x80000000 * sb.f_bsize - 1; 3847 3848 getret = VOP_GETATTR(vp, &at); 3849 vput(vp); 3850 vp = NULL; 3851 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3852 NFSX_V3POSTOPATTR + NFSX_V3FSINFO, &error)); 3853 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3854 sip = nfsm_build(&info, NFSX_V3FSINFO); 3855 3856 /* 3857 * XXX 3858 * There should be file system VFS OP(s) to get this information. 3859 * For now, assume ufs. 3860 */ 3861 if (slp->ns_so->so_type == SOCK_DGRAM) 3862 pref = NFS_MAXDGRAMDATA; 3863 else 3864 pref = NFS_MAXDATA; 3865 sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA); 3866 sip->fs_rtpref = txdr_unsigned(pref); 3867 sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE); 3868 sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA); 3869 sip->fs_wtpref = txdr_unsigned(pref); 3870 sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE); 3871 sip->fs_dtpref = txdr_unsigned(pref); 3872 txdr_hyper(maxfsize, &sip->fs_maxfilesize); 3873 sip->fs_timedelta.nfsv3_sec = 0; 3874 sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1); 3875 sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK | 3876 NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS | 3877 NFSV3FSINFO_CANSETTIME); 3878 nfsmout: 3879 *mrq = info.mreq; 3880 if (vp) 3881 vput(vp); 3882 return(error); 3883 } 3884 3885 /* 3886 * nfs pathconf service 3887 */ 3888 int 3889 nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3890 struct thread *td, struct mbuf **mrq) 3891 { 3892 struct sockaddr *nam = nfsd->nd_nam; 3893 struct ucred *cred = &nfsd->nd_cr; 3894 struct nfsv3_pathconf *pc; 3895 int error = 0, rdonly, getret = 1; 3896 register_t linkmax, namemax, chownres, notrunc; 3897 struct vnode *vp = NULL; 3898 struct mount *mp = NULL; 3899 struct vattr at; 3900 nfsfh_t nfh; 3901 fhandle_t *fhp; 3902 struct nfsm_info info; 3903 3904 info.mrep = nfsd->nd_mrep; 3905 info.mreq = NULL; 3906 info.md = nfsd->nd_md; 3907 info.dpos = nfsd->nd_dpos; 3908 3909 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3910 fhp = &nfh.fh_generic; 3911 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 3912 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 3913 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 3914 if (error) { 3915 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error)); 3916 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3917 error = 0; 3918 goto nfsmout; 3919 } 3920 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax); 3921 if (!error) 3922 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax); 3923 if (!error) 3924 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres); 3925 if (!error) 3926 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc); 3927 getret = VOP_GETATTR(vp, &at); 3928 vput(vp); 3929 vp = NULL; 3930 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3931 NFSX_V3POSTOPATTR + NFSX_V3PATHCONF, 3932 &error)); 3933 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3934 if (error) { 3935 error = 0; 3936 goto nfsmout; 3937 } 3938 pc = nfsm_build(&info, NFSX_V3PATHCONF); 3939 3940 pc->pc_linkmax = txdr_unsigned(linkmax); 3941 pc->pc_namemax = txdr_unsigned(namemax); 3942 pc->pc_notrunc = txdr_unsigned(notrunc); 3943 pc->pc_chownrestricted = txdr_unsigned(chownres); 3944 3945 /* 3946 * These should probably be supported by VOP_PATHCONF(), but 3947 * until msdosfs is exportable (why would you want to?), the 3948 * Unix defaults should be ok. 3949 */ 3950 pc->pc_caseinsensitive = nfs_false; 3951 pc->pc_casepreserving = nfs_true; 3952 nfsmout: 3953 *mrq = info.mreq; 3954 if (vp) 3955 vput(vp); 3956 return(error); 3957 } 3958 3959 /* 3960 * Null operation, used by clients to ping server 3961 */ 3962 /* ARGSUSED */ 3963 int 3964 nfsrv_null(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3965 struct thread *td, struct mbuf **mrq) 3966 { 3967 struct nfsm_info info; 3968 int error = NFSERR_RETVOID; 3969 3970 info.mrep = nfsd->nd_mrep; 3971 info.mreq = NULL; 3972 3973 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3974 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 0, &error)); 3975 nfsmout: 3976 *mrq = info.mreq; 3977 return (error); 3978 } 3979 3980 /* 3981 * No operation, used for obsolete procedures 3982 */ 3983 /* ARGSUSED */ 3984 int 3985 nfsrv_noop(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3986 struct thread *td, struct mbuf **mrq) 3987 { 3988 struct nfsm_info info; 3989 int error; 3990 3991 info.mrep = nfsd->nd_mrep; 3992 info.mreq = NULL; 3993 3994 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3995 if (nfsd->nd_repstat) 3996 error = nfsd->nd_repstat; 3997 else 3998 error = EPROCUNAVAIL; 3999 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 0, &error)); 4000 error = 0; 4001 nfsmout: 4002 *mrq = info.mreq; 4003 return (error); 4004 } 4005 4006 /* 4007 * Perform access checking for vnodes obtained from file handles that would 4008 * refer to files already opened by a Unix client. You cannot just use 4009 * vn_writechk() and VOP_ACCESS() for two reasons: 4010 * 4011 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case 4012 * 2 - The owner is to be given access irrespective of mode bits for some 4013 * operations, so that processes that chmod after opening a file don't 4014 * break. I don't like this because it opens a security hole, but since 4015 * the nfs server opens a security hole the size of a barn door anyhow, 4016 * what the heck. 4017 * 4018 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS() 4019 * will return EPERM instead of EACCESS. EPERM is always an error. 4020 */ 4021 static int 4022 nfsrv_access(struct mount *mp, struct vnode *vp, int flags, struct ucred *cred, 4023 int rdonly, struct thread *td, int override) 4024 { 4025 struct vattr vattr; 4026 int error; 4027 4028 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 4029 if (flags & VWRITE) { 4030 /* Just vn_writechk() changed to check rdonly */ 4031 /* 4032 * Disallow write attempts on read-only file systems; 4033 * unless the file is a socket or a block or character 4034 * device resident on the file system. 4035 */ 4036 if (rdonly || 4037 ((mp->mnt_flag | vp->v_mount->mnt_flag) & MNT_RDONLY)) { 4038 switch (vp->v_type) { 4039 case VREG: 4040 case VDIR: 4041 case VLNK: 4042 return (EROFS); 4043 default: 4044 break; 4045 } 4046 } 4047 /* 4048 * If there's shared text associated with 4049 * the inode, we can't allow writing. 4050 */ 4051 if (vp->v_flag & VTEXT) 4052 return (ETXTBSY); 4053 } 4054 error = VOP_GETATTR(vp, &vattr); 4055 if (error) 4056 return (error); 4057 error = VOP_ACCESS(vp, flags, cred); /* XXX ruid/rgid vs uid/gid */ 4058 /* 4059 * Allow certain operations for the owner (reads and writes 4060 * on files that are already open). 4061 */ 4062 if (override && error == EACCES && cred->cr_uid == vattr.va_uid) 4063 error = 0; 4064 return error; 4065 } 4066 #endif /* NFS_NOSERVER */ 4067 4068