1139823Simp/*- 21541Srgrimes * Copyright (c) 1989, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * This code is derived from software contributed to Berkeley by 61541Srgrimes * Rick Macklem at The University of Guelph. 71541Srgrimes * 81541Srgrimes * Redistribution and use in source and binary forms, with or without 91541Srgrimes * modification, are permitted provided that the following conditions 101541Srgrimes * are met: 111541Srgrimes * 1. Redistributions of source code must retain the above copyright 121541Srgrimes * notice, this list of conditions and the following disclaimer. 131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer in the 151541Srgrimes * documentation and/or other materials provided with the distribution. 161541Srgrimes * 4. Neither the name of the University nor the names of its contributors 171541Srgrimes * may be used to endorse or promote products derived from this software 181541Srgrimes * without specific prior written permission. 191541Srgrimes * 201541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301541Srgrimes * SUCH DAMAGE. 311541Srgrimes * 3236503Speter * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 331541Srgrimes */ 341541Srgrimes 3583651Speter#include <sys/cdefs.h> 3683651Speter__FBSDID("$FreeBSD$"); 3783651Speter 381541Srgrimes/* 391541Srgrimes * These functions support the macros and help fiddle mbuf chains for 401541Srgrimes * the nfs op functions. They do things like create the rpc header and 411541Srgrimes * copy data between mbuf chains and uio lists. 421541Srgrimes */ 4383651Speter 44190380Srwatson#include "opt_kdtrace.h" 45190380Srwatson 461541Srgrimes#include <sys/param.h> 4748274Speter#include <sys/systm.h> 4848274Speter#include <sys/kernel.h> 4960041Sphk#include <sys/bio.h> 5031886Sbde#include <sys/buf.h> 511541Srgrimes#include <sys/proc.h> 521541Srgrimes#include <sys/mount.h> 531541Srgrimes#include <sys/vnode.h> 541541Srgrimes#include <sys/namei.h> 551541Srgrimes#include <sys/mbuf.h> 561541Srgrimes#include <sys/socket.h> 571541Srgrimes#include <sys/stat.h> 589336Sdfr#include <sys/malloc.h> 592997Swollman#include <sys/sysent.h> 602997Swollman#include <sys/syscall.h> 6183651Speter#include <sys/sysproto.h> 62212506Skib#include <sys/taskqueue.h> 631541Srgrimes 643305Sphk#include <vm/vm.h> 6512662Sdg#include <vm/vm_object.h> 6612662Sdg#include <vm/vm_extern.h> 6792783Sjeff#include <vm/uma.h> 683305Sphk 699336Sdfr#include <nfs/nfsproto.h> 7083651Speter#include <nfsclient/nfs.h> 7183651Speter#include <nfsclient/nfsnode.h> 72221543Srmacklem#include <nfs/nfs_kdtrace.h> 731541Srgrimes#include <nfs/xdr_subs.h> 7483651Speter#include <nfsclient/nfsm_subs.h> 7583651Speter#include <nfsclient/nfsmount.h> 761541Srgrimes 771541Srgrimes#include <netinet/in.h> 781541Srgrimes 791541Srgrimes/* 80158739Smohans * Note that stdarg.h and the ANSI style va_start macro is used for both 81158739Smohans * ANSI and traditional C compilers. 82158739Smohans */ 83158739Smohans#include <machine/stdarg.h> 84158739Smohans 85190380Srwatson#ifdef KDTRACE_HOOKS 86190380Srwatsondtrace_nfsclient_attrcache_flush_probe_func_t 87190380Srwatson dtrace_nfsclient_attrcache_flush_done_probe; 88190380Srwatsonuint32_t nfsclient_attrcache_flush_done_id; 89190380Srwatson 90190380Srwatsondtrace_nfsclient_attrcache_get_hit_probe_func_t 91190380Srwatson dtrace_nfsclient_attrcache_get_hit_probe; 92190380Srwatsonuint32_t nfsclient_attrcache_get_hit_id; 93190380Srwatson 94190380Srwatsondtrace_nfsclient_attrcache_get_miss_probe_func_t 95190380Srwatson dtrace_nfsclient_attrcache_get_miss_probe; 96190380Srwatsonuint32_t nfsclient_attrcache_get_miss_id; 97190380Srwatson 98190380Srwatsondtrace_nfsclient_attrcache_load_probe_func_t 99190380Srwatson dtrace_nfsclient_attrcache_load_done_probe; 100190380Srwatsonuint32_t nfsclient_attrcache_load_done_id; 101190380Srwatson#endif /* !KDTRACE_HOOKS */ 102190380Srwatson 103158739Smohans/* 1041541Srgrimes * Data items converted to xdr at startup, since they are constant 1051541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps 1061541Srgrimes */ 10783651Speteru_int32_t nfs_xdrneg1; 10883651Speteru_int32_t nfs_true, nfs_false; 1091541Srgrimes 1101541Srgrimes/* And other global data */ 111176224Sjhbstatic u_int32_t nfs_xid = 0; 11212911Sphkstatic enum vtype nv2tov_type[8]= { 11383651Speter VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON 11412911Sphk}; 11512911Sphk 11683651Speterint nfs_ticks; 11783651Speterint nfs_pbuf_freecnt = -1; /* start out unlimited */ 1189336Sdfr 11983651Speterstruct nfs_bufq nfs_bufq; 120176224Sjhbstatic struct mtx nfs_xid_mtx; 121212506Skibstruct task nfs_nfsiodnew_task; 1229759Sbde 1239336Sdfr/* 1249336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers 1259336Sdfr */ 1269336Sdfrint nfsv2_procid[NFS_NPROCS] = { 1279336Sdfr NFSV2PROC_NULL, 1289336Sdfr NFSV2PROC_GETATTR, 1299336Sdfr NFSV2PROC_SETATTR, 1309336Sdfr NFSV2PROC_LOOKUP, 1319336Sdfr NFSV2PROC_NOOP, 1329336Sdfr NFSV2PROC_READLINK, 1339336Sdfr NFSV2PROC_READ, 1349336Sdfr NFSV2PROC_WRITE, 1359336Sdfr NFSV2PROC_CREATE, 1369336Sdfr NFSV2PROC_MKDIR, 1379336Sdfr NFSV2PROC_SYMLINK, 1389336Sdfr NFSV2PROC_CREATE, 1399336Sdfr NFSV2PROC_REMOVE, 1409336Sdfr NFSV2PROC_RMDIR, 1419336Sdfr NFSV2PROC_RENAME, 1429336Sdfr NFSV2PROC_LINK, 1439336Sdfr NFSV2PROC_READDIR, 1449336Sdfr NFSV2PROC_NOOP, 1459336Sdfr NFSV2PROC_STATFS, 1469336Sdfr NFSV2PROC_NOOP, 1479336Sdfr NFSV2PROC_NOOP, 1489336Sdfr NFSV2PROC_NOOP, 1499336Sdfr NFSV2PROC_NOOP, 1509336Sdfr}; 1519336Sdfr 15260938SjakeLIST_HEAD(nfsnodehashhead, nfsnode); 1533664Sphk 154176224Sjhbu_int32_t 155176224Sjhbnfs_xid_gen(void) 156176224Sjhb{ 157176224Sjhb uint32_t xid; 158176224Sjhb 159176224Sjhb mtx_lock(&nfs_xid_mtx); 160176224Sjhb 161176224Sjhb /* Get a pretty random xid to start with */ 162176224Sjhb if (!nfs_xid) 163176224Sjhb nfs_xid = random(); 164176224Sjhb /* 165176224Sjhb * Skip zero xid if it should ever happen. 166176224Sjhb */ 167176224Sjhb if (++nfs_xid == 0) 168176224Sjhb nfs_xid++; 169176224Sjhb xid = nfs_xid; 170176224Sjhb mtx_unlock(&nfs_xid_mtx); 171176224Sjhb return xid; 172176224Sjhb} 173176224Sjhb 1741541Srgrimes/* 1751541Srgrimes * Create the header for an rpc request packet 1761541Srgrimes * The hsiz is the size of the rest of the nfs request header. 1771541Srgrimes * (just used to decide if a cluster is a good idea) 1781541Srgrimes */ 1791541Srgrimesstruct mbuf * 18083651Speternfsm_reqhead(struct vnode *vp, u_long procid, int hsiz) 1811541Srgrimes{ 18283651Speter struct mbuf *mb; 1831541Srgrimes 184177599Sru MGET(mb, M_WAIT, MT_DATA); 1851541Srgrimes if (hsiz >= MINCLSIZE) 186177599Sru MCLGET(mb, M_WAIT); 1871541Srgrimes mb->m_len = 0; 1881541Srgrimes return (mb); 1891541Srgrimes} 1901541Srgrimes 1911541Srgrimes/* 19217186Sdfr * copies a uio scatter/gather list to an mbuf chain. 19317186Sdfr * NOTE: can ony handle iovcnt == 1 1941541Srgrimes */ 1951549Srgrimesint 19683651Speternfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos) 1971541Srgrimes{ 19883651Speter char *uiocp; 19983651Speter struct mbuf *mp, *mp2; 20083651Speter int xfer, left, mlen; 2011541Srgrimes int uiosiz, clflg, rem; 2021541Srgrimes char *cp; 2031541Srgrimes 204209120Skib KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1")); 20517186Sdfr 2061541Srgrimes if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 2071541Srgrimes clflg = 1; 2081541Srgrimes else 2091541Srgrimes clflg = 0; 2101541Srgrimes rem = nfsm_rndup(siz)-siz; 2111541Srgrimes mp = mp2 = *mq; 2121541Srgrimes while (siz > 0) { 2131541Srgrimes left = uiop->uio_iov->iov_len; 2141541Srgrimes uiocp = uiop->uio_iov->iov_base; 2151541Srgrimes if (left > siz) 2161541Srgrimes left = siz; 2171541Srgrimes uiosiz = left; 2181541Srgrimes while (left > 0) { 2191541Srgrimes mlen = M_TRAILINGSPACE(mp); 2201541Srgrimes if (mlen == 0) { 221177599Sru MGET(mp, M_WAIT, MT_DATA); 2221541Srgrimes if (clflg) 223177599Sru MCLGET(mp, M_WAIT); 2241541Srgrimes mp->m_len = 0; 2251541Srgrimes mp2->m_next = mp; 2261541Srgrimes mp2 = mp; 2271541Srgrimes mlen = M_TRAILINGSPACE(mp); 2281541Srgrimes } 2291541Srgrimes xfer = (left > mlen) ? mlen : left; 2301541Srgrimes#ifdef notdef 2311541Srgrimes /* Not Yet.. */ 2321541Srgrimes if (uiop->uio_iov->iov_op != NULL) 2331541Srgrimes (*(uiop->uio_iov->iov_op)) 2341541Srgrimes (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 2351541Srgrimes else 2361541Srgrimes#endif 2371541Srgrimes if (uiop->uio_segflg == UIO_SYSSPACE) 2381541Srgrimes bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 2391541Srgrimes else 2401541Srgrimes copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 2411541Srgrimes mp->m_len += xfer; 2421541Srgrimes left -= xfer; 2431541Srgrimes uiocp += xfer; 2441541Srgrimes uiop->uio_offset += xfer; 2451541Srgrimes uiop->uio_resid -= xfer; 2461541Srgrimes } 247104908Smike uiop->uio_iov->iov_base = 248104908Smike (char *)uiop->uio_iov->iov_base + uiosiz; 24917186Sdfr uiop->uio_iov->iov_len -= uiosiz; 2501541Srgrimes siz -= uiosiz; 2511541Srgrimes } 2521541Srgrimes if (rem > 0) { 2531541Srgrimes if (rem > M_TRAILINGSPACE(mp)) { 254177599Sru MGET(mp, M_WAIT, MT_DATA); 2551541Srgrimes mp->m_len = 0; 2561541Srgrimes mp2->m_next = mp; 2571541Srgrimes } 2581541Srgrimes cp = mtod(mp, caddr_t)+mp->m_len; 2591541Srgrimes for (left = 0; left < rem; left++) 2601541Srgrimes *cp++ = '\0'; 2611541Srgrimes mp->m_len += rem; 2621541Srgrimes *bpos = cp; 2631541Srgrimes } else 2641541Srgrimes *bpos = mtod(mp, caddr_t)+mp->m_len; 2651541Srgrimes *mq = mp; 2661541Srgrimes return (0); 2671541Srgrimes} 2681541Srgrimes 2691541Srgrimes/* 2701541Srgrimes * Copy a string into mbufs for the hard cases... 2711541Srgrimes */ 2721549Srgrimesint 27383651Speternfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz) 2741541Srgrimes{ 27583651Speter struct mbuf *m1 = NULL, *m2; 2761541Srgrimes long left, xfer, len, tlen; 27736541Speter u_int32_t *tl; 2781541Srgrimes int putsize; 2791541Srgrimes 2801541Srgrimes putsize = 1; 2811541Srgrimes m2 = *mb; 2821541Srgrimes left = M_TRAILINGSPACE(m2); 2831541Srgrimes if (left > 0) { 28436541Speter tl = ((u_int32_t *)(*bpos)); 2851541Srgrimes *tl++ = txdr_unsigned(siz); 2861541Srgrimes putsize = 0; 2871541Srgrimes left -= NFSX_UNSIGNED; 2881541Srgrimes m2->m_len += NFSX_UNSIGNED; 2891541Srgrimes if (left > 0) { 2901541Srgrimes bcopy(cp, (caddr_t) tl, left); 2911541Srgrimes siz -= left; 2921541Srgrimes cp += left; 2931541Srgrimes m2->m_len += left; 2941541Srgrimes left = 0; 2951541Srgrimes } 2961541Srgrimes } 2971541Srgrimes /* Loop around adding mbufs */ 2981541Srgrimes while (siz > 0) { 299177599Sru MGET(m1, M_WAIT, MT_DATA); 3001541Srgrimes if (siz > MLEN) 301177599Sru MCLGET(m1, M_WAIT); 3021541Srgrimes m1->m_len = NFSMSIZ(m1); 3031541Srgrimes m2->m_next = m1; 3041541Srgrimes m2 = m1; 30536541Speter tl = mtod(m1, u_int32_t *); 3061541Srgrimes tlen = 0; 3071541Srgrimes if (putsize) { 3081541Srgrimes *tl++ = txdr_unsigned(siz); 3091541Srgrimes m1->m_len -= NFSX_UNSIGNED; 3101541Srgrimes tlen = NFSX_UNSIGNED; 3111541Srgrimes putsize = 0; 3121541Srgrimes } 3131541Srgrimes if (siz < m1->m_len) { 3141541Srgrimes len = nfsm_rndup(siz); 3151541Srgrimes xfer = siz; 3161541Srgrimes if (xfer < len) 3171541Srgrimes *(tl+(xfer>>2)) = 0; 3181541Srgrimes } else { 3191541Srgrimes xfer = len = m1->m_len; 3201541Srgrimes } 3211541Srgrimes bcopy(cp, (caddr_t) tl, xfer); 3221541Srgrimes m1->m_len = len+tlen; 3231541Srgrimes siz -= xfer; 3241541Srgrimes cp += xfer; 3251541Srgrimes } 3261541Srgrimes *mb = m1; 3271541Srgrimes *bpos = mtod(m1, caddr_t)+m1->m_len; 3281541Srgrimes return (0); 3291541Srgrimes} 3301541Srgrimes 3311541Srgrimes/* 3321541Srgrimes * Called once to initialize data structures... 3331541Srgrimes */ 3341549Srgrimesint 33583651Speternfs_init(struct vfsconf *vfsp) 3361541Srgrimes{ 33783651Speter int i; 3381541Srgrimes 33992783Sjeff nfsmount_zone = uma_zcreate("NFSMOUNT", sizeof(struct nfsmount), 34092783Sjeff NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 3411541Srgrimes nfs_true = txdr_unsigned(TRUE); 3421541Srgrimes nfs_false = txdr_unsigned(FALSE); 3433664Sphk nfs_xdrneg1 = txdr_unsigned(-1); 3449336Sdfr nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 3459336Sdfr if (nfs_ticks < 1) 3469336Sdfr nfs_ticks = 1; 3471541Srgrimes /* Ensure async daemons disabled */ 34819449Sdfr for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 349203072Srmacklem nfs_iodwant[i] = NFSIOD_NOT_AVAILABLE; 35099797Sdillon nfs_iodmount[i] = NULL; 35119449Sdfr } 3521541Srgrimes nfs_nhinit(); /* Init the nfsnode table */ 3531541Srgrimes 3541541Srgrimes /* 3551541Srgrimes * Initialize reply list and start timer 3561541Srgrimes */ 357158739Smohans mtx_init(&nfs_iod_mtx, "NFS iod lock", NULL, MTX_DEF); 358172600Smohans mtx_init(&nfs_xid_mtx, "NFS xid lock", NULL, MTX_DEF); 359212506Skib TASK_INIT(&nfs_nfsiodnew_task, 0, nfs_nfsiodnew_tq, NULL); 36016365Sphk 36142957Sdillon nfs_pbuf_freecnt = nswbuf / 2 + 1; 36242957Sdillon 3631549Srgrimes return (0); 3641541Srgrimes} 3651541Srgrimes 36638894Sbdeint 36783651Speternfs_uninit(struct vfsconf *vfsp) 36838894Sbde{ 369128111Speadar int i; 37038894Sbde 371128111Speadar /* 372128111Speadar * Tell all nfsiod processes to exit. Clear nfs_iodmax, and wakeup 373128111Speadar * any sleeping nfsiods so they check nfs_iodmax and exit. 374212506Skib * Drain nfsiodnew task before we wait for them to finish. 375128111Speadar */ 376158739Smohans mtx_lock(&nfs_iod_mtx); 377128111Speadar nfs_iodmax = 0; 378212506Skib mtx_unlock(&nfs_iod_mtx); 379212506Skib taskqueue_drain(taskqueue_thread, &nfs_nfsiodnew_task); 380212506Skib mtx_lock(&nfs_iod_mtx); 381128111Speadar for (i = 0; i < nfs_numasync; i++) 382203072Srmacklem if (nfs_iodwant[i] == NFSIOD_AVAILABLE) 383128111Speadar wakeup(&nfs_iodwant[i]); 384128111Speadar /* The last nfsiod to exit will wake us up when nfs_numasync hits 0 */ 385128111Speadar while (nfs_numasync) 386158739Smohans msleep(&nfs_numasync, &nfs_iod_mtx, PWAIT, "ioddie", 0); 387158739Smohans mtx_unlock(&nfs_iod_mtx); 388128111Speadar nfs_nhuninit(); 389128111Speadar uma_zdestroy(nfsmount_zone); 39038894Sbde return (0); 39138894Sbde} 39238894Sbde 393158739Smohansvoid 394158739Smohansnfs_dircookie_lock(struct nfsnode *np) 395158739Smohans{ 396158739Smohans mtx_lock(&np->n_mtx); 397158739Smohans while (np->n_flag & NDIRCOOKIELK) 398158739Smohans (void) msleep(&np->n_flag, &np->n_mtx, PZERO, "nfsdirlk", 0); 399158739Smohans np->n_flag |= NDIRCOOKIELK; 400158739Smohans mtx_unlock(&np->n_mtx); 401158739Smohans} 402158739Smohans 403158739Smohansvoid 404158739Smohansnfs_dircookie_unlock(struct nfsnode *np) 405158739Smohans{ 406158739Smohans mtx_lock(&np->n_mtx); 407158739Smohans np->n_flag &= ~NDIRCOOKIELK; 408158739Smohans wakeup(&np->n_flag); 409158739Smohans mtx_unlock(&np->n_mtx); 410158739Smohans} 411158739Smohans 412158739Smohansint 413176134Sattilionfs_upgrade_vnlock(struct vnode *vp) 414158739Smohans{ 415158739Smohans int old_lock; 416196205Skib 417196205Skib ASSERT_VOP_LOCKED(vp, "nfs_upgrade_vnlock"); 418196205Skib old_lock = VOP_ISLOCKED(vp); 419196205Skib if (old_lock != LK_EXCLUSIVE) { 420196205Skib KASSERT(old_lock == LK_SHARED, 421196205Skib ("nfs_upgrade_vnlock: wrong old_lock %d", old_lock)); 422196205Skib /* Upgrade to exclusive lock, this might block */ 423196205Skib vn_lock(vp, LK_UPGRADE | LK_RETRY); 424158739Smohans } 425196205Skib return (old_lock); 426158739Smohans} 427158739Smohans 428158739Smohansvoid 429176134Sattilionfs_downgrade_vnlock(struct vnode *vp, int old_lock) 430158739Smohans{ 431158739Smohans if (old_lock != LK_EXCLUSIVE) { 432196205Skib KASSERT(old_lock == LK_SHARED, ("wrong old_lock %d", old_lock)); 433196205Skib /* Downgrade from exclusive lock. */ 434196205Skib vn_lock(vp, LK_DOWNGRADE | LK_RETRY); 435158739Smohans } 436158739Smohans} 437158739Smohans 438158739Smohansvoid 439158739Smohansnfs_printf(const char *fmt, ...) 440158739Smohans{ 441158739Smohans va_list ap; 442158739Smohans 443158739Smohans mtx_lock(&Giant); 444158739Smohans va_start(ap, fmt); 445220595Sru vprintf(fmt, ap); 446158739Smohans va_end(ap); 447158739Smohans mtx_unlock(&Giant); 448158739Smohans} 449158739Smohans 4501541Srgrimes/* 4511541Srgrimes * Attribute cache routines. 4521541Srgrimes * nfs_loadattrcache() - loads or updates the cache contents from attributes 4531541Srgrimes * that are on the mbuf list 4541541Srgrimes * nfs_getattrcache() - returns valid attributes if found in cache, returns 4551541Srgrimes * error otherwise 4561541Srgrimes */ 4571541Srgrimes 4581541Srgrimes/* 4591541Srgrimes * Load the attribute cache (that lives in the nfsnode entry) with 4601541Srgrimes * the values on the mbuf list and 4611541Srgrimes * Iff vap not NULL 4621541Srgrimes * copy the attributes to *vaper 4631541Srgrimes */ 4641549Srgrimesint 46583651Speternfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp, 466158739Smohans struct vattr *vaper, int dontshrink) 4671541Srgrimes{ 46883651Speter struct vnode *vp = *vpp; 46983651Speter struct vattr *vap; 47083651Speter struct nfs_fattr *fp; 471190380Srwatson struct nfsnode *np = NULL; 47283651Speter int32_t t1; 4739336Sdfr caddr_t cp2; 47484057Speter int rdev; 4751541Srgrimes struct mbuf *md; 4761541Srgrimes enum vtype vtyp; 4771541Srgrimes u_short vmode; 478171190Sjhb struct timespec mtime, mtime_save; 4799336Sdfr int v3 = NFS_ISV3(vp); 480190380Srwatson int error = 0; 481251671Srmacklem u_quad_t nsize; 482251671Srmacklem int setnsize; 4831541Srgrimes 4841541Srgrimes md = *mdp; 4859336Sdfr t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 486177599Sru cp2 = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, M_WAIT); 487190380Srwatson if (cp2 == NULL) { 488190380Srwatson error = EBADRPC; 489190380Srwatson goto out; 490190380Srwatson } 4919336Sdfr fp = (struct nfs_fattr *)cp2; 4929336Sdfr if (v3) { 4939336Sdfr vtyp = nfsv3tov_type(fp->fa_type); 4949336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 495130640Sphk rdev = makedev(fxdr_unsigned(int, fp->fa3_rdev.specdata1), 49616634Sbde fxdr_unsigned(int, fp->fa3_rdev.specdata2)); 4979336Sdfr fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 4981541Srgrimes } else { 4999336Sdfr vtyp = nfsv2tov_type(fp->fa_type); 5009336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 5019336Sdfr /* 5029336Sdfr * XXX 5039336Sdfr * 5049336Sdfr * The duplicate information returned in fa_type and fa_mode 5059336Sdfr * is an ambiguity in the NFS version 2 protocol. 5069336Sdfr * 5079336Sdfr * VREG should be taken literally as a regular file. If a 5089336Sdfr * server intents to return some type information differently 5099336Sdfr * in the upper bits of the mode field (e.g. for sockets, or 5109336Sdfr * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we 5119336Sdfr * leave the examination of the mode bits even in the VREG 5129336Sdfr * case to avoid breakage for bogus servers, but we make sure 5139336Sdfr * that there are actually type bits set in the upper part of 5149336Sdfr * fa_mode (and failing that, trust the va_type field). 5159336Sdfr * 5169336Sdfr * NFSv3 cleared the issue, and requires fa_mode to not 5179336Sdfr * contain any type information (while also introduing sockets 5189336Sdfr * and FIFOs for fa_type). 5199336Sdfr */ 5209336Sdfr if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) 5219336Sdfr vtyp = IFTOVT(vmode); 52236541Speter rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); 5239336Sdfr fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 5249336Sdfr 5259336Sdfr /* 5269336Sdfr * Really ugly NFSv2 kludge. 5279336Sdfr */ 5289336Sdfr if (vtyp == VCHR && rdev == 0xffffffff) 5299336Sdfr vtyp = VFIFO; 5301541Srgrimes } 5319336Sdfr 5321541Srgrimes /* 5331541Srgrimes * If v_type == VNON it is a new node, so fill in the v_type, 5348876Srgrimes * n_mtime fields. Check to see if it represents a special 5351541Srgrimes * device, and if so, check for a possible alias. Once the 5361541Srgrimes * correct vnode has been obtained, fill in the rest of the 5371541Srgrimes * information. 5381541Srgrimes */ 5391541Srgrimes np = VTONFS(vp); 540158739Smohans mtx_lock(&np->n_mtx); 54110219Sdfr if (vp->v_type != vtyp) { 5429336Sdfr vp->v_type = vtyp; 543126851Sphk if (vp->v_type == VFIFO) 544138290Sphk vp->v_op = &nfs_fifoops; 545138473Sps np->n_mtime = mtime; 5461541Srgrimes } 5471541Srgrimes vap = &np->n_vattr; 5481541Srgrimes vap->va_type = vtyp; 5491541Srgrimes vap->va_mode = (vmode & 07777); 55047028Sphk vap->va_rdev = rdev; 551171190Sjhb mtime_save = vap->va_mtime; 5521541Srgrimes vap->va_mtime = mtime; 5531541Srgrimes vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 5549336Sdfr if (v3) { 5559336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 5569336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 5579336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 55847751Speter vap->va_size = fxdr_hyper(&fp->fa3_size); 5599336Sdfr vap->va_blocksize = NFS_FABLKSIZE; 56047751Speter vap->va_bytes = fxdr_hyper(&fp->fa3_used); 56136541Speter vap->va_fileid = fxdr_unsigned(int32_t, 56236541Speter fp->fa3_fileid.nfsuquad[1]); 5639336Sdfr fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 5649336Sdfr fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 5659336Sdfr vap->va_flags = 0; 5669336Sdfr vap->va_filerev = 0; 5671541Srgrimes } else { 5689336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 5699336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 5709336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 57136541Speter vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 57236541Speter vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 57347751Speter vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) 57436541Speter * NFS_FABLKSIZE; 57536541Speter vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); 5769336Sdfr fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 5771541Srgrimes vap->va_flags = 0; 57836541Speter vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, 57936541Speter fp->fa2_ctime.nfsv2_sec); 58018397Snate vap->va_ctime.tv_nsec = 0; 58183651Speter vap->va_gen = fxdr_unsigned(u_int32_t, fp->fa2_ctime.nfsv2_usec); 5821541Srgrimes vap->va_filerev = 0; 5831541Srgrimes } 58467486Sdwmalone np->n_attrstamp = time_second; 585251671Srmacklem setnsize = 0; 586251671Srmacklem nsize = 0; 5871541Srgrimes if (vap->va_size != np->n_size) { 5881541Srgrimes if (vap->va_type == VREG) { 58967486Sdwmalone if (dontshrink && vap->va_size < np->n_size) { 59067486Sdwmalone /* 59167486Sdwmalone * We've been told not to shrink the file; 59267486Sdwmalone * zero np->n_attrstamp to indicate that 59367486Sdwmalone * the attributes are stale. 59467486Sdwmalone */ 59567486Sdwmalone vap->va_size = np->n_size; 59667486Sdwmalone np->n_attrstamp = 0; 597190380Srwatson KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 598253177Srmacklem vnode_pager_setsize(vp, np->n_size); 59967486Sdwmalone } else if (np->n_flag & NMODIFIED) { 600128263Speadar /* 601128263Speadar * We've modified the file: Use the larger 602128263Speadar * of our size, and the server's size. 603128263Speadar */ 604128263Speadar if (vap->va_size < np->n_size) { 6051541Srgrimes vap->va_size = np->n_size; 606128263Speadar } else { 6071541Srgrimes np->n_size = vap->va_size; 608128263Speadar np->n_flag |= NSIZECHANGED; 609128263Speadar } 610253177Srmacklem vnode_pager_setsize(vp, np->n_size); 611253177Srmacklem } else if (vap->va_size < np->n_size) { 612253177Srmacklem /* 613253177Srmacklem * When shrinking the size, the call to 614253177Srmacklem * vnode_pager_setsize() cannot be done 615253177Srmacklem * with the mutex held, so delay it until 616253177Srmacklem * after the mtx_unlock call. 617253177Srmacklem */ 618253177Srmacklem nsize = np->n_size = vap->va_size; 619253177Srmacklem np->n_flag |= NSIZECHANGED; 620253177Srmacklem setnsize = 1; 62154480Sdillon } else { 6221541Srgrimes np->n_size = vap->va_size; 623128263Speadar np->n_flag |= NSIZECHANGED; 624253177Srmacklem vnode_pager_setsize(vp, np->n_size); 62554480Sdillon } 62654480Sdillon } else { 6271541Srgrimes np->n_size = vap->va_size; 62854480Sdillon } 6291541Srgrimes } 630171190Sjhb /* 631171190Sjhb * The following checks are added to prevent a race between (say) 632171190Sjhb * a READDIR+ and a WRITE. 633171190Sjhb * READDIR+, WRITE requests sent out. 634171190Sjhb * READDIR+ resp, WRITE resp received on client. 635171190Sjhb * However, the WRITE resp was handled before the READDIR+ resp 636171190Sjhb * causing the post op attrs from the write to be loaded first 637171190Sjhb * and the attrs from the READDIR+ to be loaded later. If this 638171190Sjhb * happens, we have stale attrs loaded into the attrcache. 639171190Sjhb * We detect this by for the mtime moving back. We invalidate the 640171190Sjhb * attrcache when this happens. 641171190Sjhb */ 642190380Srwatson if (timespeccmp(&mtime_save, &vap->va_mtime, >)) { 643171190Sjhb /* Size changed or mtime went backwards */ 644171190Sjhb np->n_attrstamp = 0; 645190380Srwatson KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 646190380Srwatson } 6471541Srgrimes if (vaper != NULL) { 6481541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 6491541Srgrimes if (np->n_flag & NCHG) { 6509336Sdfr if (np->n_flag & NACC) 6519336Sdfr vaper->va_atime = np->n_atim; 6529336Sdfr if (np->n_flag & NUPD) 6539336Sdfr vaper->va_mtime = np->n_mtim; 6541541Srgrimes } 6551541Srgrimes } 656190396Srwatson 657190396Srwatson#ifdef KDTRACE_HOOKS 658190396Srwatson if (np->n_attrstamp != 0) 659190396Srwatson KDTRACE_NFS_ATTRCACHE_LOAD_DONE(vp, &np->n_vattr, 0); 660190396Srwatson#endif 661158739Smohans mtx_unlock(&np->n_mtx); 662251671Srmacklem if (setnsize) 663251671Srmacklem vnode_pager_setsize(vp, nsize); 664190380Srwatsonout: 665190396Srwatson#ifdef KDTRACE_HOOKS 666190396Srwatson if (error) 667190396Srwatson KDTRACE_NFS_ATTRCACHE_LOAD_DONE(vp, NULL, error); 668190380Srwatson#endif 669190380Srwatson return (error); 6701541Srgrimes} 6711541Srgrimes 67236176Speter#ifdef NFS_ACDEBUG 67336176Speter#include <sys/sysctl.h> 674221973SrmacklemSYSCTL_DECL(_vfs_oldnfs); 67536176Speterstatic int nfs_acdebug; 676221973SrmacklemSYSCTL_INT(_vfs_oldnfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, 677220595Sru "Toggle acdebug (attribute cache debug) flag"); 67836176Speter#endif 67936176Speter 6801541Srgrimes/* 6811541Srgrimes * Check the time stamp 6821541Srgrimes * If the cache is valid, copy contents to *vap and return 0 6831541Srgrimes * otherwise return an error 6841541Srgrimes */ 6851549Srgrimesint 68683651Speternfs_getattrcache(struct vnode *vp, struct vattr *vaper) 6871541Srgrimes{ 68883651Speter struct nfsnode *np; 68983651Speter struct vattr *vap; 69036176Speter struct nfsmount *nmp; 69136176Speter int timeo; 692158739Smohans 69336176Speter np = VTONFS(vp); 69436176Speter vap = &np->n_vattr; 69536176Speter nmp = VFSTONFS(vp->v_mount); 696158739Smohans#ifdef NFS_ACDEBUG 697158739Smohans mtx_lock(&Giant); /* nfs_printf() */ 698158739Smohans#endif 699158739Smohans mtx_lock(&np->n_mtx); 70036176Speter /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */ 701138473Sps timeo = (time_second - np->n_mtime.tv_sec) / 10; 70236176Speter 70336176Speter#ifdef NFS_ACDEBUG 70436176Speter if (nfs_acdebug>1) 705158739Smohans nfs_printf("nfs_getattrcache: initial timeo = %d\n", timeo); 70636176Speter#endif 70736176Speter 70836176Speter if (vap->va_type == VDIR) { 70936176Speter if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin) 71036176Speter timeo = nmp->nm_acdirmin; 71136176Speter else if (timeo > nmp->nm_acdirmax) 71236176Speter timeo = nmp->nm_acdirmax; 71336176Speter } else { 71436176Speter if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin) 71536176Speter timeo = nmp->nm_acregmin; 71636176Speter else if (timeo > nmp->nm_acregmax) 71736176Speter timeo = nmp->nm_acregmax; 71836176Speter } 71936176Speter 72036176Speter#ifdef NFS_ACDEBUG 72136176Speter if (nfs_acdebug > 2) 722158739Smohans nfs_printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n", 723158739Smohans nmp->nm_acregmin, nmp->nm_acregmax, 724158739Smohans nmp->nm_acdirmin, nmp->nm_acdirmax); 72536176Speter 72636176Speter if (nfs_acdebug) 727158739Smohans nfs_printf("nfs_getattrcache: age = %d; final timeo = %d\n", 728158739Smohans (time_second - np->n_attrstamp), timeo); 72936176Speter#endif 73036176Speter 73136176Speter if ((time_second - np->n_attrstamp) >= timeo) { 7321541Srgrimes nfsstats.attrcache_misses++; 733158739Smohans mtx_unlock(&np->n_mtx); 734220595Sru#ifdef NFS_ACDEBUG 735220595Sru mtx_unlock(&Giant); /* nfs_printf() */ 736220595Sru#endif 737190380Srwatson KDTRACE_NFS_ATTRCACHE_GET_MISS(vp); 738190380Srwatson return (ENOENT); 7391541Srgrimes } 7401541Srgrimes nfsstats.attrcache_hits++; 7411541Srgrimes if (vap->va_size != np->n_size) { 7421541Srgrimes if (vap->va_type == VREG) { 7431541Srgrimes if (np->n_flag & NMODIFIED) { 7441541Srgrimes if (vap->va_size < np->n_size) 7451541Srgrimes vap->va_size = np->n_size; 7461541Srgrimes else 7471541Srgrimes np->n_size = vap->va_size; 74854480Sdillon } else { 7491541Srgrimes np->n_size = vap->va_size; 75054480Sdillon } 75141026Speter vnode_pager_setsize(vp, np->n_size); 75254480Sdillon } else { 7531541Srgrimes np->n_size = vap->va_size; 75454480Sdillon } 7551541Srgrimes } 7561541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 7571541Srgrimes if (np->n_flag & NCHG) { 7589336Sdfr if (np->n_flag & NACC) 7599336Sdfr vaper->va_atime = np->n_atim; 7609336Sdfr if (np->n_flag & NUPD) 7619336Sdfr vaper->va_mtime = np->n_mtim; 7621541Srgrimes } 763158739Smohans mtx_unlock(&np->n_mtx); 764158739Smohans#ifdef NFS_ACDEBUG 765158739Smohans mtx_unlock(&Giant); /* nfs_printf() */ 766158739Smohans#endif 767190380Srwatson KDTRACE_NFS_ATTRCACHE_GET_HIT(vp, vap); 7681541Srgrimes return (0); 7691541Srgrimes} 7701541Srgrimes 771190785Sjhb/* 772190785Sjhb * Purge all cached information about an NFS vnode including name 773190785Sjhb * cache entries, the attribute cache, and the access cache. This is 774190785Sjhb * called when an NFS request for a node fails with a stale 775190785Sjhb * filehandle. 776190785Sjhb */ 777190785Sjhbvoid 778190785Sjhbnfs_purgecache(struct vnode *vp) 779190785Sjhb{ 780190785Sjhb struct nfsnode *np; 781190785Sjhb int i; 782190785Sjhb 783190785Sjhb np = VTONFS(vp); 784190785Sjhb cache_purge(vp); 785190785Sjhb mtx_lock(&np->n_mtx); 786190785Sjhb np->n_attrstamp = 0; 787190785Sjhb KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 788190785Sjhb for (i = 0; i < NFS_ACCESSCACHESIZE; i++) 789190785Sjhb np->n_accesscache[i].stamp = 0; 790190785Sjhb KDTRACE_NFS_ACCESSCACHE_FLUSH_DONE(vp); 791190785Sjhb mtx_unlock(&np->n_mtx); 792190785Sjhb} 793190785Sjhb 79443305Sdillonstatic nfsuint64 nfs_nullcookie = { { 0, 0 } }; 7959336Sdfr/* 7969336Sdfr * This function finds the directory cookie that corresponds to the 7979336Sdfr * logical byte offset given. 7989336Sdfr */ 7999336Sdfrnfsuint64 * 80083651Speternfs_getcookie(struct nfsnode *np, off_t off, int add) 8019336Sdfr{ 80283651Speter struct nfsdmap *dp, *dp2; 80383651Speter int pos; 804158739Smohans nfsuint64 *retval = NULL; 805158739Smohans 80636979Sbde pos = (uoff_t)off / NFS_DIRBLKSIZ; 80736979Sbde if (pos == 0 || off < 0) { 808209120Skib KASSERT(!add, ("nfs getcookie add at <= 0")); 8099336Sdfr return (&nfs_nullcookie); 8109336Sdfr } 8119336Sdfr pos--; 81283651Speter dp = LIST_FIRST(&np->n_cookies); 8139336Sdfr if (!dp) { 8149336Sdfr if (add) { 815184205Sdes dp = malloc(sizeof (struct nfsdmap), 816111119Simp M_NFSDIROFF, M_WAITOK); 8179336Sdfr dp->ndm_eocookie = 0; 8189336Sdfr LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 8199336Sdfr } else 820158739Smohans goto out; 8219336Sdfr } 8229336Sdfr while (pos >= NFSNUMCOOKIES) { 8239336Sdfr pos -= NFSNUMCOOKIES; 82483651Speter if (LIST_NEXT(dp, ndm_list)) { 8259336Sdfr if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 826158739Smohans pos >= dp->ndm_eocookie) 827158739Smohans goto out; 82883651Speter dp = LIST_NEXT(dp, ndm_list); 8299336Sdfr } else if (add) { 830184205Sdes dp2 = malloc(sizeof (struct nfsdmap), 831111119Simp M_NFSDIROFF, M_WAITOK); 8329336Sdfr dp2->ndm_eocookie = 0; 8339336Sdfr LIST_INSERT_AFTER(dp, dp2, ndm_list); 8349336Sdfr dp = dp2; 8359336Sdfr } else 836158739Smohans goto out; 8379336Sdfr } 8389336Sdfr if (pos >= dp->ndm_eocookie) { 8399336Sdfr if (add) 8409336Sdfr dp->ndm_eocookie = pos + 1; 8419336Sdfr else 842158739Smohans goto out; 8439336Sdfr } 844158739Smohans retval = &dp->ndm_cookies[pos]; 845158739Smohansout: 846158739Smohans return (retval); 8479336Sdfr} 8489336Sdfr 8499336Sdfr/* 8509336Sdfr * Invalidate cached directory information, except for the actual directory 8519336Sdfr * blocks (which are invalidated separately). 8529336Sdfr * Done mainly to avoid the use of stale offset cookies. 8539336Sdfr */ 8549336Sdfrvoid 85583651Speternfs_invaldir(struct vnode *vp) 8569336Sdfr{ 85783651Speter struct nfsnode *np = VTONFS(vp); 8589336Sdfr 859209120Skib KASSERT(vp->v_type == VDIR, ("nfs: invaldir not dir")); 860158739Smohans nfs_dircookie_lock(np); 8619336Sdfr np->n_direofoffset = 0; 8629336Sdfr np->n_cookieverf.nfsuquad[0] = 0; 8639336Sdfr np->n_cookieverf.nfsuquad[1] = 0; 86483651Speter if (LIST_FIRST(&np->n_cookies)) 86583651Speter LIST_FIRST(&np->n_cookies)->ndm_eocookie = 0; 866158739Smohans nfs_dircookie_unlock(np); 8679336Sdfr} 8689336Sdfr 8699336Sdfr/* 8709336Sdfr * The write verifier has changed (probably due to a server reboot), so all 8719336Sdfr * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 8729336Sdfr * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 87354480Sdillon * and B_CLUSTEROK flags. Once done the new write verifier can be set for the 87454480Sdillon * mount point. 87554480Sdillon * 87683651Speter * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data 87754480Sdillon * writes are not clusterable. 8789336Sdfr */ 8799336Sdfrvoid 88083651Speternfs_clearcommit(struct mount *mp) 8819336Sdfr{ 88283651Speter struct vnode *vp, *nvp; 88383651Speter struct buf *bp, *nbp; 884177493Sjeff struct bufobj *bo; 8859336Sdfr 886235626Smckusick MNT_VNODE_FOREACH_ALL(vp, mp, nvp) { 887177493Sjeff bo = &vp->v_bufobj; 888177493Sjeff vholdl(vp); 889177493Sjeff VI_UNLOCK(vp); 890177493Sjeff BO_LOCK(bo); 891177493Sjeff TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { 892175486Sattilio if (!BUF_ISLOCKED(bp) && 89348225Smckusick (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) 8949336Sdfr == (B_DELWRI | B_NEEDCOMMIT)) 89554480Sdillon bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); 8969336Sdfr } 897177493Sjeff BO_UNLOCK(bo); 898177493Sjeff vdrop(vp); 8999336Sdfr } 9009336Sdfr} 9019336Sdfr 9029336Sdfr/* 90383651Speter * Helper functions for former macros. Some of these should be 90483651Speter * moved to their callers. 9059336Sdfr */ 90683651Speter 9075455Sdgint 90883651Speternfsm_mtofh_xx(struct vnode *d, struct vnode **v, int v3, int *f, 90988091Siedowse struct mbuf **md, caddr_t *dpos) 9109336Sdfr{ 91183651Speter struct nfsnode *ttnp; 91283651Speter struct vnode *ttvp; 91383651Speter nfsfh_t *ttfhp; 91488091Siedowse u_int32_t *tl; 91583651Speter int ttfhsize; 91683651Speter int t1; 9179336Sdfr 91883651Speter if (v3) { 91988091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 92088091Siedowse if (tl == NULL) 92184057Speter return EBADRPC; 92288091Siedowse *f = fxdr_unsigned(int, *tl); 92383651Speter } else 92483651Speter *f = 1; 92583651Speter if (*f) { 92688091Siedowse t1 = nfsm_getfh_xx(&ttfhp, &ttfhsize, (v3), md, dpos); 92783651Speter if (t1 != 0) 92883651Speter return t1; 929162288Smohans t1 = nfs_nget(d->v_mount, ttfhp, ttfhsize, &ttnp, LK_EXCLUSIVE); 93083651Speter if (t1 != 0) 93183651Speter return t1; 93283651Speter *v = NFSTOV(ttnp); 93383651Speter } 93483651Speter if (v3) { 93588091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 93688091Siedowse if (tl == NULL) 93784057Speter return EBADRPC; 93883651Speter if (*f) 93988091Siedowse *f = fxdr_unsigned(int, *tl); 94088091Siedowse else if (fxdr_unsigned(int, *tl)) 94188091Siedowse nfsm_adv_xx(NFSX_V3FATTR, md, dpos); 94283651Speter } 94383651Speter if (*f) { 94483651Speter ttvp = *v; 94599797Sdillon t1 = nfs_loadattrcache(&ttvp, md, dpos, NULL, 0); 94683651Speter if (t1) 94783651Speter return t1; 94883651Speter *v = ttvp; 94983651Speter } 95083651Speter return 0; 95183651Speter} 95283651Speter 95383651Speterint 95488091Siedowsenfsm_getfh_xx(nfsfh_t **f, int *s, int v3, struct mbuf **md, caddr_t *dpos) 95583651Speter{ 95688091Siedowse u_int32_t *tl; 95783651Speter 95883651Speter if (v3) { 95988091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 96088091Siedowse if (tl == NULL) 96184057Speter return EBADRPC; 96288091Siedowse *s = fxdr_unsigned(int, *tl); 96384057Speter if (*s <= 0 || *s > NFSX_V3FHMAX) 96483651Speter return EBADRPC; 96583651Speter } else 96683651Speter *s = NFSX_V2FH; 96784057Speter *f = nfsm_dissect_xx(nfsm_rndup(*s), md, dpos); 96884057Speter if (*f == NULL) 96984057Speter return EBADRPC; 97084057Speter else 97184057Speter return 0; 97283651Speter} 97383651Speter 97483651Speter 97583651Speterint 97688091Siedowsenfsm_loadattr_xx(struct vnode **v, struct vattr *va, struct mbuf **md, 977158739Smohans caddr_t *dpos) 97883651Speter{ 97983651Speter int t1; 98083651Speter 98183651Speter struct vnode *ttvp = *v; 98283651Speter t1 = nfs_loadattrcache(&ttvp, md, dpos, va, 0); 98383651Speter if (t1 != 0) 98483651Speter return t1; 98583651Speter *v = ttvp; 98683651Speter return 0; 98783651Speter} 98883651Speter 98983651Speterint 990233285Sjhbnfsm_postop_attr_xx(struct vnode **v, int *f, struct vattr *va, 991233285Sjhb struct mbuf **md, caddr_t *dpos) 99283651Speter{ 99388091Siedowse u_int32_t *tl; 99483651Speter int t1; 99583651Speter 99683651Speter struct vnode *ttvp = *v; 99788091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 99888091Siedowse if (tl == NULL) 99984057Speter return EBADRPC; 100088091Siedowse *f = fxdr_unsigned(int, *tl); 100183914Siedowse if (*f != 0) { 1002233285Sjhb t1 = nfs_loadattrcache(&ttvp, md, dpos, va, 1); 100383651Speter if (t1 != 0) { 100483651Speter *f = 0; 100583651Speter return t1; 100683651Speter } 100783651Speter *v = ttvp; 10089336Sdfr } 100983651Speter return 0; 10109336Sdfr} 10119336Sdfr 10129336Sdfrint 101388091Siedowsenfsm_wcc_data_xx(struct vnode **v, int *f, struct mbuf **md, caddr_t *dpos) 101431886Sbde{ 101588091Siedowse u_int32_t *tl; 101683651Speter int ttattrf, ttretf = 0; 101783651Speter int t1; 10185455Sdg 101988091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 102088091Siedowse if (tl == NULL) 102184057Speter return EBADRPC; 102288091Siedowse if (*tl == nfs_true) { 102388091Siedowse tl = nfsm_dissect_xx(6 * NFSX_UNSIGNED, md, dpos); 102488091Siedowse if (tl == NULL) 102584057Speter return EBADRPC; 1026158739Smohans mtx_lock(&(VTONFS(*v))->n_mtx); 102783651Speter if (*f) 1028138473Sps ttretf = (VTONFS(*v)->n_mtime.tv_sec == fxdr_unsigned(u_int32_t, *(tl + 2)) && 1029138473Sps VTONFS(*v)->n_mtime.tv_nsec == fxdr_unsigned(u_int32_t, *(tl + 3))); 1030158739Smohans mtx_unlock(&(VTONFS(*v))->n_mtx); 103183651Speter } 1032233285Sjhb t1 = nfsm_postop_attr_xx(v, &ttattrf, NULL, md, dpos); 103383651Speter if (t1) 103483651Speter return t1; 103583651Speter if (*f) 103683651Speter *f = ttretf; 103783651Speter else 103883651Speter *f = ttattrf; 103983651Speter return 0; 10405455Sdg} 104136503Speter 104283651Speterint 104388091Siedowsenfsm_strtom_xx(const char *a, int s, int m, struct mbuf **mb, caddr_t *bpos) 104436503Speter{ 104588091Siedowse u_int32_t *tl; 104683651Speter int t1; 104736503Speter 104883651Speter if (s > m) 104983651Speter return ENAMETOOLONG; 105083651Speter t1 = nfsm_rndup(s) + NFSX_UNSIGNED; 105183651Speter if (t1 <= M_TRAILINGSPACE(*mb)) { 105288091Siedowse tl = nfsm_build_xx(t1, mb, bpos); 105388091Siedowse *tl++ = txdr_unsigned(s); 105488091Siedowse *(tl + ((t1 >> 2) - 2)) = 0; 105588091Siedowse bcopy(a, tl, s); 105683651Speter } else { 105783651Speter t1 = nfsm_strtmbuf(mb, bpos, a, s); 105883651Speter if (t1 != 0) 105983651Speter return t1; 106036503Speter } 106183651Speter return 0; 106236503Speter} 106336503Speter 106483651Speterint 106588091Siedowsenfsm_fhtom_xx(struct vnode *v, int v3, struct mbuf **mb, caddr_t *bpos) 106683651Speter{ 106788091Siedowse u_int32_t *tl; 106883651Speter int t1; 106983651Speter caddr_t cp; 107083651Speter 107183651Speter if (v3) { 107283651Speter t1 = nfsm_rndup(VTONFS(v)->n_fhsize) + NFSX_UNSIGNED; 107383651Speter if (t1 < M_TRAILINGSPACE(*mb)) { 107488091Siedowse tl = nfsm_build_xx(t1, mb, bpos); 107588091Siedowse *tl++ = txdr_unsigned(VTONFS(v)->n_fhsize); 107688091Siedowse *(tl + ((t1 >> 2) - 2)) = 0; 107788091Siedowse bcopy(VTONFS(v)->n_fhp, tl, VTONFS(v)->n_fhsize); 107883651Speter } else { 107983651Speter t1 = nfsm_strtmbuf(mb, bpos, 108083651Speter (const char *)VTONFS(v)->n_fhp, 108183651Speter VTONFS(v)->n_fhsize); 108283651Speter if (t1 != 0) 108383651Speter return t1; 108483651Speter } 108583651Speter } else { 108684002Speter cp = nfsm_build_xx(NFSX_V2FH, mb, bpos); 108783651Speter bcopy(VTONFS(v)->n_fhp, cp, NFSX_V2FH); 108883651Speter } 108983651Speter return 0; 109083651Speter} 109183651Speter 109236503Spetervoid 109388091Siedowsenfsm_v3attrbuild_xx(struct vattr *va, int full, struct mbuf **mb, 109488091Siedowse caddr_t *bpos) 109536503Speter{ 109688091Siedowse u_int32_t *tl; 109736503Speter 109883651Speter if (va->va_mode != (mode_t)VNOVAL) { 109988091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 110088091Siedowse *tl++ = nfs_true; 110188091Siedowse *tl = txdr_unsigned(va->va_mode); 110283651Speter } else { 110388091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 110488091Siedowse *tl = nfs_false; 110583651Speter } 110683651Speter if (full && va->va_uid != (uid_t)VNOVAL) { 110788091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 110888091Siedowse *tl++ = nfs_true; 110988091Siedowse *tl = txdr_unsigned(va->va_uid); 111083651Speter } else { 111188091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 111288091Siedowse *tl = nfs_false; 111383651Speter } 111483651Speter if (full && va->va_gid != (gid_t)VNOVAL) { 111588091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 111688091Siedowse *tl++ = nfs_true; 111788091Siedowse *tl = txdr_unsigned(va->va_gid); 111883651Speter } else { 111988091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 112088091Siedowse *tl = nfs_false; 112183651Speter } 112283651Speter if (full && va->va_size != VNOVAL) { 112388091Siedowse tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 112488091Siedowse *tl++ = nfs_true; 112588091Siedowse txdr_hyper(va->va_size, tl); 112683651Speter } else { 112788091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 112888091Siedowse *tl = nfs_false; 112983651Speter } 113083651Speter if (va->va_atime.tv_sec != VNOVAL) { 1131247502Sjhb if ((va->va_vaflags & VA_UTIMES_NULL) == 0) { 113288091Siedowse tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 113388091Siedowse *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 113488091Siedowse txdr_nfsv3time(&va->va_atime, tl); 113583651Speter } else { 113688091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 113788091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 113883651Speter } 113983651Speter } else { 114088091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 114188091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 114283651Speter } 114383651Speter if (va->va_mtime.tv_sec != VNOVAL) { 1144247502Sjhb if ((va->va_vaflags & VA_UTIMES_NULL) == 0) { 114588091Siedowse tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 114688091Siedowse *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 114788091Siedowse txdr_nfsv3time(&va->va_mtime, tl); 114883651Speter } else { 114988091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 115088091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 115183651Speter } 115283651Speter } else { 115388091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 115488091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 115583651Speter } 115636503Speter} 1157