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