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