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