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