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