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> 59251171Sjeff#include <sys/rwlock.h> 602997Swollman#include <sys/sysent.h> 612997Swollman#include <sys/syscall.h> 6283651Speter#include <sys/sysproto.h> 63212506Skib#include <sys/taskqueue.h> 641541Srgrimes 653305Sphk#include <vm/vm.h> 6612662Sdg#include <vm/vm_object.h> 6712662Sdg#include <vm/vm_extern.h> 6892783Sjeff#include <vm/uma.h> 693305Sphk 709336Sdfr#include <nfs/nfsproto.h> 7183651Speter#include <nfsclient/nfs.h> 7283651Speter#include <nfsclient/nfsnode.h> 73221543Srmacklem#include <nfs/nfs_kdtrace.h> 741541Srgrimes#include <nfs/xdr_subs.h> 7583651Speter#include <nfsclient/nfsm_subs.h> 7683651Speter#include <nfsclient/nfsmount.h> 771541Srgrimes 781541Srgrimes#include <netinet/in.h> 791541Srgrimes 801541Srgrimes/* 81158739Smohans * Note that stdarg.h and the ANSI style va_start macro is used for both 82158739Smohans * ANSI and traditional C compilers. 83158739Smohans */ 84158739Smohans#include <machine/stdarg.h> 85158739Smohans 86190380Srwatson#ifdef KDTRACE_HOOKS 87190380Srwatsondtrace_nfsclient_attrcache_flush_probe_func_t 88190380Srwatson dtrace_nfsclient_attrcache_flush_done_probe; 89190380Srwatsonuint32_t nfsclient_attrcache_flush_done_id; 90190380Srwatson 91190380Srwatsondtrace_nfsclient_attrcache_get_hit_probe_func_t 92190380Srwatson dtrace_nfsclient_attrcache_get_hit_probe; 93190380Srwatsonuint32_t nfsclient_attrcache_get_hit_id; 94190380Srwatson 95190380Srwatsondtrace_nfsclient_attrcache_get_miss_probe_func_t 96190380Srwatson dtrace_nfsclient_attrcache_get_miss_probe; 97190380Srwatsonuint32_t nfsclient_attrcache_get_miss_id; 98190380Srwatson 99190380Srwatsondtrace_nfsclient_attrcache_load_probe_func_t 100190380Srwatson dtrace_nfsclient_attrcache_load_done_probe; 101190380Srwatsonuint32_t nfsclient_attrcache_load_done_id; 102190380Srwatson#endif /* !KDTRACE_HOOKS */ 103190380Srwatson 104158739Smohans/* 1051541Srgrimes * Data items converted to xdr at startup, since they are constant 1061541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps 1071541Srgrimes */ 10883651Speteru_int32_t nfs_xdrneg1; 10983651Speteru_int32_t nfs_true, nfs_false; 1101541Srgrimes 1111541Srgrimes/* And other global data */ 112176224Sjhbstatic u_int32_t nfs_xid = 0; 11312911Sphkstatic enum vtype nv2tov_type[8]= { 11483651Speter VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON 11512911Sphk}; 11612911Sphk 11783651Speterint nfs_ticks; 11883651Speterint nfs_pbuf_freecnt = -1; /* start out unlimited */ 1199336Sdfr 12083651Speterstruct nfs_bufq nfs_bufq; 121176224Sjhbstatic struct mtx nfs_xid_mtx; 122212506Skibstruct task nfs_nfsiodnew_task; 1239759Sbde 1249336Sdfr/* 1259336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers 1269336Sdfr */ 1279336Sdfrint nfsv2_procid[NFS_NPROCS] = { 1289336Sdfr NFSV2PROC_NULL, 1299336Sdfr NFSV2PROC_GETATTR, 1309336Sdfr NFSV2PROC_SETATTR, 1319336Sdfr NFSV2PROC_LOOKUP, 1329336Sdfr NFSV2PROC_NOOP, 1339336Sdfr NFSV2PROC_READLINK, 1349336Sdfr NFSV2PROC_READ, 1359336Sdfr NFSV2PROC_WRITE, 1369336Sdfr NFSV2PROC_CREATE, 1379336Sdfr NFSV2PROC_MKDIR, 1389336Sdfr NFSV2PROC_SYMLINK, 1399336Sdfr NFSV2PROC_CREATE, 1409336Sdfr NFSV2PROC_REMOVE, 1419336Sdfr NFSV2PROC_RMDIR, 1429336Sdfr NFSV2PROC_RENAME, 1439336Sdfr NFSV2PROC_LINK, 1449336Sdfr NFSV2PROC_READDIR, 1459336Sdfr NFSV2PROC_NOOP, 1469336Sdfr NFSV2PROC_STATFS, 1479336Sdfr NFSV2PROC_NOOP, 1489336Sdfr NFSV2PROC_NOOP, 1499336Sdfr NFSV2PROC_NOOP, 1509336Sdfr NFSV2PROC_NOOP, 1519336Sdfr}; 1529336Sdfr 15360938SjakeLIST_HEAD(nfsnodehashhead, nfsnode); 1543664Sphk 155176224Sjhbu_int32_t 156176224Sjhbnfs_xid_gen(void) 157176224Sjhb{ 158176224Sjhb uint32_t xid; 159176224Sjhb 160176224Sjhb mtx_lock(&nfs_xid_mtx); 161176224Sjhb 162176224Sjhb /* Get a pretty random xid to start with */ 163176224Sjhb if (!nfs_xid) 164176224Sjhb nfs_xid = random(); 165176224Sjhb /* 166176224Sjhb * Skip zero xid if it should ever happen. 167176224Sjhb */ 168176224Sjhb if (++nfs_xid == 0) 169176224Sjhb nfs_xid++; 170176224Sjhb xid = nfs_xid; 171176224Sjhb mtx_unlock(&nfs_xid_mtx); 172176224Sjhb return xid; 173176224Sjhb} 174176224Sjhb 1751541Srgrimes/* 17617186Sdfr * copies a uio scatter/gather list to an mbuf chain. 17717186Sdfr * NOTE: can ony handle iovcnt == 1 1781541Srgrimes */ 1791549Srgrimesint 18083651Speternfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos) 1811541Srgrimes{ 18283651Speter char *uiocp; 18383651Speter struct mbuf *mp, *mp2; 18483651Speter int xfer, left, mlen; 1851541Srgrimes int uiosiz, clflg, rem; 1861541Srgrimes char *cp; 1871541Srgrimes 188209120Skib KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1")); 18917186Sdfr 1901541Srgrimes if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 1911541Srgrimes clflg = 1; 1921541Srgrimes else 1931541Srgrimes clflg = 0; 1941541Srgrimes rem = nfsm_rndup(siz)-siz; 1951541Srgrimes mp = mp2 = *mq; 1961541Srgrimes while (siz > 0) { 1971541Srgrimes left = uiop->uio_iov->iov_len; 1981541Srgrimes uiocp = uiop->uio_iov->iov_base; 1991541Srgrimes if (left > siz) 2001541Srgrimes left = siz; 2011541Srgrimes uiosiz = left; 2021541Srgrimes while (left > 0) { 2031541Srgrimes mlen = M_TRAILINGSPACE(mp); 2041541Srgrimes if (mlen == 0) { 2051541Srgrimes if (clflg) 206248198Sglebius mp = m_getcl(M_WAITOK, MT_DATA, 0); 207248198Sglebius else 208248198Sglebius mp = m_get(M_WAITOK, MT_DATA); 2091541Srgrimes mp2->m_next = mp; 2101541Srgrimes mp2 = mp; 2111541Srgrimes mlen = M_TRAILINGSPACE(mp); 2121541Srgrimes } 2131541Srgrimes xfer = (left > mlen) ? mlen : left; 2141541Srgrimes#ifdef notdef 2151541Srgrimes /* Not Yet.. */ 2161541Srgrimes if (uiop->uio_iov->iov_op != NULL) 2171541Srgrimes (*(uiop->uio_iov->iov_op)) 2181541Srgrimes (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 2191541Srgrimes else 2201541Srgrimes#endif 2211541Srgrimes if (uiop->uio_segflg == UIO_SYSSPACE) 2221541Srgrimes bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 2231541Srgrimes else 2241541Srgrimes copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 2251541Srgrimes mp->m_len += xfer; 2261541Srgrimes left -= xfer; 2271541Srgrimes uiocp += xfer; 2281541Srgrimes uiop->uio_offset += xfer; 2291541Srgrimes uiop->uio_resid -= xfer; 2301541Srgrimes } 231104908Smike uiop->uio_iov->iov_base = 232104908Smike (char *)uiop->uio_iov->iov_base + uiosiz; 23317186Sdfr uiop->uio_iov->iov_len -= uiosiz; 2341541Srgrimes siz -= uiosiz; 2351541Srgrimes } 2361541Srgrimes if (rem > 0) { 2371541Srgrimes if (rem > M_TRAILINGSPACE(mp)) { 238248198Sglebius mp = m_get(M_WAITOK, MT_DATA); 2391541Srgrimes mp2->m_next = mp; 2401541Srgrimes } 2411541Srgrimes cp = mtod(mp, caddr_t)+mp->m_len; 2421541Srgrimes for (left = 0; left < rem; left++) 2431541Srgrimes *cp++ = '\0'; 2441541Srgrimes mp->m_len += rem; 2451541Srgrimes *bpos = cp; 2461541Srgrimes } else 2471541Srgrimes *bpos = mtod(mp, caddr_t)+mp->m_len; 2481541Srgrimes *mq = mp; 2491541Srgrimes return (0); 2501541Srgrimes} 2511541Srgrimes 2521541Srgrimes/* 2531541Srgrimes * Copy a string into mbufs for the hard cases... 2541541Srgrimes */ 2551549Srgrimesint 25683651Speternfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz) 2571541Srgrimes{ 25883651Speter struct mbuf *m1 = NULL, *m2; 2591541Srgrimes long left, xfer, len, tlen; 26036541Speter u_int32_t *tl; 2611541Srgrimes int putsize; 2621541Srgrimes 2631541Srgrimes putsize = 1; 2641541Srgrimes m2 = *mb; 2651541Srgrimes left = M_TRAILINGSPACE(m2); 2661541Srgrimes if (left > 0) { 26736541Speter tl = ((u_int32_t *)(*bpos)); 2681541Srgrimes *tl++ = txdr_unsigned(siz); 2691541Srgrimes putsize = 0; 2701541Srgrimes left -= NFSX_UNSIGNED; 2711541Srgrimes m2->m_len += NFSX_UNSIGNED; 2721541Srgrimes if (left > 0) { 2731541Srgrimes bcopy(cp, (caddr_t) tl, left); 2741541Srgrimes siz -= left; 2751541Srgrimes cp += left; 2761541Srgrimes m2->m_len += left; 2771541Srgrimes left = 0; 2781541Srgrimes } 2791541Srgrimes } 2801541Srgrimes /* Loop around adding mbufs */ 2811541Srgrimes while (siz > 0) { 282248198Sglebius if (siz > MLEN) { 283248198Sglebius m1 = m_getcl(M_WAITOK, MT_DATA, 0); 284248198Sglebius m1->m_len = MCLBYTES; 285248198Sglebius } else { 286248198Sglebius m1 = m_get(M_WAITOK, MT_DATA); 287248198Sglebius m1->m_len = MLEN; 288248198Sglebius } 2891541Srgrimes m2->m_next = m1; 2901541Srgrimes m2 = m1; 29136541Speter tl = mtod(m1, u_int32_t *); 2921541Srgrimes tlen = 0; 2931541Srgrimes if (putsize) { 2941541Srgrimes *tl++ = txdr_unsigned(siz); 2951541Srgrimes m1->m_len -= NFSX_UNSIGNED; 2961541Srgrimes tlen = NFSX_UNSIGNED; 2971541Srgrimes putsize = 0; 2981541Srgrimes } 2991541Srgrimes if (siz < m1->m_len) { 3001541Srgrimes len = nfsm_rndup(siz); 3011541Srgrimes xfer = siz; 3021541Srgrimes if (xfer < len) 3031541Srgrimes *(tl+(xfer>>2)) = 0; 3041541Srgrimes } else { 3051541Srgrimes xfer = len = m1->m_len; 3061541Srgrimes } 3071541Srgrimes bcopy(cp, (caddr_t) tl, xfer); 3081541Srgrimes m1->m_len = len+tlen; 3091541Srgrimes siz -= xfer; 3101541Srgrimes cp += xfer; 3111541Srgrimes } 3121541Srgrimes *mb = m1; 3131541Srgrimes *bpos = mtod(m1, caddr_t)+m1->m_len; 3141541Srgrimes return (0); 3151541Srgrimes} 3161541Srgrimes 3171541Srgrimes/* 3181541Srgrimes * Called once to initialize data structures... 3191541Srgrimes */ 3201549Srgrimesint 32183651Speternfs_init(struct vfsconf *vfsp) 3221541Srgrimes{ 32383651Speter int i; 3241541Srgrimes 32592783Sjeff nfsmount_zone = uma_zcreate("NFSMOUNT", sizeof(struct nfsmount), 32692783Sjeff NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 3271541Srgrimes nfs_true = txdr_unsigned(TRUE); 3281541Srgrimes nfs_false = txdr_unsigned(FALSE); 3293664Sphk nfs_xdrneg1 = txdr_unsigned(-1); 3309336Sdfr nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 3319336Sdfr if (nfs_ticks < 1) 3329336Sdfr nfs_ticks = 1; 3331541Srgrimes /* Ensure async daemons disabled */ 33419449Sdfr for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 335203072Srmacklem nfs_iodwant[i] = NFSIOD_NOT_AVAILABLE; 33699797Sdillon nfs_iodmount[i] = NULL; 33719449Sdfr } 3381541Srgrimes nfs_nhinit(); /* Init the nfsnode table */ 3391541Srgrimes 3401541Srgrimes /* 3411541Srgrimes * Initialize reply list and start timer 3421541Srgrimes */ 343158739Smohans mtx_init(&nfs_iod_mtx, "NFS iod lock", NULL, MTX_DEF); 344172600Smohans mtx_init(&nfs_xid_mtx, "NFS xid lock", NULL, MTX_DEF); 345212506Skib TASK_INIT(&nfs_nfsiodnew_task, 0, nfs_nfsiodnew_tq, NULL); 34616365Sphk 34742957Sdillon nfs_pbuf_freecnt = nswbuf / 2 + 1; 34842957Sdillon 3491549Srgrimes return (0); 3501541Srgrimes} 3511541Srgrimes 35238894Sbdeint 35383651Speternfs_uninit(struct vfsconf *vfsp) 35438894Sbde{ 355128111Speadar int i; 35638894Sbde 357128111Speadar /* 358128111Speadar * Tell all nfsiod processes to exit. Clear nfs_iodmax, and wakeup 359128111Speadar * any sleeping nfsiods so they check nfs_iodmax and exit. 360212506Skib * Drain nfsiodnew task before we wait for them to finish. 361128111Speadar */ 362158739Smohans mtx_lock(&nfs_iod_mtx); 363128111Speadar nfs_iodmax = 0; 364212506Skib mtx_unlock(&nfs_iod_mtx); 365212506Skib taskqueue_drain(taskqueue_thread, &nfs_nfsiodnew_task); 366212506Skib mtx_lock(&nfs_iod_mtx); 367128111Speadar for (i = 0; i < nfs_numasync; i++) 368203072Srmacklem if (nfs_iodwant[i] == NFSIOD_AVAILABLE) 369128111Speadar wakeup(&nfs_iodwant[i]); 370128111Speadar /* The last nfsiod to exit will wake us up when nfs_numasync hits 0 */ 371128111Speadar while (nfs_numasync) 372158739Smohans msleep(&nfs_numasync, &nfs_iod_mtx, PWAIT, "ioddie", 0); 373158739Smohans mtx_unlock(&nfs_iod_mtx); 374128111Speadar nfs_nhuninit(); 375128111Speadar uma_zdestroy(nfsmount_zone); 37638894Sbde return (0); 37738894Sbde} 37838894Sbde 379158739Smohansvoid 380158739Smohansnfs_dircookie_lock(struct nfsnode *np) 381158739Smohans{ 382158739Smohans mtx_lock(&np->n_mtx); 383158739Smohans while (np->n_flag & NDIRCOOKIELK) 384158739Smohans (void) msleep(&np->n_flag, &np->n_mtx, PZERO, "nfsdirlk", 0); 385158739Smohans np->n_flag |= NDIRCOOKIELK; 386158739Smohans mtx_unlock(&np->n_mtx); 387158739Smohans} 388158739Smohans 389158739Smohansvoid 390158739Smohansnfs_dircookie_unlock(struct nfsnode *np) 391158739Smohans{ 392158739Smohans mtx_lock(&np->n_mtx); 393158739Smohans np->n_flag &= ~NDIRCOOKIELK; 394158739Smohans wakeup(&np->n_flag); 395158739Smohans mtx_unlock(&np->n_mtx); 396158739Smohans} 397158739Smohans 398158739Smohansint 399176134Sattilionfs_upgrade_vnlock(struct vnode *vp) 400158739Smohans{ 401158739Smohans int old_lock; 402196205Skib 403196205Skib ASSERT_VOP_LOCKED(vp, "nfs_upgrade_vnlock"); 404196205Skib old_lock = VOP_ISLOCKED(vp); 405196205Skib if (old_lock != LK_EXCLUSIVE) { 406196205Skib KASSERT(old_lock == LK_SHARED, 407196205Skib ("nfs_upgrade_vnlock: wrong old_lock %d", old_lock)); 408196205Skib /* Upgrade to exclusive lock, this might block */ 409196205Skib vn_lock(vp, LK_UPGRADE | LK_RETRY); 410158739Smohans } 411196205Skib return (old_lock); 412158739Smohans} 413158739Smohans 414158739Smohansvoid 415176134Sattilionfs_downgrade_vnlock(struct vnode *vp, int old_lock) 416158739Smohans{ 417158739Smohans if (old_lock != LK_EXCLUSIVE) { 418196205Skib KASSERT(old_lock == LK_SHARED, ("wrong old_lock %d", old_lock)); 419196205Skib /* Downgrade from exclusive lock. */ 420196205Skib vn_lock(vp, LK_DOWNGRADE | LK_RETRY); 421158739Smohans } 422158739Smohans} 423158739Smohans 424158739Smohansvoid 425158739Smohansnfs_printf(const char *fmt, ...) 426158739Smohans{ 427158739Smohans va_list ap; 428158739Smohans 429158739Smohans mtx_lock(&Giant); 430158739Smohans va_start(ap, fmt); 431220595Sru vprintf(fmt, ap); 432158739Smohans va_end(ap); 433158739Smohans mtx_unlock(&Giant); 434158739Smohans} 435158739Smohans 4361541Srgrimes/* 4371541Srgrimes * Attribute cache routines. 4381541Srgrimes * nfs_loadattrcache() - loads or updates the cache contents from attributes 4391541Srgrimes * that are on the mbuf list 4401541Srgrimes * nfs_getattrcache() - returns valid attributes if found in cache, returns 4411541Srgrimes * error otherwise 4421541Srgrimes */ 4431541Srgrimes 4441541Srgrimes/* 4451541Srgrimes * Load the attribute cache (that lives in the nfsnode entry) with 4461541Srgrimes * the values on the mbuf list and 4471541Srgrimes * Iff vap not NULL 4481541Srgrimes * copy the attributes to *vaper 4491541Srgrimes */ 4501549Srgrimesint 45183651Speternfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp, 452158739Smohans struct vattr *vaper, int dontshrink) 4531541Srgrimes{ 45483651Speter struct vnode *vp = *vpp; 45583651Speter struct vattr *vap; 45683651Speter struct nfs_fattr *fp; 457190380Srwatson struct nfsnode *np = NULL; 45883651Speter int32_t t1; 4599336Sdfr caddr_t cp2; 46084057Speter int rdev; 4611541Srgrimes struct mbuf *md; 4621541Srgrimes enum vtype vtyp; 4631541Srgrimes u_short vmode; 464171190Sjhb struct timespec mtime, mtime_save; 4659336Sdfr int v3 = NFS_ISV3(vp); 466190380Srwatson int error = 0; 467251089Srmacklem u_quad_t nsize; 468251089Srmacklem int setnsize; 4691541Srgrimes 4701541Srgrimes md = *mdp; 4719336Sdfr t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 472243882Sglebius cp2 = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, M_WAITOK); 473190380Srwatson if (cp2 == NULL) { 474190380Srwatson error = EBADRPC; 475190380Srwatson goto out; 476190380Srwatson } 4779336Sdfr fp = (struct nfs_fattr *)cp2; 4789336Sdfr if (v3) { 4799336Sdfr vtyp = nfsv3tov_type(fp->fa_type); 4809336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 481130640Sphk rdev = makedev(fxdr_unsigned(int, fp->fa3_rdev.specdata1), 48216634Sbde fxdr_unsigned(int, fp->fa3_rdev.specdata2)); 4839336Sdfr fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 4841541Srgrimes } else { 4859336Sdfr vtyp = nfsv2tov_type(fp->fa_type); 4869336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 4879336Sdfr /* 4889336Sdfr * XXX 4899336Sdfr * 4909336Sdfr * The duplicate information returned in fa_type and fa_mode 4919336Sdfr * is an ambiguity in the NFS version 2 protocol. 4929336Sdfr * 4939336Sdfr * VREG should be taken literally as a regular file. If a 4949336Sdfr * server intents to return some type information differently 4959336Sdfr * in the upper bits of the mode field (e.g. for sockets, or 4969336Sdfr * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we 4979336Sdfr * leave the examination of the mode bits even in the VREG 4989336Sdfr * case to avoid breakage for bogus servers, but we make sure 4999336Sdfr * that there are actually type bits set in the upper part of 5009336Sdfr * fa_mode (and failing that, trust the va_type field). 5019336Sdfr * 5029336Sdfr * NFSv3 cleared the issue, and requires fa_mode to not 5039336Sdfr * contain any type information (while also introduing sockets 5049336Sdfr * and FIFOs for fa_type). 5059336Sdfr */ 5069336Sdfr if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) 5079336Sdfr vtyp = IFTOVT(vmode); 50836541Speter rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); 5099336Sdfr fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 5109336Sdfr 5119336Sdfr /* 5129336Sdfr * Really ugly NFSv2 kludge. 5139336Sdfr */ 5149336Sdfr if (vtyp == VCHR && rdev == 0xffffffff) 5159336Sdfr vtyp = VFIFO; 5161541Srgrimes } 5179336Sdfr 5181541Srgrimes /* 5191541Srgrimes * If v_type == VNON it is a new node, so fill in the v_type, 5208876Srgrimes * n_mtime fields. Check to see if it represents a special 5211541Srgrimes * device, and if so, check for a possible alias. Once the 5221541Srgrimes * correct vnode has been obtained, fill in the rest of the 5231541Srgrimes * information. 5241541Srgrimes */ 5251541Srgrimes np = VTONFS(vp); 526158739Smohans mtx_lock(&np->n_mtx); 52710219Sdfr if (vp->v_type != vtyp) { 5289336Sdfr vp->v_type = vtyp; 529126851Sphk if (vp->v_type == VFIFO) 530138290Sphk vp->v_op = &nfs_fifoops; 531138473Sps np->n_mtime = mtime; 5321541Srgrimes } 5331541Srgrimes vap = &np->n_vattr; 5341541Srgrimes vap->va_type = vtyp; 5351541Srgrimes vap->va_mode = (vmode & 07777); 53647028Sphk vap->va_rdev = rdev; 537171190Sjhb mtime_save = vap->va_mtime; 5381541Srgrimes vap->va_mtime = mtime; 5391541Srgrimes vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 5409336Sdfr if (v3) { 5419336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 5429336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 5439336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 54447751Speter vap->va_size = fxdr_hyper(&fp->fa3_size); 5459336Sdfr vap->va_blocksize = NFS_FABLKSIZE; 54647751Speter vap->va_bytes = fxdr_hyper(&fp->fa3_used); 54736541Speter vap->va_fileid = fxdr_unsigned(int32_t, 54836541Speter fp->fa3_fileid.nfsuquad[1]); 5499336Sdfr fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 5509336Sdfr fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 5519336Sdfr vap->va_flags = 0; 5529336Sdfr vap->va_filerev = 0; 5531541Srgrimes } else { 5549336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 5559336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 5569336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 55736541Speter vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 55836541Speter vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 55947751Speter vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) 56036541Speter * NFS_FABLKSIZE; 56136541Speter vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); 5629336Sdfr fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 5631541Srgrimes vap->va_flags = 0; 56436541Speter vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, 56536541Speter fp->fa2_ctime.nfsv2_sec); 56618397Snate vap->va_ctime.tv_nsec = 0; 56783651Speter vap->va_gen = fxdr_unsigned(u_int32_t, fp->fa2_ctime.nfsv2_usec); 5681541Srgrimes vap->va_filerev = 0; 5691541Srgrimes } 57067486Sdwmalone np->n_attrstamp = time_second; 571251089Srmacklem setnsize = 0; 572251089Srmacklem nsize = 0; 5731541Srgrimes if (vap->va_size != np->n_size) { 5741541Srgrimes if (vap->va_type == VREG) { 57567486Sdwmalone if (dontshrink && vap->va_size < np->n_size) { 57667486Sdwmalone /* 57767486Sdwmalone * We've been told not to shrink the file; 57867486Sdwmalone * zero np->n_attrstamp to indicate that 57967486Sdwmalone * the attributes are stale. 58067486Sdwmalone */ 58167486Sdwmalone vap->va_size = np->n_size; 58267486Sdwmalone np->n_attrstamp = 0; 583190380Srwatson KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 584252673Srmacklem vnode_pager_setsize(vp, np->n_size); 58567486Sdwmalone } else if (np->n_flag & NMODIFIED) { 586128263Speadar /* 587128263Speadar * We've modified the file: Use the larger 588128263Speadar * of our size, and the server's size. 589128263Speadar */ 590128263Speadar if (vap->va_size < np->n_size) { 5911541Srgrimes vap->va_size = np->n_size; 592128263Speadar } else { 5931541Srgrimes np->n_size = vap->va_size; 594128263Speadar np->n_flag |= NSIZECHANGED; 595128263Speadar } 596252673Srmacklem vnode_pager_setsize(vp, np->n_size); 597252673Srmacklem } else if (vap->va_size < np->n_size) { 598252673Srmacklem /* 599252673Srmacklem * When shrinking the size, the call to 600252673Srmacklem * vnode_pager_setsize() cannot be done 601252673Srmacklem * with the mutex held, so delay it until 602252673Srmacklem * after the mtx_unlock call. 603252673Srmacklem */ 604252673Srmacklem nsize = np->n_size = vap->va_size; 605252673Srmacklem np->n_flag |= NSIZECHANGED; 606252673Srmacklem setnsize = 1; 60754480Sdillon } else { 6081541Srgrimes np->n_size = vap->va_size; 609128263Speadar np->n_flag |= NSIZECHANGED; 610252673Srmacklem vnode_pager_setsize(vp, np->n_size); 61154480Sdillon } 61254480Sdillon } else { 6131541Srgrimes np->n_size = vap->va_size; 61454480Sdillon } 6151541Srgrimes } 616171190Sjhb /* 617171190Sjhb * The following checks are added to prevent a race between (say) 618171190Sjhb * a READDIR+ and a WRITE. 619171190Sjhb * READDIR+, WRITE requests sent out. 620171190Sjhb * READDIR+ resp, WRITE resp received on client. 621171190Sjhb * However, the WRITE resp was handled before the READDIR+ resp 622171190Sjhb * causing the post op attrs from the write to be loaded first 623171190Sjhb * and the attrs from the READDIR+ to be loaded later. If this 624171190Sjhb * happens, we have stale attrs loaded into the attrcache. 625171190Sjhb * We detect this by for the mtime moving back. We invalidate the 626171190Sjhb * attrcache when this happens. 627171190Sjhb */ 628190380Srwatson if (timespeccmp(&mtime_save, &vap->va_mtime, >)) { 629171190Sjhb /* Size changed or mtime went backwards */ 630171190Sjhb np->n_attrstamp = 0; 631190380Srwatson KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 632190380Srwatson } 6331541Srgrimes if (vaper != NULL) { 6341541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 6351541Srgrimes if (np->n_flag & NCHG) { 6369336Sdfr if (np->n_flag & NACC) 6379336Sdfr vaper->va_atime = np->n_atim; 6389336Sdfr if (np->n_flag & NUPD) 6399336Sdfr vaper->va_mtime = np->n_mtim; 6401541Srgrimes } 6411541Srgrimes } 642190396Srwatson 643190396Srwatson#ifdef KDTRACE_HOOKS 644190396Srwatson if (np->n_attrstamp != 0) 645190396Srwatson KDTRACE_NFS_ATTRCACHE_LOAD_DONE(vp, &np->n_vattr, 0); 646190396Srwatson#endif 647158739Smohans mtx_unlock(&np->n_mtx); 648251089Srmacklem if (setnsize) 649251089Srmacklem vnode_pager_setsize(vp, nsize); 650190380Srwatsonout: 651190396Srwatson#ifdef KDTRACE_HOOKS 652190396Srwatson if (error) 653190396Srwatson KDTRACE_NFS_ATTRCACHE_LOAD_DONE(vp, NULL, error); 654190380Srwatson#endif 655190380Srwatson return (error); 6561541Srgrimes} 6571541Srgrimes 65836176Speter#ifdef NFS_ACDEBUG 65936176Speter#include <sys/sysctl.h> 660221973SrmacklemSYSCTL_DECL(_vfs_oldnfs); 66136176Speterstatic int nfs_acdebug; 662221973SrmacklemSYSCTL_INT(_vfs_oldnfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, 663220595Sru "Toggle acdebug (attribute cache debug) flag"); 66436176Speter#endif 66536176Speter 6661541Srgrimes/* 6671541Srgrimes * Check the time stamp 6681541Srgrimes * If the cache is valid, copy contents to *vap and return 0 6691541Srgrimes * otherwise return an error 6701541Srgrimes */ 6711549Srgrimesint 67283651Speternfs_getattrcache(struct vnode *vp, struct vattr *vaper) 6731541Srgrimes{ 67483651Speter struct nfsnode *np; 67583651Speter struct vattr *vap; 67636176Speter struct nfsmount *nmp; 67736176Speter int timeo; 678158739Smohans 67936176Speter np = VTONFS(vp); 68036176Speter vap = &np->n_vattr; 68136176Speter nmp = VFSTONFS(vp->v_mount); 682158739Smohans#ifdef NFS_ACDEBUG 683158739Smohans mtx_lock(&Giant); /* nfs_printf() */ 684158739Smohans#endif 685158739Smohans mtx_lock(&np->n_mtx); 68636176Speter /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */ 687138473Sps timeo = (time_second - np->n_mtime.tv_sec) / 10; 68836176Speter 68936176Speter#ifdef NFS_ACDEBUG 69036176Speter if (nfs_acdebug>1) 691158739Smohans nfs_printf("nfs_getattrcache: initial timeo = %d\n", timeo); 69236176Speter#endif 69336176Speter 69436176Speter if (vap->va_type == VDIR) { 69536176Speter if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin) 69636176Speter timeo = nmp->nm_acdirmin; 69736176Speter else if (timeo > nmp->nm_acdirmax) 69836176Speter timeo = nmp->nm_acdirmax; 69936176Speter } else { 70036176Speter if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin) 70136176Speter timeo = nmp->nm_acregmin; 70236176Speter else if (timeo > nmp->nm_acregmax) 70336176Speter timeo = nmp->nm_acregmax; 70436176Speter } 70536176Speter 70636176Speter#ifdef NFS_ACDEBUG 70736176Speter if (nfs_acdebug > 2) 708158739Smohans nfs_printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n", 709158739Smohans nmp->nm_acregmin, nmp->nm_acregmax, 710158739Smohans nmp->nm_acdirmin, nmp->nm_acdirmax); 71136176Speter 71236176Speter if (nfs_acdebug) 713158739Smohans nfs_printf("nfs_getattrcache: age = %d; final timeo = %d\n", 714158739Smohans (time_second - np->n_attrstamp), timeo); 71536176Speter#endif 71636176Speter 71736176Speter if ((time_second - np->n_attrstamp) >= timeo) { 7181541Srgrimes nfsstats.attrcache_misses++; 719158739Smohans mtx_unlock(&np->n_mtx); 720220595Sru#ifdef NFS_ACDEBUG 721220595Sru mtx_unlock(&Giant); /* nfs_printf() */ 722220595Sru#endif 723190380Srwatson KDTRACE_NFS_ATTRCACHE_GET_MISS(vp); 724190380Srwatson return (ENOENT); 7251541Srgrimes } 7261541Srgrimes nfsstats.attrcache_hits++; 7271541Srgrimes if (vap->va_size != np->n_size) { 7281541Srgrimes if (vap->va_type == VREG) { 7291541Srgrimes if (np->n_flag & NMODIFIED) { 7301541Srgrimes if (vap->va_size < np->n_size) 7311541Srgrimes vap->va_size = np->n_size; 7321541Srgrimes else 7331541Srgrimes np->n_size = vap->va_size; 73454480Sdillon } else { 7351541Srgrimes np->n_size = vap->va_size; 73654480Sdillon } 73741026Speter vnode_pager_setsize(vp, np->n_size); 73854480Sdillon } else { 7391541Srgrimes np->n_size = vap->va_size; 74054480Sdillon } 7411541Srgrimes } 7421541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 7431541Srgrimes if (np->n_flag & NCHG) { 7449336Sdfr if (np->n_flag & NACC) 7459336Sdfr vaper->va_atime = np->n_atim; 7469336Sdfr if (np->n_flag & NUPD) 7479336Sdfr vaper->va_mtime = np->n_mtim; 7481541Srgrimes } 749158739Smohans mtx_unlock(&np->n_mtx); 750158739Smohans#ifdef NFS_ACDEBUG 751158739Smohans mtx_unlock(&Giant); /* nfs_printf() */ 752158739Smohans#endif 753190380Srwatson KDTRACE_NFS_ATTRCACHE_GET_HIT(vp, vap); 7541541Srgrimes return (0); 7551541Srgrimes} 7561541Srgrimes 757190785Sjhb/* 758190785Sjhb * Purge all cached information about an NFS vnode including name 759190785Sjhb * cache entries, the attribute cache, and the access cache. This is 760190785Sjhb * called when an NFS request for a node fails with a stale 761190785Sjhb * filehandle. 762190785Sjhb */ 763190785Sjhbvoid 764190785Sjhbnfs_purgecache(struct vnode *vp) 765190785Sjhb{ 766190785Sjhb struct nfsnode *np; 767190785Sjhb int i; 768190785Sjhb 769190785Sjhb np = VTONFS(vp); 770190785Sjhb cache_purge(vp); 771190785Sjhb mtx_lock(&np->n_mtx); 772190785Sjhb np->n_attrstamp = 0; 773190785Sjhb KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 774190785Sjhb for (i = 0; i < NFS_ACCESSCACHESIZE; i++) 775190785Sjhb np->n_accesscache[i].stamp = 0; 776190785Sjhb KDTRACE_NFS_ACCESSCACHE_FLUSH_DONE(vp); 777190785Sjhb mtx_unlock(&np->n_mtx); 778190785Sjhb} 779190785Sjhb 78043305Sdillonstatic nfsuint64 nfs_nullcookie = { { 0, 0 } }; 7819336Sdfr/* 7829336Sdfr * This function finds the directory cookie that corresponds to the 7839336Sdfr * logical byte offset given. 7849336Sdfr */ 7859336Sdfrnfsuint64 * 78683651Speternfs_getcookie(struct nfsnode *np, off_t off, int add) 7879336Sdfr{ 78883651Speter struct nfsdmap *dp, *dp2; 78983651Speter int pos; 790158739Smohans nfsuint64 *retval = NULL; 791158739Smohans 79236979Sbde pos = (uoff_t)off / NFS_DIRBLKSIZ; 79336979Sbde if (pos == 0 || off < 0) { 794209120Skib KASSERT(!add, ("nfs getcookie add at <= 0")); 7959336Sdfr return (&nfs_nullcookie); 7969336Sdfr } 7979336Sdfr pos--; 79883651Speter dp = LIST_FIRST(&np->n_cookies); 7999336Sdfr if (!dp) { 8009336Sdfr if (add) { 801184205Sdes dp = malloc(sizeof (struct nfsdmap), 802111119Simp M_NFSDIROFF, M_WAITOK); 8039336Sdfr dp->ndm_eocookie = 0; 8049336Sdfr LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 8059336Sdfr } else 806158739Smohans goto out; 8079336Sdfr } 8089336Sdfr while (pos >= NFSNUMCOOKIES) { 8099336Sdfr pos -= NFSNUMCOOKIES; 81083651Speter if (LIST_NEXT(dp, ndm_list)) { 8119336Sdfr if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 812158739Smohans pos >= dp->ndm_eocookie) 813158739Smohans goto out; 81483651Speter dp = LIST_NEXT(dp, ndm_list); 8159336Sdfr } else if (add) { 816184205Sdes dp2 = malloc(sizeof (struct nfsdmap), 817111119Simp M_NFSDIROFF, M_WAITOK); 8189336Sdfr dp2->ndm_eocookie = 0; 8199336Sdfr LIST_INSERT_AFTER(dp, dp2, ndm_list); 8209336Sdfr dp = dp2; 8219336Sdfr } else 822158739Smohans goto out; 8239336Sdfr } 8249336Sdfr if (pos >= dp->ndm_eocookie) { 8259336Sdfr if (add) 8269336Sdfr dp->ndm_eocookie = pos + 1; 8279336Sdfr else 828158739Smohans goto out; 8299336Sdfr } 830158739Smohans retval = &dp->ndm_cookies[pos]; 831158739Smohansout: 832158739Smohans return (retval); 8339336Sdfr} 8349336Sdfr 8359336Sdfr/* 8369336Sdfr * Invalidate cached directory information, except for the actual directory 8379336Sdfr * blocks (which are invalidated separately). 8389336Sdfr * Done mainly to avoid the use of stale offset cookies. 8399336Sdfr */ 8409336Sdfrvoid 84183651Speternfs_invaldir(struct vnode *vp) 8429336Sdfr{ 84383651Speter struct nfsnode *np = VTONFS(vp); 8449336Sdfr 845209120Skib KASSERT(vp->v_type == VDIR, ("nfs: invaldir not dir")); 846158739Smohans nfs_dircookie_lock(np); 8479336Sdfr np->n_direofoffset = 0; 8489336Sdfr np->n_cookieverf.nfsuquad[0] = 0; 8499336Sdfr np->n_cookieverf.nfsuquad[1] = 0; 85083651Speter if (LIST_FIRST(&np->n_cookies)) 85183651Speter LIST_FIRST(&np->n_cookies)->ndm_eocookie = 0; 852158739Smohans nfs_dircookie_unlock(np); 8539336Sdfr} 8549336Sdfr 8559336Sdfr/* 8569336Sdfr * The write verifier has changed (probably due to a server reboot), so all 8579336Sdfr * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 8589336Sdfr * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 85954480Sdillon * and B_CLUSTEROK flags. Once done the new write verifier can be set for the 86054480Sdillon * mount point. 86154480Sdillon * 86283651Speter * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data 86354480Sdillon * writes are not clusterable. 8649336Sdfr */ 8659336Sdfrvoid 86683651Speternfs_clearcommit(struct mount *mp) 8679336Sdfr{ 86883651Speter struct vnode *vp, *nvp; 86983651Speter struct buf *bp, *nbp; 870177493Sjeff struct bufobj *bo; 8719336Sdfr 872234386Smckusick MNT_VNODE_FOREACH_ALL(vp, mp, nvp) { 873177493Sjeff bo = &vp->v_bufobj; 874177493Sjeff vholdl(vp); 875177493Sjeff VI_UNLOCK(vp); 876177493Sjeff BO_LOCK(bo); 877177493Sjeff TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { 878175486Sattilio if (!BUF_ISLOCKED(bp) && 87948225Smckusick (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) 8809336Sdfr == (B_DELWRI | B_NEEDCOMMIT)) 88154480Sdillon bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); 8829336Sdfr } 883177493Sjeff BO_UNLOCK(bo); 884177493Sjeff vdrop(vp); 8859336Sdfr } 8869336Sdfr} 8879336Sdfr 8889336Sdfr/* 88983651Speter * Helper functions for former macros. Some of these should be 89083651Speter * moved to their callers. 8919336Sdfr */ 89283651Speter 8935455Sdgint 89483651Speternfsm_mtofh_xx(struct vnode *d, struct vnode **v, int v3, int *f, 89588091Siedowse struct mbuf **md, caddr_t *dpos) 8969336Sdfr{ 89783651Speter struct nfsnode *ttnp; 89883651Speter struct vnode *ttvp; 89983651Speter nfsfh_t *ttfhp; 90088091Siedowse u_int32_t *tl; 90183651Speter int ttfhsize; 90283651Speter int t1; 9039336Sdfr 90483651Speter if (v3) { 90588091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 90688091Siedowse if (tl == NULL) 90784057Speter return EBADRPC; 90888091Siedowse *f = fxdr_unsigned(int, *tl); 90983651Speter } else 91083651Speter *f = 1; 91183651Speter if (*f) { 91288091Siedowse t1 = nfsm_getfh_xx(&ttfhp, &ttfhsize, (v3), md, dpos); 91383651Speter if (t1 != 0) 91483651Speter return t1; 915162288Smohans t1 = nfs_nget(d->v_mount, ttfhp, ttfhsize, &ttnp, LK_EXCLUSIVE); 91683651Speter if (t1 != 0) 91783651Speter return t1; 91883651Speter *v = NFSTOV(ttnp); 91983651Speter } 92083651Speter if (v3) { 92188091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 92288091Siedowse if (tl == NULL) 92384057Speter return EBADRPC; 92483651Speter if (*f) 92588091Siedowse *f = fxdr_unsigned(int, *tl); 92688091Siedowse else if (fxdr_unsigned(int, *tl)) 92788091Siedowse nfsm_adv_xx(NFSX_V3FATTR, md, dpos); 92883651Speter } 92983651Speter if (*f) { 93083651Speter ttvp = *v; 93199797Sdillon t1 = nfs_loadattrcache(&ttvp, md, dpos, NULL, 0); 93283651Speter if (t1) 93383651Speter return t1; 93483651Speter *v = ttvp; 93583651Speter } 93683651Speter return 0; 93783651Speter} 93883651Speter 93983651Speterint 94088091Siedowsenfsm_getfh_xx(nfsfh_t **f, int *s, int v3, struct mbuf **md, caddr_t *dpos) 94183651Speter{ 94288091Siedowse u_int32_t *tl; 94383651Speter 94483651Speter if (v3) { 94588091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 94688091Siedowse if (tl == NULL) 94784057Speter return EBADRPC; 94888091Siedowse *s = fxdr_unsigned(int, *tl); 94984057Speter if (*s <= 0 || *s > NFSX_V3FHMAX) 95083651Speter return EBADRPC; 95183651Speter } else 95283651Speter *s = NFSX_V2FH; 95384057Speter *f = nfsm_dissect_xx(nfsm_rndup(*s), md, dpos); 95484057Speter if (*f == NULL) 95584057Speter return EBADRPC; 95684057Speter else 95784057Speter return 0; 95883651Speter} 95983651Speter 96083651Speter 96183651Speterint 96288091Siedowsenfsm_loadattr_xx(struct vnode **v, struct vattr *va, struct mbuf **md, 963158739Smohans caddr_t *dpos) 96483651Speter{ 96583651Speter int t1; 96683651Speter 96783651Speter struct vnode *ttvp = *v; 96883651Speter t1 = nfs_loadattrcache(&ttvp, md, dpos, va, 0); 96983651Speter if (t1 != 0) 97083651Speter return t1; 97183651Speter *v = ttvp; 97283651Speter return 0; 97383651Speter} 97483651Speter 97583651Speterint 976230394Sjhbnfsm_postop_attr_xx(struct vnode **v, int *f, struct vattr *va, 977230394Sjhb struct mbuf **md, caddr_t *dpos) 97883651Speter{ 97988091Siedowse u_int32_t *tl; 98083651Speter int t1; 98183651Speter 98283651Speter struct vnode *ttvp = *v; 98388091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 98488091Siedowse if (tl == NULL) 98584057Speter return EBADRPC; 98688091Siedowse *f = fxdr_unsigned(int, *tl); 98783914Siedowse if (*f != 0) { 988230394Sjhb t1 = nfs_loadattrcache(&ttvp, md, dpos, va, 1); 98983651Speter if (t1 != 0) { 99083651Speter *f = 0; 99183651Speter return t1; 99283651Speter } 99383651Speter *v = ttvp; 9949336Sdfr } 99583651Speter return 0; 9969336Sdfr} 9979336Sdfr 9989336Sdfrint 99988091Siedowsenfsm_wcc_data_xx(struct vnode **v, int *f, struct mbuf **md, caddr_t *dpos) 100031886Sbde{ 100188091Siedowse u_int32_t *tl; 100283651Speter int ttattrf, ttretf = 0; 100383651Speter int t1; 10045455Sdg 100588091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 100688091Siedowse if (tl == NULL) 100784057Speter return EBADRPC; 100888091Siedowse if (*tl == nfs_true) { 100988091Siedowse tl = nfsm_dissect_xx(6 * NFSX_UNSIGNED, md, dpos); 101088091Siedowse if (tl == NULL) 101184057Speter return EBADRPC; 1012158739Smohans mtx_lock(&(VTONFS(*v))->n_mtx); 101383651Speter if (*f) 1014138473Sps ttretf = (VTONFS(*v)->n_mtime.tv_sec == fxdr_unsigned(u_int32_t, *(tl + 2)) && 1015138473Sps VTONFS(*v)->n_mtime.tv_nsec == fxdr_unsigned(u_int32_t, *(tl + 3))); 1016158739Smohans mtx_unlock(&(VTONFS(*v))->n_mtx); 101783651Speter } 1018230394Sjhb t1 = nfsm_postop_attr_xx(v, &ttattrf, NULL, md, dpos); 101983651Speter if (t1) 102083651Speter return t1; 102183651Speter if (*f) 102283651Speter *f = ttretf; 102383651Speter else 102483651Speter *f = ttattrf; 102583651Speter return 0; 10265455Sdg} 102736503Speter 102883651Speterint 102988091Siedowsenfsm_strtom_xx(const char *a, int s, int m, struct mbuf **mb, caddr_t *bpos) 103036503Speter{ 103188091Siedowse u_int32_t *tl; 103283651Speter int t1; 103336503Speter 103483651Speter if (s > m) 103583651Speter return ENAMETOOLONG; 103683651Speter t1 = nfsm_rndup(s) + NFSX_UNSIGNED; 103783651Speter if (t1 <= M_TRAILINGSPACE(*mb)) { 103888091Siedowse tl = nfsm_build_xx(t1, mb, bpos); 103988091Siedowse *tl++ = txdr_unsigned(s); 104088091Siedowse *(tl + ((t1 >> 2) - 2)) = 0; 104188091Siedowse bcopy(a, tl, s); 104283651Speter } else { 104383651Speter t1 = nfsm_strtmbuf(mb, bpos, a, s); 104483651Speter if (t1 != 0) 104583651Speter return t1; 104636503Speter } 104783651Speter return 0; 104836503Speter} 104936503Speter 105083651Speterint 105188091Siedowsenfsm_fhtom_xx(struct vnode *v, int v3, struct mbuf **mb, caddr_t *bpos) 105283651Speter{ 105388091Siedowse u_int32_t *tl; 105483651Speter int t1; 105583651Speter caddr_t cp; 105683651Speter 105783651Speter if (v3) { 105883651Speter t1 = nfsm_rndup(VTONFS(v)->n_fhsize) + NFSX_UNSIGNED; 105983651Speter if (t1 < M_TRAILINGSPACE(*mb)) { 106088091Siedowse tl = nfsm_build_xx(t1, mb, bpos); 106188091Siedowse *tl++ = txdr_unsigned(VTONFS(v)->n_fhsize); 106288091Siedowse *(tl + ((t1 >> 2) - 2)) = 0; 106388091Siedowse bcopy(VTONFS(v)->n_fhp, tl, VTONFS(v)->n_fhsize); 106483651Speter } else { 106583651Speter t1 = nfsm_strtmbuf(mb, bpos, 106683651Speter (const char *)VTONFS(v)->n_fhp, 106783651Speter VTONFS(v)->n_fhsize); 106883651Speter if (t1 != 0) 106983651Speter return t1; 107083651Speter } 107183651Speter } else { 107284002Speter cp = nfsm_build_xx(NFSX_V2FH, mb, bpos); 107383651Speter bcopy(VTONFS(v)->n_fhp, cp, NFSX_V2FH); 107483651Speter } 107583651Speter return 0; 107683651Speter} 107783651Speter 107836503Spetervoid 107988091Siedowsenfsm_v3attrbuild_xx(struct vattr *va, int full, struct mbuf **mb, 108088091Siedowse caddr_t *bpos) 108136503Speter{ 108288091Siedowse u_int32_t *tl; 108336503Speter 108483651Speter if (va->va_mode != (mode_t)VNOVAL) { 108588091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 108688091Siedowse *tl++ = nfs_true; 108788091Siedowse *tl = txdr_unsigned(va->va_mode); 108883651Speter } else { 108988091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 109088091Siedowse *tl = nfs_false; 109183651Speter } 109283651Speter if (full && va->va_uid != (uid_t)VNOVAL) { 109388091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 109488091Siedowse *tl++ = nfs_true; 109588091Siedowse *tl = txdr_unsigned(va->va_uid); 109683651Speter } else { 109788091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 109888091Siedowse *tl = nfs_false; 109983651Speter } 110083651Speter if (full && va->va_gid != (gid_t)VNOVAL) { 110188091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 110288091Siedowse *tl++ = nfs_true; 110388091Siedowse *tl = txdr_unsigned(va->va_gid); 110483651Speter } else { 110588091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 110688091Siedowse *tl = nfs_false; 110783651Speter } 110883651Speter if (full && va->va_size != VNOVAL) { 110988091Siedowse tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 111088091Siedowse *tl++ = nfs_true; 111188091Siedowse txdr_hyper(va->va_size, tl); 111283651Speter } else { 111388091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 111488091Siedowse *tl = nfs_false; 111583651Speter } 111683651Speter if (va->va_atime.tv_sec != VNOVAL) { 1117245508Sjhb if ((va->va_vaflags & VA_UTIMES_NULL) == 0) { 111888091Siedowse tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 111988091Siedowse *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 112088091Siedowse txdr_nfsv3time(&va->va_atime, tl); 112183651Speter } else { 112288091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 112388091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 112483651Speter } 112583651Speter } else { 112688091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 112788091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 112883651Speter } 112983651Speter if (va->va_mtime.tv_sec != VNOVAL) { 1130245508Sjhb if ((va->va_vaflags & VA_UTIMES_NULL) == 0) { 113188091Siedowse tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 113288091Siedowse *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 113388091Siedowse txdr_nfsv3time(&va->va_mtime, tl); 113483651Speter } else { 113588091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 113688091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 113783651Speter } 113883651Speter } else { 113988091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 114088091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 114183651Speter } 114236503Speter} 1143