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 *xmp; 2377 struct vattr dirfor, diraft, at; 2378 nfsfh_t nfh, dnfh; 2379 fhandle_t *fhp, *dfhp; 2380 struct nfsm_info info; 2381 2382 info.mrep = nfsd->nd_mrep; 2383 info.mreq = NULL; 2384 info.md = nfsd->nd_md; 2385 info.dpos = nfsd->nd_dpos; 2386 info.v3 = (nfsd->nd_flag & ND_NFSV3); 2387 2388 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 2389 nlookup_zero(&nd); 2390 dirp = dvp = vp = xp = NULL; 2391 xmp = NULL; 2392 2393 fhp = &nfh.fh_generic; 2394 dfhp = &dnfh.fh_generic; 2395 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 2396 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, dfhp, &error)); 2397 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 2398 2399 error = nfsrv_fhtovp(fhp, FALSE, &xmp, &xp, cred, slp, nam, 2400 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 2401 if (error) { 2402 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2403 NFSX_POSTOPATTR(info.v3) + 2404 NFSX_WCCDATA(info.v3), 2405 &error)); 2406 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 2407 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2408 diraft_ret, &diraft); 2409 xp = NULL; 2410 error = 0; 2411 goto nfsmout; 2412 } 2413 if (xp->v_type == VDIR) { 2414 error = EPERM; /* POSIX */ 2415 goto out1; 2416 } 2417 2418 error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp, 2419 dfhp, len, slp, nam, &info.md, &info.dpos, &dirp, 2420 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2421 if (dirp) { 2422 if (info.v3) 2423 dirfor_ret = VOP_GETATTR(dirp, &dirfor); 2424 } 2425 if (error) 2426 goto out1; 2427 2428 if (vp != NULL) { 2429 error = EEXIST; 2430 goto out; 2431 } 2432 if (xp->v_mount != dvp->v_mount) 2433 error = EXDEV; 2434 out: 2435 if (!error) { 2436 vn_unlock(dvp); 2437 error = VOP_NLINK(&nd.nl_nch, dvp, xp, nd.nl_cred); 2438 vrele(dvp); 2439 dvp = NULL; 2440 } 2441 /* fall through */ 2442 2443 out1: 2444 if (info.v3) 2445 getret = VOP_GETATTR(xp, &at); 2446 if (dirp) 2447 diraft_ret = VOP_GETATTR(dirp, &diraft); 2448 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2449 NFSX_POSTOPATTR(info.v3) + NFSX_WCCDATA(info.v3), 2450 &error)); 2451 if (info.v3) { 2452 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 2453 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2454 diraft_ret, &diraft); 2455 error = 0; 2456 } 2457 /* fall through */ 2458 2459 nfsmout: 2460 *mrq = info.mreq; 2461 nlookup_done(&nd); 2462 if (dirp) 2463 vrele(dirp); 2464 if (xp) 2465 vrele(xp); 2466 if (dvp) { 2467 if (dvp == vp) 2468 vrele(dvp); 2469 else 2470 vput(dvp); 2471 } 2472 if (vp) 2473 vput(vp); 2474 return(error); 2475 } 2476 2477 /* 2478 * nfs symbolic link service 2479 */ 2480 int 2481 nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2482 struct thread *td, struct mbuf **mrq) 2483 { 2484 struct sockaddr *nam = nfsd->nd_nam; 2485 struct ucred *cred = &nfsd->nd_cr; 2486 struct vattr va, dirfor, diraft; 2487 struct nlookupdata nd; 2488 struct vattr *vap = &va; 2489 struct nfsv2_sattr *sp; 2490 char *pathcp = NULL; 2491 struct uio io; 2492 struct iovec iv; 2493 int error = 0, len, len2, dirfor_ret = 1, diraft_ret = 1; 2494 struct vnode *dirp; 2495 struct vnode *vp; 2496 struct vnode *dvp; 2497 nfsfh_t nfh; 2498 fhandle_t *fhp; 2499 struct nfsm_info info; 2500 2501 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 2502 nlookup_zero(&nd); 2503 dirp = NULL; 2504 dvp = NULL; 2505 vp = NULL; 2506 2507 info.mrep = nfsd->nd_mrep; 2508 info.mreq = NULL; 2509 info.md = nfsd->nd_md; 2510 info.dpos = nfsd->nd_dpos; 2511 info.v3 = (nfsd->nd_flag & ND_NFSV3); 2512 2513 fhp = &nfh.fh_generic; 2514 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 2515 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 2516 2517 error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp, 2518 fhp, len, slp, nam, &info.md, &info.dpos, &dirp, 2519 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2520 if (dirp) { 2521 if (info.v3) 2522 dirfor_ret = VOP_GETATTR(dirp, &dirfor); 2523 } 2524 if (error) 2525 goto out; 2526 2527 VATTR_NULL(vap); 2528 if (info.v3) { 2529 ERROROUT(nfsm_srvsattr(&info, vap)); 2530 } 2531 NEGATIVEOUT(len2 = nfsm_strsiz(&info, NFS_MAXPATHLEN)); 2532 pathcp = kmalloc(len2 + 1, M_TEMP, M_WAITOK); 2533 iv.iov_base = pathcp; 2534 iv.iov_len = len2; 2535 io.uio_resid = len2; 2536 io.uio_offset = 0; 2537 io.uio_iov = &iv; 2538 io.uio_iovcnt = 1; 2539 io.uio_segflg = UIO_SYSSPACE; 2540 io.uio_rw = UIO_READ; 2541 io.uio_td = NULL; 2542 ERROROUT(nfsm_mtouio(&info, &io, len2)); 2543 if (info.v3 == 0) { 2544 NULLOUT(sp = nfsm_dissect(&info, NFSX_V2SATTR)); 2545 vap->va_mode = nfstov_mode(sp->sa_mode); 2546 } 2547 *(pathcp + len2) = '\0'; 2548 if (vp) { 2549 error = EEXIST; 2550 goto out; 2551 } 2552 2553 if (vap->va_mode == (mode_t)VNOVAL) 2554 vap->va_mode = 0; 2555 if (dvp != vp) 2556 vn_unlock(dvp); 2557 error = VOP_NSYMLINK(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap, pathcp); 2558 vrele(dvp); 2559 dvp = NULL; 2560 if (error == 0) { 2561 bzero(&fhp->fh_fid, sizeof(fhp->fh_fid)); 2562 error = VFS_VPTOFH(vp, &fhp->fh_fid); 2563 if (!error) 2564 error = VOP_GETATTR(vp, vap); 2565 } 2566 2567 out: 2568 if (dvp) { 2569 if (dvp == vp) 2570 vrele(dvp); 2571 else 2572 vput(dvp); 2573 } 2574 if (vp) { 2575 vput(vp); 2576 vp = NULL; 2577 } 2578 if (pathcp) { 2579 kfree(pathcp, M_TEMP); 2580 pathcp = NULL; 2581 } 2582 if (dirp) { 2583 diraft_ret = VOP_GETATTR(dirp, &diraft); 2584 vrele(dirp); 2585 dirp = NULL; 2586 } 2587 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2588 NFSX_SRVFH(info.v3) + NFSX_POSTOPATTR(info.v3) + 2589 NFSX_WCCDATA(info.v3), 2590 &error)); 2591 if (info.v3) { 2592 if (!error) { 2593 nfsm_srvpostop_fh(&info, fhp); 2594 nfsm_srvpostop_attr(&info, nfsd, 0, vap); 2595 } 2596 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2597 diraft_ret, &diraft); 2598 } 2599 error = 0; 2600 /* fall through */ 2601 2602 nfsmout: 2603 *mrq = info.mreq; 2604 nlookup_done(&nd); 2605 if (vp) 2606 vput(vp); 2607 if (dirp) 2608 vrele(dirp); 2609 if (pathcp) 2610 kfree(pathcp, M_TEMP); 2611 return (error); 2612 } 2613 2614 /* 2615 * nfs mkdir service 2616 */ 2617 int 2618 nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2619 struct thread *td, struct mbuf **mrq) 2620 { 2621 struct sockaddr *nam = nfsd->nd_nam; 2622 struct ucred *cred = &nfsd->nd_cr; 2623 struct vattr va, dirfor, diraft; 2624 struct vattr *vap = &va; 2625 struct nfs_fattr *fp; 2626 struct nlookupdata nd; 2627 u_int32_t *tl; 2628 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 2629 struct vnode *dirp; 2630 struct vnode *dvp; 2631 struct vnode *vp; 2632 nfsfh_t nfh; 2633 fhandle_t *fhp; 2634 struct nfsm_info info; 2635 2636 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 2637 nlookup_zero(&nd); 2638 dirp = NULL; 2639 dvp = NULL; 2640 vp = NULL; 2641 2642 info.dpos = nfsd->nd_dpos; 2643 info.mrep = nfsd->nd_mrep; 2644 info.mreq = NULL; 2645 info.md = nfsd->nd_md; 2646 info.v3 = (nfsd->nd_flag & ND_NFSV3); 2647 2648 fhp = &nfh.fh_generic; 2649 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 2650 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 2651 2652 error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp, 2653 fhp, len, slp, nam, &info.md, &info.dpos, &dirp, 2654 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2655 if (dirp) { 2656 if (info.v3) 2657 dirfor_ret = VOP_GETATTR(dirp, &dirfor); 2658 } 2659 if (error) { 2660 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2661 NFSX_WCCDATA(info.v3), &error)); 2662 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2663 diraft_ret, &diraft); 2664 error = 0; 2665 goto nfsmout; 2666 } 2667 VATTR_NULL(vap); 2668 if (info.v3) { 2669 ERROROUT(nfsm_srvsattr(&info, vap)); 2670 } else { 2671 NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED)); 2672 vap->va_mode = nfstov_mode(*tl++); 2673 } 2674 2675 /* 2676 * At this point nd.ni_dvp is referenced and exclusively locked and 2677 * nd.ni_vp, if it exists, is referenced but not locked. 2678 */ 2679 2680 vap->va_type = VDIR; 2681 if (vp != NULL) { 2682 error = EEXIST; 2683 goto out; 2684 } 2685 2686 /* 2687 * Issue mkdir op. Since SAVESTART is not set, the pathname 2688 * component is freed by the VOP call. This will fill-in 2689 * nd.ni_vp, reference, and exclusively lock it. 2690 */ 2691 if (vap->va_mode == (mode_t)VNOVAL) 2692 vap->va_mode = 0; 2693 vn_unlock(dvp); 2694 error = VOP_NMKDIR(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap); 2695 vrele(dvp); 2696 dvp = NULL; 2697 2698 if (error == 0) { 2699 bzero(&fhp->fh_fid, sizeof(fhp->fh_fid)); 2700 error = VFS_VPTOFH(vp, &fhp->fh_fid); 2701 if (error == 0) 2702 error = VOP_GETATTR(vp, vap); 2703 } 2704 out: 2705 if (dirp) 2706 diraft_ret = VOP_GETATTR(dirp, &diraft); 2707 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2708 NFSX_SRVFH(info.v3) + NFSX_POSTOPATTR(info.v3) + 2709 NFSX_WCCDATA(info.v3), 2710 &error)); 2711 if (info.v3) { 2712 if (!error) { 2713 nfsm_srvpostop_fh(&info, fhp); 2714 nfsm_srvpostop_attr(&info, nfsd, 0, vap); 2715 } 2716 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2717 diraft_ret, &diraft); 2718 } else { 2719 nfsm_srvfhtom(&info, fhp); 2720 fp = nfsm_build(&info, NFSX_V2FATTR); 2721 nfsm_srvfattr(nfsd, vap, fp); 2722 } 2723 error = 0; 2724 /* fall through */ 2725 2726 nfsmout: 2727 *mrq = info.mreq; 2728 nlookup_done(&nd); 2729 if (dirp) 2730 vrele(dirp); 2731 if (dvp) { 2732 if (dvp == vp) 2733 vrele(dvp); 2734 else 2735 vput(dvp); 2736 } 2737 if (vp) 2738 vput(vp); 2739 return (error); 2740 } 2741 2742 /* 2743 * nfs rmdir service 2744 */ 2745 int 2746 nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2747 struct thread *td, struct mbuf **mrq) 2748 { 2749 struct sockaddr *nam = nfsd->nd_nam; 2750 struct ucred *cred = &nfsd->nd_cr; 2751 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 2752 struct vnode *dirp; 2753 struct vnode *dvp; 2754 struct vnode *vp; 2755 struct vattr dirfor, diraft; 2756 nfsfh_t nfh; 2757 fhandle_t *fhp; 2758 struct nlookupdata nd; 2759 struct nfsm_info info; 2760 2761 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 2762 nlookup_zero(&nd); 2763 dirp = NULL; 2764 dvp = NULL; 2765 vp = NULL; 2766 2767 info.mrep = nfsd->nd_mrep; 2768 info.mreq = NULL; 2769 info.md = nfsd->nd_md; 2770 info.dpos = nfsd->nd_dpos; 2771 info.v3 = (nfsd->nd_flag & ND_NFSV3); 2772 2773 fhp = &nfh.fh_generic; 2774 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 2775 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 2776 2777 error = nfs_namei(&nd, cred, NLC_DELETE, &dvp, &vp, 2778 fhp, len, slp, nam, &info.md, &info.dpos, &dirp, 2779 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2780 if (dirp) { 2781 if (info.v3) 2782 dirfor_ret = VOP_GETATTR(dirp, &dirfor); 2783 } 2784 if (error) { 2785 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2786 NFSX_WCCDATA(info.v3), &error)); 2787 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2788 diraft_ret, &diraft); 2789 error = 0; 2790 goto nfsmout; 2791 } 2792 if (vp->v_type != VDIR) { 2793 error = ENOTDIR; 2794 goto out; 2795 } 2796 2797 /* 2798 * The root of a mounted filesystem cannot be deleted. 2799 */ 2800 if (vp->v_flag & VROOT) 2801 error = EBUSY; 2802 out: 2803 /* 2804 * Issue or abort op. Since SAVESTART is not set, path name 2805 * component is freed by the VOP after either. 2806 */ 2807 if (!error) { 2808 if (dvp != vp) 2809 vn_unlock(dvp); 2810 vput(vp); 2811 vp = NULL; 2812 error = VOP_NRMDIR(&nd.nl_nch, dvp, nd.nl_cred); 2813 vrele(dvp); 2814 dvp = NULL; 2815 } 2816 nlookup_done(&nd); 2817 2818 if (dirp) 2819 diraft_ret = VOP_GETATTR(dirp, &diraft); 2820 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_WCCDATA(info.v3), &error)); 2821 if (info.v3) { 2822 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2823 diraft_ret, &diraft); 2824 error = 0; 2825 } 2826 /* fall through */ 2827 2828 nfsmout: 2829 *mrq = info.mreq; 2830 if (dvp) { 2831 if (dvp == vp) 2832 vrele(dvp); 2833 else 2834 vput(dvp); 2835 } 2836 nlookup_done(&nd); 2837 if (dirp) 2838 vrele(dirp); 2839 if (vp) 2840 vput(vp); 2841 return(error); 2842 } 2843 2844 /* 2845 * nfs readdir service 2846 * - mallocs what it thinks is enough to read 2847 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 2848 * - calls VOP_READDIR() 2849 * - loops around building the reply 2850 * if the output generated exceeds count break out of loop 2851 * The nfsm_clget macro is used here so that the reply will be packed 2852 * tightly in mbuf clusters. 2853 * - it only knows that it has encountered eof when the VOP_READDIR() 2854 * reads nothing 2855 * - as such one readdir rpc will return eof false although you are there 2856 * and then the next will return eof 2857 * - it trims out records with d_fileno == 0 2858 * this doesn't matter for Unix clients, but they might confuse clients 2859 * for other os'. 2860 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 2861 * than requested, but this may not apply to all filesystems. For 2862 * example, client NFS does not { although it is never remote mounted 2863 * anyhow } 2864 * The alternate call nfsrv_readdirplus() does lookups as well. 2865 * PS: The NFS protocol spec. does not clarify what the "count" byte 2866 * argument is a count of.. just name strings and file id's or the 2867 * entire reply rpc or ... 2868 * I tried just file name and id sizes and it confused the Sun client, 2869 * so I am using the full rpc size now. The "paranoia.." comment refers 2870 * to including the status longwords that are not a part of the dir. 2871 * "entry" structures, but are in the rpc. 2872 */ 2873 struct flrep { 2874 nfsuint64 fl_off; 2875 u_int32_t fl_postopok; 2876 u_int32_t fl_fattr[NFSX_V3FATTR / sizeof (u_int32_t)]; 2877 u_int32_t fl_fhok; 2878 u_int32_t fl_fhsize; 2879 u_int32_t fl_nfh[NFSX_V3FH / sizeof (u_int32_t)]; 2880 }; 2881 2882 int 2883 nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2884 struct thread *td, struct mbuf **mrq) 2885 { 2886 struct sockaddr *nam = nfsd->nd_nam; 2887 struct ucred *cred = &nfsd->nd_cr; 2888 char *bp, *be; 2889 struct dirent *dp; 2890 caddr_t cp; 2891 u_int32_t *tl; 2892 struct mbuf *mp1, *mp2; 2893 char *cpos, *cend, *rbuf; 2894 struct vnode *vp = NULL; 2895 struct mount *mp = NULL; 2896 struct vattr at; 2897 nfsfh_t nfh; 2898 fhandle_t *fhp; 2899 struct uio io; 2900 struct iovec iv; 2901 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1; 2902 int siz, cnt, fullsiz, eofflag, rdonly, ncookies; 2903 u_quad_t off, toff; 2904 #if 0 2905 u_quad_t verf; 2906 #endif 2907 off_t *cookies = NULL, *cookiep; 2908 struct nfsm_info info; 2909 2910 info.mrep = nfsd->nd_mrep; 2911 info.mreq = NULL; 2912 info.md = nfsd->nd_md; 2913 info.dpos = nfsd->nd_dpos; 2914 info.v3 = (nfsd->nd_flag & ND_NFSV3); 2915 2916 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 2917 fhp = &nfh.fh_generic; 2918 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 2919 if (info.v3) { 2920 NULLOUT(tl = nfsm_dissect(&info, 5 * NFSX_UNSIGNED)); 2921 toff = fxdr_hyper(tl); 2922 tl += 2; 2923 #if 0 2924 verf = fxdr_hyper(tl); 2925 #endif 2926 tl += 2; 2927 } else { 2928 NULLOUT(tl = nfsm_dissect(&info, 2 * NFSX_UNSIGNED)); 2929 toff = fxdr_unsigned(u_quad_t, *tl++); 2930 #if 0 2931 verf = 0; /* shut up gcc */ 2932 #endif 2933 } 2934 off = toff; 2935 cnt = fxdr_unsigned(int, *tl); 2936 siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); 2937 xfer = NFS_SRVMAXDATA(nfsd); 2938 if ((unsigned)cnt > xfer) 2939 cnt = xfer; 2940 if ((unsigned)siz > xfer) 2941 siz = xfer; 2942 fullsiz = siz; 2943 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 2944 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 2945 if (!error && vp->v_type != VDIR) { 2946 error = ENOTDIR; 2947 vput(vp); 2948 vp = NULL; 2949 } 2950 if (error) { 2951 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error)); 2952 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 2953 error = 0; 2954 goto nfsmout; 2955 } 2956 2957 /* 2958 * Obtain lock on vnode for this section of the code 2959 */ 2960 2961 if (info.v3) { 2962 error = getret = VOP_GETATTR(vp, &at); 2963 #if 0 2964 /* 2965 * XXX This check may be too strict for Solaris 2.5 clients. 2966 */ 2967 if (!error && toff && verf && verf != at.va_filerev) 2968 error = NFSERR_BAD_COOKIE; 2969 #endif 2970 } 2971 if (!error) 2972 error = nfsrv_access(mp, vp, VEXEC, cred, rdonly, td, 0); 2973 if (error) { 2974 vput(vp); 2975 vp = NULL; 2976 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2977 NFSX_POSTOPATTR(info.v3), &error)); 2978 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 2979 error = 0; 2980 goto nfsmout; 2981 } 2982 vn_unlock(vp); 2983 2984 /* 2985 * end section. Allocate rbuf and continue 2986 */ 2987 rbuf = kmalloc(siz, M_TEMP, M_WAITOK); 2988 again: 2989 iv.iov_base = rbuf; 2990 iv.iov_len = fullsiz; 2991 io.uio_iov = &iv; 2992 io.uio_iovcnt = 1; 2993 io.uio_offset = (off_t)off; 2994 io.uio_resid = fullsiz; 2995 io.uio_segflg = UIO_SYSSPACE; 2996 io.uio_rw = UIO_READ; 2997 io.uio_td = NULL; 2998 eofflag = 0; 2999 if (cookies) { 3000 kfree((caddr_t)cookies, M_TEMP); 3001 cookies = NULL; 3002 } 3003 error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies); 3004 off = (off_t)io.uio_offset; 3005 if (!cookies && !error) 3006 error = NFSERR_PERM; 3007 if (info.v3) { 3008 getret = VOP_GETATTR(vp, &at); 3009 if (!error) 3010 error = getret; 3011 } 3012 if (error) { 3013 vrele(vp); 3014 vp = NULL; 3015 kfree((caddr_t)rbuf, M_TEMP); 3016 if (cookies) 3017 kfree((caddr_t)cookies, M_TEMP); 3018 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3019 NFSX_POSTOPATTR(info.v3), &error)); 3020 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3021 error = 0; 3022 goto nfsmout; 3023 } 3024 if (io.uio_resid) { 3025 siz -= io.uio_resid; 3026 3027 /* 3028 * If nothing read, return eof 3029 * rpc reply 3030 */ 3031 if (siz == 0) { 3032 vrele(vp); 3033 vp = NULL; 3034 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3035 NFSX_POSTOPATTR(info.v3) + 3036 NFSX_COOKIEVERF(info.v3) + 3037 2 * NFSX_UNSIGNED, 3038 &error)); 3039 if (info.v3) { 3040 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3041 tl = nfsm_build(&info, 4 * NFSX_UNSIGNED); 3042 txdr_hyper(at.va_filerev, tl); 3043 tl += 2; 3044 } else 3045 tl = nfsm_build(&info, 2 * NFSX_UNSIGNED); 3046 *tl++ = nfs_false; 3047 *tl = nfs_true; 3048 kfree((caddr_t)rbuf, M_TEMP); 3049 kfree((caddr_t)cookies, M_TEMP); 3050 error = 0; 3051 goto nfsmout; 3052 } 3053 } 3054 3055 /* 3056 * Check for degenerate cases of nothing useful read. 3057 * If so go try again 3058 */ 3059 cpos = rbuf; 3060 cend = rbuf + siz; 3061 dp = (struct dirent *)cpos; 3062 cookiep = cookies; 3063 /* 3064 * For some reason FreeBSD's ufs_readdir() chooses to back the 3065 * directory offset up to a block boundary, so it is necessary to 3066 * skip over the records that preceed the requested offset. This 3067 * requires the assumption that file offset cookies monotonically 3068 * increase. 3069 */ 3070 while (cpos < cend && ncookies > 0 && 3071 (dp->d_ino == 0 || dp->d_type == DT_WHT || 3072 ((u_quad_t)(*cookiep)) <= toff)) { 3073 dp = _DIRENT_NEXT(dp); 3074 cpos = (char *)dp; 3075 cookiep++; 3076 ncookies--; 3077 } 3078 if (cpos >= cend || ncookies == 0) { 3079 toff = off; 3080 siz = fullsiz; 3081 goto again; 3082 } 3083 3084 len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 3085 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3086 NFSX_POSTOPATTR(info.v3) + 3087 NFSX_COOKIEVERF(info.v3) + siz, 3088 &error)); 3089 if (info.v3) { 3090 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3091 tl = nfsm_build(&info, 2 * NFSX_UNSIGNED); 3092 txdr_hyper(at.va_filerev, tl); 3093 } 3094 mp1 = mp2 = info.mb; 3095 bp = info.bpos; 3096 be = bp + M_TRAILINGSPACE(mp1); 3097 3098 /* Loop through the records and build reply */ 3099 while (cpos < cend && ncookies > 0) { 3100 if (dp->d_ino != 0 && dp->d_type != DT_WHT) { 3101 nlen = dp->d_namlen; 3102 rem = nfsm_rndup(nlen) - nlen; 3103 len += (4 * NFSX_UNSIGNED + nlen + rem); 3104 if (info.v3) 3105 len += 2 * NFSX_UNSIGNED; 3106 if (len > cnt) { 3107 eofflag = 0; 3108 break; 3109 } 3110 /* 3111 * Build the directory record xdr from 3112 * the dirent entry. 3113 */ 3114 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3115 *tl = nfs_true; 3116 bp += NFSX_UNSIGNED; 3117 if (info.v3) { 3118 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3119 *tl = txdr_unsigned(dp->d_ino >> 32); 3120 bp += NFSX_UNSIGNED; 3121 } 3122 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3123 *tl = txdr_unsigned(dp->d_ino); 3124 bp += NFSX_UNSIGNED; 3125 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3126 *tl = txdr_unsigned(nlen); 3127 bp += NFSX_UNSIGNED; 3128 3129 /* And loop around copying the name */ 3130 xfer = nlen; 3131 cp = dp->d_name; 3132 while (xfer > 0) { 3133 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3134 if ((bp+xfer) > be) 3135 tsiz = be-bp; 3136 else 3137 tsiz = xfer; 3138 bcopy(cp, bp, tsiz); 3139 bp += tsiz; 3140 xfer -= tsiz; 3141 if (xfer > 0) 3142 cp += tsiz; 3143 } 3144 /* And null pad to a int32_t boundary */ 3145 for (i = 0; i < rem; i++) 3146 *bp++ = '\0'; 3147 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3148 3149 /* Finish off the record */ 3150 if (info.v3) { 3151 *tl = txdr_unsigned(*cookiep >> 32); 3152 bp += NFSX_UNSIGNED; 3153 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3154 } 3155 *tl = txdr_unsigned(*cookiep); 3156 bp += NFSX_UNSIGNED; 3157 } 3158 dp = _DIRENT_NEXT(dp); 3159 cpos = (char *)dp; 3160 cookiep++; 3161 ncookies--; 3162 } 3163 vrele(vp); 3164 vp = NULL; 3165 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3166 *tl = nfs_false; 3167 bp += NFSX_UNSIGNED; 3168 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3169 if (eofflag) 3170 *tl = nfs_true; 3171 else 3172 *tl = nfs_false; 3173 bp += NFSX_UNSIGNED; 3174 if (mp1 != info.mb) { 3175 if (bp < be) 3176 mp1->m_len = bp - mtod(mp1, caddr_t); 3177 } else 3178 mp1->m_len += bp - info.bpos; 3179 kfree((caddr_t)rbuf, M_TEMP); 3180 kfree((caddr_t)cookies, M_TEMP); 3181 3182 nfsmout: 3183 *mrq = info.mreq; 3184 if (vp) 3185 vrele(vp); 3186 return(error); 3187 } 3188 3189 int 3190 nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3191 struct thread *td, struct mbuf **mrq) 3192 { 3193 struct sockaddr *nam = nfsd->nd_nam; 3194 struct ucred *cred = &nfsd->nd_cr; 3195 char *bp, *be; 3196 struct dirent *dp; 3197 caddr_t cp; 3198 u_int32_t *tl; 3199 struct mbuf *mp1, *mp2; 3200 char *cpos, *cend, *rbuf; 3201 struct vnode *vp = NULL, *nvp; 3202 struct mount *mp = NULL; 3203 struct flrep fl; 3204 nfsfh_t nfh; 3205 fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh; 3206 struct uio io; 3207 struct iovec iv; 3208 struct vattr va, at, *vap = &va; 3209 struct nfs_fattr *fp; 3210 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1; 3211 int siz, cnt, fullsiz, eofflag, rdonly, dirlen, ncookies; 3212 u_quad_t off, toff; 3213 #if 0 3214 u_quad_t verf; 3215 #endif 3216 off_t *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */ 3217 struct nfsm_info info; 3218 3219 info.mrep = nfsd->nd_mrep; 3220 info.mreq = NULL; 3221 info.md = nfsd->nd_md; 3222 info.dpos = nfsd->nd_dpos; 3223 info.v3 = (nfsd->nd_flag & ND_NFSV3); 3224 3225 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3226 fhp = &nfh.fh_generic; 3227 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 3228 NULLOUT(tl = nfsm_dissect(&info, 6 * NFSX_UNSIGNED)); 3229 toff = fxdr_hyper(tl); 3230 tl += 2; 3231 #if 0 3232 verf = fxdr_hyper(tl); 3233 #endif 3234 tl += 2; 3235 siz = fxdr_unsigned(int, *tl++); 3236 cnt = fxdr_unsigned(int, *tl); 3237 off = toff; 3238 siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); 3239 xfer = NFS_SRVMAXDATA(nfsd); 3240 if ((unsigned)cnt > xfer) 3241 cnt = xfer; 3242 if ((unsigned)siz > xfer) 3243 siz = xfer; 3244 fullsiz = siz; 3245 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 3246 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 3247 if (!error && vp->v_type != VDIR) { 3248 error = ENOTDIR; 3249 vput(vp); 3250 vp = NULL; 3251 } 3252 if (error) { 3253 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error)); 3254 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3255 error = 0; 3256 goto nfsmout; 3257 } 3258 error = getret = VOP_GETATTR(vp, &at); 3259 #if 0 3260 /* 3261 * XXX This check may be too strict for Solaris 2.5 clients. 3262 */ 3263 if (!error && toff && verf && verf != at.va_filerev) 3264 error = NFSERR_BAD_COOKIE; 3265 #endif 3266 if (!error) { 3267 error = nfsrv_access(mp, vp, VEXEC, cred, rdonly, td, 0); 3268 } 3269 if (error) { 3270 vput(vp); 3271 vp = NULL; 3272 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3273 NFSX_V3POSTOPATTR, &error)); 3274 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3275 error = 0; 3276 goto nfsmout; 3277 } 3278 vn_unlock(vp); 3279 rbuf = kmalloc(siz, M_TEMP, M_WAITOK); 3280 again: 3281 iv.iov_base = rbuf; 3282 iv.iov_len = fullsiz; 3283 io.uio_iov = &iv; 3284 io.uio_iovcnt = 1; 3285 io.uio_offset = (off_t)off; 3286 io.uio_resid = fullsiz; 3287 io.uio_segflg = UIO_SYSSPACE; 3288 io.uio_rw = UIO_READ; 3289 io.uio_td = NULL; 3290 eofflag = 0; 3291 if (cookies) { 3292 kfree((caddr_t)cookies, M_TEMP); 3293 cookies = NULL; 3294 } 3295 error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies); 3296 off = (u_quad_t)io.uio_offset; 3297 getret = VOP_GETATTR(vp, &at); 3298 if (!cookies && !error) 3299 error = NFSERR_PERM; 3300 if (!error) 3301 error = getret; 3302 if (error) { 3303 vrele(vp); 3304 vp = NULL; 3305 if (cookies) 3306 kfree((caddr_t)cookies, M_TEMP); 3307 kfree((caddr_t)rbuf, M_TEMP); 3308 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3309 NFSX_V3POSTOPATTR, &error)); 3310 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3311 error = 0; 3312 goto nfsmout; 3313 } 3314 if (io.uio_resid) { 3315 siz -= io.uio_resid; 3316 3317 /* 3318 * If nothing read, return eof 3319 * rpc reply 3320 */ 3321 if (siz == 0) { 3322 vrele(vp); 3323 vp = NULL; 3324 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3325 NFSX_V3POSTOPATTR + 3326 NFSX_V3COOKIEVERF + 3327 2 * NFSX_UNSIGNED, 3328 &error)); 3329 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3330 tl = nfsm_build(&info, 4 * NFSX_UNSIGNED); 3331 txdr_hyper(at.va_filerev, tl); 3332 tl += 2; 3333 *tl++ = nfs_false; 3334 *tl = nfs_true; 3335 kfree((caddr_t)cookies, M_TEMP); 3336 kfree((caddr_t)rbuf, M_TEMP); 3337 error = 0; 3338 goto nfsmout; 3339 } 3340 } 3341 3342 /* 3343 * Check for degenerate cases of nothing useful read. 3344 * If so go try again 3345 */ 3346 cpos = rbuf; 3347 cend = rbuf + siz; 3348 dp = (struct dirent *)cpos; 3349 cookiep = cookies; 3350 /* 3351 * For some reason FreeBSD's ufs_readdir() chooses to back the 3352 * directory offset up to a block boundary, so it is necessary to 3353 * skip over the records that preceed the requested offset. This 3354 * requires the assumption that file offset cookies monotonically 3355 * increase. 3356 */ 3357 while (cpos < cend && ncookies > 0 && 3358 (dp->d_ino == 0 || dp->d_type == DT_WHT || 3359 ((u_quad_t)(*cookiep)) <= toff)) { 3360 dp = _DIRENT_NEXT(dp); 3361 cpos = (char *)dp; 3362 cookiep++; 3363 ncookies--; 3364 } 3365 if (cpos >= cend || ncookies == 0) { 3366 toff = off; 3367 siz = fullsiz; 3368 goto again; 3369 } 3370 3371 /* 3372 * Probe one of the directory entries to see if the filesystem 3373 * supports VGET. 3374 */ 3375 if (VFS_VGET(vp->v_mount, vp, dp->d_ino, &nvp) == EOPNOTSUPP) { 3376 error = NFSERR_NOTSUPP; 3377 vrele(vp); 3378 vp = NULL; 3379 kfree((caddr_t)cookies, M_TEMP); 3380 kfree((caddr_t)rbuf, M_TEMP); 3381 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3382 NFSX_V3POSTOPATTR, &error)); 3383 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3384 error = 0; 3385 goto nfsmout; 3386 } 3387 if (nvp) { 3388 vput(nvp); 3389 nvp = NULL; 3390 } 3391 3392 dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 3393 2 * NFSX_UNSIGNED; 3394 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, cnt, &error)); 3395 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3396 tl = nfsm_build(&info, 2 * NFSX_UNSIGNED); 3397 txdr_hyper(at.va_filerev, tl); 3398 mp1 = mp2 = info.mb; 3399 bp = info.bpos; 3400 be = bp + M_TRAILINGSPACE(mp1); 3401 3402 /* Loop through the records and build reply */ 3403 while (cpos < cend && ncookies > 0) { 3404 if (dp->d_ino != 0 && dp->d_type != DT_WHT) { 3405 nlen = dp->d_namlen; 3406 rem = nfsm_rndup(nlen) - nlen; 3407 3408 /* 3409 * For readdir_and_lookup get the vnode using 3410 * the file number. 3411 */ 3412 if (VFS_VGET(vp->v_mount, vp, dp->d_ino, &nvp)) 3413 goto invalid; 3414 bzero((caddr_t)nfhp, NFSX_V3FH); 3415 nfhp->fh_fsid = fhp->fh_fsid; 3416 if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) { 3417 vput(nvp); 3418 nvp = NULL; 3419 goto invalid; 3420 } 3421 if (VOP_GETATTR(nvp, vap)) { 3422 vput(nvp); 3423 nvp = NULL; 3424 goto invalid; 3425 } 3426 vput(nvp); 3427 nvp = NULL; 3428 3429 /* 3430 * If either the dircount or maxcount will be 3431 * exceeded, get out now. Both of these lengths 3432 * are calculated conservatively, including all 3433 * XDR overheads. 3434 */ 3435 len += (8 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH + 3436 NFSX_V3POSTOPATTR); 3437 dirlen += (6 * NFSX_UNSIGNED + nlen + rem); 3438 if (len > cnt || dirlen > fullsiz) { 3439 eofflag = 0; 3440 break; 3441 } 3442 3443 /* 3444 * Build the directory record xdr from 3445 * the dirent entry. 3446 */ 3447 fp = (struct nfs_fattr *)&fl.fl_fattr; 3448 nfsm_srvfattr(nfsd, vap, fp); 3449 fl.fl_off.nfsuquad[0] = txdr_unsigned(*cookiep >> 32); 3450 fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep); 3451 fl.fl_postopok = nfs_true; 3452 fl.fl_fhok = nfs_true; 3453 fl.fl_fhsize = txdr_unsigned(NFSX_V3FH); 3454 3455 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3456 *tl = nfs_true; 3457 bp += NFSX_UNSIGNED; 3458 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3459 *tl = txdr_unsigned(dp->d_ino >> 32); 3460 bp += NFSX_UNSIGNED; 3461 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3462 *tl = txdr_unsigned(dp->d_ino); 3463 bp += NFSX_UNSIGNED; 3464 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3465 *tl = txdr_unsigned(nlen); 3466 bp += NFSX_UNSIGNED; 3467 3468 /* And loop around copying the name */ 3469 xfer = nlen; 3470 cp = dp->d_name; 3471 while (xfer > 0) { 3472 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3473 if ((bp + xfer) > be) 3474 tsiz = be - bp; 3475 else 3476 tsiz = xfer; 3477 bcopy(cp, bp, tsiz); 3478 bp += tsiz; 3479 xfer -= tsiz; 3480 cp += tsiz; 3481 } 3482 /* And null pad to a int32_t boundary */ 3483 for (i = 0; i < rem; i++) 3484 *bp++ = '\0'; 3485 3486 /* 3487 * Now copy the flrep structure out. 3488 */ 3489 xfer = sizeof (struct flrep); 3490 cp = (caddr_t)&fl; 3491 while (xfer > 0) { 3492 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3493 if ((bp + xfer) > be) 3494 tsiz = be - bp; 3495 else 3496 tsiz = xfer; 3497 bcopy(cp, bp, tsiz); 3498 bp += tsiz; 3499 xfer -= tsiz; 3500 cp += tsiz; 3501 } 3502 } 3503 invalid: 3504 dp = _DIRENT_NEXT(dp); 3505 cpos = (char *)dp; 3506 cookiep++; 3507 ncookies--; 3508 } 3509 vrele(vp); 3510 vp = NULL; 3511 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3512 *tl = nfs_false; 3513 bp += NFSX_UNSIGNED; 3514 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3515 if (eofflag) 3516 *tl = nfs_true; 3517 else 3518 *tl = nfs_false; 3519 bp += NFSX_UNSIGNED; 3520 if (mp1 != info.mb) { 3521 if (bp < be) 3522 mp1->m_len = bp - mtod(mp1, caddr_t); 3523 } else 3524 mp1->m_len += bp - info.bpos; 3525 kfree((caddr_t)cookies, M_TEMP); 3526 kfree((caddr_t)rbuf, M_TEMP); 3527 nfsmout: 3528 *mrq = info.mreq; 3529 if (vp) 3530 vrele(vp); 3531 return(error); 3532 } 3533 3534 /* 3535 * nfs commit service 3536 */ 3537 int 3538 nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3539 struct thread *td, struct mbuf **mrq) 3540 { 3541 struct sockaddr *nam = nfsd->nd_nam; 3542 struct ucred *cred = &nfsd->nd_cr; 3543 struct vattr bfor, aft; 3544 struct vnode *vp = NULL; 3545 struct mount *mp = NULL; 3546 nfsfh_t nfh; 3547 fhandle_t *fhp; 3548 u_int32_t *tl; 3549 int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt; 3550 u_quad_t off; 3551 struct nfsm_info info; 3552 3553 info.mrep = nfsd->nd_mrep; 3554 info.mreq = NULL; 3555 info.md = nfsd->nd_md; 3556 info.dpos = nfsd->nd_dpos; 3557 3558 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3559 fhp = &nfh.fh_generic; 3560 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 3561 NULLOUT(tl = nfsm_dissect(&info, 3 * NFSX_UNSIGNED)); 3562 3563 /* 3564 * XXX At this time VOP_FSYNC() does not accept offset and byte 3565 * count parameters, so these arguments are useless (someday maybe). 3566 */ 3567 off = fxdr_hyper(tl); 3568 tl += 2; 3569 cnt = fxdr_unsigned(int, *tl); 3570 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 3571 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 3572 if (error) { 3573 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3574 2 * NFSX_UNSIGNED, &error)); 3575 nfsm_srvwcc_data(&info, nfsd, for_ret, &bfor, 3576 aft_ret, &aft); 3577 error = 0; 3578 goto nfsmout; 3579 } 3580 for_ret = VOP_GETATTR(vp, &bfor); 3581 3582 /* 3583 * RFC 1813 3.3.21: If count is 0, a flush from offset to the end of 3584 * file is done. At this time VOP_FSYNC does not accept offset and 3585 * byte count parameters, so call VOP_FSYNC the whole file for now. 3586 */ 3587 if (cnt == 0 || cnt > MAX_COMMIT_COUNT) { 3588 /* 3589 * Give up and do the whole thing 3590 */ 3591 if (vp->v_object && 3592 (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) { 3593 vm_object_page_clean(vp->v_object, 0, 0, OBJPC_SYNC); 3594 } 3595 error = VOP_FSYNC(vp, MNT_WAIT, 0); 3596 } else { 3597 /* 3598 * Locate and synchronously write any buffers that fall 3599 * into the requested range. Note: we are assuming that 3600 * f_iosize is a power of 2. 3601 */ 3602 int iosize = vp->v_mount->mnt_stat.f_iosize; 3603 int iomask = iosize - 1; 3604 off_t loffset; 3605 3606 /* 3607 * Align to iosize boundry, super-align to page boundry. 3608 */ 3609 if (off & iomask) { 3610 cnt += off & iomask; 3611 off &= ~(u_quad_t)iomask; 3612 } 3613 if (off & PAGE_MASK) { 3614 cnt += off & PAGE_MASK; 3615 off &= ~(u_quad_t)PAGE_MASK; 3616 } 3617 loffset = off; 3618 3619 if (vp->v_object && 3620 (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) { 3621 vm_object_page_clean(vp->v_object, off / PAGE_SIZE, 3622 (cnt + PAGE_MASK) / PAGE_SIZE, OBJPC_SYNC); 3623 } 3624 3625 crit_enter(); 3626 while (error == 0 || cnt > 0) { 3627 struct buf *bp; 3628 3629 /* 3630 * If we have a buffer and it is marked B_DELWRI we 3631 * have to lock and write it. Otherwise the prior 3632 * write is assumed to have already been committed. 3633 * 3634 * WARNING: FINDBLK_TEST buffers represent stable 3635 * storage but not necessarily stable 3636 * content. It is ok in this case. 3637 */ 3638 if ((bp = findblk(vp, loffset, FINDBLK_TEST)) != NULL) { 3639 if (bp->b_flags & B_DELWRI) 3640 bp = findblk(vp, loffset, 0); 3641 else 3642 bp = NULL; 3643 } 3644 if (bp) { 3645 if (bp->b_flags & B_DELWRI) { 3646 bremfree(bp); 3647 error = bwrite(bp); 3648 ++nfs_commit_miss; 3649 } else { 3650 BUF_UNLOCK(bp); 3651 } 3652 } 3653 ++nfs_commit_blks; 3654 if (cnt < iosize) 3655 break; 3656 cnt -= iosize; 3657 loffset += iosize; 3658 } 3659 crit_exit(); 3660 } 3661 3662 aft_ret = VOP_GETATTR(vp, &aft); 3663 vput(vp); 3664 vp = NULL; 3665 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3666 NFSX_V3WCCDATA + NFSX_V3WRITEVERF, 3667 &error)); 3668 nfsm_srvwcc_data(&info, nfsd, for_ret, &bfor, 3669 aft_ret, &aft); 3670 if (!error) { 3671 tl = nfsm_build(&info, NFSX_V3WRITEVERF); 3672 if (nfsver.tv_sec == 0) 3673 nfsver = boottime; 3674 *tl++ = txdr_unsigned(nfsver.tv_sec); 3675 *tl = txdr_unsigned(nfsver.tv_nsec / 1000); 3676 } else { 3677 error = 0; 3678 } 3679 nfsmout: 3680 *mrq = info.mreq; 3681 if (vp) 3682 vput(vp); 3683 return(error); 3684 } 3685 3686 /* 3687 * nfs statfs service 3688 */ 3689 int 3690 nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3691 struct thread *td, struct mbuf **mrq) 3692 { 3693 struct sockaddr *nam = nfsd->nd_nam; 3694 struct ucred *cred = &nfsd->nd_cr; 3695 struct statfs *sf; 3696 struct nfs_statfs *sfp; 3697 int error = 0, rdonly, getret = 1; 3698 struct vnode *vp = NULL; 3699 struct mount *mp = NULL; 3700 struct vattr at; 3701 nfsfh_t nfh; 3702 fhandle_t *fhp; 3703 struct statfs statfs; 3704 u_quad_t tval; 3705 struct nfsm_info info; 3706 3707 info.mrep = nfsd->nd_mrep; 3708 info.mreq = NULL; 3709 info.md = nfsd->nd_md; 3710 info.dpos = nfsd->nd_dpos; 3711 info.v3 = (nfsd->nd_flag & ND_NFSV3); 3712 3713 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3714 fhp = &nfh.fh_generic; 3715 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 3716 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 3717 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 3718 if (error) { 3719 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error)); 3720 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3721 error = 0; 3722 goto nfsmout; 3723 } 3724 sf = &statfs; 3725 error = VFS_STATFS(vp->v_mount, sf, proc0.p_ucred); 3726 getret = VOP_GETATTR(vp, &at); 3727 vput(vp); 3728 vp = NULL; 3729 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3730 NFSX_POSTOPATTR(info.v3) + NFSX_STATFS(info.v3), 3731 &error)); 3732 if (info.v3) 3733 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3734 if (error) { 3735 error = 0; 3736 goto nfsmout; 3737 } 3738 sfp = nfsm_build(&info, NFSX_STATFS(info.v3)); 3739 if (info.v3) { 3740 tval = (u_quad_t)sf->f_blocks; 3741 tval *= (u_quad_t)sf->f_bsize; 3742 txdr_hyper(tval, &sfp->sf_tbytes); 3743 tval = (u_quad_t)sf->f_bfree; 3744 tval *= (u_quad_t)sf->f_bsize; 3745 txdr_hyper(tval, &sfp->sf_fbytes); 3746 tval = (u_quad_t)sf->f_bavail; 3747 tval *= (u_quad_t)sf->f_bsize; 3748 txdr_hyper(tval, &sfp->sf_abytes); 3749 sfp->sf_tfiles.nfsuquad[0] = 0; 3750 sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files); 3751 sfp->sf_ffiles.nfsuquad[0] = 0; 3752 sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree); 3753 sfp->sf_afiles.nfsuquad[0] = 0; 3754 sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree); 3755 sfp->sf_invarsec = 0; 3756 } else { 3757 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 3758 sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 3759 sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 3760 sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 3761 sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 3762 } 3763 nfsmout: 3764 *mrq = info.mreq; 3765 if (vp) 3766 vput(vp); 3767 return(error); 3768 } 3769 3770 /* 3771 * nfs fsinfo service 3772 */ 3773 int 3774 nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3775 struct thread *td, struct mbuf **mrq) 3776 { 3777 struct sockaddr *nam = nfsd->nd_nam; 3778 struct ucred *cred = &nfsd->nd_cr; 3779 struct nfsv3_fsinfo *sip; 3780 int error = 0, rdonly, getret = 1, pref; 3781 struct vnode *vp = NULL; 3782 struct mount *mp = NULL; 3783 struct vattr at; 3784 nfsfh_t nfh; 3785 fhandle_t *fhp; 3786 u_quad_t maxfsize; 3787 struct statfs sb; 3788 struct nfsm_info info; 3789 3790 info.mrep = nfsd->nd_mrep; 3791 info.mreq = NULL; 3792 info.md = nfsd->nd_md; 3793 info.dpos = nfsd->nd_dpos; 3794 3795 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3796 fhp = &nfh.fh_generic; 3797 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 3798 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 3799 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 3800 if (error) { 3801 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error)); 3802 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3803 error = 0; 3804 goto nfsmout; 3805 } 3806 3807 /* XXX Try to make a guess on the max file size. */ 3808 VFS_STATFS(vp->v_mount, &sb, proc0.p_ucred); 3809 maxfsize = (u_quad_t)0x80000000 * sb.f_bsize - 1; 3810 3811 getret = VOP_GETATTR(vp, &at); 3812 vput(vp); 3813 vp = NULL; 3814 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3815 NFSX_V3POSTOPATTR + NFSX_V3FSINFO, &error)); 3816 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3817 sip = nfsm_build(&info, NFSX_V3FSINFO); 3818 3819 /* 3820 * XXX 3821 * There should be file system VFS OP(s) to get this information. 3822 * For now, assume ufs. 3823 */ 3824 if (slp->ns_so->so_type == SOCK_DGRAM) 3825 pref = NFS_MAXDGRAMDATA; 3826 else 3827 pref = NFS_MAXDATA; 3828 sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA); 3829 sip->fs_rtpref = txdr_unsigned(pref); 3830 sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE); 3831 sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA); 3832 sip->fs_wtpref = txdr_unsigned(pref); 3833 sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE); 3834 sip->fs_dtpref = txdr_unsigned(pref); 3835 txdr_hyper(maxfsize, &sip->fs_maxfilesize); 3836 sip->fs_timedelta.nfsv3_sec = 0; 3837 sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1); 3838 sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK | 3839 NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS | 3840 NFSV3FSINFO_CANSETTIME); 3841 nfsmout: 3842 *mrq = info.mreq; 3843 if (vp) 3844 vput(vp); 3845 return(error); 3846 } 3847 3848 /* 3849 * nfs pathconf service 3850 */ 3851 int 3852 nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3853 struct thread *td, struct mbuf **mrq) 3854 { 3855 struct sockaddr *nam = nfsd->nd_nam; 3856 struct ucred *cred = &nfsd->nd_cr; 3857 struct nfsv3_pathconf *pc; 3858 int error = 0, rdonly, getret = 1; 3859 register_t linkmax, namemax, chownres, notrunc; 3860 struct vnode *vp = NULL; 3861 struct mount *mp = NULL; 3862 struct vattr at; 3863 nfsfh_t nfh; 3864 fhandle_t *fhp; 3865 struct nfsm_info info; 3866 3867 info.mrep = nfsd->nd_mrep; 3868 info.mreq = NULL; 3869 info.md = nfsd->nd_md; 3870 info.dpos = nfsd->nd_dpos; 3871 3872 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3873 fhp = &nfh.fh_generic; 3874 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 3875 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 3876 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 3877 if (error) { 3878 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error)); 3879 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3880 error = 0; 3881 goto nfsmout; 3882 } 3883 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax); 3884 if (!error) 3885 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax); 3886 if (!error) 3887 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres); 3888 if (!error) 3889 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc); 3890 getret = VOP_GETATTR(vp, &at); 3891 vput(vp); 3892 vp = NULL; 3893 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3894 NFSX_V3POSTOPATTR + NFSX_V3PATHCONF, 3895 &error)); 3896 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3897 if (error) { 3898 error = 0; 3899 goto nfsmout; 3900 } 3901 pc = nfsm_build(&info, NFSX_V3PATHCONF); 3902 3903 pc->pc_linkmax = txdr_unsigned(linkmax); 3904 pc->pc_namemax = txdr_unsigned(namemax); 3905 pc->pc_notrunc = txdr_unsigned(notrunc); 3906 pc->pc_chownrestricted = txdr_unsigned(chownres); 3907 3908 /* 3909 * These should probably be supported by VOP_PATHCONF(), but 3910 * until msdosfs is exportable (why would you want to?), the 3911 * Unix defaults should be ok. 3912 */ 3913 pc->pc_caseinsensitive = nfs_false; 3914 pc->pc_casepreserving = nfs_true; 3915 nfsmout: 3916 *mrq = info.mreq; 3917 if (vp) 3918 vput(vp); 3919 return(error); 3920 } 3921 3922 /* 3923 * Null operation, used by clients to ping server 3924 */ 3925 /* ARGSUSED */ 3926 int 3927 nfsrv_null(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3928 struct thread *td, struct mbuf **mrq) 3929 { 3930 struct nfsm_info info; 3931 int error = NFSERR_RETVOID; 3932 3933 info.mrep = nfsd->nd_mrep; 3934 info.mreq = NULL; 3935 3936 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3937 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 0, &error)); 3938 nfsmout: 3939 *mrq = info.mreq; 3940 return (error); 3941 } 3942 3943 /* 3944 * No operation, used for obsolete procedures 3945 */ 3946 /* ARGSUSED */ 3947 int 3948 nfsrv_noop(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3949 struct thread *td, struct mbuf **mrq) 3950 { 3951 struct nfsm_info info; 3952 int error; 3953 3954 info.mrep = nfsd->nd_mrep; 3955 info.mreq = NULL; 3956 3957 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3958 if (nfsd->nd_repstat) 3959 error = nfsd->nd_repstat; 3960 else 3961 error = EPROCUNAVAIL; 3962 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 0, &error)); 3963 error = 0; 3964 nfsmout: 3965 *mrq = info.mreq; 3966 return (error); 3967 } 3968 3969 /* 3970 * Perform access checking for vnodes obtained from file handles that would 3971 * refer to files already opened by a Unix client. You cannot just use 3972 * vn_writechk() and VOP_ACCESS() for two reasons. 3973 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case 3974 * 2 - The owner is to be given access irrespective of mode bits for some 3975 * operations, so that processes that chmod after opening a file don't 3976 * break. I don't like this because it opens a security hole, but since 3977 * the nfs server opens a security hole the size of a barn door anyhow, 3978 * what the heck. 3979 * 3980 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS() 3981 * will return EPERM instead of EACCESS. EPERM is always an error. 3982 */ 3983 static int 3984 nfsrv_access(struct mount *mp, struct vnode *vp, int flags, struct ucred *cred, 3985 int rdonly, struct thread *td, int override) 3986 { 3987 struct vattr vattr; 3988 int error; 3989 3990 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3991 if (flags & VWRITE) { 3992 /* Just vn_writechk() changed to check rdonly */ 3993 /* 3994 * Disallow write attempts on read-only file systems; 3995 * unless the file is a socket or a block or character 3996 * device resident on the file system. 3997 */ 3998 if (rdonly || 3999 ((mp->mnt_flag | vp->v_mount->mnt_flag) & MNT_RDONLY)) { 4000 switch (vp->v_type) { 4001 case VREG: 4002 case VDIR: 4003 case VLNK: 4004 return (EROFS); 4005 default: 4006 break; 4007 } 4008 } 4009 /* 4010 * If there's shared text associated with 4011 * the inode, we can't allow writing. 4012 */ 4013 if (vp->v_flag & VTEXT) 4014 return (ETXTBSY); 4015 } 4016 error = VOP_GETATTR(vp, &vattr); 4017 if (error) 4018 return (error); 4019 error = VOP_ACCESS(vp, flags, cred); /* XXX ruid/rgid vs uid/gid */ 4020 /* 4021 * Allow certain operations for the owner (reads and writes 4022 * on files that are already open). 4023 */ 4024 if (override && error == EACCES && cred->cr_uid == vattr.va_uid) 4025 error = 0; 4026 return error; 4027 } 4028 #endif /* NFS_NOSERVER */ 4029 4030