nfs_subs.c revision 128111
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 128111 2004-04-11 13:30:20Z peadar $"); 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 */ 88static u_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 nfs_bufq nfs_bufq; 98 99static int nfs_prev_nfsclnt_sy_narg; 100static sy_call_t *nfs_prev_nfsclnt_sy_call; 101 102/* 103 * and the reverse mapping from generic to Version 2 procedure numbers 104 */ 105int nfsv2_procid[NFS_NPROCS] = { 106 NFSV2PROC_NULL, 107 NFSV2PROC_GETATTR, 108 NFSV2PROC_SETATTR, 109 NFSV2PROC_LOOKUP, 110 NFSV2PROC_NOOP, 111 NFSV2PROC_READLINK, 112 NFSV2PROC_READ, 113 NFSV2PROC_WRITE, 114 NFSV2PROC_CREATE, 115 NFSV2PROC_MKDIR, 116 NFSV2PROC_SYMLINK, 117 NFSV2PROC_CREATE, 118 NFSV2PROC_REMOVE, 119 NFSV2PROC_RMDIR, 120 NFSV2PROC_RENAME, 121 NFSV2PROC_LINK, 122 NFSV2PROC_READDIR, 123 NFSV2PROC_NOOP, 124 NFSV2PROC_STATFS, 125 NFSV2PROC_NOOP, 126 NFSV2PROC_NOOP, 127 NFSV2PROC_NOOP, 128 NFSV2PROC_NOOP, 129}; 130 131LIST_HEAD(nfsnodehashhead, nfsnode); 132 133/* 134 * Create the header for an rpc request packet 135 * The hsiz is the size of the rest of the nfs request header. 136 * (just used to decide if a cluster is a good idea) 137 */ 138struct mbuf * 139nfsm_reqhead(struct vnode *vp, u_long procid, int hsiz) 140{ 141 struct mbuf *mb; 142 143 MGET(mb, M_TRYWAIT, MT_DATA); 144 if (hsiz >= MINCLSIZE) 145 MCLGET(mb, M_TRYWAIT); 146 mb->m_len = 0; 147 return (mb); 148} 149 150/* 151 * Build the RPC header and fill in the authorization info. 152 * The authorization string argument is only used when the credentials 153 * come from outside of the kernel. 154 * Returns the head of the mbuf list. 155 */ 156struct mbuf * 157nfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type, 158 int auth_len, struct mbuf *mrest, int mrest_len, struct mbuf **mbp, 159 u_int32_t *xidp) 160{ 161 struct mbuf *mb; 162 u_int32_t *tl; 163 caddr_t bpos; 164 int i; 165 struct mbuf *mreq; 166 int grpsiz, authsiz; 167 168 authsiz = nfsm_rndup(auth_len); 169 MGETHDR(mb, M_TRYWAIT, MT_DATA); 170 if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { 171 MCLGET(mb, M_TRYWAIT); 172 } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { 173 MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 174 } else { 175 MH_ALIGN(mb, 8 * NFSX_UNSIGNED); 176 } 177 mb->m_len = 0; 178 mreq = mb; 179 bpos = mtod(mb, caddr_t); 180 181 /* 182 * First the RPC header. 183 */ 184 tl = nfsm_build(u_int32_t *, 8 * NFSX_UNSIGNED); 185 186 /* Get a pretty random xid to start with */ 187 if (!nfs_xid) 188 nfs_xid = random(); 189 /* 190 * Skip zero xid if it should ever happen. 191 */ 192 if (++nfs_xid == 0) 193 nfs_xid++; 194 195 *tl++ = *xidp = 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, 0); 418 419 nfs_prev_nfsclnt_sy_narg = sysent[SYS_nfsclnt].sy_narg; 420 sysent[SYS_nfsclnt].sy_narg = 2; 421 nfs_prev_nfsclnt_sy_call = sysent[SYS_nfsclnt].sy_call; 422 sysent[SYS_nfsclnt].sy_call = (sy_call_t *)nfsclnt; 423 424 nfs_pbuf_freecnt = nswbuf / 2 + 1; 425 426 return (0); 427} 428 429int 430nfs_uninit(struct vfsconf *vfsp) 431{ 432 int i; 433 434 callout_stop(&nfs_callout); 435 sysent[SYS_nfsclnt].sy_narg = nfs_prev_nfsclnt_sy_narg; 436 sysent[SYS_nfsclnt].sy_call = nfs_prev_nfsclnt_sy_call; 437 438 KASSERT(TAILQ_ISEMPTY(&nfs_reqq), 439 ("nfs_uninit: request queue not empty")); 440 441 /* 442 * Tell all nfsiod processes to exit. Clear nfs_iodmax, and wakeup 443 * any sleeping nfsiods so they check nfs_iodmax and exit. 444 */ 445 nfs_iodmax = 0; 446 for (i = 0; i < nfs_numasync; i++) 447 if (nfs_iodwant[i]) 448 wakeup(&nfs_iodwant[i]); 449 /* The last nfsiod to exit will wake us up when nfs_numasync hits 0 */ 450 while (nfs_numasync) 451 tsleep(&nfs_numasync, PWAIT, "ioddie", 0); 452 453 nfs_nhuninit(); 454 uma_zdestroy(nfsmount_zone); 455 return (0); 456} 457 458/* 459 * Attribute cache routines. 460 * nfs_loadattrcache() - loads or updates the cache contents from attributes 461 * that are on the mbuf list 462 * nfs_getattrcache() - returns valid attributes if found in cache, returns 463 * error otherwise 464 */ 465 466/* 467 * Load the attribute cache (that lives in the nfsnode entry) with 468 * the values on the mbuf list and 469 * Iff vap not NULL 470 * copy the attributes to *vaper 471 */ 472int 473nfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp, 474 struct vattr *vaper, int dontshrink) 475{ 476 struct vnode *vp = *vpp; 477 struct vattr *vap; 478 struct nfs_fattr *fp; 479 struct nfsnode *np; 480 int32_t t1; 481 caddr_t cp2; 482 int rdev; 483 struct mbuf *md; 484 enum vtype vtyp; 485 u_short vmode; 486 struct timespec mtime; 487 int v3 = NFS_ISV3(vp); 488 489 md = *mdp; 490 t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 491 cp2 = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1); 492 if (cp2 == NULL) 493 return EBADRPC; 494 fp = (struct nfs_fattr *)cp2; 495 if (v3) { 496 vtyp = nfsv3tov_type(fp->fa_type); 497 vmode = fxdr_unsigned(u_short, fp->fa_mode); 498 rdev = makeudev(fxdr_unsigned(int, fp->fa3_rdev.specdata1), 499 fxdr_unsigned(int, fp->fa3_rdev.specdata2)); 500 fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 501 } else { 502 vtyp = nfsv2tov_type(fp->fa_type); 503 vmode = fxdr_unsigned(u_short, fp->fa_mode); 504 /* 505 * XXX 506 * 507 * The duplicate information returned in fa_type and fa_mode 508 * is an ambiguity in the NFS version 2 protocol. 509 * 510 * VREG should be taken literally as a regular file. If a 511 * server intents to return some type information differently 512 * in the upper bits of the mode field (e.g. for sockets, or 513 * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we 514 * leave the examination of the mode bits even in the VREG 515 * case to avoid breakage for bogus servers, but we make sure 516 * that there are actually type bits set in the upper part of 517 * fa_mode (and failing that, trust the va_type field). 518 * 519 * NFSv3 cleared the issue, and requires fa_mode to not 520 * contain any type information (while also introduing sockets 521 * and FIFOs for fa_type). 522 */ 523 if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) 524 vtyp = IFTOVT(vmode); 525 rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); 526 fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 527 528 /* 529 * Really ugly NFSv2 kludge. 530 */ 531 if (vtyp == VCHR && rdev == 0xffffffff) 532 vtyp = VFIFO; 533 } 534 535 /* 536 * If v_type == VNON it is a new node, so fill in the v_type, 537 * n_mtime fields. Check to see if it represents a special 538 * device, and if so, check for a possible alias. Once the 539 * correct vnode has been obtained, fill in the rest of the 540 * information. 541 */ 542 np = VTONFS(vp); 543 if (vp->v_type != vtyp) { 544 vp->v_type = vtyp; 545 if (vp->v_type == VFIFO) 546 vp->v_op = fifo_nfsnodeop_p; 547 else if (vp->v_type == VBLK) 548 vp->v_op = spec_nfsnodeop_p; 549 else if (vp->v_type == VCHR) { 550 vp->v_op = spec_nfsnodeop_p; 551 vp = addaliasu(vp, rdev); 552 np->n_vnode = vp; 553 } 554 np->n_mtime = mtime.tv_sec; 555 } 556 vap = &np->n_vattr; 557 vap->va_type = vtyp; 558 vap->va_mode = (vmode & 07777); 559 vap->va_rdev = rdev; 560 vap->va_mtime = mtime; 561 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 562 if (v3) { 563 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 564 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 565 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 566 vap->va_size = fxdr_hyper(&fp->fa3_size); 567 vap->va_blocksize = NFS_FABLKSIZE; 568 vap->va_bytes = fxdr_hyper(&fp->fa3_used); 569 vap->va_fileid = fxdr_unsigned(int32_t, 570 fp->fa3_fileid.nfsuquad[1]); 571 fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 572 fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 573 vap->va_flags = 0; 574 vap->va_filerev = 0; 575 } else { 576 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 577 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 578 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 579 vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 580 vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 581 vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) 582 * NFS_FABLKSIZE; 583 vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); 584 fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 585 vap->va_flags = 0; 586 vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, 587 fp->fa2_ctime.nfsv2_sec); 588 vap->va_ctime.tv_nsec = 0; 589 vap->va_gen = fxdr_unsigned(u_int32_t, fp->fa2_ctime.nfsv2_usec); 590 vap->va_filerev = 0; 591 } 592 np->n_attrstamp = time_second; 593 if (vap->va_size != np->n_size) { 594 if (vap->va_type == VREG) { 595 if (dontshrink && vap->va_size < np->n_size) { 596 /* 597 * We've been told not to shrink the file; 598 * zero np->n_attrstamp to indicate that 599 * the attributes are stale. 600 */ 601 vap->va_size = np->n_size; 602 np->n_attrstamp = 0; 603 } else if (np->n_flag & NMODIFIED) { 604 if (vap->va_size < np->n_size) 605 vap->va_size = np->n_size; 606 else 607 np->n_size = vap->va_size; 608 } else { 609 np->n_size = vap->va_size; 610 } 611 vnode_pager_setsize(vp, np->n_size); 612 } else { 613 np->n_size = vap->va_size; 614 } 615 } 616 if (vaper != NULL) { 617 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 618 if (np->n_flag & NCHG) { 619 if (np->n_flag & NACC) 620 vaper->va_atime = np->n_atim; 621 if (np->n_flag & NUPD) 622 vaper->va_mtime = np->n_mtim; 623 } 624 } 625 return (0); 626} 627 628#ifdef NFS_ACDEBUG 629#include <sys/sysctl.h> 630SYSCTL_DECL(_vfs_nfs); 631static int nfs_acdebug; 632SYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, ""); 633#endif 634 635/* 636 * Check the time stamp 637 * If the cache is valid, copy contents to *vap and return 0 638 * otherwise return an error 639 */ 640int 641nfs_getattrcache(struct vnode *vp, struct vattr *vaper) 642{ 643 struct nfsnode *np; 644 struct vattr *vap; 645 struct nfsmount *nmp; 646 int timeo; 647 648 np = VTONFS(vp); 649 vap = &np->n_vattr; 650 nmp = VFSTONFS(vp->v_mount); 651 /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */ 652 timeo = (time_second - np->n_mtime) / 10; 653 654#ifdef NFS_ACDEBUG 655 if (nfs_acdebug>1) 656 printf("nfs_getattrcache: initial timeo = %d\n", timeo); 657#endif 658 659 if (vap->va_type == VDIR) { 660 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin) 661 timeo = nmp->nm_acdirmin; 662 else if (timeo > nmp->nm_acdirmax) 663 timeo = nmp->nm_acdirmax; 664 } else { 665 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin) 666 timeo = nmp->nm_acregmin; 667 else if (timeo > nmp->nm_acregmax) 668 timeo = nmp->nm_acregmax; 669 } 670 671#ifdef NFS_ACDEBUG 672 if (nfs_acdebug > 2) 673 printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n", 674 nmp->nm_acregmin, nmp->nm_acregmax, 675 nmp->nm_acdirmin, nmp->nm_acdirmax); 676 677 if (nfs_acdebug) 678 printf("nfs_getattrcache: age = %d; final timeo = %d\n", 679 (time_second - np->n_attrstamp), timeo); 680#endif 681 682 if ((time_second - np->n_attrstamp) >= timeo) { 683 nfsstats.attrcache_misses++; 684 return (ENOENT); 685 } 686 nfsstats.attrcache_hits++; 687 if (vap->va_size != np->n_size) { 688 if (vap->va_type == VREG) { 689 if (np->n_flag & NMODIFIED) { 690 if (vap->va_size < np->n_size) 691 vap->va_size = np->n_size; 692 else 693 np->n_size = vap->va_size; 694 } else { 695 np->n_size = vap->va_size; 696 } 697 vnode_pager_setsize(vp, np->n_size); 698 } else { 699 np->n_size = vap->va_size; 700 } 701 } 702 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 703 if (np->n_flag & NCHG) { 704 if (np->n_flag & NACC) 705 vaper->va_atime = np->n_atim; 706 if (np->n_flag & NUPD) 707 vaper->va_mtime = np->n_mtim; 708 } 709 return (0); 710} 711 712static nfsuint64 nfs_nullcookie = { { 0, 0 } }; 713/* 714 * This function finds the directory cookie that corresponds to the 715 * logical byte offset given. 716 */ 717nfsuint64 * 718nfs_getcookie(struct nfsnode *np, off_t off, int add) 719{ 720 struct nfsdmap *dp, *dp2; 721 int pos; 722 723 pos = (uoff_t)off / NFS_DIRBLKSIZ; 724 if (pos == 0 || off < 0) { 725#ifdef DIAGNOSTIC 726 if (add) 727 panic("nfs getcookie add at <= 0"); 728#endif 729 return (&nfs_nullcookie); 730 } 731 pos--; 732 dp = LIST_FIRST(&np->n_cookies); 733 if (!dp) { 734 if (add) { 735 MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 736 M_NFSDIROFF, M_WAITOK); 737 dp->ndm_eocookie = 0; 738 LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 739 } else 740 return (NULL); 741 } 742 while (pos >= NFSNUMCOOKIES) { 743 pos -= NFSNUMCOOKIES; 744 if (LIST_NEXT(dp, ndm_list)) { 745 if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 746 pos >= dp->ndm_eocookie) 747 return (NULL); 748 dp = LIST_NEXT(dp, ndm_list); 749 } else if (add) { 750 MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 751 M_NFSDIROFF, M_WAITOK); 752 dp2->ndm_eocookie = 0; 753 LIST_INSERT_AFTER(dp, dp2, ndm_list); 754 dp = dp2; 755 } else 756 return (NULL); 757 } 758 if (pos >= dp->ndm_eocookie) { 759 if (add) 760 dp->ndm_eocookie = pos + 1; 761 else 762 return (NULL); 763 } 764 return (&dp->ndm_cookies[pos]); 765} 766 767/* 768 * Invalidate cached directory information, except for the actual directory 769 * blocks (which are invalidated separately). 770 * Done mainly to avoid the use of stale offset cookies. 771 */ 772void 773nfs_invaldir(struct vnode *vp) 774{ 775 struct nfsnode *np = VTONFS(vp); 776 777#ifdef DIAGNOSTIC 778 if (vp->v_type != VDIR) 779 panic("nfs: invaldir not dir"); 780#endif 781 np->n_direofoffset = 0; 782 np->n_cookieverf.nfsuquad[0] = 0; 783 np->n_cookieverf.nfsuquad[1] = 0; 784 if (LIST_FIRST(&np->n_cookies)) 785 LIST_FIRST(&np->n_cookies)->ndm_eocookie = 0; 786} 787 788/* 789 * The write verifier has changed (probably due to a server reboot), so all 790 * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 791 * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 792 * and B_CLUSTEROK flags. Once done the new write verifier can be set for the 793 * mount point. 794 * 795 * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data 796 * writes are not clusterable. 797 */ 798void 799nfs_clearcommit(struct mount *mp) 800{ 801 struct vnode *vp, *nvp; 802 struct buf *bp, *nbp; 803 int s; 804 805 GIANT_REQUIRED; 806 807 s = splbio(); 808 MNT_ILOCK(mp); 809loop: 810 for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp; vp = nvp) { 811 if (vp->v_mount != mp) /* Paranoia */ 812 goto loop; 813 nvp = TAILQ_NEXT(vp, v_nmntvnodes); 814 VI_LOCK(vp); 815 if (vp->v_iflag & VI_XLOCK) { 816 VI_UNLOCK(vp); 817 continue; 818 } 819 MNT_IUNLOCK(mp); 820 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 821 nbp = TAILQ_NEXT(bp, b_vnbufs); 822 if (BUF_REFCNT(bp) == 0 && 823 (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) 824 == (B_DELWRI | B_NEEDCOMMIT)) 825 bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); 826 } 827 VI_UNLOCK(vp); 828 MNT_ILOCK(mp); 829 } 830 MNT_IUNLOCK(mp); 831 splx(s); 832} 833 834/* 835 * Helper functions for former macros. Some of these should be 836 * moved to their callers. 837 */ 838 839int 840nfsm_mtofh_xx(struct vnode *d, struct vnode **v, int v3, int *f, 841 struct mbuf **md, caddr_t *dpos) 842{ 843 struct nfsnode *ttnp; 844 struct vnode *ttvp; 845 nfsfh_t *ttfhp; 846 u_int32_t *tl; 847 int ttfhsize; 848 int t1; 849 850 if (v3) { 851 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 852 if (tl == NULL) 853 return EBADRPC; 854 *f = fxdr_unsigned(int, *tl); 855 } else 856 *f = 1; 857 if (*f) { 858 t1 = nfsm_getfh_xx(&ttfhp, &ttfhsize, (v3), md, dpos); 859 if (t1 != 0) 860 return t1; 861 t1 = nfs_nget(d->v_mount, ttfhp, ttfhsize, &ttnp); 862 if (t1 != 0) 863 return t1; 864 *v = NFSTOV(ttnp); 865 } 866 if (v3) { 867 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 868 if (tl == NULL) 869 return EBADRPC; 870 if (*f) 871 *f = fxdr_unsigned(int, *tl); 872 else if (fxdr_unsigned(int, *tl)) 873 nfsm_adv_xx(NFSX_V3FATTR, md, dpos); 874 } 875 if (*f) { 876 ttvp = *v; 877 t1 = nfs_loadattrcache(&ttvp, md, dpos, NULL, 0); 878 if (t1) 879 return t1; 880 *v = ttvp; 881 } 882 return 0; 883} 884 885int 886nfsm_getfh_xx(nfsfh_t **f, int *s, int v3, struct mbuf **md, caddr_t *dpos) 887{ 888 u_int32_t *tl; 889 890 if (v3) { 891 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 892 if (tl == NULL) 893 return EBADRPC; 894 *s = fxdr_unsigned(int, *tl); 895 if (*s <= 0 || *s > NFSX_V3FHMAX) 896 return EBADRPC; 897 } else 898 *s = NFSX_V2FH; 899 *f = nfsm_dissect_xx(nfsm_rndup(*s), md, dpos); 900 if (*f == NULL) 901 return EBADRPC; 902 else 903 return 0; 904} 905 906 907int 908nfsm_loadattr_xx(struct vnode **v, struct vattr *va, struct mbuf **md, 909 caddr_t *dpos) 910{ 911 int t1; 912 913 struct vnode *ttvp = *v; 914 t1 = nfs_loadattrcache(&ttvp, md, dpos, va, 0); 915 if (t1 != 0) 916 return t1; 917 *v = ttvp; 918 return 0; 919} 920 921int 922nfsm_postop_attr_xx(struct vnode **v, int *f, struct mbuf **md, 923 caddr_t *dpos) 924{ 925 u_int32_t *tl; 926 int t1; 927 928 struct vnode *ttvp = *v; 929 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 930 if (tl == NULL) 931 return EBADRPC; 932 *f = fxdr_unsigned(int, *tl); 933 if (*f != 0) { 934 t1 = nfs_loadattrcache(&ttvp, md, dpos, NULL, 1); 935 if (t1 != 0) { 936 *f = 0; 937 return t1; 938 } 939 *v = ttvp; 940 } 941 return 0; 942} 943 944int 945nfsm_wcc_data_xx(struct vnode **v, int *f, struct mbuf **md, caddr_t *dpos) 946{ 947 u_int32_t *tl; 948 int ttattrf, ttretf = 0; 949 int t1; 950 951 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 952 if (tl == NULL) 953 return EBADRPC; 954 if (*tl == nfs_true) { 955 tl = nfsm_dissect_xx(6 * NFSX_UNSIGNED, md, dpos); 956 if (tl == NULL) 957 return EBADRPC; 958 if (*f) 959 ttretf = (VTONFS(*v)->n_mtime == 960 fxdr_unsigned(u_int32_t, *(tl + 2))); 961 } 962 t1 = nfsm_postop_attr_xx(v, &ttattrf, md, dpos); 963 if (t1) 964 return t1; 965 if (*f) 966 *f = ttretf; 967 else 968 *f = ttattrf; 969 return 0; 970} 971 972int 973nfsm_strtom_xx(const char *a, int s, int m, struct mbuf **mb, caddr_t *bpos) 974{ 975 u_int32_t *tl; 976 int t1; 977 978 if (s > m) 979 return ENAMETOOLONG; 980 t1 = nfsm_rndup(s) + NFSX_UNSIGNED; 981 if (t1 <= M_TRAILINGSPACE(*mb)) { 982 tl = nfsm_build_xx(t1, mb, bpos); 983 *tl++ = txdr_unsigned(s); 984 *(tl + ((t1 >> 2) - 2)) = 0; 985 bcopy(a, tl, s); 986 } else { 987 t1 = nfsm_strtmbuf(mb, bpos, a, s); 988 if (t1 != 0) 989 return t1; 990 } 991 return 0; 992} 993 994int 995nfsm_fhtom_xx(struct vnode *v, int v3, struct mbuf **mb, caddr_t *bpos) 996{ 997 u_int32_t *tl; 998 int t1; 999 caddr_t cp; 1000 1001 if (v3) { 1002 t1 = nfsm_rndup(VTONFS(v)->n_fhsize) + NFSX_UNSIGNED; 1003 if (t1 < M_TRAILINGSPACE(*mb)) { 1004 tl = nfsm_build_xx(t1, mb, bpos); 1005 *tl++ = txdr_unsigned(VTONFS(v)->n_fhsize); 1006 *(tl + ((t1 >> 2) - 2)) = 0; 1007 bcopy(VTONFS(v)->n_fhp, tl, VTONFS(v)->n_fhsize); 1008 } else { 1009 t1 = nfsm_strtmbuf(mb, bpos, 1010 (const char *)VTONFS(v)->n_fhp, 1011 VTONFS(v)->n_fhsize); 1012 if (t1 != 0) 1013 return t1; 1014 } 1015 } else { 1016 cp = nfsm_build_xx(NFSX_V2FH, mb, bpos); 1017 bcopy(VTONFS(v)->n_fhp, cp, NFSX_V2FH); 1018 } 1019 return 0; 1020} 1021 1022void 1023nfsm_v3attrbuild_xx(struct vattr *va, int full, struct mbuf **mb, 1024 caddr_t *bpos) 1025{ 1026 u_int32_t *tl; 1027 1028 if (va->va_mode != (mode_t)VNOVAL) { 1029 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 1030 *tl++ = nfs_true; 1031 *tl = txdr_unsigned(va->va_mode); 1032 } else { 1033 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1034 *tl = nfs_false; 1035 } 1036 if (full && va->va_uid != (uid_t)VNOVAL) { 1037 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 1038 *tl++ = nfs_true; 1039 *tl = txdr_unsigned(va->va_uid); 1040 } else { 1041 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1042 *tl = nfs_false; 1043 } 1044 if (full && va->va_gid != (gid_t)VNOVAL) { 1045 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 1046 *tl++ = nfs_true; 1047 *tl = txdr_unsigned(va->va_gid); 1048 } else { 1049 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1050 *tl = nfs_false; 1051 } 1052 if (full && va->va_size != VNOVAL) { 1053 tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 1054 *tl++ = nfs_true; 1055 txdr_hyper(va->va_size, tl); 1056 } else { 1057 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1058 *tl = nfs_false; 1059 } 1060 if (va->va_atime.tv_sec != VNOVAL) { 1061 if (va->va_atime.tv_sec != time_second) { 1062 tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 1063 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 1064 txdr_nfsv3time(&va->va_atime, tl); 1065 } else { 1066 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1067 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 1068 } 1069 } else { 1070 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1071 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 1072 } 1073 if (va->va_mtime.tv_sec != VNOVAL) { 1074 if (va->va_mtime.tv_sec != time_second) { 1075 tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 1076 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 1077 txdr_nfsv3time(&va->va_mtime, tl); 1078 } else { 1079 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1080 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 1081 } 1082 } else { 1083 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1084 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 1085 } 1086} 1087