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