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