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