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