1 /* $NetBSD: nfs_serv.c,v 1.66 2002/12/01 23:02:10 matt 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.66 2002/12/01 23:02:10 matt 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 const nfstype nfsv2_type[9]; 95 extern const 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 if (nd.ni_cnd.cn_flags & ISSYMLINK) { 1419 vrele(nd.ni_dvp); 1420 vput(nd.ni_vp); 1421 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1422 error = EINVAL; 1423 nfsm_reply(0); 1424 } 1425 } else { 1426 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1427 vput(nd.ni_dvp); 1428 error = ENXIO; 1429 } 1430 vp = nd.ni_vp; 1431 } else { 1432 vp = nd.ni_vp; 1433 if (nd.ni_dvp == vp) 1434 vrele(nd.ni_dvp); 1435 else 1436 vput(nd.ni_dvp); 1437 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1438 if (!error && va.va_size != -1) { 1439 error = nfsrv_access(vp, VWRITE, cred, 1440 (nd.ni_cnd.cn_flags & RDONLY), procp, 0); 1441 if (!error) { 1442 nqsrv_getl(vp, ND_WRITE); 1443 tempsize = va.va_size; 1444 VATTR_NULL(&va); 1445 va.va_size = tempsize; 1446 error = VOP_SETATTR(vp, &va, cred, 1447 procp); 1448 } 1449 } 1450 if (error) 1451 vput(vp); 1452 } 1453 if (!error) { 1454 memset((caddr_t)fhp, 0, sizeof(nfh)); 1455 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 1456 error = VFS_VPTOFH(vp, &fhp->fh_fid); 1457 if (!error) 1458 error = VOP_GETATTR(vp, &va, cred, procp); 1459 vput(vp); 1460 } 1461 if (v3) { 1462 if (exclusive_flag && !error && 1463 memcmp(cverf, (caddr_t)&va.va_atime, NFSX_V3CREATEVERF)) 1464 error = EEXIST; 1465 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1466 vrele(dirp); 1467 } 1468 nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3)); 1469 if (v3) { 1470 if (!error) { 1471 nfsm_srvpostop_fh(fhp); 1472 nfsm_srvpostop_attr(0, &va); 1473 } 1474 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 1475 } else { 1476 nfsm_srvfhtom(fhp, v3); 1477 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); 1478 nfsm_srvfillattr(&va, fp); 1479 } 1480 return (0); 1481 nfsmout: 1482 if (dirp) 1483 vrele(dirp); 1484 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1485 if (nd.ni_dvp == nd.ni_vp) 1486 vrele(nd.ni_dvp); 1487 else 1488 vput(nd.ni_dvp); 1489 if (nd.ni_vp) 1490 vput(nd.ni_vp); 1491 return (error); 1492 } 1493 1494 /* 1495 * nfs v3 mknod service 1496 */ 1497 int 1498 nfsrv_mknod(nfsd, slp, procp, mrq) 1499 struct nfsrv_descript *nfsd; 1500 struct nfssvc_sock *slp; 1501 struct proc *procp; 1502 struct mbuf **mrq; 1503 { 1504 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 1505 struct mbuf *nam = nfsd->nd_nam; 1506 caddr_t dpos = nfsd->nd_dpos; 1507 struct ucred *cred = &nfsd->nd_cr; 1508 struct vattr va, dirfor, diraft; 1509 u_int32_t *tl; 1510 struct nameidata nd; 1511 int32_t t1; 1512 caddr_t bpos; 1513 int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1; 1514 u_int32_t major, minor; 1515 enum vtype vtyp; 1516 char *cp2; 1517 struct mbuf *mb, *mb2, *mreq; 1518 struct vnode *vp, *dirp = (struct vnode *)0; 1519 nfsfh_t nfh; 1520 fhandle_t *fhp; 1521 u_quad_t frev; 1522 1523 nd.ni_cnd.cn_nameiop = 0; 1524 fhp = &nfh.fh_generic; 1525 nfsm_srvmtofh(fhp); 1526 nfsm_srvnamesiz(len); 1527 nd.ni_cnd.cn_cred = cred; 1528 nd.ni_cnd.cn_nameiop = CREATE; 1529 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 1530 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, 1531 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 1532 if (dirp) 1533 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp); 1534 if (error) { 1535 nfsm_reply(NFSX_WCCDATA(1)); 1536 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 1537 if (dirp) 1538 vrele(dirp); 1539 return (0); 1540 } 1541 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 1542 vtyp = nfsv3tov_type(*tl); 1543 if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) { 1544 error = NFSERR_BADTYPE; 1545 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1546 if (nd.ni_dvp == nd.ni_vp) 1547 vrele(nd.ni_dvp); 1548 else 1549 vput(nd.ni_dvp); 1550 if (nd.ni_vp) 1551 vput(nd.ni_vp); 1552 goto out; 1553 } 1554 VATTR_NULL(&va); 1555 nfsm_srvsattr(&va); 1556 if (vtyp == VCHR || vtyp == VBLK) { 1557 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1558 major = fxdr_unsigned(u_int32_t, *tl++); 1559 minor = fxdr_unsigned(u_int32_t, *tl); 1560 va.va_rdev = makedev(major, minor); 1561 } 1562 1563 /* 1564 * Iff doesn't exist, create it. 1565 */ 1566 if (nd.ni_vp) { 1567 error = EEXIST; 1568 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1569 if (nd.ni_dvp == nd.ni_vp) 1570 vrele(nd.ni_dvp); 1571 else 1572 vput(nd.ni_dvp); 1573 vput(nd.ni_vp); 1574 goto out; 1575 } 1576 va.va_type = vtyp; 1577 if (vtyp == VSOCK) { 1578 nqsrv_getl(nd.ni_dvp, ND_WRITE); 1579 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va); 1580 } else { 1581 if (va.va_type != VFIFO && 1582 (error = suser(cred, (u_short *)0))) { 1583 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1584 vput(nd.ni_dvp); 1585 goto out; 1586 } 1587 nqsrv_getl(nd.ni_dvp, ND_WRITE); 1588 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va); 1589 if (error) { 1590 goto out; 1591 } 1592 if (error) 1593 goto out; 1594 if (nd.ni_cnd.cn_flags & ISSYMLINK) { 1595 vput(nd.ni_vp); 1596 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1597 error = EINVAL; 1598 } 1599 } 1600 out: 1601 vp = nd.ni_vp; 1602 if (!error) { 1603 memset((caddr_t)fhp, 0, sizeof(nfh)); 1604 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 1605 error = VFS_VPTOFH(vp, &fhp->fh_fid); 1606 if (!error) 1607 error = VOP_GETATTR(vp, &va, cred, procp); 1608 vput(vp); 1609 } 1610 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1611 vrele(dirp); 1612 nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1)); 1613 if (!error) { 1614 nfsm_srvpostop_fh(fhp); 1615 nfsm_srvpostop_attr(0, &va); 1616 } 1617 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 1618 return (0); 1619 nfsmout: 1620 if (dirp) 1621 vrele(dirp); 1622 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1623 if (nd.ni_dvp == nd.ni_vp) 1624 vrele(nd.ni_dvp); 1625 else 1626 vput(nd.ni_dvp); 1627 if (nd.ni_vp) 1628 vput(nd.ni_vp); 1629 return (error); 1630 } 1631 1632 /* 1633 * nfs remove service 1634 */ 1635 int 1636 nfsrv_remove(nfsd, slp, procp, mrq) 1637 struct nfsrv_descript *nfsd; 1638 struct nfssvc_sock *slp; 1639 struct proc *procp; 1640 struct mbuf **mrq; 1641 { 1642 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 1643 struct mbuf *nam = nfsd->nd_nam; 1644 caddr_t dpos = nfsd->nd_dpos; 1645 struct ucred *cred = &nfsd->nd_cr; 1646 struct nameidata nd; 1647 u_int32_t *tl; 1648 int32_t t1; 1649 caddr_t bpos; 1650 int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1; 1651 int v3 = (nfsd->nd_flag & ND_NFSV3); 1652 char *cp2; 1653 struct mbuf *mb, *mreq; 1654 struct vnode *vp, *dirp; 1655 struct vattr dirfor, diraft; 1656 nfsfh_t nfh; 1657 fhandle_t *fhp; 1658 u_quad_t frev; 1659 1660 #ifndef nolint 1661 vp = (struct vnode *)0; 1662 #endif 1663 fhp = &nfh.fh_generic; 1664 nfsm_srvmtofh(fhp); 1665 nfsm_srvnamesiz(len); 1666 nd.ni_cnd.cn_cred = cred; 1667 nd.ni_cnd.cn_nameiop = DELETE; 1668 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 1669 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, 1670 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 1671 if (dirp) { 1672 if (v3) 1673 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 1674 procp); 1675 else 1676 vrele(dirp); 1677 } 1678 if (!error) { 1679 vp = nd.ni_vp; 1680 if (vp->v_type == VDIR && 1681 (error = suser(cred, (u_short *)0)) != 0) 1682 goto out; 1683 /* 1684 * The root of a mounted filesystem cannot be deleted. 1685 */ 1686 if (vp->v_flag & VROOT) { 1687 error = EBUSY; 1688 goto out; 1689 } 1690 out: 1691 if (!error) { 1692 nqsrv_getl(nd.ni_dvp, ND_WRITE); 1693 nqsrv_getl(vp, ND_WRITE); 1694 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1695 } else { 1696 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1697 if (nd.ni_dvp == vp) 1698 vrele(nd.ni_dvp); 1699 else 1700 vput(nd.ni_dvp); 1701 vput(vp); 1702 } 1703 } 1704 if (dirp && v3) { 1705 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1706 vrele(dirp); 1707 } 1708 nfsm_reply(NFSX_WCCDATA(v3)); 1709 if (v3) { 1710 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 1711 return (0); 1712 } 1713 nfsm_srvdone; 1714 } 1715 1716 /* 1717 * nfs rename service 1718 */ 1719 int 1720 nfsrv_rename(nfsd, slp, procp, mrq) 1721 struct nfsrv_descript *nfsd; 1722 struct nfssvc_sock *slp; 1723 struct proc *procp; 1724 struct mbuf **mrq; 1725 { 1726 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 1727 struct mbuf *nam = nfsd->nd_nam; 1728 caddr_t dpos = nfsd->nd_dpos; 1729 struct ucred *cred = &nfsd->nd_cr; 1730 u_int32_t *tl; 1731 int32_t t1; 1732 caddr_t bpos; 1733 int error = 0, cache, len, len2, fdirfor_ret = 1, fdiraft_ret = 1; 1734 int tdirfor_ret = 1, tdiraft_ret = 1; 1735 int v3 = (nfsd->nd_flag & ND_NFSV3); 1736 char *cp2; 1737 struct mbuf *mb, *mreq; 1738 struct nameidata fromnd, tond; 1739 struct vnode *fvp, *tvp, *tdvp, *fdirp = (struct vnode *)0; 1740 struct vnode *tdirp = (struct vnode *)0; 1741 struct vattr fdirfor, fdiraft, tdirfor, tdiraft; 1742 nfsfh_t fnfh, tnfh; 1743 fhandle_t *ffhp, *tfhp; 1744 u_quad_t frev; 1745 uid_t saved_uid; 1746 1747 #ifndef nolint 1748 fvp = (struct vnode *)0; 1749 #endif 1750 ffhp = &fnfh.fh_generic; 1751 tfhp = &tnfh.fh_generic; 1752 fromnd.ni_cnd.cn_nameiop = 0; 1753 tond.ni_cnd.cn_nameiop = 0; 1754 nfsm_srvmtofh(ffhp); 1755 nfsm_srvnamesiz(len); 1756 /* 1757 * Remember our original uid so that we can reset cr_uid before 1758 * the second nfs_namei() call, in case it is remapped. 1759 */ 1760 saved_uid = cred->cr_uid; 1761 fromnd.ni_cnd.cn_cred = cred; 1762 fromnd.ni_cnd.cn_nameiop = DELETE; 1763 fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; 1764 error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md, 1765 &dpos, &fdirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 1766 if (fdirp) { 1767 if (v3) 1768 fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred, 1769 procp); 1770 else { 1771 vrele(fdirp); 1772 fdirp = (struct vnode *)0; 1773 } 1774 } 1775 if (error) { 1776 nfsm_reply(2 * NFSX_WCCDATA(v3)); 1777 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 1778 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1779 if (fdirp) 1780 vrele(fdirp); 1781 return (0); 1782 } 1783 fvp = fromnd.ni_vp; 1784 nfsm_srvmtofh(tfhp); 1785 nfsm_strsiz(len2, NFS_MAXNAMLEN); 1786 cred->cr_uid = saved_uid; 1787 tond.ni_cnd.cn_cred = cred; 1788 tond.ni_cnd.cn_nameiop = RENAME; 1789 tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 1790 error = nfs_namei(&tond, tfhp, len2, slp, nam, &md, 1791 &dpos, &tdirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 1792 if (tdirp) { 1793 if (v3) 1794 tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred, 1795 procp); 1796 else { 1797 vrele(tdirp); 1798 tdirp = (struct vnode *)0; 1799 } 1800 } 1801 if (error) { 1802 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1803 vrele(fromnd.ni_dvp); 1804 vrele(fvp); 1805 goto out1; 1806 } 1807 tdvp = tond.ni_dvp; 1808 tvp = tond.ni_vp; 1809 if (tvp != NULL) { 1810 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 1811 if (v3) 1812 error = EEXIST; 1813 else 1814 error = EISDIR; 1815 goto out; 1816 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 1817 if (v3) 1818 error = EEXIST; 1819 else 1820 error = ENOTDIR; 1821 goto out; 1822 } 1823 if (tvp->v_type == VDIR && tvp->v_mountedhere) { 1824 if (v3) 1825 error = EXDEV; 1826 else 1827 error = ENOTEMPTY; 1828 goto out; 1829 } 1830 } 1831 if (fvp->v_type == VDIR && fvp->v_mountedhere) { 1832 if (v3) 1833 error = EXDEV; 1834 else 1835 error = ENOTEMPTY; 1836 goto out; 1837 } 1838 if (fvp->v_mount != tdvp->v_mount) { 1839 if (v3) 1840 error = EXDEV; 1841 else 1842 error = ENOTEMPTY; 1843 goto out; 1844 } 1845 if (fvp == tdvp) { 1846 if (v3) 1847 error = EINVAL; 1848 else 1849 error = ENOTEMPTY; 1850 } 1851 /* 1852 * If source is the same as the destination (that is the 1853 * same vnode with the same name in the same directory), 1854 * then there is nothing to do. 1855 */ 1856 if (fvp == tvp && fromnd.ni_dvp == tdvp && 1857 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 1858 !memcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 1859 fromnd.ni_cnd.cn_namelen)) 1860 error = -1; 1861 out: 1862 if (!error) { 1863 nqsrv_getl(fromnd.ni_dvp, ND_WRITE); 1864 nqsrv_getl(tdvp, ND_WRITE); 1865 if (tvp) { 1866 nqsrv_getl(tvp, ND_WRITE); 1867 } 1868 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 1869 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 1870 } else { 1871 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 1872 if (tdvp == tvp) 1873 vrele(tdvp); 1874 else 1875 vput(tdvp); 1876 if (tvp) 1877 vput(tvp); 1878 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1879 vrele(fromnd.ni_dvp); 1880 vrele(fvp); 1881 if (error == -1) 1882 error = 0; 1883 } 1884 vrele(tond.ni_startdir); 1885 PNBUF_PUT(tond.ni_cnd.cn_pnbuf); 1886 out1: 1887 if (fdirp) { 1888 fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp); 1889 vrele(fdirp); 1890 } 1891 if (tdirp) { 1892 tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp); 1893 vrele(tdirp); 1894 } 1895 vrele(fromnd.ni_startdir); 1896 PNBUF_PUT(fromnd.ni_cnd.cn_pnbuf); 1897 nfsm_reply(2 * NFSX_WCCDATA(v3)); 1898 if (v3) { 1899 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 1900 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1901 } 1902 return (0); 1903 1904 nfsmout: 1905 if (fdirp) 1906 vrele(fdirp); 1907 if (tdirp) 1908 vrele(tdirp); 1909 if (tond.ni_cnd.cn_nameiop) { 1910 vrele(tond.ni_startdir); 1911 PNBUF_PUT(tond.ni_cnd.cn_pnbuf); 1912 } 1913 if (fromnd.ni_cnd.cn_nameiop) { 1914 vrele(fromnd.ni_startdir); 1915 PNBUF_PUT(fromnd.ni_cnd.cn_pnbuf); 1916 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1917 vrele(fromnd.ni_dvp); 1918 vrele(fvp); 1919 } 1920 return (error); 1921 } 1922 1923 /* 1924 * nfs link service 1925 */ 1926 int 1927 nfsrv_link(nfsd, slp, procp, mrq) 1928 struct nfsrv_descript *nfsd; 1929 struct nfssvc_sock *slp; 1930 struct proc *procp; 1931 struct mbuf **mrq; 1932 { 1933 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 1934 struct mbuf *nam = nfsd->nd_nam; 1935 caddr_t dpos = nfsd->nd_dpos; 1936 struct ucred *cred = &nfsd->nd_cr; 1937 struct nameidata nd; 1938 u_int32_t *tl; 1939 int32_t t1; 1940 caddr_t bpos; 1941 int error = 0, rdonly, cache, len, dirfor_ret = 1, diraft_ret = 1; 1942 int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3); 1943 char *cp2; 1944 struct mbuf *mb, *mreq; 1945 struct vnode *vp, *xp, *dirp = (struct vnode *)0; 1946 struct vattr dirfor, diraft, at; 1947 nfsfh_t nfh, dnfh; 1948 fhandle_t *fhp, *dfhp; 1949 u_quad_t frev; 1950 1951 fhp = &nfh.fh_generic; 1952 dfhp = &dnfh.fh_generic; 1953 nfsm_srvmtofh(fhp); 1954 nfsm_srvmtofh(dfhp); 1955 nfsm_srvnamesiz(len); 1956 error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam, 1957 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 1958 if (error) { 1959 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); 1960 nfsm_srvpostop_attr(getret, &at); 1961 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 1962 return (0); 1963 } 1964 if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0)) != 0) 1965 goto out1; 1966 nd.ni_cnd.cn_cred = cred; 1967 nd.ni_cnd.cn_nameiop = CREATE; 1968 nd.ni_cnd.cn_flags = LOCKPARENT; 1969 error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos, 1970 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 1971 if (dirp) { 1972 if (v3) 1973 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 1974 procp); 1975 else { 1976 vrele(dirp); 1977 dirp = (struct vnode *)0; 1978 } 1979 } 1980 if (error) 1981 goto out1; 1982 xp = nd.ni_vp; 1983 if (xp != NULL) { 1984 error = EEXIST; 1985 goto out; 1986 } 1987 xp = nd.ni_dvp; 1988 if (vp->v_mount != xp->v_mount) 1989 error = EXDEV; 1990 out: 1991 if (!error) { 1992 nqsrv_getl(vp, ND_WRITE); 1993 nqsrv_getl(xp, ND_WRITE); 1994 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 1995 } else { 1996 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1997 if (nd.ni_dvp == nd.ni_vp) 1998 vrele(nd.ni_dvp); 1999 else 2000 vput(nd.ni_dvp); 2001 if (nd.ni_vp) 2002 vrele(nd.ni_vp); 2003 } 2004 out1: 2005 if (v3) 2006 getret = VOP_GETATTR(vp, &at, cred, procp); 2007 if (dirp) { 2008 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 2009 vrele(dirp); 2010 } 2011 vrele(vp); 2012 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); 2013 if (v3) { 2014 nfsm_srvpostop_attr(getret, &at); 2015 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 2016 return (0); 2017 } 2018 nfsm_srvdone; 2019 } 2020 2021 /* 2022 * nfs symbolic link service 2023 */ 2024 int 2025 nfsrv_symlink(nfsd, slp, procp, mrq) 2026 struct nfsrv_descript *nfsd; 2027 struct nfssvc_sock *slp; 2028 struct proc *procp; 2029 struct mbuf **mrq; 2030 { 2031 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 2032 struct mbuf *nam = nfsd->nd_nam; 2033 caddr_t dpos = nfsd->nd_dpos; 2034 struct ucred *cred = &nfsd->nd_cr; 2035 struct vattr va, dirfor, diraft; 2036 struct nameidata nd; 2037 u_int32_t *tl; 2038 int32_t t1; 2039 struct nfsv2_sattr *sp; 2040 char *bpos, *pathcp = NULL, *cp2; 2041 struct uio io; 2042 struct iovec iv; 2043 int error = 0, cache, len, len2, dirfor_ret = 1, diraft_ret = 1; 2044 int v3 = (nfsd->nd_flag & ND_NFSV3); 2045 struct mbuf *mb, *mreq, *mb2; 2046 struct vnode *dirp = (struct vnode *)0; 2047 nfsfh_t nfh; 2048 fhandle_t *fhp; 2049 u_quad_t frev; 2050 2051 nd.ni_cnd.cn_nameiop = 0; 2052 fhp = &nfh.fh_generic; 2053 nfsm_srvmtofh(fhp); 2054 nfsm_srvnamesiz(len); 2055 nd.ni_cnd.cn_cred = cred; 2056 nd.ni_cnd.cn_nameiop = CREATE; 2057 nd.ni_cnd.cn_flags = LOCKPARENT; 2058 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, 2059 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2060 if (dirp) { 2061 if (v3) 2062 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 2063 procp); 2064 else { 2065 vrele(dirp); 2066 dirp = (struct vnode *)0; 2067 } 2068 } 2069 if (error) 2070 goto out; 2071 VATTR_NULL(&va); 2072 if (v3) 2073 nfsm_srvsattr(&va); 2074 nfsm_strsiz(len2, NFS_MAXPATHLEN); 2075 pathcp = malloc(len2 + 1, M_TEMP, M_WAITOK); 2076 iv.iov_base = pathcp; 2077 iv.iov_len = len2; 2078 io.uio_resid = len2; 2079 io.uio_offset = 0; 2080 io.uio_iov = &iv; 2081 io.uio_iovcnt = 1; 2082 io.uio_segflg = UIO_SYSSPACE; 2083 io.uio_rw = UIO_READ; 2084 io.uio_procp = (struct proc *)0; 2085 nfsm_mtouio(&io, len2); 2086 if (!v3) { 2087 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 2088 va.va_mode = fxdr_unsigned(u_int16_t, sp->sa_mode); 2089 } 2090 *(pathcp + len2) = '\0'; 2091 if (nd.ni_vp) { 2092 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2093 if (nd.ni_dvp == nd.ni_vp) 2094 vrele(nd.ni_dvp); 2095 else 2096 vput(nd.ni_dvp); 2097 vrele(nd.ni_vp); 2098 error = EEXIST; 2099 goto out; 2100 } 2101 nqsrv_getl(nd.ni_dvp, ND_WRITE); 2102 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, pathcp); 2103 if (!error) { 2104 if (v3) { 2105 memset((caddr_t)fhp, 0, sizeof(nfh)); 2106 fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid; 2107 error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid); 2108 if (!error) 2109 error = VOP_GETATTR(nd.ni_vp, &va, cred, 2110 procp); 2111 vput(nd.ni_vp); 2112 } else { 2113 vput(nd.ni_vp); 2114 } 2115 } 2116 out: 2117 if (pathcp) 2118 free(pathcp, M_TEMP); 2119 if (dirp) { 2120 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 2121 vrele(dirp); 2122 } 2123 nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); 2124 if (v3) { 2125 if (!error) { 2126 nfsm_srvpostop_fh(fhp); 2127 nfsm_srvpostop_attr(0, &va); 2128 } 2129 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 2130 } 2131 return (0); 2132 nfsmout: 2133 if (dirp) 2134 vrele(dirp); 2135 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2136 if (nd.ni_dvp == nd.ni_vp) 2137 vrele(nd.ni_dvp); 2138 else 2139 vput(nd.ni_dvp); 2140 if (nd.ni_vp) 2141 vrele(nd.ni_vp); 2142 if (pathcp) 2143 free(pathcp, M_TEMP); 2144 return (error); 2145 } 2146 2147 /* 2148 * nfs mkdir service 2149 */ 2150 int 2151 nfsrv_mkdir(nfsd, slp, procp, mrq) 2152 struct nfsrv_descript *nfsd; 2153 struct nfssvc_sock *slp; 2154 struct proc *procp; 2155 struct mbuf **mrq; 2156 { 2157 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 2158 struct mbuf *nam = nfsd->nd_nam; 2159 caddr_t dpos = nfsd->nd_dpos; 2160 struct ucred *cred = &nfsd->nd_cr; 2161 struct vattr va, dirfor, diraft; 2162 struct nfs_fattr *fp; 2163 struct nameidata nd; 2164 caddr_t cp; 2165 u_int32_t *tl; 2166 int32_t t1; 2167 caddr_t bpos; 2168 int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1; 2169 int v3 = (nfsd->nd_flag & ND_NFSV3); 2170 char *cp2; 2171 struct mbuf *mb, *mb2, *mreq; 2172 struct vnode *vp, *dirp = (struct vnode *)0; 2173 nfsfh_t nfh; 2174 fhandle_t *fhp; 2175 u_quad_t frev; 2176 2177 fhp = &nfh.fh_generic; 2178 nfsm_srvmtofh(fhp); 2179 nfsm_srvnamesiz(len); 2180 nd.ni_cnd.cn_cred = cred; 2181 nd.ni_cnd.cn_nameiop = CREATE; 2182 nd.ni_cnd.cn_flags = LOCKPARENT; 2183 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, 2184 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2185 if (dirp) { 2186 if (v3) 2187 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 2188 procp); 2189 else { 2190 vrele(dirp); 2191 dirp = (struct vnode *)0; 2192 } 2193 } 2194 if (error) { 2195 nfsm_reply(NFSX_WCCDATA(v3)); 2196 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 2197 if (dirp) 2198 vrele(dirp); 2199 return (0); 2200 } 2201 VATTR_NULL(&va); 2202 if (v3) { 2203 nfsm_srvsattr(&va); 2204 } else { 2205 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 2206 va.va_mode = nfstov_mode(*tl++); 2207 } 2208 va.va_type = VDIR; 2209 vp = nd.ni_vp; 2210 if (vp != NULL) { 2211 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2212 if (nd.ni_dvp == vp) 2213 vrele(nd.ni_dvp); 2214 else 2215 vput(nd.ni_dvp); 2216 vrele(vp); 2217 error = EEXIST; 2218 goto out; 2219 } 2220 nqsrv_getl(nd.ni_dvp, ND_WRITE); 2221 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va); 2222 if (!error) { 2223 vp = nd.ni_vp; 2224 memset((caddr_t)fhp, 0, sizeof(nfh)); 2225 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 2226 error = VFS_VPTOFH(vp, &fhp->fh_fid); 2227 if (!error) 2228 error = VOP_GETATTR(vp, &va, cred, procp); 2229 vput(vp); 2230 } 2231 out: 2232 if (dirp) { 2233 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 2234 vrele(dirp); 2235 } 2236 nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); 2237 if (v3) { 2238 if (!error) { 2239 nfsm_srvpostop_fh(fhp); 2240 nfsm_srvpostop_attr(0, &va); 2241 } 2242 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 2243 } else { 2244 nfsm_srvfhtom(fhp, v3); 2245 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); 2246 nfsm_srvfillattr(&va, fp); 2247 } 2248 return (0); 2249 nfsmout: 2250 if (dirp) 2251 vrele(dirp); 2252 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2253 if (nd.ni_dvp == nd.ni_vp) 2254 vrele(nd.ni_dvp); 2255 else 2256 vput(nd.ni_dvp); 2257 if (nd.ni_vp) 2258 vrele(nd.ni_vp); 2259 return (error); 2260 } 2261 2262 /* 2263 * nfs rmdir service 2264 */ 2265 int 2266 nfsrv_rmdir(nfsd, slp, procp, mrq) 2267 struct nfsrv_descript *nfsd; 2268 struct nfssvc_sock *slp; 2269 struct proc *procp; 2270 struct mbuf **mrq; 2271 { 2272 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 2273 struct mbuf *nam = nfsd->nd_nam; 2274 caddr_t dpos = nfsd->nd_dpos; 2275 struct ucred *cred = &nfsd->nd_cr; 2276 u_int32_t *tl; 2277 int32_t t1; 2278 caddr_t bpos; 2279 int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1; 2280 int v3 = (nfsd->nd_flag & ND_NFSV3); 2281 char *cp2; 2282 struct mbuf *mb, *mreq; 2283 struct vnode *vp, *dirp = (struct vnode *)0; 2284 struct vattr dirfor, diraft; 2285 nfsfh_t nfh; 2286 fhandle_t *fhp; 2287 struct nameidata nd; 2288 u_quad_t frev; 2289 2290 fhp = &nfh.fh_generic; 2291 nfsm_srvmtofh(fhp); 2292 nfsm_srvnamesiz(len); 2293 nd.ni_cnd.cn_cred = cred; 2294 nd.ni_cnd.cn_nameiop = DELETE; 2295 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 2296 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, 2297 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2298 if (dirp) { 2299 if (v3) 2300 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 2301 procp); 2302 else { 2303 vrele(dirp); 2304 dirp = (struct vnode *)0; 2305 } 2306 } 2307 if (error) { 2308 nfsm_reply(NFSX_WCCDATA(v3)); 2309 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 2310 if (dirp) 2311 vrele(dirp); 2312 return (0); 2313 } 2314 vp = nd.ni_vp; 2315 if (vp->v_type != VDIR) { 2316 error = ENOTDIR; 2317 goto out; 2318 } 2319 /* 2320 * No rmdir "." please. 2321 */ 2322 if (nd.ni_dvp == vp) { 2323 error = EINVAL; 2324 goto out; 2325 } 2326 /* 2327 * The root of a mounted filesystem cannot be deleted. 2328 */ 2329 if (vp->v_flag & VROOT) 2330 error = EBUSY; 2331 out: 2332 if (!error) { 2333 nqsrv_getl(nd.ni_dvp, ND_WRITE); 2334 nqsrv_getl(vp, ND_WRITE); 2335 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 2336 } else { 2337 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2338 if (nd.ni_dvp == nd.ni_vp) 2339 vrele(nd.ni_dvp); 2340 else 2341 vput(nd.ni_dvp); 2342 vput(vp); 2343 } 2344 if (dirp) { 2345 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 2346 vrele(dirp); 2347 } 2348 nfsm_reply(NFSX_WCCDATA(v3)); 2349 if (v3) { 2350 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 2351 return (0); 2352 } 2353 nfsm_srvdone; 2354 } 2355 2356 /* 2357 * nfs readdir service 2358 * - mallocs what it thinks is enough to read 2359 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 2360 * - calls VOP_READDIR() 2361 * - loops around building the reply 2362 * if the output generated exceeds count break out of loop 2363 * The nfsm_clget macro is used here so that the reply will be packed 2364 * tightly in mbuf clusters. 2365 * - it only knows that it has encountered eof when the VOP_READDIR() 2366 * reads nothing 2367 * - as such one readdir rpc will return eof false although you are there 2368 * and then the next will return eof 2369 * - it trims out records with d_fileno == 0 2370 * this doesn't matter for Unix clients, but they might confuse clients 2371 * for other os'. 2372 * - it trims out records with d_type == DT_WHT 2373 * these cannot be seen through NFS (unless we extend the protocol) 2374 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 2375 * than requested, but this may not apply to all filesystems. For 2376 * example, client NFS does not { although it is never remote mounted 2377 * anyhow } 2378 * The alternate call nfsrv_readdirplus() does lookups as well. 2379 * PS: The NFS protocol spec. does not clarify what the "count" byte 2380 * argument is a count of.. just name strings and file id's or the 2381 * entire reply rpc or ... 2382 * I tried just file name and id sizes and it confused the Sun client, 2383 * so I am using the full rpc size now. The "paranoia.." comment refers 2384 * to including the status longwords that are not a part of the dir. 2385 * "entry" structures, but are in the rpc. 2386 */ 2387 struct flrep { 2388 nfsuint64 fl_off; 2389 u_int32_t fl_postopok; 2390 u_int32_t fl_fattr[NFSX_V3FATTR / sizeof (u_int32_t)]; 2391 u_int32_t fl_fhok; 2392 u_int32_t fl_fhsize; 2393 u_int32_t fl_nfh[NFSX_V3FH / sizeof (u_int32_t)]; 2394 }; 2395 2396 int 2397 nfsrv_readdir(nfsd, slp, procp, mrq) 2398 struct nfsrv_descript *nfsd; 2399 struct nfssvc_sock *slp; 2400 struct proc *procp; 2401 struct mbuf **mrq; 2402 { 2403 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 2404 struct mbuf *nam = nfsd->nd_nam; 2405 caddr_t dpos = nfsd->nd_dpos; 2406 struct ucred *cred = &nfsd->nd_cr; 2407 char *bp, *be; 2408 struct mbuf *mp; 2409 struct dirent *dp; 2410 caddr_t cp; 2411 u_int32_t *tl; 2412 int32_t t1; 2413 caddr_t bpos; 2414 struct mbuf *mb, *mb2, *mreq, *mp2; 2415 char *cpos, *cend, *cp2, *rbuf; 2416 struct vnode *vp; 2417 struct vattr at; 2418 nfsfh_t nfh; 2419 fhandle_t *fhp; 2420 struct uio io; 2421 struct iovec iv; 2422 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1; 2423 int siz, cnt, fullsiz, eofflag, rdonly, cache, ncookies; 2424 int v3 = (nfsd->nd_flag & ND_NFSV3); 2425 u_quad_t frev, off, toff, verf; 2426 off_t *cookies = NULL, *cookiep; 2427 nfsuint64 jar; 2428 2429 fhp = &nfh.fh_generic; 2430 nfsm_srvmtofh(fhp); 2431 if (v3) { 2432 nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2433 toff = fxdr_hyper(tl); 2434 tl += 2; 2435 verf = fxdr_hyper(tl); 2436 tl += 2; 2437 } else { 2438 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2439 toff = fxdr_unsigned(u_quad_t, *tl++); 2440 } 2441 off = toff; 2442 cnt = fxdr_unsigned(int, *tl); 2443 siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); 2444 xfer = NFS_SRVMAXDATA(nfsd); 2445 if (siz > xfer) 2446 siz = xfer; 2447 fullsiz = siz; 2448 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, 2449 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2450 if (!error && vp->v_type != VDIR) { 2451 error = ENOTDIR; 2452 vput(vp); 2453 } 2454 if (error) { 2455 nfsm_reply(NFSX_UNSIGNED); 2456 nfsm_srvpostop_attr(getret, &at); 2457 return (0); 2458 } 2459 nqsrv_getl(vp, ND_READ); 2460 if (v3) { 2461 error = getret = VOP_GETATTR(vp, &at, cred, procp); 2462 #ifdef NFS3_STRICTVERF 2463 /* 2464 * XXX This check is too strict for Solaris 2.5 clients. 2465 */ 2466 if (!error && toff && verf != at.va_filerev) 2467 error = NFSERR_BAD_COOKIE; 2468 #endif 2469 } 2470 if (!error) 2471 error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0); 2472 if (error) { 2473 vput(vp); 2474 nfsm_reply(NFSX_POSTOPATTR(v3)); 2475 nfsm_srvpostop_attr(getret, &at); 2476 return (0); 2477 } 2478 VOP_UNLOCK(vp, 0); 2479 rbuf = malloc(siz, M_TEMP, M_WAITOK); 2480 again: 2481 iv.iov_base = rbuf; 2482 iv.iov_len = fullsiz; 2483 io.uio_iov = &iv; 2484 io.uio_iovcnt = 1; 2485 io.uio_offset = (off_t)off; 2486 io.uio_resid = fullsiz; 2487 io.uio_segflg = UIO_SYSSPACE; 2488 io.uio_rw = UIO_READ; 2489 io.uio_procp = (struct proc *)0; 2490 eofflag = 0; 2491 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2492 2493 error = VOP_READDIR(vp, &io, cred, &eofflag, &cookies, &ncookies); 2494 2495 off = (off_t)io.uio_offset; 2496 if (!cookies && !error) 2497 error = NFSERR_PERM; 2498 if (v3) { 2499 getret = VOP_GETATTR(vp, &at, cred, procp); 2500 if (!error) 2501 error = getret; 2502 } 2503 2504 VOP_UNLOCK(vp, 0); 2505 if (error) { 2506 vrele(vp); 2507 free((caddr_t)rbuf, M_TEMP); 2508 if (cookies) 2509 free((caddr_t)cookies, M_TEMP); 2510 nfsm_reply(NFSX_POSTOPATTR(v3)); 2511 nfsm_srvpostop_attr(getret, &at); 2512 return (0); 2513 } 2514 if (io.uio_resid) { 2515 siz -= io.uio_resid; 2516 2517 /* 2518 * If nothing read, return eof 2519 * rpc reply 2520 */ 2521 if (siz == 0) { 2522 vrele(vp); 2523 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + 2524 2 * NFSX_UNSIGNED); 2525 if (v3) { 2526 nfsm_srvpostop_attr(getret, &at); 2527 nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 2528 txdr_hyper(at.va_filerev, tl); 2529 tl += 2; 2530 } else 2531 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2532 *tl++ = nfs_false; 2533 *tl = nfs_true; 2534 free((caddr_t)rbuf, M_TEMP); 2535 free((caddr_t)cookies, M_TEMP); 2536 return (0); 2537 } 2538 } 2539 2540 /* 2541 * Check for degenerate cases of nothing useful read. 2542 * If so go try again 2543 */ 2544 cpos = rbuf; 2545 cend = rbuf + siz; 2546 dp = (struct dirent *)cpos; 2547 cookiep = cookies; 2548 2549 while (cpos < cend && ncookies > 0 && 2550 (dp->d_fileno == 0 || dp->d_type == DT_WHT)) { 2551 cpos += dp->d_reclen; 2552 dp = (struct dirent *)cpos; 2553 cookiep++; 2554 ncookies--; 2555 } 2556 if (cpos >= cend || ncookies == 0) { 2557 toff = off; 2558 siz = fullsiz; 2559 goto again; 2560 } 2561 2562 len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 2563 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz); 2564 if (v3) { 2565 nfsm_srvpostop_attr(getret, &at); 2566 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2567 txdr_hyper(at.va_filerev, tl); 2568 } 2569 mp = mp2 = mb; 2570 bp = bpos; 2571 be = bp + M_TRAILINGSPACE(mp); 2572 2573 /* Loop through the records and build reply */ 2574 while (cpos < cend && ncookies > 0) { 2575 if (dp->d_fileno != 0 && dp->d_type != DT_WHT) { 2576 nlen = dp->d_namlen; 2577 rem = nfsm_rndup(nlen)-nlen; 2578 len += (4 * NFSX_UNSIGNED + nlen + rem); 2579 if (v3) 2580 len += 2 * NFSX_UNSIGNED; 2581 if (len > cnt) { 2582 eofflag = 0; 2583 break; 2584 } 2585 /* 2586 * Build the directory record xdr from 2587 * the dirent entry. 2588 */ 2589 nfsm_clget; 2590 *tl = nfs_true; 2591 bp += NFSX_UNSIGNED; 2592 if (v3) { 2593 nfsm_clget; 2594 *tl = 0; 2595 bp += NFSX_UNSIGNED; 2596 } 2597 nfsm_clget; 2598 *tl = txdr_unsigned(dp->d_fileno); 2599 bp += NFSX_UNSIGNED; 2600 nfsm_clget; 2601 *tl = txdr_unsigned(nlen); 2602 bp += NFSX_UNSIGNED; 2603 2604 /* And loop around copying the name */ 2605 xfer = nlen; 2606 cp = dp->d_name; 2607 while (xfer > 0) { 2608 nfsm_clget; 2609 if ((bp+xfer) > be) 2610 tsiz = be-bp; 2611 else 2612 tsiz = xfer; 2613 memcpy(bp, cp, tsiz); 2614 bp += tsiz; 2615 xfer -= tsiz; 2616 if (xfer > 0) 2617 cp += tsiz; 2618 } 2619 /* And null pad to an int32_t boundary */ 2620 for (i = 0; i < rem; i++) 2621 *bp++ = '\0'; 2622 nfsm_clget; 2623 2624 /* Finish off the record */ 2625 txdr_hyper(*cookiep, &jar); 2626 if (v3) { 2627 *tl = jar.nfsuquad[0]; 2628 bp += NFSX_UNSIGNED; 2629 nfsm_clget; 2630 } 2631 *tl = jar.nfsuquad[1]; 2632 bp += NFSX_UNSIGNED; 2633 } 2634 cpos += dp->d_reclen; 2635 dp = (struct dirent *)cpos; 2636 cookiep++; 2637 ncookies--; 2638 } 2639 vrele(vp); 2640 nfsm_clget; 2641 *tl = nfs_false; 2642 bp += NFSX_UNSIGNED; 2643 nfsm_clget; 2644 if (eofflag) 2645 *tl = nfs_true; 2646 else 2647 *tl = nfs_false; 2648 bp += NFSX_UNSIGNED; 2649 if (mp != mb) { 2650 if (bp < be) 2651 mp->m_len = bp - mtod(mp, caddr_t); 2652 } else 2653 mp->m_len += bp - bpos; 2654 free((caddr_t)rbuf, M_TEMP); 2655 free((caddr_t)cookies, M_TEMP); 2656 nfsm_srvdone; 2657 } 2658 2659 int 2660 nfsrv_readdirplus(nfsd, slp, procp, mrq) 2661 struct nfsrv_descript *nfsd; 2662 struct nfssvc_sock *slp; 2663 struct proc *procp; 2664 struct mbuf **mrq; 2665 { 2666 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 2667 struct mbuf *nam = nfsd->nd_nam; 2668 caddr_t dpos = nfsd->nd_dpos; 2669 struct ucred *cred = &nfsd->nd_cr; 2670 char *bp, *be; 2671 struct mbuf *mp; 2672 struct dirent *dp; 2673 caddr_t cp; 2674 u_int32_t *tl; 2675 int32_t t1; 2676 caddr_t bpos; 2677 struct mbuf *mb, *mb2, *mreq, *mp2; 2678 char *cpos, *cend, *cp2, *rbuf; 2679 struct vnode *vp, *nvp; 2680 struct flrep fl; 2681 nfsfh_t nfh; 2682 fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh; 2683 struct uio io; 2684 struct iovec iv; 2685 struct vattr va, at, *vap = &va; 2686 struct nfs_fattr *fp; 2687 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1; 2688 int siz, cnt, fullsiz, eofflag, rdonly, cache, dirlen, ncookies; 2689 u_quad_t frev, off, toff, verf; 2690 off_t *cookies = NULL, *cookiep; 2691 2692 fhp = &nfh.fh_generic; 2693 nfsm_srvmtofh(fhp); 2694 nfsm_dissect(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 2695 toff = fxdr_hyper(tl); 2696 tl += 2; 2697 verf = fxdr_hyper(tl); 2698 tl += 2; 2699 siz = fxdr_unsigned(int, *tl++); 2700 cnt = fxdr_unsigned(int, *tl); 2701 off = toff; 2702 siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); 2703 xfer = NFS_SRVMAXDATA(nfsd); 2704 if (siz > xfer) 2705 siz = xfer; 2706 fullsiz = siz; 2707 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, 2708 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 2709 if (!error && vp->v_type != VDIR) { 2710 error = ENOTDIR; 2711 vput(vp); 2712 } 2713 if (error) { 2714 nfsm_reply(NFSX_UNSIGNED); 2715 nfsm_srvpostop_attr(getret, &at); 2716 return (0); 2717 } 2718 error = getret = VOP_GETATTR(vp, &at, cred, procp); 2719 #ifdef NFS3_STRICTVERF 2720 /* 2721 * XXX This check is too strict for Solaris 2.5 clients. 2722 */ 2723 if (!error && toff && verf != at.va_filerev) 2724 error = NFSERR_BAD_COOKIE; 2725 #endif 2726 if (!error) { 2727 nqsrv_getl(vp, ND_READ); 2728 error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0); 2729 } 2730 if (error) { 2731 vput(vp); 2732 nfsm_reply(NFSX_V3POSTOPATTR); 2733 nfsm_srvpostop_attr(getret, &at); 2734 return (0); 2735 } 2736 VOP_UNLOCK(vp, 0); 2737 2738 rbuf = malloc(siz, M_TEMP, M_WAITOK); 2739 again: 2740 iv.iov_base = rbuf; 2741 iv.iov_len = fullsiz; 2742 io.uio_iov = &iv; 2743 io.uio_iovcnt = 1; 2744 io.uio_offset = (off_t)off; 2745 io.uio_resid = fullsiz; 2746 io.uio_segflg = UIO_SYSSPACE; 2747 io.uio_rw = UIO_READ; 2748 io.uio_procp = (struct proc *)0; 2749 eofflag = 0; 2750 2751 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2752 2753 error = VOP_READDIR(vp, &io, cred, &eofflag, &cookies, &ncookies); 2754 2755 off = (u_quad_t)io.uio_offset; 2756 getret = VOP_GETATTR(vp, &at, cred, procp); 2757 2758 VOP_UNLOCK(vp, 0); 2759 2760 /* 2761 * If the VGET operation doesn't work for this filesystem, 2762 * we can't support readdirplus. Returning NOTSUPP should 2763 * make clients fall back to plain readdir. 2764 * There's no need to check for VPTOFH as well, we wouldn't 2765 * even be here otherwise. 2766 */ 2767 if (!getret) { 2768 if ((getret = VFS_VGET(vp->v_mount, at.va_fileid, &nvp))) 2769 getret = (getret == EOPNOTSUPP) ? 2770 NFSERR_NOTSUPP : NFSERR_IO; 2771 else 2772 vput(nvp); 2773 } 2774 2775 if (!cookies && !error) 2776 error = NFSERR_PERM; 2777 if (!error) 2778 error = getret; 2779 if (error) { 2780 vrele(vp); 2781 if (cookies) 2782 free((caddr_t)cookies, M_TEMP); 2783 free((caddr_t)rbuf, M_TEMP); 2784 nfsm_reply(NFSX_V3POSTOPATTR); 2785 nfsm_srvpostop_attr(getret, &at); 2786 return (0); 2787 } 2788 if (io.uio_resid) { 2789 siz -= io.uio_resid; 2790 2791 /* 2792 * If nothing read, return eof 2793 * rpc reply 2794 */ 2795 if (siz == 0) { 2796 vrele(vp); 2797 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2798 2 * NFSX_UNSIGNED); 2799 nfsm_srvpostop_attr(getret, &at); 2800 nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 2801 txdr_hyper(at.va_filerev, tl); 2802 tl += 2; 2803 *tl++ = nfs_false; 2804 *tl = nfs_true; 2805 free((caddr_t)cookies, M_TEMP); 2806 free((caddr_t)rbuf, M_TEMP); 2807 return (0); 2808 } 2809 } 2810 2811 /* 2812 * Check for degenerate cases of nothing useful read. 2813 * If so go try again 2814 */ 2815 cpos = rbuf; 2816 cend = rbuf + siz; 2817 dp = (struct dirent *)cpos; 2818 cookiep = cookies; 2819 2820 while (cpos < cend && ncookies > 0 && 2821 (dp->d_fileno == 0 || dp->d_type == DT_WHT)) { 2822 cpos += dp->d_reclen; 2823 dp = (struct dirent *)cpos; 2824 cookiep++; 2825 ncookies--; 2826 } 2827 if (cpos >= cend || ncookies == 0) { 2828 toff = off; 2829 siz = fullsiz; 2830 goto again; 2831 } 2832 2833 dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED; 2834 nfsm_reply(cnt); 2835 nfsm_srvpostop_attr(getret, &at); 2836 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2837 txdr_hyper(at.va_filerev, tl); 2838 mp = mp2 = mb; 2839 bp = bpos; 2840 be = bp + M_TRAILINGSPACE(mp); 2841 2842 /* Loop through the records and build reply */ 2843 while (cpos < cend && ncookies > 0) { 2844 if (dp->d_fileno != 0 && dp->d_type != DT_WHT) { 2845 nlen = dp->d_namlen; 2846 rem = nfsm_rndup(nlen)-nlen; 2847 2848 /* 2849 * For readdir_and_lookup get the vnode using 2850 * the file number. 2851 */ 2852 if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp)) 2853 goto invalid; 2854 memset((caddr_t)nfhp, 0, NFSX_V3FH); 2855 nfhp->fh_fsid = 2856 nvp->v_mount->mnt_stat.f_fsid; 2857 if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) { 2858 vput(nvp); 2859 goto invalid; 2860 } 2861 if (VOP_GETATTR(nvp, vap, cred, procp)) { 2862 vput(nvp); 2863 goto invalid; 2864 } 2865 vput(nvp); 2866 2867 /* 2868 * If either the dircount or maxcount will be 2869 * exceeded, get out now. Both of these lengths 2870 * are calculated conservatively, including all 2871 * XDR overheads. 2872 */ 2873 len += (8 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH + 2874 NFSX_V3POSTOPATTR); 2875 dirlen += (6 * NFSX_UNSIGNED + nlen + rem); 2876 if (len > cnt || dirlen > fullsiz) { 2877 eofflag = 0; 2878 break; 2879 } 2880 2881 /* 2882 * Build the directory record xdr from 2883 * the dirent entry. 2884 */ 2885 fp = (struct nfs_fattr *)&fl.fl_fattr; 2886 nfsm_srvfillattr(vap, fp); 2887 fl.fl_fhsize = txdr_unsigned(NFSX_V3FH); 2888 fl.fl_fhok = nfs_true; 2889 fl.fl_postopok = nfs_true; 2890 txdr_hyper(*cookiep, fl.fl_off.nfsuquad); 2891 2892 nfsm_clget; 2893 *tl = nfs_true; 2894 bp += NFSX_UNSIGNED; 2895 nfsm_clget; 2896 *tl = 0; 2897 bp += NFSX_UNSIGNED; 2898 nfsm_clget; 2899 *tl = txdr_unsigned(dp->d_fileno); 2900 bp += NFSX_UNSIGNED; 2901 nfsm_clget; 2902 *tl = txdr_unsigned(nlen); 2903 bp += NFSX_UNSIGNED; 2904 2905 /* And loop around copying the name */ 2906 xfer = nlen; 2907 cp = dp->d_name; 2908 while (xfer > 0) { 2909 nfsm_clget; 2910 if ((bp + xfer) > be) 2911 tsiz = be - bp; 2912 else 2913 tsiz = xfer; 2914 memcpy(bp, cp, tsiz); 2915 bp += tsiz; 2916 xfer -= tsiz; 2917 if (xfer > 0) 2918 cp += tsiz; 2919 } 2920 /* And null pad to an int32_t boundary */ 2921 for (i = 0; i < rem; i++) 2922 *bp++ = '\0'; 2923 2924 /* 2925 * Now copy the flrep structure out. 2926 */ 2927 xfer = sizeof (struct flrep); 2928 cp = (caddr_t)&fl; 2929 while (xfer > 0) { 2930 nfsm_clget; 2931 if ((bp + xfer) > be) 2932 tsiz = be - bp; 2933 else 2934 tsiz = xfer; 2935 memcpy(bp, cp, tsiz); 2936 bp += tsiz; 2937 xfer -= tsiz; 2938 if (xfer > 0) 2939 cp += tsiz; 2940 } 2941 } 2942 invalid: 2943 cpos += dp->d_reclen; 2944 dp = (struct dirent *)cpos; 2945 cookiep++; 2946 ncookies--; 2947 } 2948 vrele(vp); 2949 nfsm_clget; 2950 *tl = nfs_false; 2951 bp += NFSX_UNSIGNED; 2952 nfsm_clget; 2953 if (eofflag) 2954 *tl = nfs_true; 2955 else 2956 *tl = nfs_false; 2957 bp += NFSX_UNSIGNED; 2958 if (mp != mb) { 2959 if (bp < be) 2960 mp->m_len = bp - mtod(mp, caddr_t); 2961 } else 2962 mp->m_len += bp - bpos; 2963 free((caddr_t)cookies, M_TEMP); 2964 free((caddr_t)rbuf, M_TEMP); 2965 nfsm_srvdone; 2966 } 2967 2968 /* 2969 * nfs commit service 2970 */ 2971 int 2972 nfsrv_commit(nfsd, slp, procp, mrq) 2973 struct nfsrv_descript *nfsd; 2974 struct nfssvc_sock *slp; 2975 struct proc *procp; 2976 struct mbuf **mrq; 2977 { 2978 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 2979 struct mbuf *nam = nfsd->nd_nam; 2980 caddr_t dpos = nfsd->nd_dpos; 2981 struct ucred *cred = &nfsd->nd_cr; 2982 struct vattr bfor, aft; 2983 struct vnode *vp; 2984 nfsfh_t nfh; 2985 fhandle_t *fhp; 2986 u_int32_t *tl; 2987 int32_t t1; 2988 caddr_t bpos; 2989 int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt, cache; 2990 char *cp2; 2991 struct mbuf *mb, *mb2, *mreq; 2992 u_quad_t frev, off, end; 2993 2994 #ifndef nolint 2995 cache = 0; 2996 #endif 2997 fhp = &nfh.fh_generic; 2998 nfsm_srvmtofh(fhp); 2999 nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3000 3001 off = fxdr_hyper(tl); 3002 tl += 2; 3003 cnt = fxdr_unsigned(int, *tl); 3004 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, 3005 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 3006 if (error) { 3007 nfsm_reply(2 * NFSX_UNSIGNED); 3008 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft); 3009 return (0); 3010 } 3011 for_ret = VOP_GETATTR(vp, &bfor, cred, procp); 3012 end = (cnt > 0) ? off + cnt : vp->v_size; 3013 if (end < off || end > vp->v_size) 3014 end = vp->v_size; 3015 error = VOP_FSYNC(vp, cred, FSYNC_WAIT, off, end, procp); 3016 aft_ret = VOP_GETATTR(vp, &aft, cred, procp); 3017 vput(vp); 3018 nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF); 3019 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft); 3020 if (!error) { 3021 nfsm_build(tl, u_int32_t *, NFSX_V3WRITEVERF); 3022 *tl++ = txdr_unsigned(boottime.tv_sec); 3023 *tl = txdr_unsigned(boottime.tv_usec); 3024 } else 3025 return (0); 3026 nfsm_srvdone; 3027 } 3028 3029 /* 3030 * nfs statfs service 3031 */ 3032 int 3033 nfsrv_statfs(nfsd, slp, procp, mrq) 3034 struct nfsrv_descript *nfsd; 3035 struct nfssvc_sock *slp; 3036 struct proc *procp; 3037 struct mbuf **mrq; 3038 { 3039 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 3040 struct mbuf *nam = nfsd->nd_nam; 3041 caddr_t dpos = nfsd->nd_dpos; 3042 struct ucred *cred = &nfsd->nd_cr; 3043 struct statfs *sf; 3044 struct nfs_statfs *sfp; 3045 u_int32_t *tl; 3046 int32_t t1; 3047 caddr_t bpos; 3048 int error = 0, rdonly, cache, getret = 1; 3049 int v3 = (nfsd->nd_flag & ND_NFSV3); 3050 char *cp2; 3051 struct mbuf *mb, *mb2, *mreq; 3052 struct vnode *vp; 3053 struct vattr at; 3054 nfsfh_t nfh; 3055 fhandle_t *fhp; 3056 struct statfs statfs; 3057 u_quad_t frev, tval; 3058 3059 #ifndef nolint 3060 cache = 0; 3061 #endif 3062 fhp = &nfh.fh_generic; 3063 nfsm_srvmtofh(fhp); 3064 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, 3065 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 3066 if (error) { 3067 nfsm_reply(NFSX_UNSIGNED); 3068 nfsm_srvpostop_attr(getret, &at); 3069 return (0); 3070 } 3071 sf = &statfs; 3072 error = VFS_STATFS(vp->v_mount, sf, procp); 3073 getret = VOP_GETATTR(vp, &at, cred, procp); 3074 vput(vp); 3075 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3)); 3076 if (v3) 3077 nfsm_srvpostop_attr(getret, &at); 3078 if (error) 3079 return (0); 3080 nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3)); 3081 if (v3) { 3082 tval = (u_quad_t)((quad_t)sf->f_blocks * (quad_t)sf->f_bsize); 3083 txdr_hyper(tval, &sfp->sf_tbytes); 3084 tval = (u_quad_t)((quad_t)sf->f_bfree * (quad_t)sf->f_bsize); 3085 txdr_hyper(tval, &sfp->sf_fbytes); 3086 tval = (u_quad_t)((quad_t)sf->f_bavail * (quad_t)sf->f_bsize); 3087 txdr_hyper(tval, &sfp->sf_abytes); 3088 tval = (u_quad_t)sf->f_files; 3089 txdr_hyper(tval, &sfp->sf_tfiles); 3090 tval = (u_quad_t)sf->f_ffree; 3091 txdr_hyper(tval, &sfp->sf_ffiles); 3092 txdr_hyper(tval, &sfp->sf_afiles); 3093 sfp->sf_invarsec = 0; 3094 } else { 3095 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 3096 sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 3097 sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 3098 sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 3099 sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 3100 } 3101 nfsm_srvdone; 3102 } 3103 3104 /* 3105 * nfs fsinfo service 3106 */ 3107 int 3108 nfsrv_fsinfo(nfsd, slp, procp, mrq) 3109 struct nfsrv_descript *nfsd; 3110 struct nfssvc_sock *slp; 3111 struct proc *procp; 3112 struct mbuf **mrq; 3113 { 3114 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 3115 struct mbuf *nam = nfsd->nd_nam; 3116 caddr_t dpos = nfsd->nd_dpos; 3117 struct ucred *cred = &nfsd->nd_cr; 3118 u_int32_t *tl; 3119 struct nfsv3_fsinfo *sip; 3120 int32_t t1; 3121 caddr_t bpos; 3122 int error = 0, rdonly, cache, getret = 1, pref; 3123 char *cp2; 3124 struct mbuf *mb, *mb2, *mreq; 3125 struct vnode *vp; 3126 struct vattr at; 3127 nfsfh_t nfh; 3128 fhandle_t *fhp; 3129 u_quad_t frev, maxfsize; 3130 struct statfs sb; 3131 3132 #ifndef nolint 3133 cache = 0; 3134 #endif 3135 fhp = &nfh.fh_generic; 3136 nfsm_srvmtofh(fhp); 3137 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, 3138 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 3139 if (error) { 3140 nfsm_reply(NFSX_UNSIGNED); 3141 nfsm_srvpostop_attr(getret, &at); 3142 return (0); 3143 } 3144 3145 /* XXX Try to make a guess on the max file size. */ 3146 VFS_STATFS(vp->v_mount, &sb, (struct proc *)0); 3147 maxfsize = (u_quad_t)0x80000000 * sb.f_bsize - 1; 3148 3149 getret = VOP_GETATTR(vp, &at, cred, procp); 3150 vput(vp); 3151 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO); 3152 nfsm_srvpostop_attr(getret, &at); 3153 nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO); 3154 3155 /* 3156 * XXX 3157 * There should be file system VFS OP(s) to get this information. 3158 * For now, assume ufs. 3159 */ 3160 if (slp->ns_so->so_type == SOCK_DGRAM) 3161 pref = NFS_MAXDGRAMDATA; 3162 else 3163 pref = NFS_MAXDATA; 3164 sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA); 3165 sip->fs_rtpref = txdr_unsigned(pref); 3166 sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE); 3167 sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA); 3168 sip->fs_wtpref = txdr_unsigned(pref); 3169 sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE); 3170 sip->fs_dtpref = txdr_unsigned(pref); 3171 txdr_hyper(maxfsize, &sip->fs_maxfilesize); 3172 sip->fs_timedelta.nfsv3_sec = 0; 3173 sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1); 3174 sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK | 3175 NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS | 3176 NFSV3FSINFO_CANSETTIME); 3177 nfsm_srvdone; 3178 } 3179 3180 /* 3181 * nfs pathconf service 3182 */ 3183 int 3184 nfsrv_pathconf(nfsd, slp, procp, mrq) 3185 struct nfsrv_descript *nfsd; 3186 struct nfssvc_sock *slp; 3187 struct proc *procp; 3188 struct mbuf **mrq; 3189 { 3190 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 3191 struct mbuf *nam = nfsd->nd_nam; 3192 caddr_t dpos = nfsd->nd_dpos; 3193 struct ucred *cred = &nfsd->nd_cr; 3194 u_int32_t *tl; 3195 struct nfsv3_pathconf *pc; 3196 int32_t t1; 3197 caddr_t bpos; 3198 int error = 0, rdonly, cache, getret = 1; 3199 register_t linkmax, namemax, chownres, notrunc; 3200 char *cp2; 3201 struct mbuf *mb, *mb2, *mreq; 3202 struct vnode *vp; 3203 struct vattr at; 3204 nfsfh_t nfh; 3205 fhandle_t *fhp; 3206 u_quad_t frev; 3207 3208 #ifndef nolint 3209 cache = 0; 3210 #endif 3211 fhp = &nfh.fh_generic; 3212 nfsm_srvmtofh(fhp); 3213 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, 3214 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE); 3215 if (error) { 3216 nfsm_reply(NFSX_UNSIGNED); 3217 nfsm_srvpostop_attr(getret, &at); 3218 return (0); 3219 } 3220 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax); 3221 if (!error) 3222 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax); 3223 if (!error) 3224 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres); 3225 if (!error) 3226 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc); 3227 getret = VOP_GETATTR(vp, &at, cred, procp); 3228 vput(vp); 3229 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF); 3230 nfsm_srvpostop_attr(getret, &at); 3231 if (error) 3232 return (0); 3233 nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); 3234 3235 pc->pc_linkmax = txdr_unsigned(linkmax); 3236 pc->pc_namemax = txdr_unsigned(namemax); 3237 pc->pc_notrunc = txdr_unsigned(notrunc); 3238 pc->pc_chownrestricted = txdr_unsigned(chownres); 3239 3240 /* 3241 * These should probably be supported by VOP_PATHCONF(), but 3242 * until msdosfs is exportable (why would you want to?), the 3243 * Unix defaults should be ok. 3244 */ 3245 pc->pc_caseinsensitive = nfs_false; 3246 pc->pc_casepreserving = nfs_true; 3247 nfsm_srvdone; 3248 } 3249 3250 /* 3251 * Null operation, used by clients to ping server 3252 */ 3253 /* ARGSUSED */ 3254 int 3255 nfsrv_null(nfsd, slp, procp, mrq) 3256 struct nfsrv_descript *nfsd; 3257 struct nfssvc_sock *slp; 3258 struct proc *procp; 3259 struct mbuf **mrq; 3260 { 3261 struct mbuf *mrep = nfsd->nd_mrep; 3262 caddr_t bpos; 3263 int error = NFSERR_RETVOID, cache = 0; 3264 struct mbuf *mb, *mreq; 3265 u_quad_t frev; 3266 3267 nfsm_reply(0); 3268 return (0); 3269 } 3270 3271 /* 3272 * No operation, used for obsolete procedures 3273 */ 3274 /* ARGSUSED */ 3275 int 3276 nfsrv_noop(nfsd, slp, procp, mrq) 3277 struct nfsrv_descript *nfsd; 3278 struct nfssvc_sock *slp; 3279 struct proc *procp; 3280 struct mbuf **mrq; 3281 { 3282 struct mbuf *mrep = nfsd->nd_mrep; 3283 caddr_t bpos; 3284 int error, cache = 0; 3285 struct mbuf *mb, *mreq; 3286 u_quad_t frev; 3287 3288 if (nfsd->nd_repstat) 3289 error = nfsd->nd_repstat; 3290 else 3291 error = EPROCUNAVAIL; 3292 nfsm_reply(0); 3293 return (0); 3294 } 3295 3296 /* 3297 * Perform access checking for vnodes obtained from file handles that would 3298 * refer to files already opened by a Unix client. You cannot just use 3299 * vn_writechk() and VOP_ACCESS() for two reasons. 3300 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case 3301 * 2 - The owner is to be given access irrespective of mode bits for some 3302 * operations, so that processes that chmod after opening a file don't 3303 * break. I don't like this because it opens a security hole, but since 3304 * the nfs server opens a security hole the size of a barn door anyhow, 3305 * what the heck. 3306 * 3307 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS() 3308 * will return EPERM instead of EACCESS. EPERM is always an error. 3309 */ 3310 int 3311 nfsrv_access(vp, flags, cred, rdonly, p, override) 3312 struct vnode *vp; 3313 int flags; 3314 struct ucred *cred; 3315 int rdonly; 3316 struct proc *p; 3317 { 3318 struct vattr vattr; 3319 int error; 3320 if (flags & VWRITE) { 3321 /* Just vn_writechk() changed to check rdonly */ 3322 /* 3323 * Disallow write attempts on read-only file systems; 3324 * unless the file is a socket or a block or character 3325 * device resident on the file system. 3326 */ 3327 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 3328 switch (vp->v_type) { 3329 case VREG: 3330 case VDIR: 3331 case VLNK: 3332 return (EROFS); 3333 default: 3334 break; 3335 } 3336 } 3337 3338 /* 3339 * If the vnode is in use as a process's text, 3340 * we can't allow writing. 3341 */ 3342 if (vp->v_flag & VTEXT) 3343 return (ETXTBSY); 3344 } 3345 error = VOP_GETATTR(vp, &vattr, cred, p); 3346 if (error) 3347 return (error); 3348 error = VOP_ACCESS(vp, flags, cred, p); 3349 /* 3350 * Allow certain operations for the owner (reads and writes 3351 * on files that are already open). 3352 */ 3353 if (override && error == EACCES && cred->cr_uid == vattr.va_uid) 3354 error = 0; 3355 return error; 3356 } 3357