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