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