nfs_subs.c revision 158739
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 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: head/sys/nfsclient/nfs_subs.c 158739 2006-05-19 00:04:24Z mohans $"); 37 38/* 39 * These functions support the macros and help fiddle mbuf chains for 40 * the nfs op functions. They do things like create the rpc header and 41 * copy data between mbuf chains and uio lists. 42 */ 43 44#include <sys/param.h> 45#include <sys/systm.h> 46#include <sys/kernel.h> 47#include <sys/bio.h> 48#include <sys/buf.h> 49#include <sys/proc.h> 50#include <sys/mount.h> 51#include <sys/vnode.h> 52#include <sys/namei.h> 53#include <sys/mbuf.h> 54#include <sys/socket.h> 55#include <sys/stat.h> 56#include <sys/malloc.h> 57#include <sys/sysent.h> 58#include <sys/syscall.h> 59#include <sys/sysproto.h> 60 61#include <vm/vm.h> 62#include <vm/vm_object.h> 63#include <vm/vm_extern.h> 64#include <vm/uma.h> 65 66#include <rpc/rpcclnt.h> 67 68#include <nfs/rpcv2.h> 69#include <nfs/nfsproto.h> 70#include <nfsclient/nfs.h> 71#include <nfsclient/nfsnode.h> 72#include <nfs/xdr_subs.h> 73#include <nfsclient/nfsm_subs.h> 74#include <nfsclient/nfsmount.h> 75 76#include <netinet/in.h> 77 78/* 79 * Note that stdarg.h and the ANSI style va_start macro is used for both 80 * ANSI and traditional C compilers. 81 */ 82#include <machine/stdarg.h> 83 84/* 85 * Data items converted to xdr at startup, since they are constant 86 * This is kinda hokey, but may save a little time doing byte swaps 87 */ 88u_int32_t nfs_xdrneg1; 89u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 90 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 91u_int32_t nfs_true, nfs_false; 92 93/* And other global data */ 94u_int32_t nfs_xid = 0; 95static enum vtype nv2tov_type[8]= { 96 VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON 97}; 98 99int nfs_ticks; 100int nfs_pbuf_freecnt = -1; /* start out unlimited */ 101 102struct nfs_reqq nfs_reqq; 103struct mtx nfs_reqq_mtx; 104struct nfs_bufq nfs_bufq; 105 106/* 107 * and the reverse mapping from generic to Version 2 procedure numbers 108 */ 109int nfsv2_procid[NFS_NPROCS] = { 110 NFSV2PROC_NULL, 111 NFSV2PROC_GETATTR, 112 NFSV2PROC_SETATTR, 113 NFSV2PROC_LOOKUP, 114 NFSV2PROC_NOOP, 115 NFSV2PROC_READLINK, 116 NFSV2PROC_READ, 117 NFSV2PROC_WRITE, 118 NFSV2PROC_CREATE, 119 NFSV2PROC_MKDIR, 120 NFSV2PROC_SYMLINK, 121 NFSV2PROC_CREATE, 122 NFSV2PROC_REMOVE, 123 NFSV2PROC_RMDIR, 124 NFSV2PROC_RENAME, 125 NFSV2PROC_LINK, 126 NFSV2PROC_READDIR, 127 NFSV2PROC_NOOP, 128 NFSV2PROC_STATFS, 129 NFSV2PROC_NOOP, 130 NFSV2PROC_NOOP, 131 NFSV2PROC_NOOP, 132 NFSV2PROC_NOOP, 133}; 134 135LIST_HEAD(nfsnodehashhead, nfsnode); 136 137/* 138 * Create the header for an rpc request packet 139 * The hsiz is the size of the rest of the nfs request header. 140 * (just used to decide if a cluster is a good idea) 141 */ 142struct mbuf * 143nfsm_reqhead(struct vnode *vp, u_long procid, int hsiz) 144{ 145 struct mbuf *mb; 146 147 MGET(mb, M_TRYWAIT, MT_DATA); 148 if (hsiz >= MINCLSIZE) 149 MCLGET(mb, M_TRYWAIT); 150 mb->m_len = 0; 151 return (mb); 152} 153 154/* 155 * Build the RPC header and fill in the authorization info. 156 * The authorization string argument is only used when the credentials 157 * come from outside of the kernel. 158 * Returns the head of the mbuf list. 159 */ 160struct mbuf * 161nfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type, 162 int auth_len, struct mbuf *mrest, int mrest_len, struct mbuf **mbp, 163 u_int32_t **xidpp) 164{ 165 struct mbuf *mb; 166 u_int32_t *tl; 167 caddr_t bpos; 168 int i; 169 struct mbuf *mreq; 170 int grpsiz, authsiz; 171 172 authsiz = nfsm_rndup(auth_len); 173 MGETHDR(mb, M_TRYWAIT, MT_DATA); 174 if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { 175 MCLGET(mb, M_TRYWAIT); 176 } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { 177 MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 178 } else { 179 MH_ALIGN(mb, 8 * NFSX_UNSIGNED); 180 } 181 mb->m_len = 0; 182 mreq = mb; 183 bpos = mtod(mb, caddr_t); 184 185 /* 186 * First the RPC header. 187 */ 188 tl = nfsm_build(u_int32_t *, 8 * NFSX_UNSIGNED); 189 190 mtx_lock(&nfs_reqq_mtx); 191 /* Get a pretty random xid to start with */ 192 if (!nfs_xid) 193 nfs_xid = random(); 194 /* 195 * Skip zero xid if it should ever happen. 196 */ 197 if (++nfs_xid == 0) 198 nfs_xid++; 199 200 *xidpp = tl; 201 *tl++ = txdr_unsigned(nfs_xid); 202 mtx_unlock(&nfs_reqq_mtx); 203 *tl++ = rpc_call; 204 *tl++ = rpc_vers; 205 *tl++ = txdr_unsigned(NFS_PROG); 206 if (nmflag & NFSMNT_NFSV3) { 207 *tl++ = txdr_unsigned(NFS_VER3); 208 *tl++ = txdr_unsigned(procid); 209 } else { 210 *tl++ = txdr_unsigned(NFS_VER2); 211 *tl++ = txdr_unsigned(nfsv2_procid[procid]); 212 } 213 214 /* 215 * And then the authorization cred. 216 */ 217 *tl++ = txdr_unsigned(auth_type); 218 *tl = txdr_unsigned(authsiz); 219 switch (auth_type) { 220 case RPCAUTH_UNIX: 221 tl = nfsm_build(u_int32_t *, auth_len); 222 *tl++ = 0; /* stamp ?? */ 223 *tl++ = 0; /* NULL hostname */ 224 *tl++ = txdr_unsigned(cr->cr_uid); 225 *tl++ = txdr_unsigned(cr->cr_groups[0]); 226 grpsiz = (auth_len >> 2) - 5; 227 *tl++ = txdr_unsigned(grpsiz); 228 for (i = 1; i <= grpsiz; i++) 229 *tl++ = txdr_unsigned(cr->cr_groups[i]); 230 break; 231 } 232 233 /* 234 * And the verifier... 235 */ 236 tl = nfsm_build(u_int32_t *, 2 * NFSX_UNSIGNED); 237 *tl++ = txdr_unsigned(RPCAUTH_NULL); 238 *tl = 0; 239 mb->m_next = mrest; 240 mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; 241 mreq->m_pkthdr.rcvif = NULL; 242 *mbp = mb; 243 return (mreq); 244} 245 246/* 247 * copies a uio scatter/gather list to an mbuf chain. 248 * NOTE: can ony handle iovcnt == 1 249 */ 250int 251nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos) 252{ 253 char *uiocp; 254 struct mbuf *mp, *mp2; 255 int xfer, left, mlen; 256 int uiosiz, clflg, rem; 257 char *cp; 258 259#ifdef DIAGNOSTIC 260 if (uiop->uio_iovcnt != 1) 261 panic("nfsm_uiotombuf: iovcnt != 1"); 262#endif 263 264 if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 265 clflg = 1; 266 else 267 clflg = 0; 268 rem = nfsm_rndup(siz)-siz; 269 mp = mp2 = *mq; 270 while (siz > 0) { 271 left = uiop->uio_iov->iov_len; 272 uiocp = uiop->uio_iov->iov_base; 273 if (left > siz) 274 left = siz; 275 uiosiz = left; 276 while (left > 0) { 277 mlen = M_TRAILINGSPACE(mp); 278 if (mlen == 0) { 279 MGET(mp, M_TRYWAIT, MT_DATA); 280 if (clflg) 281 MCLGET(mp, M_TRYWAIT); 282 mp->m_len = 0; 283 mp2->m_next = mp; 284 mp2 = mp; 285 mlen = M_TRAILINGSPACE(mp); 286 } 287 xfer = (left > mlen) ? mlen : left; 288#ifdef notdef 289 /* Not Yet.. */ 290 if (uiop->uio_iov->iov_op != NULL) 291 (*(uiop->uio_iov->iov_op)) 292 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 293 else 294#endif 295 if (uiop->uio_segflg == UIO_SYSSPACE) 296 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 297 else 298 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 299 mp->m_len += xfer; 300 left -= xfer; 301 uiocp += xfer; 302 uiop->uio_offset += xfer; 303 uiop->uio_resid -= xfer; 304 } 305 uiop->uio_iov->iov_base = 306 (char *)uiop->uio_iov->iov_base + uiosiz; 307 uiop->uio_iov->iov_len -= uiosiz; 308 siz -= uiosiz; 309 } 310 if (rem > 0) { 311 if (rem > M_TRAILINGSPACE(mp)) { 312 MGET(mp, M_TRYWAIT, MT_DATA); 313 mp->m_len = 0; 314 mp2->m_next = mp; 315 } 316 cp = mtod(mp, caddr_t)+mp->m_len; 317 for (left = 0; left < rem; left++) 318 *cp++ = '\0'; 319 mp->m_len += rem; 320 *bpos = cp; 321 } else 322 *bpos = mtod(mp, caddr_t)+mp->m_len; 323 *mq = mp; 324 return (0); 325} 326 327/* 328 * Copy a string into mbufs for the hard cases... 329 */ 330int 331nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz) 332{ 333 struct mbuf *m1 = NULL, *m2; 334 long left, xfer, len, tlen; 335 u_int32_t *tl; 336 int putsize; 337 338 putsize = 1; 339 m2 = *mb; 340 left = M_TRAILINGSPACE(m2); 341 if (left > 0) { 342 tl = ((u_int32_t *)(*bpos)); 343 *tl++ = txdr_unsigned(siz); 344 putsize = 0; 345 left -= NFSX_UNSIGNED; 346 m2->m_len += NFSX_UNSIGNED; 347 if (left > 0) { 348 bcopy(cp, (caddr_t) tl, left); 349 siz -= left; 350 cp += left; 351 m2->m_len += left; 352 left = 0; 353 } 354 } 355 /* Loop around adding mbufs */ 356 while (siz > 0) { 357 MGET(m1, M_TRYWAIT, MT_DATA); 358 if (siz > MLEN) 359 MCLGET(m1, M_TRYWAIT); 360 m1->m_len = NFSMSIZ(m1); 361 m2->m_next = m1; 362 m2 = m1; 363 tl = mtod(m1, u_int32_t *); 364 tlen = 0; 365 if (putsize) { 366 *tl++ = txdr_unsigned(siz); 367 m1->m_len -= NFSX_UNSIGNED; 368 tlen = NFSX_UNSIGNED; 369 putsize = 0; 370 } 371 if (siz < m1->m_len) { 372 len = nfsm_rndup(siz); 373 xfer = siz; 374 if (xfer < len) 375 *(tl+(xfer>>2)) = 0; 376 } else { 377 xfer = len = m1->m_len; 378 } 379 bcopy(cp, (caddr_t) tl, xfer); 380 m1->m_len = len+tlen; 381 siz -= xfer; 382 cp += xfer; 383 } 384 *mb = m1; 385 *bpos = mtod(m1, caddr_t)+m1->m_len; 386 return (0); 387} 388 389/* 390 * Called once to initialize data structures... 391 */ 392int 393nfs_init(struct vfsconf *vfsp) 394{ 395 int i; 396 397 nfsmount_zone = uma_zcreate("NFSMOUNT", sizeof(struct nfsmount), 398 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 399 rpc_vers = txdr_unsigned(RPC_VER2); 400 rpc_call = txdr_unsigned(RPC_CALL); 401 rpc_reply = txdr_unsigned(RPC_REPLY); 402 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 403 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 404 rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 405 rpc_autherr = txdr_unsigned(RPC_AUTHERR); 406 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 407 nfs_true = txdr_unsigned(TRUE); 408 nfs_false = txdr_unsigned(FALSE); 409 nfs_xdrneg1 = txdr_unsigned(-1); 410 nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 411 if (nfs_ticks < 1) 412 nfs_ticks = 1; 413 /* Ensure async daemons disabled */ 414 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 415 nfs_iodwant[i] = NULL; 416 nfs_iodmount[i] = NULL; 417 } 418 nfs_nhinit(); /* Init the nfsnode table */ 419 420 /* 421 * Initialize reply list and start timer 422 */ 423 TAILQ_INIT(&nfs_reqq); 424 callout_init(&nfs_callout, CALLOUT_MPSAFE); 425 mtx_init(&nfs_reqq_mtx, "NFS reqq lock", NULL, MTX_DEF); 426 mtx_init(&nfs_iod_mtx, "NFS iod lock", NULL, MTX_DEF); 427 428 nfs_pbuf_freecnt = nswbuf / 2 + 1; 429 430 return (0); 431} 432 433int 434nfs_uninit(struct vfsconf *vfsp) 435{ 436 int i; 437 438 callout_stop(&nfs_callout); 439 440 KASSERT(TAILQ_EMPTY(&nfs_reqq), 441 ("nfs_uninit: request queue not empty")); 442 443 /* 444 * Tell all nfsiod processes to exit. Clear nfs_iodmax, and wakeup 445 * any sleeping nfsiods so they check nfs_iodmax and exit. 446 */ 447 mtx_lock(&nfs_iod_mtx); 448 nfs_iodmax = 0; 449 for (i = 0; i < nfs_numasync; i++) 450 if (nfs_iodwant[i]) 451 wakeup(&nfs_iodwant[i]); 452 /* The last nfsiod to exit will wake us up when nfs_numasync hits 0 */ 453 while (nfs_numasync) 454 msleep(&nfs_numasync, &nfs_iod_mtx, PWAIT, "ioddie", 0); 455 mtx_unlock(&nfs_iod_mtx); 456 nfs_nhuninit(); 457 uma_zdestroy(nfsmount_zone); 458 return (0); 459} 460 461void 462nfs_dircookie_lock(struct nfsnode *np) 463{ 464 mtx_lock(&np->n_mtx); 465 while (np->n_flag & NDIRCOOKIELK) 466 (void) msleep(&np->n_flag, &np->n_mtx, PZERO, "nfsdirlk", 0); 467 np->n_flag |= NDIRCOOKIELK; 468 mtx_unlock(&np->n_mtx); 469} 470 471void 472nfs_dircookie_unlock(struct nfsnode *np) 473{ 474 mtx_lock(&np->n_mtx); 475 np->n_flag &= ~NDIRCOOKIELK; 476 wakeup(&np->n_flag); 477 mtx_unlock(&np->n_mtx); 478} 479 480int 481nfs_upgrade_vnlock(struct vnode *vp, struct thread *td) 482{ 483 int old_lock; 484 485 if ((old_lock = VOP_ISLOCKED(vp, td)) != LK_EXCLUSIVE) { 486 if (old_lock == LK_SHARED) { 487 /* Upgrade to exclusive lock, this might block */ 488 vn_lock(vp, LK_UPGRADE | LK_RETRY, td); 489 } else { 490 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 491 } 492 } 493 return old_lock; 494} 495 496void 497nfs_downgrade_vnlock(struct vnode *vp, struct thread *td, int old_lock) 498{ 499 if (old_lock != LK_EXCLUSIVE) { 500 if (old_lock == LK_SHARED) { 501 /* Downgrade from exclusive lock, this might block */ 502 vn_lock(vp, LK_DOWNGRADE, td); 503 } else { 504 VOP_UNLOCK(vp, 0, td); 505 } 506 } 507} 508 509void 510nfs_printf(const char *fmt, ...) 511{ 512 va_list ap; 513 514 mtx_lock(&Giant); 515 va_start(ap, fmt); 516 printf(fmt, ap); 517 va_end(ap); 518 mtx_unlock(&Giant); 519} 520 521/* 522 * Attribute cache routines. 523 * nfs_loadattrcache() - loads or updates the cache contents from attributes 524 * that are on the mbuf list 525 * nfs_getattrcache() - returns valid attributes if found in cache, returns 526 * error otherwise 527 */ 528 529/* 530 * Load the attribute cache (that lives in the nfsnode entry) with 531 * the values on the mbuf list and 532 * Iff vap not NULL 533 * copy the attributes to *vaper 534 */ 535int 536nfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp, 537 struct vattr *vaper, int dontshrink) 538{ 539 struct vnode *vp = *vpp; 540 struct vattr *vap; 541 struct nfs_fattr *fp; 542 struct nfsnode *np; 543 int32_t t1; 544 caddr_t cp2; 545 int rdev; 546 struct mbuf *md; 547 enum vtype vtyp; 548 u_short vmode; 549 struct timespec mtime; 550 int v3 = NFS_ISV3(vp); 551 552 md = *mdp; 553 t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 554 cp2 = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, M_TRYWAIT); 555 if (cp2 == NULL) 556 return EBADRPC; 557 fp = (struct nfs_fattr *)cp2; 558 if (v3) { 559 vtyp = nfsv3tov_type(fp->fa_type); 560 vmode = fxdr_unsigned(u_short, fp->fa_mode); 561 rdev = makedev(fxdr_unsigned(int, fp->fa3_rdev.specdata1), 562 fxdr_unsigned(int, fp->fa3_rdev.specdata2)); 563 fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 564 } else { 565 vtyp = nfsv2tov_type(fp->fa_type); 566 vmode = fxdr_unsigned(u_short, fp->fa_mode); 567 /* 568 * XXX 569 * 570 * The duplicate information returned in fa_type and fa_mode 571 * is an ambiguity in the NFS version 2 protocol. 572 * 573 * VREG should be taken literally as a regular file. If a 574 * server intents to return some type information differently 575 * in the upper bits of the mode field (e.g. for sockets, or 576 * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we 577 * leave the examination of the mode bits even in the VREG 578 * case to avoid breakage for bogus servers, but we make sure 579 * that there are actually type bits set in the upper part of 580 * fa_mode (and failing that, trust the va_type field). 581 * 582 * NFSv3 cleared the issue, and requires fa_mode to not 583 * contain any type information (while also introduing sockets 584 * and FIFOs for fa_type). 585 */ 586 if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) 587 vtyp = IFTOVT(vmode); 588 rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); 589 fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 590 591 /* 592 * Really ugly NFSv2 kludge. 593 */ 594 if (vtyp == VCHR && rdev == 0xffffffff) 595 vtyp = VFIFO; 596 } 597 598 /* 599 * If v_type == VNON it is a new node, so fill in the v_type, 600 * n_mtime fields. Check to see if it represents a special 601 * device, and if so, check for a possible alias. Once the 602 * correct vnode has been obtained, fill in the rest of the 603 * information. 604 */ 605 np = VTONFS(vp); 606 mtx_lock(&np->n_mtx); 607 if (vp->v_type != vtyp) { 608 vp->v_type = vtyp; 609 if (vp->v_type == VFIFO) 610 vp->v_op = &nfs_fifoops; 611 np->n_mtime = mtime; 612 } 613 vap = &np->n_vattr; 614 vap->va_type = vtyp; 615 vap->va_mode = (vmode & 07777); 616 vap->va_rdev = rdev; 617 vap->va_mtime = mtime; 618 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 619 if (v3) { 620 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 621 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 622 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 623 vap->va_size = fxdr_hyper(&fp->fa3_size); 624 vap->va_blocksize = NFS_FABLKSIZE; 625 vap->va_bytes = fxdr_hyper(&fp->fa3_used); 626 vap->va_fileid = fxdr_unsigned(int32_t, 627 fp->fa3_fileid.nfsuquad[1]); 628 fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 629 fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 630 vap->va_flags = 0; 631 vap->va_filerev = 0; 632 } else { 633 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 634 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 635 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 636 vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 637 vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 638 vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) 639 * NFS_FABLKSIZE; 640 vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); 641 fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 642 vap->va_flags = 0; 643 vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, 644 fp->fa2_ctime.nfsv2_sec); 645 vap->va_ctime.tv_nsec = 0; 646 vap->va_gen = fxdr_unsigned(u_int32_t, fp->fa2_ctime.nfsv2_usec); 647 vap->va_filerev = 0; 648 } 649 np->n_attrstamp = time_second; 650 if (vap->va_size != np->n_size) { 651 if (vap->va_type == VREG) { 652 if (dontshrink && vap->va_size < np->n_size) { 653 /* 654 * We've been told not to shrink the file; 655 * zero np->n_attrstamp to indicate that 656 * the attributes are stale. 657 */ 658 vap->va_size = np->n_size; 659 np->n_attrstamp = 0; 660 } else if (np->n_flag & NMODIFIED) { 661 /* 662 * We've modified the file: Use the larger 663 * of our size, and the server's size. 664 */ 665 if (vap->va_size < np->n_size) { 666 vap->va_size = np->n_size; 667 } else { 668 np->n_size = vap->va_size; 669 np->n_flag |= NSIZECHANGED; 670 } 671 } else { 672 np->n_size = vap->va_size; 673 np->n_flag |= NSIZECHANGED; 674 } 675 vnode_pager_setsize(vp, np->n_size); 676 } else { 677 np->n_size = vap->va_size; 678 } 679 } 680 if (vaper != NULL) { 681 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 682 if (np->n_flag & NCHG) { 683 if (np->n_flag & NACC) 684 vaper->va_atime = np->n_atim; 685 if (np->n_flag & NUPD) 686 vaper->va_mtime = np->n_mtim; 687 } 688 } 689 mtx_unlock(&np->n_mtx); 690 return (0); 691} 692 693#ifdef NFS_ACDEBUG 694#include <sys/sysctl.h> 695SYSCTL_DECL(_vfs_nfs); 696static int nfs_acdebug; 697SYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, ""); 698#endif 699 700/* 701 * Check the time stamp 702 * If the cache is valid, copy contents to *vap and return 0 703 * otherwise return an error 704 */ 705int 706nfs_getattrcache(struct vnode *vp, struct vattr *vaper) 707{ 708 struct nfsnode *np; 709 struct vattr *vap; 710 struct nfsmount *nmp; 711 int timeo; 712 713 np = VTONFS(vp); 714 vap = &np->n_vattr; 715 nmp = VFSTONFS(vp->v_mount); 716#ifdef NFS_ACDEBUG 717 mtx_lock(&Giant); /* nfs_printf() */ 718#endif 719 mtx_lock(&np->n_mtx); 720 /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */ 721 timeo = (time_second - np->n_mtime.tv_sec) / 10; 722 723#ifdef NFS_ACDEBUG 724 if (nfs_acdebug>1) 725 nfs_printf("nfs_getattrcache: initial timeo = %d\n", timeo); 726#endif 727 728 if (vap->va_type == VDIR) { 729 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin) 730 timeo = nmp->nm_acdirmin; 731 else if (timeo > nmp->nm_acdirmax) 732 timeo = nmp->nm_acdirmax; 733 } else { 734 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin) 735 timeo = nmp->nm_acregmin; 736 else if (timeo > nmp->nm_acregmax) 737 timeo = nmp->nm_acregmax; 738 } 739 740#ifdef NFS_ACDEBUG 741 if (nfs_acdebug > 2) 742 nfs_printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n", 743 nmp->nm_acregmin, nmp->nm_acregmax, 744 nmp->nm_acdirmin, nmp->nm_acdirmax); 745 746 if (nfs_acdebug) 747 nfs_printf("nfs_getattrcache: age = %d; final timeo = %d\n", 748 (time_second - np->n_attrstamp), timeo); 749#endif 750 751 if ((time_second - np->n_attrstamp) >= timeo) { 752 nfsstats.attrcache_misses++; 753 mtx_unlock(&np->n_mtx); 754 return( ENOENT); 755 } 756 nfsstats.attrcache_hits++; 757 if (vap->va_size != np->n_size) { 758 if (vap->va_type == VREG) { 759 if (np->n_flag & NMODIFIED) { 760 if (vap->va_size < np->n_size) 761 vap->va_size = np->n_size; 762 else 763 np->n_size = vap->va_size; 764 } else { 765 np->n_size = vap->va_size; 766 } 767 vnode_pager_setsize(vp, np->n_size); 768 } else { 769 np->n_size = vap->va_size; 770 } 771 } 772 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 773 if (np->n_flag & NCHG) { 774 if (np->n_flag & NACC) 775 vaper->va_atime = np->n_atim; 776 if (np->n_flag & NUPD) 777 vaper->va_mtime = np->n_mtim; 778 } 779 mtx_unlock(&np->n_mtx); 780#ifdef NFS_ACDEBUG 781 mtx_unlock(&Giant); /* nfs_printf() */ 782#endif 783 return (0); 784} 785 786static nfsuint64 nfs_nullcookie = { { 0, 0 } }; 787/* 788 * This function finds the directory cookie that corresponds to the 789 * logical byte offset given. 790 */ 791nfsuint64 * 792nfs_getcookie(struct nfsnode *np, off_t off, int add) 793{ 794 struct nfsdmap *dp, *dp2; 795 int pos; 796 nfsuint64 *retval = NULL; 797 798 pos = (uoff_t)off / NFS_DIRBLKSIZ; 799 if (pos == 0 || off < 0) { 800#ifdef DIAGNOSTIC 801 if (add) 802 panic("nfs getcookie add at <= 0"); 803#endif 804 return (&nfs_nullcookie); 805 } 806 pos--; 807 dp = LIST_FIRST(&np->n_cookies); 808 if (!dp) { 809 if (add) { 810 MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 811 M_NFSDIROFF, M_WAITOK); 812 dp->ndm_eocookie = 0; 813 LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 814 } else 815 goto out; 816 } 817 while (pos >= NFSNUMCOOKIES) { 818 pos -= NFSNUMCOOKIES; 819 if (LIST_NEXT(dp, ndm_list)) { 820 if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 821 pos >= dp->ndm_eocookie) 822 goto out; 823 dp = LIST_NEXT(dp, ndm_list); 824 } else if (add) { 825 MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 826 M_NFSDIROFF, M_WAITOK); 827 dp2->ndm_eocookie = 0; 828 LIST_INSERT_AFTER(dp, dp2, ndm_list); 829 dp = dp2; 830 } else 831 goto out; 832 } 833 if (pos >= dp->ndm_eocookie) { 834 if (add) 835 dp->ndm_eocookie = pos + 1; 836 else 837 goto out; 838 } 839 retval = &dp->ndm_cookies[pos]; 840out: 841 return (retval); 842} 843 844/* 845 * Invalidate cached directory information, except for the actual directory 846 * blocks (which are invalidated separately). 847 * Done mainly to avoid the use of stale offset cookies. 848 */ 849void 850nfs_invaldir(struct vnode *vp) 851{ 852 struct nfsnode *np = VTONFS(vp); 853 854#ifdef DIAGNOSTIC 855 if (vp->v_type != VDIR) 856 panic("nfs: invaldir not dir"); 857#endif 858 nfs_dircookie_lock(np); 859 np->n_direofoffset = 0; 860 np->n_cookieverf.nfsuquad[0] = 0; 861 np->n_cookieverf.nfsuquad[1] = 0; 862 if (LIST_FIRST(&np->n_cookies)) 863 LIST_FIRST(&np->n_cookies)->ndm_eocookie = 0; 864 nfs_dircookie_unlock(np); 865} 866 867/* 868 * The write verifier has changed (probably due to a server reboot), so all 869 * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 870 * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 871 * and B_CLUSTEROK flags. Once done the new write verifier can be set for the 872 * mount point. 873 * 874 * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data 875 * writes are not clusterable. 876 */ 877void 878nfs_clearcommit(struct mount *mp) 879{ 880 struct vnode *vp, *nvp; 881 struct buf *bp, *nbp; 882 int s; 883 884 s = splbio(); 885 MNT_ILOCK(mp); 886 MNT_VNODE_FOREACH(vp, mp, nvp) { 887 VI_LOCK(vp); 888 if (vp->v_iflag & VI_DOOMED) { 889 VI_UNLOCK(vp); 890 continue; 891 } 892 MNT_IUNLOCK(mp); 893 TAILQ_FOREACH_SAFE(bp, &vp->v_bufobj.bo_dirty.bv_hd, b_bobufs, nbp) { 894 if (BUF_REFCNT(bp) == 0 && 895 (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) 896 == (B_DELWRI | B_NEEDCOMMIT)) 897 bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); 898 } 899 VI_UNLOCK(vp); 900 MNT_ILOCK(mp); 901 } 902 MNT_IUNLOCK(mp); 903 splx(s); 904} 905 906/* 907 * Helper functions for former macros. Some of these should be 908 * moved to their callers. 909 */ 910 911int 912nfsm_mtofh_xx(struct vnode *d, struct vnode **v, int v3, int *f, 913 struct mbuf **md, caddr_t *dpos) 914{ 915 struct nfsnode *ttnp; 916 struct vnode *ttvp; 917 nfsfh_t *ttfhp; 918 u_int32_t *tl; 919 int ttfhsize; 920 int t1; 921 922 if (v3) { 923 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 924 if (tl == NULL) 925 return EBADRPC; 926 *f = fxdr_unsigned(int, *tl); 927 } else 928 *f = 1; 929 if (*f) { 930 t1 = nfsm_getfh_xx(&ttfhp, &ttfhsize, (v3), md, dpos); 931 if (t1 != 0) 932 return t1; 933 t1 = nfs_nget(d->v_mount, ttfhp, ttfhsize, &ttnp); 934 if (t1 != 0) 935 return t1; 936 *v = NFSTOV(ttnp); 937 } 938 if (v3) { 939 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 940 if (tl == NULL) 941 return EBADRPC; 942 if (*f) 943 *f = fxdr_unsigned(int, *tl); 944 else if (fxdr_unsigned(int, *tl)) 945 nfsm_adv_xx(NFSX_V3FATTR, md, dpos); 946 } 947 if (*f) { 948 ttvp = *v; 949 t1 = nfs_loadattrcache(&ttvp, md, dpos, NULL, 0); 950 if (t1) 951 return t1; 952 *v = ttvp; 953 } 954 return 0; 955} 956 957int 958nfsm_getfh_xx(nfsfh_t **f, int *s, int v3, struct mbuf **md, caddr_t *dpos) 959{ 960 u_int32_t *tl; 961 962 if (v3) { 963 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 964 if (tl == NULL) 965 return EBADRPC; 966 *s = fxdr_unsigned(int, *tl); 967 if (*s <= 0 || *s > NFSX_V3FHMAX) 968 return EBADRPC; 969 } else 970 *s = NFSX_V2FH; 971 *f = nfsm_dissect_xx(nfsm_rndup(*s), md, dpos); 972 if (*f == NULL) 973 return EBADRPC; 974 else 975 return 0; 976} 977 978 979int 980nfsm_loadattr_xx(struct vnode **v, struct vattr *va, struct mbuf **md, 981 caddr_t *dpos) 982{ 983 int t1; 984 985 struct vnode *ttvp = *v; 986 t1 = nfs_loadattrcache(&ttvp, md, dpos, va, 0); 987 if (t1 != 0) 988 return t1; 989 *v = ttvp; 990 return 0; 991} 992 993int 994nfsm_postop_attr_xx(struct vnode **v, int *f, struct mbuf **md, 995 caddr_t *dpos) 996{ 997 u_int32_t *tl; 998 int t1; 999 1000 struct vnode *ttvp = *v; 1001 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 1002 if (tl == NULL) 1003 return EBADRPC; 1004 *f = fxdr_unsigned(int, *tl); 1005 if (*f != 0) { 1006 t1 = nfs_loadattrcache(&ttvp, md, dpos, NULL, 1); 1007 if (t1 != 0) { 1008 *f = 0; 1009 return t1; 1010 } 1011 *v = ttvp; 1012 } 1013 return 0; 1014} 1015 1016int 1017nfsm_wcc_data_xx(struct vnode **v, int *f, struct mbuf **md, caddr_t *dpos) 1018{ 1019 u_int32_t *tl; 1020 int ttattrf, ttretf = 0; 1021 int t1; 1022 1023 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 1024 if (tl == NULL) 1025 return EBADRPC; 1026 if (*tl == nfs_true) { 1027 tl = nfsm_dissect_xx(6 * NFSX_UNSIGNED, md, dpos); 1028 if (tl == NULL) 1029 return EBADRPC; 1030 mtx_lock(&(VTONFS(*v))->n_mtx); 1031 if (*f) 1032 ttretf = (VTONFS(*v)->n_mtime.tv_sec == fxdr_unsigned(u_int32_t, *(tl + 2)) && 1033 VTONFS(*v)->n_mtime.tv_nsec == fxdr_unsigned(u_int32_t, *(tl + 3))); 1034 mtx_unlock(&(VTONFS(*v))->n_mtx); 1035 } 1036 t1 = nfsm_postop_attr_xx(v, &ttattrf, md, dpos); 1037 if (t1) 1038 return t1; 1039 if (*f) 1040 *f = ttretf; 1041 else 1042 *f = ttattrf; 1043 return 0; 1044} 1045 1046int 1047nfsm_strtom_xx(const char *a, int s, int m, struct mbuf **mb, caddr_t *bpos) 1048{ 1049 u_int32_t *tl; 1050 int t1; 1051 1052 if (s > m) 1053 return ENAMETOOLONG; 1054 t1 = nfsm_rndup(s) + NFSX_UNSIGNED; 1055 if (t1 <= M_TRAILINGSPACE(*mb)) { 1056 tl = nfsm_build_xx(t1, mb, bpos); 1057 *tl++ = txdr_unsigned(s); 1058 *(tl + ((t1 >> 2) - 2)) = 0; 1059 bcopy(a, tl, s); 1060 } else { 1061 t1 = nfsm_strtmbuf(mb, bpos, a, s); 1062 if (t1 != 0) 1063 return t1; 1064 } 1065 return 0; 1066} 1067 1068int 1069nfsm_fhtom_xx(struct vnode *v, int v3, struct mbuf **mb, caddr_t *bpos) 1070{ 1071 u_int32_t *tl; 1072 int t1; 1073 caddr_t cp; 1074 1075 if (v3) { 1076 t1 = nfsm_rndup(VTONFS(v)->n_fhsize) + NFSX_UNSIGNED; 1077 if (t1 < M_TRAILINGSPACE(*mb)) { 1078 tl = nfsm_build_xx(t1, mb, bpos); 1079 *tl++ = txdr_unsigned(VTONFS(v)->n_fhsize); 1080 *(tl + ((t1 >> 2) - 2)) = 0; 1081 bcopy(VTONFS(v)->n_fhp, tl, VTONFS(v)->n_fhsize); 1082 } else { 1083 t1 = nfsm_strtmbuf(mb, bpos, 1084 (const char *)VTONFS(v)->n_fhp, 1085 VTONFS(v)->n_fhsize); 1086 if (t1 != 0) 1087 return t1; 1088 } 1089 } else { 1090 cp = nfsm_build_xx(NFSX_V2FH, mb, bpos); 1091 bcopy(VTONFS(v)->n_fhp, cp, NFSX_V2FH); 1092 } 1093 return 0; 1094} 1095 1096void 1097nfsm_v3attrbuild_xx(struct vattr *va, int full, struct mbuf **mb, 1098 caddr_t *bpos) 1099{ 1100 u_int32_t *tl; 1101 1102 if (va->va_mode != (mode_t)VNOVAL) { 1103 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 1104 *tl++ = nfs_true; 1105 *tl = txdr_unsigned(va->va_mode); 1106 } else { 1107 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1108 *tl = nfs_false; 1109 } 1110 if (full && va->va_uid != (uid_t)VNOVAL) { 1111 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 1112 *tl++ = nfs_true; 1113 *tl = txdr_unsigned(va->va_uid); 1114 } else { 1115 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1116 *tl = nfs_false; 1117 } 1118 if (full && va->va_gid != (gid_t)VNOVAL) { 1119 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 1120 *tl++ = nfs_true; 1121 *tl = txdr_unsigned(va->va_gid); 1122 } else { 1123 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1124 *tl = nfs_false; 1125 } 1126 if (full && va->va_size != VNOVAL) { 1127 tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 1128 *tl++ = nfs_true; 1129 txdr_hyper(va->va_size, tl); 1130 } else { 1131 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1132 *tl = nfs_false; 1133 } 1134 if (va->va_atime.tv_sec != VNOVAL) { 1135 if (va->va_atime.tv_sec != time_second) { 1136 tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 1137 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 1138 txdr_nfsv3time(&va->va_atime, tl); 1139 } else { 1140 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1141 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 1142 } 1143 } else { 1144 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1145 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 1146 } 1147 if (va->va_mtime.tv_sec != VNOVAL) { 1148 if (va->va_mtime.tv_sec != time_second) { 1149 tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 1150 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 1151 txdr_nfsv3time(&va->va_mtime, tl); 1152 } else { 1153 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1154 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 1155 } 1156 } else { 1157 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1158 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 1159 } 1160} 1161