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