nfs_subs.c revision 85339
1251876Speter/* 2251876Speter * Copyright (c) 1989, 1993 3251876Speter * The Regents of the University of California. All rights reserved. 4251876Speter * 5251876Speter * This code is derived from software contributed to Berkeley by 6251876Speter * Rick Macklem at The University of Guelph. 7251876Speter * 8251876Speter * Redistribution and use in source and binary forms, with or without 9251876Speter * modification, are permitted provided that the following conditions 10251876Speter * are met: 11251876Speter * 1. Redistributions of source code must retain the above copyright 12251876Speter * notice, this list of conditions and the following disclaimer. 13251876Speter * 2. Redistributions in binary form must reproduce the above copyright 14251876Speter * notice, this list of conditions and the following disclaimer in the 15251876Speter * documentation and/or other materials provided with the distribution. 16251876Speter * 3. All advertising materials mentioning features or use of this software 17251876Speter * must display the following acknowledgement: 18251876Speter * This product includes software developed by the University of 19251876Speter * California, Berkeley and its contributors. 20251876Speter * 4. Neither the name of the University nor the names of its contributors 21251876Speter * may be used to endorse or promote products derived from this software 22251876Speter * without specific prior written permission. 23251876Speter * 24251876Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25251876Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26251876Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27251876Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28251876Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29251876Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30251876Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31251876Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32251876Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33251876Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34251876Speter * SUCH DAMAGE. 35251876Speter * 36251876Speter * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 37251876Speter */ 38251876Speter 39251876Speter#include <sys/cdefs.h> 40251876Speter__FBSDID("$FreeBSD: head/sys/nfsclient/nfs_subs.c 85339 2001-10-23 01:21:29Z dillon $"); 41251876Speter 42251876Speter/* 43251876Speter * These functions support the macros and help fiddle mbuf chains for 44251876Speter * the nfs op functions. They do things like create the rpc header and 45251876Speter * copy data between mbuf chains and uio lists. 46251876Speter */ 47251876Speter 48251876Speter#include <sys/param.h> 49251876Speter#include <sys/systm.h> 50251876Speter#include <sys/kernel.h> 51251876Speter#include <sys/bio.h> 52251876Speter#include <sys/buf.h> 53251876Speter#include <sys/proc.h> 54251876Speter#include <sys/mount.h> 55251876Speter#include <sys/vnode.h> 56251876Speter#include <sys/namei.h> 57251876Speter#include <sys/mbuf.h> 58251876Speter#include <sys/socket.h> 59251876Speter#include <sys/stat.h> 60251876Speter#include <sys/malloc.h> 61251876Speter#include <sys/sysent.h> 62251876Speter#include <sys/syscall.h> 63251876Speter#include <sys/sysproto.h> 64251876Speter 65251876Speter#include <vm/vm.h> 66251876Speter#include <vm/vm_object.h> 67251876Speter#include <vm/vm_extern.h> 68251876Speter#include <vm/vm_zone.h> 69251876Speter 70251876Speter#include <nfs/rpcv2.h> 71251876Speter#include <nfs/nfsproto.h> 72251876Speter#include <nfsclient/nfs.h> 73251876Speter#include <nfsclient/nfsnode.h> 74251876Speter#include <nfs/xdr_subs.h> 75251876Speter#include <nfsclient/nfsm_subs.h> 76251876Speter#include <nfsclient/nfsmount.h> 77251876Speter 78251876Speter#include <netinet/in.h> 79251876Speter 80251876Speter/* 81251876Speter * Data items converted to xdr at startup, since they are constant 82251876Speter * This is kinda hokey, but may save a little time doing byte swaps 83251876Speter */ 84251876Speteru_int32_t nfs_xdrneg1; 85251876Speteru_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 86251876Speter rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 87251876Speteru_int32_t nfs_true, nfs_false; 88251876Speter 89251876Speter/* And other global data */ 90251876Speterstatic u_int32_t nfs_xid = 0; 91251876Speterstatic enum vtype nv2tov_type[8]= { 92251876Speter VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON 93251876Speter}; 94251876Speter 95251876Speterint nfs_ticks; 96251876Speterint nfs_pbuf_freecnt = -1; /* start out unlimited */ 97251876Speter 98251876Speterstruct nfs_reqq nfs_reqq; 99251876Speterstruct nfs_bufq nfs_bufq; 100251876Speter 101251876Speterstatic int nfs_prev_nfsclnt_sy_narg; 102251876Speterstatic sy_call_t *nfs_prev_nfsclnt_sy_call; 103251876Speter 104251876Speter/* 105251876Speter * and the reverse mapping from generic to Version 2 procedure numbers 106251876Speter */ 107251876Speterint nfsv2_procid[NFS_NPROCS] = { 108251876Speter NFSV2PROC_NULL, 109251876Speter NFSV2PROC_GETATTR, 110251876Speter NFSV2PROC_SETATTR, 111251876Speter NFSV2PROC_LOOKUP, 112251876Speter NFSV2PROC_NOOP, 113251876Speter NFSV2PROC_READLINK, 114251876Speter NFSV2PROC_READ, 115251876Speter NFSV2PROC_WRITE, 116251876Speter NFSV2PROC_CREATE, 117251876Speter NFSV2PROC_MKDIR, 118251876Speter NFSV2PROC_SYMLINK, 119251876Speter NFSV2PROC_CREATE, 120251876Speter NFSV2PROC_REMOVE, 121251876Speter NFSV2PROC_RMDIR, 122251876Speter NFSV2PROC_RENAME, 123251876Speter NFSV2PROC_LINK, 124251876Speter NFSV2PROC_READDIR, 125251876Speter NFSV2PROC_NOOP, 126251876Speter NFSV2PROC_STATFS, 127251876Speter NFSV2PROC_NOOP, 128251876Speter NFSV2PROC_NOOP, 129251876Speter NFSV2PROC_NOOP, 130251876Speter NFSV2PROC_NOOP, 131251876Speter}; 132251876Speter 133251876SpeterLIST_HEAD(nfsnodehashhead, nfsnode); 134251876Speter 135251876Speter/* 136251876Speter * Create the header for an rpc request packet 137251876Speter * The hsiz is the size of the rest of the nfs request header. 138251876Speter * (just used to decide if a cluster is a good idea) 139251876Speter */ 140251876Speterstruct mbuf * 141251876Speternfsm_reqhead(struct vnode *vp, u_long procid, int hsiz) 142251876Speter{ 143251876Speter struct mbuf *mb; 144251876Speter 145251876Speter MGET(mb, M_TRYWAIT, MT_DATA); 146251876Speter if (hsiz >= MINCLSIZE) 147251876Speter MCLGET(mb, M_TRYWAIT); 148251876Speter mb->m_len = 0; 149251876Speter return (mb); 150251876Speter} 151251876Speter 152251876Speter/* 153251876Speter * Build the RPC header and fill in the authorization info. 154251876Speter * The authorization string argument is only used when the credentials 155251876Speter * come from outside of the kernel. 156251876Speter * Returns the head of the mbuf list. 157251876Speter */ 158251876Speterstruct mbuf * 159251876Speternfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type, 160251876Speter int auth_len, struct mbuf *mrest, int mrest_len, struct mbuf **mbp, 161251876Speter u_int32_t *xidp) 162251876Speter{ 163251876Speter struct mbuf *mb; 164251876Speter u_int32_t *tl; 165251876Speter caddr_t bpos; 166251876Speter int i; 167251876Speter struct mbuf *mreq; 168251876Speter int grpsiz, authsiz; 169251876Speter 170251876Speter authsiz = nfsm_rndup(auth_len); 171251876Speter MGETHDR(mb, M_TRYWAIT, MT_DATA); 172251876Speter if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { 173251876Speter MCLGET(mb, M_TRYWAIT); 174251876Speter } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { 175251876Speter MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 176251876Speter } else { 177251876Speter MH_ALIGN(mb, 8 * NFSX_UNSIGNED); 178251876Speter } 179251876Speter mb->m_len = 0; 180251876Speter mreq = mb; 181251876Speter bpos = mtod(mb, caddr_t); 182251876Speter 183251876Speter /* 184251876Speter * First the RPC header. 185251876Speter */ 186251876Speter tl = nfsm_build(u_int32_t *, 8 * NFSX_UNSIGNED); 187251876Speter 188251876Speter /* Get a pretty random xid to start with */ 189251876Speter if (!nfs_xid) 190251876Speter nfs_xid = random(); 191251876Speter /* 192251876Speter * Skip zero xid if it should ever happen. 193251876Speter */ 194251876Speter if (++nfs_xid == 0) 195251876Speter nfs_xid++; 196251876Speter 197251876Speter *tl++ = *xidp = txdr_unsigned(nfs_xid); 198251876Speter *tl++ = rpc_call; 199251876Speter *tl++ = rpc_vers; 200251876Speter *tl++ = txdr_unsigned(NFS_PROG); 201251876Speter if (nmflag & NFSMNT_NFSV3) { 202251876Speter *tl++ = txdr_unsigned(NFS_VER3); 203251876Speter *tl++ = txdr_unsigned(procid); 204251876Speter } else { 205251876Speter *tl++ = txdr_unsigned(NFS_VER2); 206251876Speter *tl++ = txdr_unsigned(nfsv2_procid[procid]); 207251876Speter } 208251876Speter 209251876Speter /* 210251876Speter * And then the authorization cred. 211251876Speter */ 212251876Speter *tl++ = txdr_unsigned(auth_type); 213251876Speter *tl = txdr_unsigned(authsiz); 214251876Speter switch (auth_type) { 215251876Speter case RPCAUTH_UNIX: 216251876Speter tl = nfsm_build(u_int32_t *, auth_len); 217251876Speter *tl++ = 0; /* stamp ?? */ 218251876Speter *tl++ = 0; /* NULL hostname */ 219251876Speter *tl++ = txdr_unsigned(cr->cr_uid); 220251876Speter *tl++ = txdr_unsigned(cr->cr_groups[0]); 221251876Speter grpsiz = (auth_len >> 2) - 5; 222251876Speter *tl++ = txdr_unsigned(grpsiz); 223251876Speter for (i = 1; i <= grpsiz; i++) 224251876Speter *tl++ = txdr_unsigned(cr->cr_groups[i]); 225251876Speter break; 226251876Speter } 227251876Speter 228251876Speter /* 229251876Speter * And the verifier... 230251876Speter */ 231251876Speter tl = nfsm_build(u_int32_t *, 2 * NFSX_UNSIGNED); 232251876Speter *tl++ = txdr_unsigned(RPCAUTH_NULL); 233251876Speter *tl = 0; 234251876Speter mb->m_next = mrest; 235251876Speter mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; 236251876Speter mreq->m_pkthdr.rcvif = (struct ifnet *)0; 237251876Speter *mbp = mb; 238251876Speter return (mreq); 239251876Speter} 240251876Speter 241251876Speter/* 242251876Speter * copies a uio scatter/gather list to an mbuf chain. 243251876Speter * NOTE: can ony handle iovcnt == 1 244251876Speter */ 245251876Speterint 246251876Speternfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos) 247251876Speter{ 248251876Speter char *uiocp; 249251876Speter struct mbuf *mp, *mp2; 250251876Speter int xfer, left, mlen; 251251876Speter int uiosiz, clflg, rem; 252251876Speter char *cp; 253251876Speter 254251876Speter#ifdef DIAGNOSTIC 255251876Speter if (uiop->uio_iovcnt != 1) 256251876Speter panic("nfsm_uiotombuf: iovcnt != 1"); 257251876Speter#endif 258251876Speter 259251876Speter if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 260251876Speter clflg = 1; 261251876Speter else 262251876Speter clflg = 0; 263251876Speter rem = nfsm_rndup(siz)-siz; 264251876Speter mp = mp2 = *mq; 265251876Speter while (siz > 0) { 266251876Speter left = uiop->uio_iov->iov_len; 267251876Speter uiocp = uiop->uio_iov->iov_base; 268251876Speter if (left > siz) 269251876Speter left = siz; 270251876Speter uiosiz = left; 271251876Speter while (left > 0) { 272251876Speter mlen = M_TRAILINGSPACE(mp); 273251876Speter if (mlen == 0) { 274251876Speter MGET(mp, M_TRYWAIT, MT_DATA); 275251876Speter if (clflg) 276251876Speter MCLGET(mp, M_TRYWAIT); 277251876Speter mp->m_len = 0; 278251876Speter mp2->m_next = mp; 279251876Speter mp2 = mp; 280251876Speter mlen = M_TRAILINGSPACE(mp); 281251876Speter } 282251876Speter xfer = (left > mlen) ? mlen : left; 283251876Speter#ifdef notdef 284251876Speter /* Not Yet.. */ 285251876Speter if (uiop->uio_iov->iov_op != NULL) 286251876Speter (*(uiop->uio_iov->iov_op)) 287251876Speter (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 288251876Speter else 289251876Speter#endif 290251876Speter if (uiop->uio_segflg == UIO_SYSSPACE) 291251876Speter bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 292251876Speter else 293251876Speter copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 294251876Speter mp->m_len += xfer; 295251876Speter left -= xfer; 296251876Speter uiocp += xfer; 297 uiop->uio_offset += xfer; 298 uiop->uio_resid -= xfer; 299 } 300 uiop->uio_iov->iov_base += uiosiz; 301 uiop->uio_iov->iov_len -= uiosiz; 302 siz -= uiosiz; 303 } 304 if (rem > 0) { 305 if (rem > M_TRAILINGSPACE(mp)) { 306 MGET(mp, M_TRYWAIT, MT_DATA); 307 mp->m_len = 0; 308 mp2->m_next = mp; 309 } 310 cp = mtod(mp, caddr_t)+mp->m_len; 311 for (left = 0; left < rem; left++) 312 *cp++ = '\0'; 313 mp->m_len += rem; 314 *bpos = cp; 315 } else 316 *bpos = mtod(mp, caddr_t)+mp->m_len; 317 *mq = mp; 318 return (0); 319} 320 321/* 322 * Copy a string into mbufs for the hard cases... 323 */ 324int 325nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz) 326{ 327 struct mbuf *m1 = NULL, *m2; 328 long left, xfer, len, tlen; 329 u_int32_t *tl; 330 int putsize; 331 332 putsize = 1; 333 m2 = *mb; 334 left = M_TRAILINGSPACE(m2); 335 if (left > 0) { 336 tl = ((u_int32_t *)(*bpos)); 337 *tl++ = txdr_unsigned(siz); 338 putsize = 0; 339 left -= NFSX_UNSIGNED; 340 m2->m_len += NFSX_UNSIGNED; 341 if (left > 0) { 342 bcopy(cp, (caddr_t) tl, left); 343 siz -= left; 344 cp += left; 345 m2->m_len += left; 346 left = 0; 347 } 348 } 349 /* Loop around adding mbufs */ 350 while (siz > 0) { 351 MGET(m1, M_TRYWAIT, MT_DATA); 352 if (siz > MLEN) 353 MCLGET(m1, M_TRYWAIT); 354 m1->m_len = NFSMSIZ(m1); 355 m2->m_next = m1; 356 m2 = m1; 357 tl = mtod(m1, u_int32_t *); 358 tlen = 0; 359 if (putsize) { 360 *tl++ = txdr_unsigned(siz); 361 m1->m_len -= NFSX_UNSIGNED; 362 tlen = NFSX_UNSIGNED; 363 putsize = 0; 364 } 365 if (siz < m1->m_len) { 366 len = nfsm_rndup(siz); 367 xfer = siz; 368 if (xfer < len) 369 *(tl+(xfer>>2)) = 0; 370 } else { 371 xfer = len = m1->m_len; 372 } 373 bcopy(cp, (caddr_t) tl, xfer); 374 m1->m_len = len+tlen; 375 siz -= xfer; 376 cp += xfer; 377 } 378 *mb = m1; 379 *bpos = mtod(m1, caddr_t)+m1->m_len; 380 return (0); 381} 382 383/* 384 * Called once to initialize data structures... 385 */ 386int 387nfs_init(struct vfsconf *vfsp) 388{ 389 int i; 390 391 nfsmount_zone = zinit("NFSMOUNT", sizeof(struct nfsmount), 0, 0, 1); 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] = (struct proc *)0; 409 nfs_iodmount[i] = (struct nfsmount *)0; 410 } 411 nfs_nhinit(); /* Init the nfsnode table */ 412 413 /* 414 * Initialize reply list and start timer 415 */ 416 TAILQ_INIT(&nfs_reqq); 417 418 nfs_timer(0); 419 420 nfs_prev_nfsclnt_sy_narg = sysent[SYS_nfsclnt].sy_narg; 421 sysent[SYS_nfsclnt].sy_narg = 2; 422 nfs_prev_nfsclnt_sy_call = sysent[SYS_nfsclnt].sy_call; 423 sysent[SYS_nfsclnt].sy_call = (sy_call_t *)nfsclnt; 424 425 nfs_pbuf_freecnt = nswbuf / 2 + 1; 426 427 return (0); 428} 429 430int 431nfs_uninit(struct vfsconf *vfsp) 432{ 433 434 untimeout(nfs_timer, (void *)NULL, nfs_timer_handle); 435 sysent[SYS_nfsclnt].sy_narg = nfs_prev_nfsclnt_sy_narg; 436 sysent[SYS_nfsclnt].sy_call = nfs_prev_nfsclnt_sy_call; 437 return (0); 438} 439 440/* 441 * Attribute cache routines. 442 * nfs_loadattrcache() - loads or updates the cache contents from attributes 443 * that are on the mbuf list 444 * nfs_getattrcache() - returns valid attributes if found in cache, returns 445 * error otherwise 446 */ 447 448/* 449 * Load the attribute cache (that lives in the nfsnode entry) with 450 * the values on the mbuf list and 451 * Iff vap not NULL 452 * copy the attributes to *vaper 453 */ 454int 455nfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp, 456 struct vattr *vaper, int dontshrink) 457{ 458 struct vnode *vp = *vpp; 459 struct vattr *vap; 460 struct nfs_fattr *fp; 461 struct nfsnode *np; 462 int32_t t1; 463 caddr_t cp2; 464 int rdev; 465 struct mbuf *md; 466 enum vtype vtyp; 467 u_short vmode; 468 struct timespec mtime; 469 int v3 = NFS_ISV3(vp); 470 471 md = *mdp; 472 t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 473 cp2 = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1); 474 if (cp2 == NULL) 475 return EBADRPC; 476 fp = (struct nfs_fattr *)cp2; 477 if (v3) { 478 vtyp = nfsv3tov_type(fp->fa_type); 479 vmode = fxdr_unsigned(u_short, fp->fa_mode); 480 rdev = makeudev(fxdr_unsigned(int, fp->fa3_rdev.specdata1), 481 fxdr_unsigned(int, fp->fa3_rdev.specdata2)); 482 fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 483 } else { 484 vtyp = nfsv2tov_type(fp->fa_type); 485 vmode = fxdr_unsigned(u_short, fp->fa_mode); 486 /* 487 * XXX 488 * 489 * The duplicate information returned in fa_type and fa_mode 490 * is an ambiguity in the NFS version 2 protocol. 491 * 492 * VREG should be taken literally as a regular file. If a 493 * server intents to return some type information differently 494 * in the upper bits of the mode field (e.g. for sockets, or 495 * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we 496 * leave the examination of the mode bits even in the VREG 497 * case to avoid breakage for bogus servers, but we make sure 498 * that there are actually type bits set in the upper part of 499 * fa_mode (and failing that, trust the va_type field). 500 * 501 * NFSv3 cleared the issue, and requires fa_mode to not 502 * contain any type information (while also introduing sockets 503 * and FIFOs for fa_type). 504 */ 505 if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) 506 vtyp = IFTOVT(vmode); 507 rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); 508 fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 509 510 /* 511 * Really ugly NFSv2 kludge. 512 */ 513 if (vtyp == VCHR && rdev == 0xffffffff) 514 vtyp = VFIFO; 515 } 516 517 /* 518 * If v_type == VNON it is a new node, so fill in the v_type, 519 * n_mtime fields. Check to see if it represents a special 520 * device, and if so, check for a possible alias. Once the 521 * correct vnode has been obtained, fill in the rest of the 522 * information. 523 */ 524 np = VTONFS(vp); 525 if (vp->v_type != vtyp) { 526 vp->v_type = vtyp; 527 if (vp->v_type == VFIFO) { 528 vp->v_op = fifo_nfsv2nodeop_p; 529 } 530 if (vp->v_type == VCHR || vp->v_type == VBLK) { 531 vp->v_op = spec_nfsv2nodeop_p; 532 vp = addaliasu(vp, rdev); 533 np->n_vnode = vp; 534 } 535 np->n_mtime = mtime.tv_sec; 536 } 537 vap = &np->n_vattr; 538 vap->va_type = vtyp; 539 vap->va_mode = (vmode & 07777); 540 vap->va_rdev = rdev; 541 vap->va_mtime = mtime; 542 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 543 if (v3) { 544 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 545 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 546 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 547 vap->va_size = fxdr_hyper(&fp->fa3_size); 548 vap->va_blocksize = NFS_FABLKSIZE; 549 vap->va_bytes = fxdr_hyper(&fp->fa3_used); 550 vap->va_fileid = fxdr_unsigned(int32_t, 551 fp->fa3_fileid.nfsuquad[1]); 552 fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 553 fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 554 vap->va_flags = 0; 555 vap->va_filerev = 0; 556 } else { 557 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 558 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 559 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 560 vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 561 vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 562 vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) 563 * NFS_FABLKSIZE; 564 vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); 565 fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 566 vap->va_flags = 0; 567 vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, 568 fp->fa2_ctime.nfsv2_sec); 569 vap->va_ctime.tv_nsec = 0; 570 vap->va_gen = fxdr_unsigned(u_int32_t, fp->fa2_ctime.nfsv2_usec); 571 vap->va_filerev = 0; 572 } 573 np->n_attrstamp = time_second; 574 if (vap->va_size != np->n_size) { 575 if (vap->va_type == VREG) { 576 if (dontshrink && vap->va_size < np->n_size) { 577 /* 578 * We've been told not to shrink the file; 579 * zero np->n_attrstamp to indicate that 580 * the attributes are stale. 581 */ 582 vap->va_size = np->n_size; 583 np->n_attrstamp = 0; 584 } else if (np->n_flag & NMODIFIED) { 585 if (vap->va_size < np->n_size) 586 vap->va_size = np->n_size; 587 else 588 np->n_size = vap->va_size; 589 } else { 590 np->n_size = vap->va_size; 591 } 592 vnode_pager_setsize(vp, np->n_size); 593 } else { 594 np->n_size = vap->va_size; 595 } 596 } 597 if (vaper != NULL) { 598 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 599 if (np->n_flag & NCHG) { 600 if (np->n_flag & NACC) 601 vaper->va_atime = np->n_atim; 602 if (np->n_flag & NUPD) 603 vaper->va_mtime = np->n_mtim; 604 } 605 } 606 return (0); 607} 608 609#ifdef NFS_ACDEBUG 610#include <sys/sysctl.h> 611SYSCTL_DECL(_vfs_nfs); 612static int nfs_acdebug; 613SYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, ""); 614#endif 615 616/* 617 * Check the time stamp 618 * If the cache is valid, copy contents to *vap and return 0 619 * otherwise return an error 620 */ 621int 622nfs_getattrcache(struct vnode *vp, struct vattr *vaper) 623{ 624 struct nfsnode *np; 625 struct vattr *vap; 626 struct nfsmount *nmp; 627 int timeo; 628 629 np = VTONFS(vp); 630 vap = &np->n_vattr; 631 nmp = VFSTONFS(vp->v_mount); 632 /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */ 633 timeo = (time_second - np->n_mtime) / 10; 634 635#ifdef NFS_ACDEBUG 636 if (nfs_acdebug>1) 637 printf("nfs_getattrcache: initial timeo = %d\n", timeo); 638#endif 639 640 if (vap->va_type == VDIR) { 641 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin) 642 timeo = nmp->nm_acdirmin; 643 else if (timeo > nmp->nm_acdirmax) 644 timeo = nmp->nm_acdirmax; 645 } else { 646 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin) 647 timeo = nmp->nm_acregmin; 648 else if (timeo > nmp->nm_acregmax) 649 timeo = nmp->nm_acregmax; 650 } 651 652#ifdef NFS_ACDEBUG 653 if (nfs_acdebug > 2) 654 printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n", 655 nmp->nm_acregmin, nmp->nm_acregmax, 656 nmp->nm_acdirmin, nmp->nm_acdirmax); 657 658 if (nfs_acdebug) 659 printf("nfs_getattrcache: age = %d; final timeo = %d\n", 660 (time_second - np->n_attrstamp), timeo); 661#endif 662 663 if ((time_second - np->n_attrstamp) >= timeo) { 664 nfsstats.attrcache_misses++; 665 return (ENOENT); 666 } 667 nfsstats.attrcache_hits++; 668 if (vap->va_size != np->n_size) { 669 if (vap->va_type == VREG) { 670 if (np->n_flag & NMODIFIED) { 671 if (vap->va_size < np->n_size) 672 vap->va_size = np->n_size; 673 else 674 np->n_size = vap->va_size; 675 } else { 676 np->n_size = vap->va_size; 677 } 678 vnode_pager_setsize(vp, np->n_size); 679 } else { 680 np->n_size = vap->va_size; 681 } 682 } 683 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 684 if (np->n_flag & NCHG) { 685 if (np->n_flag & NACC) 686 vaper->va_atime = np->n_atim; 687 if (np->n_flag & NUPD) 688 vaper->va_mtime = np->n_mtim; 689 } 690 return (0); 691} 692 693static nfsuint64 nfs_nullcookie = { { 0, 0 } }; 694/* 695 * This function finds the directory cookie that corresponds to the 696 * logical byte offset given. 697 */ 698nfsuint64 * 699nfs_getcookie(struct nfsnode *np, off_t off, int add) 700{ 701 struct nfsdmap *dp, *dp2; 702 int pos; 703 704 pos = (uoff_t)off / NFS_DIRBLKSIZ; 705 if (pos == 0 || off < 0) { 706#ifdef DIAGNOSTIC 707 if (add) 708 panic("nfs getcookie add at <= 0"); 709#endif 710 return (&nfs_nullcookie); 711 } 712 pos--; 713 dp = LIST_FIRST(&np->n_cookies); 714 if (!dp) { 715 if (add) { 716 MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 717 M_NFSDIROFF, M_WAITOK); 718 dp->ndm_eocookie = 0; 719 LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 720 } else 721 return ((nfsuint64 *)0); 722 } 723 while (pos >= NFSNUMCOOKIES) { 724 pos -= NFSNUMCOOKIES; 725 if (LIST_NEXT(dp, ndm_list)) { 726 if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 727 pos >= dp->ndm_eocookie) 728 return ((nfsuint64 *)0); 729 dp = LIST_NEXT(dp, ndm_list); 730 } else if (add) { 731 MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 732 M_NFSDIROFF, M_WAITOK); 733 dp2->ndm_eocookie = 0; 734 LIST_INSERT_AFTER(dp, dp2, ndm_list); 735 dp = dp2; 736 } else 737 return ((nfsuint64 *)0); 738 } 739 if (pos >= dp->ndm_eocookie) { 740 if (add) 741 dp->ndm_eocookie = pos + 1; 742 else 743 return ((nfsuint64 *)0); 744 } 745 return (&dp->ndm_cookies[pos]); 746} 747 748/* 749 * Invalidate cached directory information, except for the actual directory 750 * blocks (which are invalidated separately). 751 * Done mainly to avoid the use of stale offset cookies. 752 */ 753void 754nfs_invaldir(struct vnode *vp) 755{ 756 struct nfsnode *np = VTONFS(vp); 757 758#ifdef DIAGNOSTIC 759 if (vp->v_type != VDIR) 760 panic("nfs: invaldir not dir"); 761#endif 762 np->n_direofoffset = 0; 763 np->n_cookieverf.nfsuquad[0] = 0; 764 np->n_cookieverf.nfsuquad[1] = 0; 765 if (LIST_FIRST(&np->n_cookies)) 766 LIST_FIRST(&np->n_cookies)->ndm_eocookie = 0; 767} 768 769/* 770 * The write verifier has changed (probably due to a server reboot), so all 771 * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 772 * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 773 * and B_CLUSTEROK flags. Once done the new write verifier can be set for the 774 * mount point. 775 * 776 * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data 777 * writes are not clusterable. 778 */ 779void 780nfs_clearcommit(struct mount *mp) 781{ 782 struct vnode *vp, *nvp; 783 struct buf *bp, *nbp; 784 int s; 785 786 GIANT_REQUIRED; 787 788 s = splbio(); 789 mtx_lock(&mntvnode_mtx); 790loop: 791 for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp; vp = nvp) { 792 if (vp->v_mount != mp) /* Paranoia */ 793 goto loop; 794 nvp = TAILQ_NEXT(vp, v_nmntvnodes); 795 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 796 nbp = TAILQ_NEXT(bp, b_vnbufs); 797 if (BUF_REFCNT(bp) == 0 && 798 (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) 799 == (B_DELWRI | B_NEEDCOMMIT)) 800 bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); 801 } 802 } 803 mtx_unlock(&mntvnode_mtx); 804 splx(s); 805} 806 807/* 808 * Helper functions for former macros. Some of these should be 809 * moved to their callers. 810 */ 811 812int 813nfsm_mtofh_xx(struct vnode *d, struct vnode **v, int v3, int *f, 814 u_int32_t **tl, struct mbuf **md, caddr_t *dpos) 815{ 816 struct nfsnode *ttnp; 817 struct vnode *ttvp; 818 nfsfh_t *ttfhp; 819 int ttfhsize; 820 int t1; 821 822 if (v3) { 823 *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 824 if (*tl == NULL) 825 return EBADRPC; 826 *f = fxdr_unsigned(int, **tl); 827 } else 828 *f = 1; 829 if (*f) { 830 t1 = nfsm_getfh_xx(&ttfhp, &ttfhsize, (v3), tl, md, dpos); 831 if (t1 != 0) 832 return t1; 833 t1 = nfs_nget(d->v_mount, ttfhp, ttfhsize, &ttnp); 834 if (t1 != 0) 835 return t1; 836 *v = NFSTOV(ttnp); 837 } 838 if (v3) { 839 *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 840 if (*tl == NULL) 841 return EBADRPC; 842 if (*f) 843 *f = fxdr_unsigned(int, **tl); 844 else if (fxdr_unsigned(int, **tl)) 845 nfsm_adv_xx(NFSX_V3FATTR, tl, md, dpos); 846 } 847 if (*f) { 848 ttvp = *v; 849 t1 = nfs_loadattrcache(&ttvp, md, dpos, (struct vattr *)0, 0); 850 if (t1) 851 return t1; 852 *v = ttvp; 853 } 854 return 0; 855} 856 857int 858nfsm_getfh_xx(nfsfh_t **f, int *s, int v3, 859 u_int32_t **tl, struct mbuf **md, caddr_t *dpos) 860{ 861 862 if (v3) { 863 *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 864 if (*tl == NULL) 865 return EBADRPC; 866 *s = fxdr_unsigned(int, **tl); 867 if (*s <= 0 || *s > NFSX_V3FHMAX) 868 return EBADRPC; 869 } else 870 *s = NFSX_V2FH; 871 *f = nfsm_dissect_xx(nfsm_rndup(*s), md, dpos); 872 if (*f == NULL) 873 return EBADRPC; 874 else 875 return 0; 876} 877 878 879int 880nfsm_loadattr_xx(struct vnode **v, struct vattr *va, 881 u_int32_t **tl, struct mbuf **md, caddr_t *dpos) 882{ 883 int t1; 884 885 struct vnode *ttvp = *v; 886 t1 = nfs_loadattrcache(&ttvp, md, dpos, va, 0); 887 if (t1 != 0) 888 return t1; 889 *v = ttvp; 890 return 0; 891} 892 893int 894nfsm_postop_attr_xx(struct vnode **v, int *f, 895 u_int32_t **tl, struct mbuf **md, caddr_t *dpos) 896{ 897 int t1; 898 899 struct vnode *ttvp = *v; 900 *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 901 if (*tl == NULL) 902 return EBADRPC; 903 *f = fxdr_unsigned(int, **tl); 904 if (*f != 0) { 905 t1 = nfs_loadattrcache(&ttvp, md, dpos, (struct vattr *)0, 1); 906 if (t1 != 0) { 907 *f = 0; 908 return t1; 909 } 910 *v = ttvp; 911 } 912 return 0; 913} 914 915int 916nfsm_wcc_data_xx(struct vnode **v, int *f, 917 u_int32_t **tl, struct mbuf **md, caddr_t *dpos) 918{ 919 int ttattrf, ttretf = 0; 920 int t1; 921 922 *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 923 if (*tl == NULL) 924 return EBADRPC; 925 if (**tl == nfs_true) { 926 *tl = nfsm_dissect_xx(6 * NFSX_UNSIGNED, md, dpos); 927 if (*tl == NULL) 928 return EBADRPC; 929 if (*f) 930 ttretf = (VTONFS(*v)->n_mtime == 931 fxdr_unsigned(u_int32_t, *((*tl) + 2))); 932 } 933 t1 = nfsm_postop_attr_xx(v, &ttattrf, tl, md, dpos); 934 if (t1) 935 return t1; 936 if (*f) 937 *f = ttretf; 938 else 939 *f = ttattrf; 940 return 0; 941} 942 943int 944nfsm_strtom_xx(const char *a, int s, int m, 945 u_int32_t **tl, struct mbuf **mb, caddr_t *bpos) 946{ 947 int t1; 948 949 if (s > m) 950 return ENAMETOOLONG; 951 t1 = nfsm_rndup(s) + NFSX_UNSIGNED; 952 if (t1 <= M_TRAILINGSPACE(*mb)) { 953 *tl = nfsm_build_xx(t1, mb, bpos); 954 *(*tl)++ = txdr_unsigned(s); 955 *((*tl) + ((t1 >> 2) - 2)) = 0; 956 bcopy(a, *tl, s); 957 } else { 958 t1 = nfsm_strtmbuf(mb, bpos, a, s); 959 if (t1 != 0) 960 return t1; 961 } 962 return 0; 963} 964 965int 966nfsm_fhtom_xx(struct vnode *v, int v3, 967 u_int32_t **tl, struct mbuf **mb, caddr_t *bpos) 968{ 969 int t1; 970 caddr_t cp; 971 972 if (v3) { 973 t1 = nfsm_rndup(VTONFS(v)->n_fhsize) + NFSX_UNSIGNED; 974 if (t1 < M_TRAILINGSPACE(*mb)) { 975 *tl = nfsm_build_xx(t1, mb, bpos); 976 *(*tl)++ = txdr_unsigned(VTONFS(v)->n_fhsize); 977 *((*tl) + ((t1 >> 2) - 2)) = 0; 978 bcopy(VTONFS(v)->n_fhp, *tl, VTONFS(v)->n_fhsize); 979 } else { 980 t1 = nfsm_strtmbuf(mb, bpos, 981 (const char *)VTONFS(v)->n_fhp, 982 VTONFS(v)->n_fhsize); 983 if (t1 != 0) 984 return t1; 985 } 986 } else { 987 cp = nfsm_build_xx(NFSX_V2FH, mb, bpos); 988 bcopy(VTONFS(v)->n_fhp, cp, NFSX_V2FH); 989 } 990 return 0; 991} 992 993void 994nfsm_v3attrbuild_xx(struct vattr *va, int full, 995 u_int32_t **tl, struct mbuf **mb, caddr_t *bpos) 996{ 997 998 if (va->va_mode != (mode_t)VNOVAL) { 999 *tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 1000 *(*tl)++ = nfs_true; 1001 **tl = txdr_unsigned(va->va_mode); 1002 } else { 1003 *tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1004 **tl = nfs_false; 1005 } 1006 if (full && va->va_uid != (uid_t)VNOVAL) { 1007 *tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 1008 *(*tl)++ = nfs_true; 1009 **tl = txdr_unsigned(va->va_uid); 1010 } else { 1011 *tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1012 **tl = nfs_false; 1013 } 1014 if (full && va->va_gid != (gid_t)VNOVAL) { 1015 *tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 1016 *(*tl)++ = nfs_true; 1017 **tl = txdr_unsigned(va->va_gid); 1018 } else { 1019 *tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1020 **tl = nfs_false; 1021 } 1022 if (full && va->va_size != VNOVAL) { 1023 *tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 1024 *(*tl)++ = nfs_true; 1025 txdr_hyper(va->va_size, *tl); 1026 } else { 1027 *tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1028 **tl = nfs_false; 1029 } 1030 if (va->va_atime.tv_sec != VNOVAL) { 1031 if (va->va_atime.tv_sec != time_second) { 1032 *tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 1033 *(*tl)++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 1034 txdr_nfsv3time(&va->va_atime, *tl); 1035 } else { 1036 *tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1037 **tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 1038 } 1039 } else { 1040 *tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1041 **tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 1042 } 1043 if (va->va_mtime.tv_sec != VNOVAL) { 1044 if (va->va_mtime.tv_sec != time_second) { 1045 *tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 1046 *(*tl)++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 1047 txdr_nfsv3time(&va->va_mtime, *tl); 1048 } else { 1049 *tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1050 **tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 1051 } 1052 } else { 1053 *tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1054 **tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 1055 } 1056} 1057