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; 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 return (error); 1876 } 1877 1878 /* 1879 * nfs v3 mknod service 1880 */ 1881 int 1882 nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1883 struct thread *td, struct mbuf **mrq) 1884 { 1885 struct sockaddr *nam = nfsd->nd_nam; 1886 struct ucred *cred = &nfsd->nd_cr; 1887 struct vattr va, dirfor, diraft; 1888 struct vattr *vap = &va; 1889 u_int32_t *tl; 1890 struct nlookupdata nd; 1891 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 1892 enum vtype vtyp; 1893 struct vnode *dirp; 1894 struct vnode *dvp; 1895 struct vnode *vp; 1896 nfsfh_t nfh; 1897 fhandle_t *fhp; 1898 struct nfsm_info info; 1899 1900 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 1901 nlookup_zero(&nd); 1902 dirp = NULL; 1903 dvp = NULL; 1904 vp = NULL; 1905 1906 info.mrep = nfsd->nd_mrep; 1907 info.mreq = NULL; 1908 info.md = nfsd->nd_md; 1909 info.dpos = nfsd->nd_dpos; 1910 1911 fhp = &nfh.fh_generic; 1912 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 1913 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 1914 1915 /* 1916 * Handle nfs_namei() call. If an error occurs, the nd structure 1917 * is not valid. However, nfsm_*() routines may still jump to 1918 * nfsmout. 1919 */ 1920 1921 error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp, 1922 fhp, len, slp, nam, &info.md, &info.dpos, &dirp, 1923 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 1924 if (dirp) 1925 dirfor_ret = VOP_GETATTR(dirp, &dirfor); 1926 if (error) { 1927 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 1928 NFSX_WCCDATA(1), &error)); 1929 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 1930 diraft_ret, &diraft); 1931 error = 0; 1932 goto nfsmout; 1933 } 1934 NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED)); 1935 vtyp = nfsv3tov_type(*tl); 1936 if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) { 1937 error = NFSERR_BADTYPE; 1938 goto out; 1939 } 1940 VATTR_NULL(vap); 1941 ERROROUT(nfsm_srvsattr(&info, vap)); 1942 if (vtyp == VCHR || vtyp == VBLK) { 1943 NULLOUT(tl = nfsm_dissect(&info, 2 * NFSX_UNSIGNED)); 1944 vap->va_rmajor = fxdr_unsigned(u_int32_t, *tl++); 1945 vap->va_rminor = fxdr_unsigned(u_int32_t, *tl); 1946 } 1947 1948 /* 1949 * Iff doesn't exist, create it. 1950 */ 1951 if (vp) { 1952 error = EEXIST; 1953 goto out; 1954 } 1955 vap->va_type = vtyp; 1956 if (vap->va_mode == (mode_t)VNOVAL) 1957 vap->va_mode = 0; 1958 if (vtyp == VSOCK) { 1959 vn_unlock(dvp); 1960 error = VOP_NCREATE(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap); 1961 vrele(dvp); 1962 dvp = NULL; 1963 } else { 1964 if (vtyp != VFIFO && (error = priv_check_cred(cred, PRIV_ROOT, 0))) 1965 goto out; 1966 1967 vn_unlock(dvp); 1968 error = VOP_NMKNOD(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap); 1969 vrele(dvp); 1970 dvp = NULL; 1971 if (error) 1972 goto out; 1973 } 1974 1975 /* 1976 * send response, cleanup, return. 1977 */ 1978 out: 1979 nlookup_done(&nd); 1980 if (dvp) { 1981 if (dvp == vp) 1982 vrele(dvp); 1983 else 1984 vput(dvp); 1985 dvp = NULL; 1986 } 1987 if (!error) { 1988 bzero(&fhp->fh_fid, sizeof(fhp->fh_fid)); 1989 error = VFS_VPTOFH(vp, &fhp->fh_fid); 1990 if (!error) 1991 error = VOP_GETATTR(vp, vap); 1992 } 1993 if (vp) { 1994 vput(vp); 1995 vp = NULL; 1996 } 1997 diraft_ret = VOP_GETATTR(dirp, &diraft); 1998 if (dirp) { 1999 vrele(dirp); 2000 dirp = NULL; 2001 } 2002 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2003 NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + 2004 NFSX_WCCDATA(1), &error)); 2005 if (!error) { 2006 nfsm_srvpostop_fh(&info, fhp); 2007 nfsm_srvpostop_attr(&info, nfsd, 0, vap); 2008 } 2009 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2010 diraft_ret, &diraft); 2011 *mrq = info.mreq; 2012 return (0); 2013 nfsmout: 2014 *mrq = info.mreq; 2015 if (dirp) 2016 vrele(dirp); 2017 nlookup_done(&nd); 2018 if (dvp) { 2019 if (dvp == vp) 2020 vrele(dvp); 2021 else 2022 vput(dvp); 2023 } 2024 if (vp) 2025 vput(vp); 2026 return (error); 2027 } 2028 2029 /* 2030 * nfs remove service 2031 */ 2032 int 2033 nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2034 struct thread *td, struct mbuf **mrq) 2035 { 2036 struct sockaddr *nam = nfsd->nd_nam; 2037 struct ucred *cred = &nfsd->nd_cr; 2038 struct nlookupdata nd; 2039 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 2040 struct vnode *dirp; 2041 struct vnode *dvp; 2042 struct vnode *vp; 2043 struct vattr dirfor, diraft; 2044 nfsfh_t nfh; 2045 fhandle_t *fhp; 2046 struct nfsm_info info; 2047 2048 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 2049 nlookup_zero(&nd); 2050 dirp = NULL; 2051 dvp = NULL; 2052 vp = NULL; 2053 2054 info.mrep = nfsd->nd_mrep; 2055 info.mreq = NULL; 2056 info.md = nfsd->nd_md; 2057 info.dpos = nfsd->nd_dpos; 2058 info.v3 = (nfsd->nd_flag & ND_NFSV3); 2059 2060 fhp = &nfh.fh_generic; 2061 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 2062 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 2063 2064 error = nfs_namei(&nd, cred, NLC_DELETE, &dvp, &vp, 2065 fhp, len, slp, nam, &info.md, &info.dpos, &dirp, 2066 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2067 if (dirp) { 2068 if (info.v3) 2069 dirfor_ret = VOP_GETATTR(dirp, &dirfor); 2070 } 2071 if (error == 0) { 2072 if (vp->v_type == VDIR) { 2073 error = EPERM; /* POSIX */ 2074 goto out; 2075 } 2076 /* 2077 * The root of a mounted filesystem cannot be deleted. 2078 */ 2079 if (vp->v_flag & VROOT) { 2080 error = EBUSY; 2081 goto out; 2082 } 2083 out: 2084 if (!error) { 2085 if (dvp != vp) 2086 vn_unlock(dvp); 2087 if (vp) { 2088 vput(vp); 2089 vp = NULL; 2090 } 2091 error = VOP_NREMOVE(&nd.nl_nch, dvp, nd.nl_cred); 2092 vrele(dvp); 2093 dvp = NULL; 2094 } 2095 } 2096 if (dirp && info.v3) 2097 diraft_ret = VOP_GETATTR(dirp, &diraft); 2098 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_WCCDATA(info.v3), &error)); 2099 if (info.v3) { 2100 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2101 diraft_ret, &diraft); 2102 error = 0; 2103 } 2104 nfsmout: 2105 *mrq = info.mreq; 2106 nlookup_done(&nd); 2107 if (dirp) 2108 vrele(dirp); 2109 if (dvp) { 2110 if (dvp == vp) 2111 vrele(dvp); 2112 else 2113 vput(dvp); 2114 } 2115 if (vp) 2116 vput(vp); 2117 return(error); 2118 } 2119 2120 /* 2121 * nfs rename service 2122 */ 2123 int 2124 nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2125 struct thread *td, struct mbuf **mrq) 2126 { 2127 struct sockaddr *nam = nfsd->nd_nam; 2128 struct ucred *cred = &nfsd->nd_cr; 2129 int error = 0, len, len2, fdirfor_ret = 1, fdiraft_ret = 1; 2130 int tdirfor_ret = 1, tdiraft_ret = 1; 2131 struct nlookupdata fromnd, tond; 2132 struct vnode *fvp, *fdirp, *fdvp; 2133 struct vnode *tvp, *tdirp, *tdvp; 2134 struct namecache *ncp; 2135 struct vattr fdirfor, fdiraft, tdirfor, tdiraft; 2136 nfsfh_t fnfh, tnfh; 2137 fhandle_t *ffhp, *tfhp; 2138 uid_t saved_uid; 2139 struct nfsm_info info; 2140 2141 info.mrep = nfsd->nd_mrep; 2142 info.mreq = NULL; 2143 info.md = nfsd->nd_md; 2144 info.dpos = nfsd->nd_dpos; 2145 info.v3 = (nfsd->nd_flag & ND_NFSV3); 2146 2147 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 2148 #ifndef nolint 2149 fvp = NULL; 2150 #endif 2151 ffhp = &fnfh.fh_generic; 2152 tfhp = &tnfh.fh_generic; 2153 2154 /* 2155 * Clear fields incase goto nfsmout occurs from macro. 2156 */ 2157 2158 nlookup_zero(&fromnd); 2159 nlookup_zero(&tond); 2160 fdirp = NULL; 2161 tdirp = NULL; 2162 2163 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, ffhp, &error)); 2164 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 2165 2166 /* 2167 * Remember our original uid so that we can reset cr_uid before 2168 * the second nfs_namei() call, in case it is remapped. 2169 */ 2170 saved_uid = cred->cr_uid; 2171 error = nfs_namei(&fromnd, cred, NLC_RENAME_SRC, 2172 NULL, NULL, 2173 ffhp, len, slp, nam, &info.md, &info.dpos, &fdirp, 2174 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2175 if (fdirp) { 2176 if (info.v3) 2177 fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor); 2178 } 2179 if (error) { 2180 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2181 2 * NFSX_WCCDATA(info.v3), &error)); 2182 nfsm_srvwcc_data(&info, nfsd, fdirfor_ret, &fdirfor, 2183 fdiraft_ret, &fdiraft); 2184 nfsm_srvwcc_data(&info, nfsd, tdirfor_ret, &tdirfor, 2185 tdiraft_ret, &tdiraft); 2186 error = 0; 2187 goto nfsmout; 2188 } 2189 2190 /* 2191 * We have to unlock the from ncp before we can safely lookup 2192 * the target ncp. 2193 */ 2194 KKASSERT(fromnd.nl_flags & NLC_NCPISLOCKED); 2195 cache_unlock(&fromnd.nl_nch); 2196 fromnd.nl_flags &= ~NLC_NCPISLOCKED; 2197 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, tfhp, &error)); 2198 NEGATIVEOUT(len2 = nfsm_strsiz(&info, NFS_MAXNAMLEN)); 2199 cred->cr_uid = saved_uid; 2200 2201 error = nfs_namei(&tond, cred, NLC_RENAME_DST, NULL, NULL, 2202 tfhp, len2, slp, nam, &info.md, &info.dpos, &tdirp, 2203 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2204 if (tdirp) { 2205 if (info.v3) 2206 tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor); 2207 } 2208 if (error) 2209 goto out1; 2210 2211 /* 2212 * relock the source 2213 */ 2214 if (cache_lock_nonblock(&fromnd.nl_nch) == 0) { 2215 cache_resolve(&fromnd.nl_nch, fromnd.nl_cred); 2216 } else if (fromnd.nl_nch.ncp > tond.nl_nch.ncp) { 2217 cache_lock(&fromnd.nl_nch); 2218 cache_resolve(&fromnd.nl_nch, fromnd.nl_cred); 2219 } else { 2220 cache_unlock(&tond.nl_nch); 2221 cache_lock(&fromnd.nl_nch); 2222 cache_resolve(&fromnd.nl_nch, fromnd.nl_cred); 2223 cache_lock(&tond.nl_nch); 2224 cache_resolve(&tond.nl_nch, tond.nl_cred); 2225 } 2226 fromnd.nl_flags |= NLC_NCPISLOCKED; 2227 2228 fvp = fromnd.nl_nch.ncp->nc_vp; 2229 tvp = tond.nl_nch.ncp->nc_vp; 2230 2231 /* 2232 * Set fdvp and tdvp. We haven't done all the topology checks 2233 * so these can wind up NULL (e.g. if either fvp or tvp is a mount 2234 * point). If we get through the checks these will be guarenteed 2235 * to be non-NULL. 2236 * 2237 * Holding the children ncp's should be sufficient to prevent 2238 * fdvp and tdvp ripouts. 2239 */ 2240 if (fromnd.nl_nch.ncp->nc_parent) 2241 fdvp = fromnd.nl_nch.ncp->nc_parent->nc_vp; 2242 else 2243 fdvp = NULL; 2244 if (tond.nl_nch.ncp->nc_parent) 2245 tdvp = tond.nl_nch.ncp->nc_parent->nc_vp; 2246 else 2247 tdvp = NULL; 2248 2249 if (tvp != NULL) { 2250 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 2251 if (info.v3) 2252 error = EEXIST; 2253 else 2254 error = EISDIR; 2255 goto out; 2256 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 2257 if (info.v3) 2258 error = EEXIST; 2259 else 2260 error = ENOTDIR; 2261 goto out; 2262 } 2263 if (tvp->v_type == VDIR && (tond.nl_nch.ncp->nc_flag & NCF_ISMOUNTPT)) { 2264 if (info.v3) 2265 error = EXDEV; 2266 else 2267 error = ENOTEMPTY; 2268 goto out; 2269 } 2270 } 2271 if (fvp->v_type == VDIR && (fromnd.nl_nch.ncp->nc_flag & NCF_ISMOUNTPT)) { 2272 if (info.v3) 2273 error = EXDEV; 2274 else 2275 error = ENOTEMPTY; 2276 goto out; 2277 } 2278 if (fromnd.nl_nch.mount != tond.nl_nch.mount) { 2279 if (info.v3) 2280 error = EXDEV; 2281 else 2282 error = ENOTEMPTY; 2283 goto out; 2284 } 2285 if (fromnd.nl_nch.ncp == tond.nl_nch.ncp->nc_parent) { 2286 if (info.v3) 2287 error = EINVAL; 2288 else 2289 error = ENOTEMPTY; 2290 } 2291 2292 /* 2293 * You cannot rename a source into itself or a subdirectory of itself. 2294 * We check this by travsering the target directory upwards looking 2295 * for a match against the source. 2296 */ 2297 if (error == 0) { 2298 for (ncp = tond.nl_nch.ncp; ncp; ncp = ncp->nc_parent) { 2299 if (fromnd.nl_nch.ncp == ncp) { 2300 error = EINVAL; 2301 break; 2302 } 2303 } 2304 } 2305 2306 /* 2307 * If source is the same as the destination (that is the 2308 * same vnode with the same name in the same directory), 2309 * then there is nothing to do. 2310 */ 2311 if (fromnd.nl_nch.ncp == tond.nl_nch.ncp) 2312 error = -1; 2313 out: 2314 if (!error) { 2315 /* 2316 * The VOP_NRENAME function releases all vnode references & 2317 * locks prior to returning so we need to clear the pointers 2318 * to bypass cleanup code later on. 2319 */ 2320 error = VOP_NRENAME(&fromnd.nl_nch, &tond.nl_nch, 2321 fdvp, tdvp, tond.nl_cred); 2322 } else { 2323 if (error == -1) 2324 error = 0; 2325 } 2326 /* fall through */ 2327 2328 out1: 2329 if (fdirp) 2330 fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft); 2331 if (tdirp) 2332 tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft); 2333 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2334 2 * NFSX_WCCDATA(info.v3), &error)); 2335 if (info.v3) { 2336 nfsm_srvwcc_data(&info, nfsd, fdirfor_ret, &fdirfor, 2337 fdiraft_ret, &fdiraft); 2338 nfsm_srvwcc_data(&info, nfsd, tdirfor_ret, &tdirfor, 2339 tdiraft_ret, &tdiraft); 2340 } 2341 error = 0; 2342 /* fall through */ 2343 2344 nfsmout: 2345 *mrq = info.mreq; 2346 if (tdirp) 2347 vrele(tdirp); 2348 nlookup_done(&tond); 2349 if (fdirp) 2350 vrele(fdirp); 2351 nlookup_done(&fromnd); 2352 return (error); 2353 } 2354 2355 /* 2356 * nfs link service 2357 */ 2358 int 2359 nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2360 struct thread *td, struct mbuf **mrq) 2361 { 2362 struct sockaddr *nam = nfsd->nd_nam; 2363 struct ucred *cred = &nfsd->nd_cr; 2364 struct nlookupdata nd; 2365 int error = 0, rdonly, len, dirfor_ret = 1, diraft_ret = 1; 2366 int getret = 1; 2367 struct vnode *dirp; 2368 struct vnode *dvp; 2369 struct vnode *vp; 2370 struct vnode *xp; 2371 struct mount *xmp; 2372 struct vattr dirfor, diraft, at; 2373 nfsfh_t nfh, dnfh; 2374 fhandle_t *fhp, *dfhp; 2375 struct nfsm_info info; 2376 2377 info.mrep = nfsd->nd_mrep; 2378 info.mreq = NULL; 2379 info.md = nfsd->nd_md; 2380 info.dpos = nfsd->nd_dpos; 2381 info.v3 = (nfsd->nd_flag & ND_NFSV3); 2382 2383 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 2384 nlookup_zero(&nd); 2385 dirp = dvp = vp = xp = NULL; 2386 xmp = NULL; 2387 2388 fhp = &nfh.fh_generic; 2389 dfhp = &dnfh.fh_generic; 2390 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 2391 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, dfhp, &error)); 2392 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 2393 2394 error = nfsrv_fhtovp(fhp, FALSE, &xmp, &xp, cred, slp, nam, 2395 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 2396 if (error) { 2397 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2398 NFSX_POSTOPATTR(info.v3) + 2399 NFSX_WCCDATA(info.v3), 2400 &error)); 2401 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 2402 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2403 diraft_ret, &diraft); 2404 xp = NULL; 2405 error = 0; 2406 goto nfsmout; 2407 } 2408 if (xp->v_type == VDIR) { 2409 error = EPERM; /* POSIX */ 2410 goto out1; 2411 } 2412 2413 error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp, 2414 dfhp, len, slp, nam, &info.md, &info.dpos, &dirp, 2415 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2416 if (dirp) { 2417 if (info.v3) 2418 dirfor_ret = VOP_GETATTR(dirp, &dirfor); 2419 } 2420 if (error) 2421 goto out1; 2422 2423 if (vp != NULL) { 2424 error = EEXIST; 2425 goto out; 2426 } 2427 if (xp->v_mount != dvp->v_mount) 2428 error = EXDEV; 2429 out: 2430 if (!error) { 2431 vn_unlock(dvp); 2432 error = VOP_NLINK(&nd.nl_nch, dvp, xp, nd.nl_cred); 2433 vrele(dvp); 2434 dvp = NULL; 2435 } 2436 /* fall through */ 2437 2438 out1: 2439 if (info.v3) 2440 getret = VOP_GETATTR(xp, &at); 2441 if (dirp) 2442 diraft_ret = VOP_GETATTR(dirp, &diraft); 2443 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2444 NFSX_POSTOPATTR(info.v3) + NFSX_WCCDATA(info.v3), 2445 &error)); 2446 if (info.v3) { 2447 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 2448 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2449 diraft_ret, &diraft); 2450 error = 0; 2451 } 2452 /* fall through */ 2453 2454 nfsmout: 2455 *mrq = info.mreq; 2456 nlookup_done(&nd); 2457 if (dirp) 2458 vrele(dirp); 2459 if (xp) 2460 vrele(xp); 2461 if (dvp) { 2462 if (dvp == vp) 2463 vrele(dvp); 2464 else 2465 vput(dvp); 2466 } 2467 if (vp) 2468 vput(vp); 2469 return(error); 2470 } 2471 2472 /* 2473 * nfs symbolic link service 2474 */ 2475 int 2476 nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2477 struct thread *td, struct mbuf **mrq) 2478 { 2479 struct sockaddr *nam = nfsd->nd_nam; 2480 struct ucred *cred = &nfsd->nd_cr; 2481 struct vattr va, dirfor, diraft; 2482 struct nlookupdata nd; 2483 struct vattr *vap = &va; 2484 struct nfsv2_sattr *sp; 2485 char *pathcp = NULL; 2486 struct uio io; 2487 struct iovec iv; 2488 int error = 0, len, len2, dirfor_ret = 1, diraft_ret = 1; 2489 struct vnode *dirp; 2490 struct vnode *vp; 2491 struct vnode *dvp; 2492 nfsfh_t nfh; 2493 fhandle_t *fhp; 2494 struct nfsm_info info; 2495 2496 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 2497 nlookup_zero(&nd); 2498 dirp = NULL; 2499 dvp = NULL; 2500 vp = NULL; 2501 2502 info.mrep = nfsd->nd_mrep; 2503 info.mreq = NULL; 2504 info.md = nfsd->nd_md; 2505 info.dpos = nfsd->nd_dpos; 2506 info.v3 = (nfsd->nd_flag & ND_NFSV3); 2507 2508 fhp = &nfh.fh_generic; 2509 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 2510 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 2511 2512 error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp, 2513 fhp, len, slp, nam, &info.md, &info.dpos, &dirp, 2514 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2515 if (dirp) { 2516 if (info.v3) 2517 dirfor_ret = VOP_GETATTR(dirp, &dirfor); 2518 } 2519 if (error) 2520 goto out; 2521 2522 VATTR_NULL(vap); 2523 if (info.v3) { 2524 ERROROUT(nfsm_srvsattr(&info, vap)); 2525 } 2526 NEGATIVEOUT(len2 = nfsm_strsiz(&info, NFS_MAXPATHLEN)); 2527 pathcp = kmalloc(len2 + 1, M_TEMP, M_WAITOK); 2528 iv.iov_base = pathcp; 2529 iv.iov_len = len2; 2530 io.uio_resid = len2; 2531 io.uio_offset = 0; 2532 io.uio_iov = &iv; 2533 io.uio_iovcnt = 1; 2534 io.uio_segflg = UIO_SYSSPACE; 2535 io.uio_rw = UIO_READ; 2536 io.uio_td = NULL; 2537 ERROROUT(nfsm_mtouio(&info, &io, len2)); 2538 if (info.v3 == 0) { 2539 NULLOUT(sp = nfsm_dissect(&info, NFSX_V2SATTR)); 2540 vap->va_mode = nfstov_mode(sp->sa_mode); 2541 } 2542 *(pathcp + len2) = '\0'; 2543 if (vp) { 2544 error = EEXIST; 2545 goto out; 2546 } 2547 2548 if (vap->va_mode == (mode_t)VNOVAL) 2549 vap->va_mode = 0; 2550 if (dvp != vp) 2551 vn_unlock(dvp); 2552 error = VOP_NSYMLINK(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap, pathcp); 2553 vrele(dvp); 2554 dvp = NULL; 2555 if (error == 0) { 2556 bzero(&fhp->fh_fid, sizeof(fhp->fh_fid)); 2557 error = VFS_VPTOFH(vp, &fhp->fh_fid); 2558 if (!error) 2559 error = VOP_GETATTR(vp, vap); 2560 } 2561 2562 out: 2563 if (dvp) { 2564 if (dvp == vp) 2565 vrele(dvp); 2566 else 2567 vput(dvp); 2568 } 2569 if (vp) { 2570 vput(vp); 2571 vp = NULL; 2572 } 2573 if (pathcp) { 2574 kfree(pathcp, M_TEMP); 2575 pathcp = NULL; 2576 } 2577 if (dirp) { 2578 diraft_ret = VOP_GETATTR(dirp, &diraft); 2579 vrele(dirp); 2580 dirp = NULL; 2581 } 2582 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2583 NFSX_SRVFH(info.v3) + NFSX_POSTOPATTR(info.v3) + 2584 NFSX_WCCDATA(info.v3), 2585 &error)); 2586 if (info.v3) { 2587 if (!error) { 2588 nfsm_srvpostop_fh(&info, fhp); 2589 nfsm_srvpostop_attr(&info, nfsd, 0, vap); 2590 } 2591 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2592 diraft_ret, &diraft); 2593 } 2594 error = 0; 2595 /* fall through */ 2596 2597 nfsmout: 2598 *mrq = info.mreq; 2599 nlookup_done(&nd); 2600 if (vp) 2601 vput(vp); 2602 if (dirp) 2603 vrele(dirp); 2604 if (pathcp) 2605 kfree(pathcp, M_TEMP); 2606 return (error); 2607 } 2608 2609 /* 2610 * nfs mkdir service 2611 */ 2612 int 2613 nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2614 struct thread *td, struct mbuf **mrq) 2615 { 2616 struct sockaddr *nam = nfsd->nd_nam; 2617 struct ucred *cred = &nfsd->nd_cr; 2618 struct vattr va, dirfor, diraft; 2619 struct vattr *vap = &va; 2620 struct nfs_fattr *fp; 2621 struct nlookupdata nd; 2622 u_int32_t *tl; 2623 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 2624 struct vnode *dirp; 2625 struct vnode *dvp; 2626 struct vnode *vp; 2627 nfsfh_t nfh; 2628 fhandle_t *fhp; 2629 struct nfsm_info info; 2630 2631 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 2632 nlookup_zero(&nd); 2633 dirp = NULL; 2634 dvp = NULL; 2635 vp = NULL; 2636 2637 info.dpos = nfsd->nd_dpos; 2638 info.mrep = nfsd->nd_mrep; 2639 info.mreq = NULL; 2640 info.md = nfsd->nd_md; 2641 info.v3 = (nfsd->nd_flag & ND_NFSV3); 2642 2643 fhp = &nfh.fh_generic; 2644 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 2645 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 2646 2647 error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp, 2648 fhp, len, slp, nam, &info.md, &info.dpos, &dirp, 2649 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2650 if (dirp) { 2651 if (info.v3) 2652 dirfor_ret = VOP_GETATTR(dirp, &dirfor); 2653 } 2654 if (error) { 2655 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2656 NFSX_WCCDATA(info.v3), &error)); 2657 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2658 diraft_ret, &diraft); 2659 error = 0; 2660 goto nfsmout; 2661 } 2662 VATTR_NULL(vap); 2663 if (info.v3) { 2664 ERROROUT(nfsm_srvsattr(&info, vap)); 2665 } else { 2666 NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED)); 2667 vap->va_mode = nfstov_mode(*tl++); 2668 } 2669 2670 /* 2671 * At this point nd.ni_dvp is referenced and exclusively locked and 2672 * nd.ni_vp, if it exists, is referenced but not locked. 2673 */ 2674 2675 vap->va_type = VDIR; 2676 if (vp != NULL) { 2677 error = EEXIST; 2678 goto out; 2679 } 2680 2681 /* 2682 * Issue mkdir op. Since SAVESTART is not set, the pathname 2683 * component is freed by the VOP call. This will fill-in 2684 * nd.ni_vp, reference, and exclusively lock it. 2685 */ 2686 if (vap->va_mode == (mode_t)VNOVAL) 2687 vap->va_mode = 0; 2688 vn_unlock(dvp); 2689 error = VOP_NMKDIR(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap); 2690 vrele(dvp); 2691 dvp = NULL; 2692 2693 if (error == 0) { 2694 bzero(&fhp->fh_fid, sizeof(fhp->fh_fid)); 2695 error = VFS_VPTOFH(vp, &fhp->fh_fid); 2696 if (error == 0) 2697 error = VOP_GETATTR(vp, vap); 2698 } 2699 out: 2700 if (dirp) 2701 diraft_ret = VOP_GETATTR(dirp, &diraft); 2702 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2703 NFSX_SRVFH(info.v3) + NFSX_POSTOPATTR(info.v3) + 2704 NFSX_WCCDATA(info.v3), 2705 &error)); 2706 if (info.v3) { 2707 if (!error) { 2708 nfsm_srvpostop_fh(&info, fhp); 2709 nfsm_srvpostop_attr(&info, nfsd, 0, vap); 2710 } 2711 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2712 diraft_ret, &diraft); 2713 } else { 2714 nfsm_srvfhtom(&info, fhp); 2715 fp = nfsm_build(&info, NFSX_V2FATTR); 2716 nfsm_srvfattr(nfsd, vap, fp); 2717 } 2718 error = 0; 2719 /* fall through */ 2720 2721 nfsmout: 2722 *mrq = info.mreq; 2723 nlookup_done(&nd); 2724 if (dirp) 2725 vrele(dirp); 2726 if (dvp) { 2727 if (dvp == vp) 2728 vrele(dvp); 2729 else 2730 vput(dvp); 2731 } 2732 if (vp) 2733 vput(vp); 2734 return (error); 2735 } 2736 2737 /* 2738 * nfs rmdir service 2739 */ 2740 int 2741 nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2742 struct thread *td, struct mbuf **mrq) 2743 { 2744 struct sockaddr *nam = nfsd->nd_nam; 2745 struct ucred *cred = &nfsd->nd_cr; 2746 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 2747 struct vnode *dirp; 2748 struct vnode *dvp; 2749 struct vnode *vp; 2750 struct vattr dirfor, diraft; 2751 nfsfh_t nfh; 2752 fhandle_t *fhp; 2753 struct nlookupdata nd; 2754 struct nfsm_info info; 2755 2756 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 2757 nlookup_zero(&nd); 2758 dirp = NULL; 2759 dvp = NULL; 2760 vp = NULL; 2761 2762 info.mrep = nfsd->nd_mrep; 2763 info.mreq = NULL; 2764 info.md = nfsd->nd_md; 2765 info.dpos = nfsd->nd_dpos; 2766 info.v3 = (nfsd->nd_flag & ND_NFSV3); 2767 2768 fhp = &nfh.fh_generic; 2769 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 2770 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error)); 2771 2772 error = nfs_namei(&nd, cred, NLC_DELETE, &dvp, &vp, 2773 fhp, len, slp, nam, &info.md, &info.dpos, &dirp, 2774 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2775 if (dirp) { 2776 if (info.v3) 2777 dirfor_ret = VOP_GETATTR(dirp, &dirfor); 2778 } 2779 if (error) { 2780 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2781 NFSX_WCCDATA(info.v3), &error)); 2782 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2783 diraft_ret, &diraft); 2784 error = 0; 2785 goto nfsmout; 2786 } 2787 if (vp->v_type != VDIR) { 2788 error = ENOTDIR; 2789 goto out; 2790 } 2791 2792 /* 2793 * The root of a mounted filesystem cannot be deleted. 2794 */ 2795 if (vp->v_flag & VROOT) 2796 error = EBUSY; 2797 out: 2798 /* 2799 * Issue or abort op. Since SAVESTART is not set, path name 2800 * component is freed by the VOP after either. 2801 */ 2802 if (!error) { 2803 if (dvp != vp) 2804 vn_unlock(dvp); 2805 vput(vp); 2806 vp = NULL; 2807 error = VOP_NRMDIR(&nd.nl_nch, dvp, nd.nl_cred); 2808 vrele(dvp); 2809 dvp = NULL; 2810 } 2811 nlookup_done(&nd); 2812 2813 if (dirp) 2814 diraft_ret = VOP_GETATTR(dirp, &diraft); 2815 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_WCCDATA(info.v3), &error)); 2816 if (info.v3) { 2817 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor, 2818 diraft_ret, &diraft); 2819 error = 0; 2820 } 2821 /* fall through */ 2822 2823 nfsmout: 2824 *mrq = info.mreq; 2825 if (dvp) { 2826 if (dvp == vp) 2827 vrele(dvp); 2828 else 2829 vput(dvp); 2830 } 2831 nlookup_done(&nd); 2832 if (dirp) 2833 vrele(dirp); 2834 if (vp) 2835 vput(vp); 2836 return(error); 2837 } 2838 2839 /* 2840 * nfs readdir service 2841 * - mallocs what it thinks is enough to read 2842 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 2843 * - calls VOP_READDIR() 2844 * - loops around building the reply 2845 * if the output generated exceeds count break out of loop 2846 * The nfsm_clget macro is used here so that the reply will be packed 2847 * tightly in mbuf clusters. 2848 * - it only knows that it has encountered eof when the VOP_READDIR() 2849 * reads nothing 2850 * - as such one readdir rpc will return eof false although you are there 2851 * and then the next will return eof 2852 * - it trims out records with d_fileno == 0 2853 * this doesn't matter for Unix clients, but they might confuse clients 2854 * for other os'. 2855 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 2856 * than requested, but this may not apply to all filesystems. For 2857 * example, client NFS does not { although it is never remote mounted 2858 * anyhow } 2859 * The alternate call nfsrv_readdirplus() does lookups as well. 2860 * PS: The NFS protocol spec. does not clarify what the "count" byte 2861 * argument is a count of.. just name strings and file id's or the 2862 * entire reply rpc or ... 2863 * I tried just file name and id sizes and it confused the Sun client, 2864 * so I am using the full rpc size now. The "paranoia.." comment refers 2865 * to including the status longwords that are not a part of the dir. 2866 * "entry" structures, but are in the rpc. 2867 */ 2868 struct flrep { 2869 nfsuint64 fl_off; 2870 u_int32_t fl_postopok; 2871 u_int32_t fl_fattr[NFSX_V3FATTR / sizeof (u_int32_t)]; 2872 u_int32_t fl_fhok; 2873 u_int32_t fl_fhsize; 2874 u_int32_t fl_nfh[NFSX_V3FH / sizeof (u_int32_t)]; 2875 }; 2876 2877 int 2878 nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2879 struct thread *td, struct mbuf **mrq) 2880 { 2881 struct sockaddr *nam = nfsd->nd_nam; 2882 struct ucred *cred = &nfsd->nd_cr; 2883 char *bp, *be; 2884 struct dirent *dp; 2885 caddr_t cp; 2886 u_int32_t *tl; 2887 struct mbuf *mp1, *mp2; 2888 char *cpos, *cend, *rbuf; 2889 struct vnode *vp = NULL; 2890 struct mount *mp = NULL; 2891 struct vattr at; 2892 nfsfh_t nfh; 2893 fhandle_t *fhp; 2894 struct uio io; 2895 struct iovec iv; 2896 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1; 2897 int siz, cnt, fullsiz, eofflag, rdonly, ncookies; 2898 u_quad_t off, toff; 2899 #if 0 2900 u_quad_t verf; 2901 #endif 2902 off_t *cookies = NULL, *cookiep; 2903 struct nfsm_info info; 2904 2905 info.mrep = nfsd->nd_mrep; 2906 info.mreq = NULL; 2907 info.md = nfsd->nd_md; 2908 info.dpos = nfsd->nd_dpos; 2909 info.v3 = (nfsd->nd_flag & ND_NFSV3); 2910 2911 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 2912 fhp = &nfh.fh_generic; 2913 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 2914 if (info.v3) { 2915 NULLOUT(tl = nfsm_dissect(&info, 5 * NFSX_UNSIGNED)); 2916 toff = fxdr_hyper(tl); 2917 tl += 2; 2918 #if 0 2919 verf = fxdr_hyper(tl); 2920 #endif 2921 tl += 2; 2922 } else { 2923 NULLOUT(tl = nfsm_dissect(&info, 2 * NFSX_UNSIGNED)); 2924 toff = fxdr_unsigned(u_quad_t, *tl++); 2925 #if 0 2926 verf = 0; /* shut up gcc */ 2927 #endif 2928 } 2929 off = toff; 2930 cnt = fxdr_unsigned(int, *tl); 2931 siz = roundup2(cnt, DIRBLKSIZ); 2932 xfer = NFS_SRVMAXDATA(nfsd); 2933 if ((unsigned)cnt > xfer) 2934 cnt = xfer; 2935 if ((unsigned)siz > xfer) 2936 siz = xfer; 2937 fullsiz = siz; 2938 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 2939 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 2940 if (!error && vp->v_type != VDIR) { 2941 error = ENOTDIR; 2942 vput(vp); 2943 vp = NULL; 2944 } 2945 if (error) { 2946 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error)); 2947 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 2948 error = 0; 2949 goto nfsmout; 2950 } 2951 2952 /* 2953 * Obtain lock on vnode for this section of the code 2954 */ 2955 2956 if (info.v3) { 2957 error = getret = VOP_GETATTR(vp, &at); 2958 #if 0 2959 /* 2960 * XXX This check may be too strict for Solaris 2.5 clients. 2961 */ 2962 if (!error && toff && verf && verf != at.va_filerev) 2963 error = NFSERR_BAD_COOKIE; 2964 #endif 2965 } 2966 if (!error) 2967 error = nfsrv_access(mp, vp, VEXEC, cred, rdonly, td, 0); 2968 if (error) { 2969 vput(vp); 2970 vp = NULL; 2971 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 2972 NFSX_POSTOPATTR(info.v3), &error)); 2973 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 2974 error = 0; 2975 goto nfsmout; 2976 } 2977 vn_unlock(vp); 2978 2979 /* 2980 * end section. Allocate rbuf and continue 2981 */ 2982 rbuf = kmalloc(siz, M_TEMP, M_WAITOK); 2983 again: 2984 iv.iov_base = rbuf; 2985 iv.iov_len = fullsiz; 2986 io.uio_iov = &iv; 2987 io.uio_iovcnt = 1; 2988 io.uio_offset = (off_t)off; 2989 io.uio_resid = fullsiz; 2990 io.uio_segflg = UIO_SYSSPACE; 2991 io.uio_rw = UIO_READ; 2992 io.uio_td = NULL; 2993 eofflag = 0; 2994 if (cookies) { 2995 kfree((caddr_t)cookies, M_TEMP); 2996 cookies = NULL; 2997 } 2998 error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies); 2999 off = (off_t)io.uio_offset; 3000 if (!cookies && !error) 3001 error = NFSERR_PERM; 3002 if (info.v3) { 3003 getret = VOP_GETATTR(vp, &at); 3004 if (!error) 3005 error = getret; 3006 } 3007 if (error) { 3008 vrele(vp); 3009 vp = NULL; 3010 kfree((caddr_t)rbuf, M_TEMP); 3011 if (cookies) 3012 kfree((caddr_t)cookies, M_TEMP); 3013 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3014 NFSX_POSTOPATTR(info.v3), &error)); 3015 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3016 error = 0; 3017 goto nfsmout; 3018 } 3019 if (io.uio_resid) { 3020 siz -= io.uio_resid; 3021 3022 /* 3023 * If nothing read, return eof 3024 * rpc reply 3025 */ 3026 if (siz == 0) { 3027 vrele(vp); 3028 vp = NULL; 3029 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3030 NFSX_POSTOPATTR(info.v3) + 3031 NFSX_COOKIEVERF(info.v3) + 3032 2 * NFSX_UNSIGNED, 3033 &error)); 3034 if (info.v3) { 3035 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3036 tl = nfsm_build(&info, 4 * NFSX_UNSIGNED); 3037 txdr_hyper(at.va_filerev, tl); 3038 tl += 2; 3039 } else 3040 tl = nfsm_build(&info, 2 * NFSX_UNSIGNED); 3041 *tl++ = nfs_false; 3042 *tl = nfs_true; 3043 kfree((caddr_t)rbuf, M_TEMP); 3044 kfree((caddr_t)cookies, M_TEMP); 3045 error = 0; 3046 goto nfsmout; 3047 } 3048 } 3049 3050 /* 3051 * Check for degenerate cases of nothing useful read. 3052 * If so go try again 3053 */ 3054 cpos = rbuf; 3055 cend = rbuf + siz; 3056 dp = (struct dirent *)cpos; 3057 cookiep = cookies; 3058 /* 3059 * For some reason FreeBSD's ufs_readdir() chooses to back the 3060 * directory offset up to a block boundary, so it is necessary to 3061 * skip over the records that preceed the requested offset. This 3062 * requires the assumption that file offset cookies monotonically 3063 * increase. 3064 */ 3065 while (cpos < cend && ncookies > 0 && 3066 (dp->d_ino == 0 || dp->d_type == DT_WHT || 3067 ((u_quad_t)(*cookiep)) <= toff)) { 3068 dp = _DIRENT_NEXT(dp); 3069 cpos = (char *)dp; 3070 cookiep++; 3071 ncookies--; 3072 } 3073 if (cpos >= cend || ncookies == 0) { 3074 toff = off; 3075 siz = fullsiz; 3076 goto again; 3077 } 3078 3079 len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 3080 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3081 NFSX_POSTOPATTR(info.v3) + 3082 NFSX_COOKIEVERF(info.v3) + siz, 3083 &error)); 3084 if (info.v3) { 3085 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3086 tl = nfsm_build(&info, 2 * NFSX_UNSIGNED); 3087 txdr_hyper(at.va_filerev, tl); 3088 } 3089 mp1 = mp2 = info.mb; 3090 bp = info.bpos; 3091 be = bp + M_TRAILINGSPACE(mp1); 3092 3093 /* Loop through the records and build reply */ 3094 while (cpos < cend && ncookies > 0) { 3095 if (dp->d_ino != 0 && dp->d_type != DT_WHT) { 3096 nlen = dp->d_namlen; 3097 rem = nfsm_rndup(nlen) - nlen; 3098 len += (4 * NFSX_UNSIGNED + nlen + rem); 3099 if (info.v3) 3100 len += 2 * NFSX_UNSIGNED; 3101 if (len > cnt) { 3102 eofflag = 0; 3103 break; 3104 } 3105 /* 3106 * Build the directory record xdr from 3107 * the dirent entry. 3108 */ 3109 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3110 *tl = nfs_true; 3111 bp += NFSX_UNSIGNED; 3112 if (info.v3) { 3113 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3114 *tl = txdr_unsigned(dp->d_ino >> 32); 3115 bp += NFSX_UNSIGNED; 3116 } 3117 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3118 *tl = txdr_unsigned(dp->d_ino); 3119 bp += NFSX_UNSIGNED; 3120 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3121 *tl = txdr_unsigned(nlen); 3122 bp += NFSX_UNSIGNED; 3123 3124 /* And loop around copying the name */ 3125 xfer = nlen; 3126 cp = dp->d_name; 3127 while (xfer > 0) { 3128 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3129 if ((bp+xfer) > be) 3130 tsiz = be-bp; 3131 else 3132 tsiz = xfer; 3133 bcopy(cp, bp, tsiz); 3134 bp += tsiz; 3135 xfer -= tsiz; 3136 if (xfer > 0) 3137 cp += tsiz; 3138 } 3139 /* And null pad to a int32_t boundary */ 3140 for (i = 0; i < rem; i++) 3141 *bp++ = '\0'; 3142 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3143 3144 /* Finish off the record */ 3145 if (info.v3) { 3146 *tl = txdr_unsigned(*cookiep >> 32); 3147 bp += NFSX_UNSIGNED; 3148 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3149 } 3150 *tl = txdr_unsigned(*cookiep); 3151 bp += NFSX_UNSIGNED; 3152 } 3153 dp = _DIRENT_NEXT(dp); 3154 cpos = (char *)dp; 3155 cookiep++; 3156 ncookies--; 3157 } 3158 vrele(vp); 3159 vp = NULL; 3160 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3161 *tl = nfs_false; 3162 bp += NFSX_UNSIGNED; 3163 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3164 if (eofflag) 3165 *tl = nfs_true; 3166 else 3167 *tl = nfs_false; 3168 bp += NFSX_UNSIGNED; 3169 if (mp1 != info.mb) { 3170 if (bp < be) 3171 mp1->m_len = bp - mtod(mp1, caddr_t); 3172 } else 3173 mp1->m_len += bp - info.bpos; 3174 kfree((caddr_t)rbuf, M_TEMP); 3175 kfree((caddr_t)cookies, M_TEMP); 3176 3177 nfsmout: 3178 *mrq = info.mreq; 3179 if (vp) 3180 vrele(vp); 3181 return(error); 3182 } 3183 3184 int 3185 nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3186 struct thread *td, struct mbuf **mrq) 3187 { 3188 struct sockaddr *nam = nfsd->nd_nam; 3189 struct ucred *cred = &nfsd->nd_cr; 3190 char *bp, *be; 3191 struct dirent *dp; 3192 caddr_t cp; 3193 u_int32_t *tl; 3194 struct mbuf *mp1, *mp2; 3195 char *cpos, *cend, *rbuf; 3196 struct vnode *vp = NULL, *nvp; 3197 struct mount *mp = NULL; 3198 struct flrep fl; 3199 nfsfh_t nfh; 3200 fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh; 3201 struct uio io; 3202 struct iovec iv; 3203 struct vattr va, at, *vap = &va; 3204 struct nfs_fattr *fp; 3205 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1; 3206 int siz, cnt, fullsiz, eofflag, rdonly, dirlen, ncookies; 3207 u_quad_t off, toff; 3208 #if 0 3209 u_quad_t verf; 3210 #endif 3211 off_t *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */ 3212 struct nfsm_info info; 3213 3214 info.mrep = nfsd->nd_mrep; 3215 info.mreq = NULL; 3216 info.md = nfsd->nd_md; 3217 info.dpos = nfsd->nd_dpos; 3218 info.v3 = (nfsd->nd_flag & ND_NFSV3); 3219 3220 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3221 fhp = &nfh.fh_generic; 3222 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 3223 NULLOUT(tl = nfsm_dissect(&info, 6 * NFSX_UNSIGNED)); 3224 toff = fxdr_hyper(tl); 3225 tl += 2; 3226 #if 0 3227 verf = fxdr_hyper(tl); 3228 #endif 3229 tl += 2; 3230 siz = fxdr_unsigned(int, *tl++); 3231 cnt = fxdr_unsigned(int, *tl); 3232 off = toff; 3233 siz = roundup2(siz, DIRBLKSIZ); 3234 xfer = NFS_SRVMAXDATA(nfsd); 3235 if ((unsigned)cnt > xfer) 3236 cnt = xfer; 3237 if ((unsigned)siz > xfer) 3238 siz = xfer; 3239 fullsiz = siz; 3240 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 3241 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 3242 if (!error && vp->v_type != VDIR) { 3243 error = ENOTDIR; 3244 vput(vp); 3245 vp = NULL; 3246 } 3247 if (error) { 3248 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error)); 3249 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3250 error = 0; 3251 goto nfsmout; 3252 } 3253 error = getret = VOP_GETATTR(vp, &at); 3254 #if 0 3255 /* 3256 * XXX This check may be too strict for Solaris 2.5 clients. 3257 */ 3258 if (!error && toff && verf && verf != at.va_filerev) 3259 error = NFSERR_BAD_COOKIE; 3260 #endif 3261 if (!error) { 3262 error = nfsrv_access(mp, vp, VEXEC, cred, rdonly, td, 0); 3263 } 3264 if (error) { 3265 vput(vp); 3266 vp = NULL; 3267 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3268 NFSX_V3POSTOPATTR, &error)); 3269 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3270 error = 0; 3271 goto nfsmout; 3272 } 3273 vn_unlock(vp); 3274 rbuf = kmalloc(siz, M_TEMP, M_WAITOK); 3275 again: 3276 iv.iov_base = rbuf; 3277 iv.iov_len = fullsiz; 3278 io.uio_iov = &iv; 3279 io.uio_iovcnt = 1; 3280 io.uio_offset = (off_t)off; 3281 io.uio_resid = fullsiz; 3282 io.uio_segflg = UIO_SYSSPACE; 3283 io.uio_rw = UIO_READ; 3284 io.uio_td = NULL; 3285 eofflag = 0; 3286 if (cookies) { 3287 kfree((caddr_t)cookies, M_TEMP); 3288 cookies = NULL; 3289 } 3290 error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies); 3291 off = (u_quad_t)io.uio_offset; 3292 getret = VOP_GETATTR(vp, &at); 3293 if (!cookies && !error) 3294 error = NFSERR_PERM; 3295 if (!error) 3296 error = getret; 3297 if (error) { 3298 vrele(vp); 3299 vp = NULL; 3300 if (cookies) 3301 kfree((caddr_t)cookies, M_TEMP); 3302 kfree((caddr_t)rbuf, M_TEMP); 3303 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3304 NFSX_V3POSTOPATTR, &error)); 3305 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3306 error = 0; 3307 goto nfsmout; 3308 } 3309 if (io.uio_resid) { 3310 siz -= io.uio_resid; 3311 3312 /* 3313 * If nothing read, return eof 3314 * rpc reply 3315 */ 3316 if (siz == 0) { 3317 vrele(vp); 3318 vp = NULL; 3319 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3320 NFSX_V3POSTOPATTR + 3321 NFSX_V3COOKIEVERF + 3322 2 * NFSX_UNSIGNED, 3323 &error)); 3324 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3325 tl = nfsm_build(&info, 4 * NFSX_UNSIGNED); 3326 txdr_hyper(at.va_filerev, tl); 3327 tl += 2; 3328 *tl++ = nfs_false; 3329 *tl = nfs_true; 3330 kfree((caddr_t)cookies, M_TEMP); 3331 kfree((caddr_t)rbuf, M_TEMP); 3332 error = 0; 3333 goto nfsmout; 3334 } 3335 } 3336 3337 /* 3338 * Check for degenerate cases of nothing useful read. 3339 * If so go try again 3340 */ 3341 cpos = rbuf; 3342 cend = rbuf + siz; 3343 dp = (struct dirent *)cpos; 3344 cookiep = cookies; 3345 /* 3346 * For some reason FreeBSD's ufs_readdir() chooses to back the 3347 * directory offset up to a block boundary, so it is necessary to 3348 * skip over the records that preceed the requested offset. This 3349 * requires the assumption that file offset cookies monotonically 3350 * increase. 3351 */ 3352 while (cpos < cend && ncookies > 0 && 3353 (dp->d_ino == 0 || dp->d_type == DT_WHT || 3354 ((u_quad_t)(*cookiep)) <= toff)) { 3355 dp = _DIRENT_NEXT(dp); 3356 cpos = (char *)dp; 3357 cookiep++; 3358 ncookies--; 3359 } 3360 if (cpos >= cend || ncookies == 0) { 3361 toff = off; 3362 siz = fullsiz; 3363 goto again; 3364 } 3365 3366 /* 3367 * Probe one of the directory entries to see if the filesystem 3368 * supports VGET. 3369 */ 3370 if (VFS_VGET(vp->v_mount, vp, dp->d_ino, &nvp) == EOPNOTSUPP) { 3371 error = NFSERR_NOTSUPP; 3372 vrele(vp); 3373 vp = NULL; 3374 kfree((caddr_t)cookies, M_TEMP); 3375 kfree((caddr_t)rbuf, M_TEMP); 3376 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3377 NFSX_V3POSTOPATTR, &error)); 3378 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3379 error = 0; 3380 goto nfsmout; 3381 } 3382 if (nvp) { 3383 vput(nvp); 3384 nvp = NULL; 3385 } 3386 3387 dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 3388 2 * NFSX_UNSIGNED; 3389 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, cnt, &error)); 3390 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3391 tl = nfsm_build(&info, 2 * NFSX_UNSIGNED); 3392 txdr_hyper(at.va_filerev, tl); 3393 mp1 = mp2 = info.mb; 3394 bp = info.bpos; 3395 be = bp + M_TRAILINGSPACE(mp1); 3396 3397 /* Loop through the records and build reply */ 3398 while (cpos < cend && ncookies > 0) { 3399 if (dp->d_ino != 0 && dp->d_type != DT_WHT) { 3400 nlen = dp->d_namlen; 3401 rem = nfsm_rndup(nlen) - nlen; 3402 3403 /* 3404 * For readdir_and_lookup get the vnode using 3405 * the file number. 3406 */ 3407 if (VFS_VGET(vp->v_mount, vp, dp->d_ino, &nvp)) 3408 goto invalid; 3409 bzero((caddr_t)nfhp, NFSX_V3FH); 3410 nfhp->fh_fsid = fhp->fh_fsid; 3411 if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) { 3412 vput(nvp); 3413 nvp = NULL; 3414 goto invalid; 3415 } 3416 if (VOP_GETATTR(nvp, vap)) { 3417 vput(nvp); 3418 nvp = NULL; 3419 goto invalid; 3420 } 3421 vput(nvp); 3422 nvp = NULL; 3423 3424 /* 3425 * If either the dircount or maxcount will be 3426 * exceeded, get out now. Both of these lengths 3427 * are calculated conservatively, including all 3428 * XDR overheads. 3429 */ 3430 len += (8 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH + 3431 NFSX_V3POSTOPATTR); 3432 dirlen += (6 * NFSX_UNSIGNED + nlen + rem); 3433 if (len > cnt || dirlen > fullsiz) { 3434 eofflag = 0; 3435 break; 3436 } 3437 3438 /* 3439 * Build the directory record xdr from 3440 * the dirent entry. 3441 */ 3442 fp = (struct nfs_fattr *)&fl.fl_fattr; 3443 nfsm_srvfattr(nfsd, vap, fp); 3444 fl.fl_off.nfsuquad[0] = txdr_unsigned(*cookiep >> 32); 3445 fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep); 3446 fl.fl_postopok = nfs_true; 3447 fl.fl_fhok = nfs_true; 3448 fl.fl_fhsize = txdr_unsigned(NFSX_V3FH); 3449 3450 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3451 *tl = nfs_true; 3452 bp += NFSX_UNSIGNED; 3453 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3454 *tl = txdr_unsigned(dp->d_ino >> 32); 3455 bp += NFSX_UNSIGNED; 3456 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3457 *tl = txdr_unsigned(dp->d_ino); 3458 bp += NFSX_UNSIGNED; 3459 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3460 *tl = txdr_unsigned(nlen); 3461 bp += NFSX_UNSIGNED; 3462 3463 /* And loop around copying the name */ 3464 xfer = nlen; 3465 cp = dp->d_name; 3466 while (xfer > 0) { 3467 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3468 if ((bp + xfer) > be) 3469 tsiz = be - bp; 3470 else 3471 tsiz = xfer; 3472 bcopy(cp, bp, tsiz); 3473 bp += tsiz; 3474 xfer -= tsiz; 3475 cp += tsiz; 3476 } 3477 /* And null pad to a int32_t boundary */ 3478 for (i = 0; i < rem; i++) 3479 *bp++ = '\0'; 3480 3481 /* 3482 * Now copy the flrep structure out. 3483 */ 3484 xfer = sizeof (struct flrep); 3485 cp = (caddr_t)&fl; 3486 while (xfer > 0) { 3487 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3488 if ((bp + xfer) > be) 3489 tsiz = be - bp; 3490 else 3491 tsiz = xfer; 3492 bcopy(cp, bp, tsiz); 3493 bp += tsiz; 3494 xfer -= tsiz; 3495 cp += tsiz; 3496 } 3497 } 3498 invalid: 3499 dp = _DIRENT_NEXT(dp); 3500 cpos = (char *)dp; 3501 cookiep++; 3502 ncookies--; 3503 } 3504 vrele(vp); 3505 vp = NULL; 3506 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3507 *tl = nfs_false; 3508 bp += NFSX_UNSIGNED; 3509 tl = nfsm_clget(&info, mp1, mp2, bp, be); 3510 if (eofflag) 3511 *tl = nfs_true; 3512 else 3513 *tl = nfs_false; 3514 bp += NFSX_UNSIGNED; 3515 if (mp1 != info.mb) { 3516 if (bp < be) 3517 mp1->m_len = bp - mtod(mp1, caddr_t); 3518 } else 3519 mp1->m_len += bp - info.bpos; 3520 kfree((caddr_t)cookies, M_TEMP); 3521 kfree((caddr_t)rbuf, M_TEMP); 3522 nfsmout: 3523 *mrq = info.mreq; 3524 if (vp) 3525 vrele(vp); 3526 return(error); 3527 } 3528 3529 /* 3530 * nfs commit service 3531 */ 3532 int 3533 nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3534 struct thread *td, struct mbuf **mrq) 3535 { 3536 struct sockaddr *nam = nfsd->nd_nam; 3537 struct ucred *cred = &nfsd->nd_cr; 3538 struct vattr bfor, aft; 3539 struct vnode *vp = NULL; 3540 struct mount *mp = NULL; 3541 nfsfh_t nfh; 3542 fhandle_t *fhp; 3543 u_int32_t *tl; 3544 int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt; 3545 u_quad_t off; 3546 struct nfsm_info info; 3547 3548 info.mrep = nfsd->nd_mrep; 3549 info.mreq = NULL; 3550 info.md = nfsd->nd_md; 3551 info.dpos = nfsd->nd_dpos; 3552 3553 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3554 fhp = &nfh.fh_generic; 3555 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 3556 NULLOUT(tl = nfsm_dissect(&info, 3 * NFSX_UNSIGNED)); 3557 3558 /* 3559 * XXX At this time VOP_FSYNC() does not accept offset and byte 3560 * count parameters, so these arguments are useless (someday maybe). 3561 */ 3562 off = fxdr_hyper(tl); 3563 tl += 2; 3564 cnt = fxdr_unsigned(int, *tl); 3565 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 3566 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 3567 if (error) { 3568 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3569 2 * NFSX_UNSIGNED, &error)); 3570 nfsm_srvwcc_data(&info, nfsd, for_ret, &bfor, 3571 aft_ret, &aft); 3572 error = 0; 3573 goto nfsmout; 3574 } 3575 for_ret = VOP_GETATTR(vp, &bfor); 3576 3577 /* 3578 * RFC 1813 3.3.21: If count is 0, a flush from offset to the end of 3579 * file is done. At this time VOP_FSYNC does not accept offset and 3580 * byte count parameters, so call VOP_FSYNC the whole file for now. 3581 */ 3582 if (cnt == 0 || cnt > MAX_COMMIT_COUNT) { 3583 /* 3584 * Give up and do the whole thing 3585 */ 3586 if (vp->v_object && 3587 (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) { 3588 vm_object_page_clean(vp->v_object, 0, 0, OBJPC_SYNC); 3589 } 3590 error = VOP_FSYNC(vp, MNT_WAIT, 0); 3591 } else { 3592 /* 3593 * Locate and synchronously write any buffers that fall 3594 * into the requested range. Note: we are assuming that 3595 * f_iosize is a power of 2. 3596 */ 3597 int iosize = vp->v_mount->mnt_stat.f_iosize; 3598 int iomask = iosize - 1; 3599 off_t loffset; 3600 3601 /* 3602 * Align to iosize boundry, super-align to page boundry. 3603 */ 3604 if (off & iomask) { 3605 cnt += off & iomask; 3606 off &= ~(u_quad_t)iomask; 3607 } 3608 if (off & PAGE_MASK) { 3609 cnt += off & PAGE_MASK; 3610 off &= ~(u_quad_t)PAGE_MASK; 3611 } 3612 loffset = off; 3613 3614 if (vp->v_object && 3615 (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) { 3616 vm_object_page_clean(vp->v_object, off / PAGE_SIZE, 3617 (cnt + PAGE_MASK) / PAGE_SIZE, OBJPC_SYNC); 3618 } 3619 3620 crit_enter(); 3621 while (error == 0 || cnt > 0) { 3622 struct buf *bp; 3623 3624 /* 3625 * If we have a buffer and it is marked B_DELWRI we 3626 * have to lock and write it. Otherwise the prior 3627 * write is assumed to have already been committed. 3628 * 3629 * WARNING: FINDBLK_TEST buffers represent stable 3630 * storage but not necessarily stable 3631 * content. It is ok in this case. 3632 */ 3633 if ((bp = findblk(vp, loffset, FINDBLK_TEST)) != NULL) { 3634 if (bp->b_flags & B_DELWRI) 3635 bp = findblk(vp, loffset, 0); 3636 else 3637 bp = NULL; 3638 } 3639 if (bp) { 3640 if (bp->b_flags & B_DELWRI) { 3641 bremfree(bp); 3642 error = bwrite(bp); 3643 ++nfs_commit_miss; 3644 } else { 3645 BUF_UNLOCK(bp); 3646 } 3647 } 3648 ++nfs_commit_blks; 3649 if (cnt < iosize) 3650 break; 3651 cnt -= iosize; 3652 loffset += iosize; 3653 } 3654 crit_exit(); 3655 } 3656 3657 aft_ret = VOP_GETATTR(vp, &aft); 3658 vput(vp); 3659 vp = NULL; 3660 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3661 NFSX_V3WCCDATA + NFSX_V3WRITEVERF, 3662 &error)); 3663 nfsm_srvwcc_data(&info, nfsd, for_ret, &bfor, 3664 aft_ret, &aft); 3665 if (!error) { 3666 tl = nfsm_build(&info, NFSX_V3WRITEVERF); 3667 if (nfsver.tv_sec == 0) 3668 nfsver = boottime; 3669 *tl++ = txdr_unsigned(nfsver.tv_sec); 3670 *tl = txdr_unsigned(nfsver.tv_nsec / 1000); 3671 } else { 3672 error = 0; 3673 } 3674 nfsmout: 3675 *mrq = info.mreq; 3676 if (vp) 3677 vput(vp); 3678 return(error); 3679 } 3680 3681 /* 3682 * nfs statfs service 3683 */ 3684 int 3685 nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3686 struct thread *td, struct mbuf **mrq) 3687 { 3688 struct sockaddr *nam = nfsd->nd_nam; 3689 struct ucred *cred = &nfsd->nd_cr; 3690 struct statfs *sf; 3691 struct nfs_statfs *sfp; 3692 int error = 0, rdonly, getret = 1; 3693 struct vnode *vp = NULL; 3694 struct mount *mp = NULL; 3695 struct vattr at; 3696 nfsfh_t nfh; 3697 fhandle_t *fhp; 3698 struct statfs statfs; 3699 u_quad_t tval; 3700 struct nfsm_info info; 3701 3702 info.mrep = nfsd->nd_mrep; 3703 info.mreq = NULL; 3704 info.md = nfsd->nd_md; 3705 info.dpos = nfsd->nd_dpos; 3706 info.v3 = (nfsd->nd_flag & ND_NFSV3); 3707 3708 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3709 fhp = &nfh.fh_generic; 3710 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 3711 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 3712 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 3713 if (error) { 3714 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error)); 3715 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3716 error = 0; 3717 goto nfsmout; 3718 } 3719 sf = &statfs; 3720 error = VFS_STATFS(vp->v_mount, sf, proc0.p_ucred); 3721 getret = VOP_GETATTR(vp, &at); 3722 vput(vp); 3723 vp = NULL; 3724 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3725 NFSX_POSTOPATTR(info.v3) + NFSX_STATFS(info.v3), 3726 &error)); 3727 if (info.v3) 3728 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3729 if (error) { 3730 error = 0; 3731 goto nfsmout; 3732 } 3733 sfp = nfsm_build(&info, NFSX_STATFS(info.v3)); 3734 if (info.v3) { 3735 tval = (u_quad_t)sf->f_blocks; 3736 tval *= (u_quad_t)sf->f_bsize; 3737 txdr_hyper(tval, &sfp->sf_tbytes); 3738 tval = (u_quad_t)sf->f_bfree; 3739 tval *= (u_quad_t)sf->f_bsize; 3740 txdr_hyper(tval, &sfp->sf_fbytes); 3741 tval = (u_quad_t)sf->f_bavail; 3742 tval *= (u_quad_t)sf->f_bsize; 3743 txdr_hyper(tval, &sfp->sf_abytes); 3744 sfp->sf_tfiles.nfsuquad[0] = 0; 3745 sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files); 3746 sfp->sf_ffiles.nfsuquad[0] = 0; 3747 sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree); 3748 sfp->sf_afiles.nfsuquad[0] = 0; 3749 sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree); 3750 sfp->sf_invarsec = 0; 3751 } else { 3752 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 3753 sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 3754 sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 3755 sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 3756 sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 3757 } 3758 nfsmout: 3759 *mrq = info.mreq; 3760 if (vp) 3761 vput(vp); 3762 return(error); 3763 } 3764 3765 /* 3766 * nfs fsinfo service 3767 */ 3768 int 3769 nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3770 struct thread *td, struct mbuf **mrq) 3771 { 3772 struct sockaddr *nam = nfsd->nd_nam; 3773 struct ucred *cred = &nfsd->nd_cr; 3774 struct nfsv3_fsinfo *sip; 3775 int error = 0, rdonly, getret = 1, pref; 3776 struct vnode *vp = NULL; 3777 struct mount *mp = NULL; 3778 struct vattr at; 3779 nfsfh_t nfh; 3780 fhandle_t *fhp; 3781 u_quad_t maxfsize; 3782 struct statfs sb; 3783 struct nfsm_info info; 3784 3785 info.mrep = nfsd->nd_mrep; 3786 info.mreq = NULL; 3787 info.md = nfsd->nd_md; 3788 info.dpos = nfsd->nd_dpos; 3789 3790 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3791 fhp = &nfh.fh_generic; 3792 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 3793 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 3794 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 3795 if (error) { 3796 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error)); 3797 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3798 error = 0; 3799 goto nfsmout; 3800 } 3801 3802 /* XXX Try to make a guess on the max file size. */ 3803 VFS_STATFS(vp->v_mount, &sb, proc0.p_ucred); 3804 maxfsize = (u_quad_t)0x80000000 * sb.f_bsize - 1; 3805 3806 getret = VOP_GETATTR(vp, &at); 3807 vput(vp); 3808 vp = NULL; 3809 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3810 NFSX_V3POSTOPATTR + NFSX_V3FSINFO, &error)); 3811 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3812 sip = nfsm_build(&info, NFSX_V3FSINFO); 3813 3814 /* 3815 * XXX 3816 * There should be file system VFS OP(s) to get this information. 3817 * For now, assume ufs. 3818 */ 3819 if (slp->ns_so->so_type == SOCK_DGRAM) 3820 pref = NFS_MAXDGRAMDATA; 3821 else 3822 pref = NFS_MAXDATA; 3823 sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA); 3824 sip->fs_rtpref = txdr_unsigned(pref); 3825 sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE); 3826 sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA); 3827 sip->fs_wtpref = txdr_unsigned(pref); 3828 sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE); 3829 sip->fs_dtpref = txdr_unsigned(pref); 3830 txdr_hyper(maxfsize, &sip->fs_maxfilesize); 3831 sip->fs_timedelta.nfsv3_sec = 0; 3832 sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1); 3833 sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK | 3834 NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS | 3835 NFSV3FSINFO_CANSETTIME); 3836 nfsmout: 3837 *mrq = info.mreq; 3838 if (vp) 3839 vput(vp); 3840 return(error); 3841 } 3842 3843 /* 3844 * nfs pathconf service 3845 */ 3846 int 3847 nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3848 struct thread *td, struct mbuf **mrq) 3849 { 3850 struct sockaddr *nam = nfsd->nd_nam; 3851 struct ucred *cred = &nfsd->nd_cr; 3852 struct nfsv3_pathconf *pc; 3853 int error = 0, rdonly, getret = 1; 3854 register_t linkmax, namemax, chownres, notrunc; 3855 struct vnode *vp = NULL; 3856 struct mount *mp = NULL; 3857 struct vattr at; 3858 nfsfh_t nfh; 3859 fhandle_t *fhp; 3860 struct nfsm_info info; 3861 3862 info.mrep = nfsd->nd_mrep; 3863 info.mreq = NULL; 3864 info.md = nfsd->nd_md; 3865 info.dpos = nfsd->nd_dpos; 3866 3867 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3868 fhp = &nfh.fh_generic; 3869 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error)); 3870 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, 3871 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); 3872 if (error) { 3873 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error)); 3874 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3875 error = 0; 3876 goto nfsmout; 3877 } 3878 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax); 3879 if (!error) 3880 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax); 3881 if (!error) 3882 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres); 3883 if (!error) 3884 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc); 3885 getret = VOP_GETATTR(vp, &at); 3886 vput(vp); 3887 vp = NULL; 3888 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 3889 NFSX_V3POSTOPATTR + NFSX_V3PATHCONF, 3890 &error)); 3891 nfsm_srvpostop_attr(&info, nfsd, getret, &at); 3892 if (error) { 3893 error = 0; 3894 goto nfsmout; 3895 } 3896 pc = nfsm_build(&info, NFSX_V3PATHCONF); 3897 3898 pc->pc_linkmax = txdr_unsigned(linkmax); 3899 pc->pc_namemax = txdr_unsigned(namemax); 3900 pc->pc_notrunc = txdr_unsigned(notrunc); 3901 pc->pc_chownrestricted = txdr_unsigned(chownres); 3902 3903 /* 3904 * These should probably be supported by VOP_PATHCONF(), but 3905 * until msdosfs is exportable (why would you want to?), the 3906 * Unix defaults should be ok. 3907 */ 3908 pc->pc_caseinsensitive = nfs_false; 3909 pc->pc_casepreserving = nfs_true; 3910 nfsmout: 3911 *mrq = info.mreq; 3912 if (vp) 3913 vput(vp); 3914 return(error); 3915 } 3916 3917 /* 3918 * Null operation, used by clients to ping server 3919 */ 3920 /* ARGSUSED */ 3921 int 3922 nfsrv_null(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3923 struct thread *td, struct mbuf **mrq) 3924 { 3925 struct nfsm_info info; 3926 int error = NFSERR_RETVOID; 3927 3928 info.mrep = nfsd->nd_mrep; 3929 info.mreq = NULL; 3930 3931 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3932 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 0, &error)); 3933 nfsmout: 3934 *mrq = info.mreq; 3935 return (error); 3936 } 3937 3938 /* 3939 * No operation, used for obsolete procedures 3940 */ 3941 /* ARGSUSED */ 3942 int 3943 nfsrv_noop(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3944 struct thread *td, struct mbuf **mrq) 3945 { 3946 struct nfsm_info info; 3947 int error; 3948 3949 info.mrep = nfsd->nd_mrep; 3950 info.mreq = NULL; 3951 3952 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3953 if (nfsd->nd_repstat) 3954 error = nfsd->nd_repstat; 3955 else 3956 error = EPROCUNAVAIL; 3957 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 0, &error)); 3958 error = 0; 3959 nfsmout: 3960 *mrq = info.mreq; 3961 return (error); 3962 } 3963 3964 /* 3965 * Perform access checking for vnodes obtained from file handles that would 3966 * refer to files already opened by a Unix client. You cannot just use 3967 * vn_writechk() and VOP_ACCESS() for two reasons. 3968 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case 3969 * 2 - The owner is to be given access irrespective of mode bits for some 3970 * operations, so that processes that chmod after opening a file don't 3971 * break. I don't like this because it opens a security hole, but since 3972 * the nfs server opens a security hole the size of a barn door anyhow, 3973 * what the heck. 3974 * 3975 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS() 3976 * will return EPERM instead of EACCESS. EPERM is always an error. 3977 */ 3978 static int 3979 nfsrv_access(struct mount *mp, struct vnode *vp, int flags, struct ucred *cred, 3980 int rdonly, struct thread *td, int override) 3981 { 3982 struct vattr vattr; 3983 int error; 3984 3985 nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); 3986 if (flags & VWRITE) { 3987 /* Just vn_writechk() changed to check rdonly */ 3988 /* 3989 * Disallow write attempts on read-only file systems; 3990 * unless the file is a socket or a block or character 3991 * device resident on the file system. 3992 */ 3993 if (rdonly || 3994 ((mp->mnt_flag | vp->v_mount->mnt_flag) & MNT_RDONLY)) { 3995 switch (vp->v_type) { 3996 case VREG: 3997 case VDIR: 3998 case VLNK: 3999 return (EROFS); 4000 default: 4001 break; 4002 } 4003 } 4004 /* 4005 * If there's shared text associated with 4006 * the inode, we can't allow writing. 4007 */ 4008 if (vp->v_flag & VTEXT) 4009 return (ETXTBSY); 4010 } 4011 error = VOP_GETATTR(vp, &vattr); 4012 if (error) 4013 return (error); 4014 error = VOP_ACCESS(vp, flags, cred); /* XXX ruid/rgid vs uid/gid */ 4015 /* 4016 * Allow certain operations for the owner (reads and writes 4017 * on files that are already open). 4018 */ 4019 if (override && error == EACCES && cred->cr_uid == vattr.va_uid) 4020 error = 0; 4021 return error; 4022 } 4023 #endif /* NFS_NOSERVER */ 4024 4025