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