nfs_subs.c revision 190380
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: head/sys/nfsclient/nfs_subs.c 190380 2009-03-24 17:14:34Z rwatson $"); 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> 621541Srgrimes 633305Sphk#include <vm/vm.h> 6412662Sdg#include <vm/vm_object.h> 6512662Sdg#include <vm/vm_extern.h> 6692783Sjeff#include <vm/uma.h> 673305Sphk 68122698Salfred#include <rpc/rpcclnt.h> 69122698Salfred 701541Srgrimes#include <nfs/rpcv2.h> 719336Sdfr#include <nfs/nfsproto.h> 7283651Speter#include <nfsclient/nfs.h> 7383651Speter#include <nfsclient/nfsnode.h> 74190380Srwatson#include <nfsclient/nfs_kdtrace.h> 751541Srgrimes#include <nfs/xdr_subs.h> 7683651Speter#include <nfsclient/nfsm_subs.h> 7783651Speter#include <nfsclient/nfsmount.h> 781541Srgrimes 791541Srgrimes#include <netinet/in.h> 801541Srgrimes 811541Srgrimes/* 82158739Smohans * Note that stdarg.h and the ANSI style va_start macro is used for both 83158739Smohans * ANSI and traditional C compilers. 84158739Smohans */ 85158739Smohans#include <machine/stdarg.h> 86158739Smohans 87190380Srwatson#ifdef KDTRACE_HOOKS 88190380Srwatsondtrace_nfsclient_attrcache_flush_probe_func_t 89190380Srwatson dtrace_nfsclient_attrcache_flush_done_probe; 90190380Srwatsonuint32_t nfsclient_attrcache_flush_done_id; 91190380Srwatson 92190380Srwatsondtrace_nfsclient_attrcache_get_hit_probe_func_t 93190380Srwatson dtrace_nfsclient_attrcache_get_hit_probe; 94190380Srwatsonuint32_t nfsclient_attrcache_get_hit_id; 95190380Srwatson 96190380Srwatsondtrace_nfsclient_attrcache_get_miss_probe_func_t 97190380Srwatson dtrace_nfsclient_attrcache_get_miss_probe; 98190380Srwatsonuint32_t nfsclient_attrcache_get_miss_id; 99190380Srwatson 100190380Srwatsondtrace_nfsclient_attrcache_load_probe_func_t 101190380Srwatson dtrace_nfsclient_attrcache_load_done_probe; 102190380Srwatsonuint32_t nfsclient_attrcache_load_done_id; 103190380Srwatson#endif /* !KDTRACE_HOOKS */ 104190380Srwatson 105158739Smohans/* 1061541Srgrimes * Data items converted to xdr at startup, since they are constant 1071541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps 1081541Srgrimes */ 10983651Speteru_int32_t nfs_xdrneg1; 11083651Speteru_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 11183651Speter rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 11283651Speteru_int32_t nfs_true, nfs_false; 1131541Srgrimes 1141541Srgrimes/* And other global data */ 115176224Sjhbstatic u_int32_t nfs_xid = 0; 11612911Sphkstatic enum vtype nv2tov_type[8]= { 11783651Speter VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON 11812911Sphk}; 11912911Sphk 12083651Speterint nfs_ticks; 12183651Speterint nfs_pbuf_freecnt = -1; /* start out unlimited */ 1229336Sdfr 123184588Sdfr#ifdef NFS_LEGACYRPC 12483651Speterstruct nfs_reqq nfs_reqq; 125138496Spsstruct mtx nfs_reqq_mtx; 126184588Sdfr#endif 12783651Speterstruct nfs_bufq nfs_bufq; 128176224Sjhbstatic struct mtx nfs_xid_mtx; 1299759Sbde 1309336Sdfr/* 1319336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers 1329336Sdfr */ 1339336Sdfrint nfsv2_procid[NFS_NPROCS] = { 1349336Sdfr NFSV2PROC_NULL, 1359336Sdfr NFSV2PROC_GETATTR, 1369336Sdfr NFSV2PROC_SETATTR, 1379336Sdfr NFSV2PROC_LOOKUP, 1389336Sdfr NFSV2PROC_NOOP, 1399336Sdfr NFSV2PROC_READLINK, 1409336Sdfr NFSV2PROC_READ, 1419336Sdfr NFSV2PROC_WRITE, 1429336Sdfr NFSV2PROC_CREATE, 1439336Sdfr NFSV2PROC_MKDIR, 1449336Sdfr NFSV2PROC_SYMLINK, 1459336Sdfr NFSV2PROC_CREATE, 1469336Sdfr NFSV2PROC_REMOVE, 1479336Sdfr NFSV2PROC_RMDIR, 1489336Sdfr NFSV2PROC_RENAME, 1499336Sdfr NFSV2PROC_LINK, 1509336Sdfr NFSV2PROC_READDIR, 1519336Sdfr NFSV2PROC_NOOP, 1529336Sdfr NFSV2PROC_STATFS, 1539336Sdfr NFSV2PROC_NOOP, 1549336Sdfr NFSV2PROC_NOOP, 1559336Sdfr NFSV2PROC_NOOP, 1569336Sdfr NFSV2PROC_NOOP, 1579336Sdfr}; 1589336Sdfr 15960938SjakeLIST_HEAD(nfsnodehashhead, nfsnode); 1603664Sphk 161176224Sjhbu_int32_t 162176224Sjhbnfs_xid_gen(void) 163176224Sjhb{ 164176224Sjhb uint32_t xid; 165176224Sjhb 166176224Sjhb mtx_lock(&nfs_xid_mtx); 167176224Sjhb 168176224Sjhb /* Get a pretty random xid to start with */ 169176224Sjhb if (!nfs_xid) 170176224Sjhb nfs_xid = random(); 171176224Sjhb /* 172176224Sjhb * Skip zero xid if it should ever happen. 173176224Sjhb */ 174176224Sjhb if (++nfs_xid == 0) 175176224Sjhb nfs_xid++; 176176224Sjhb xid = nfs_xid; 177176224Sjhb mtx_unlock(&nfs_xid_mtx); 178176224Sjhb return xid; 179176224Sjhb} 180176224Sjhb 1811541Srgrimes/* 1821541Srgrimes * Create the header for an rpc request packet 1831541Srgrimes * The hsiz is the size of the rest of the nfs request header. 1841541Srgrimes * (just used to decide if a cluster is a good idea) 1851541Srgrimes */ 1861541Srgrimesstruct mbuf * 18783651Speternfsm_reqhead(struct vnode *vp, u_long procid, int hsiz) 1881541Srgrimes{ 18983651Speter struct mbuf *mb; 1901541Srgrimes 191177599Sru MGET(mb, M_WAIT, MT_DATA); 1921541Srgrimes if (hsiz >= MINCLSIZE) 193177599Sru MCLGET(mb, M_WAIT); 1941541Srgrimes mb->m_len = 0; 1951541Srgrimes return (mb); 1961541Srgrimes} 1971541Srgrimes 1981541Srgrimes/* 1991541Srgrimes * Build the RPC header and fill in the authorization info. 2001541Srgrimes * The authorization string argument is only used when the credentials 2011541Srgrimes * come from outside of the kernel. 2021541Srgrimes * Returns the head of the mbuf list. 2031541Srgrimes */ 2041541Srgrimesstruct mbuf * 20583651Speternfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type, 20683651Speter int auth_len, struct mbuf *mrest, int mrest_len, struct mbuf **mbp, 207152652Srees u_int32_t **xidpp) 2081541Srgrimes{ 20983651Speter struct mbuf *mb; 21083651Speter u_int32_t *tl; 21183651Speter caddr_t bpos; 21283651Speter int i; 21383651Speter struct mbuf *mreq; 21483651Speter int grpsiz, authsiz; 2151541Srgrimes 2161541Srgrimes authsiz = nfsm_rndup(auth_len); 217177599Sru MGETHDR(mb, M_WAIT, MT_DATA); 2189336Sdfr if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { 219177599Sru MCLGET(mb, M_WAIT); 2209336Sdfr } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { 2219336Sdfr MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 2221541Srgrimes } else { 2239336Sdfr MH_ALIGN(mb, 8 * NFSX_UNSIGNED); 2241541Srgrimes } 2251541Srgrimes mb->m_len = 0; 2261541Srgrimes mreq = mb; 2271541Srgrimes bpos = mtod(mb, caddr_t); 2281541Srgrimes 2291541Srgrimes /* 2301541Srgrimes * First the RPC header. 2311541Srgrimes */ 23284002Speter tl = nfsm_build(u_int32_t *, 8 * NFSX_UNSIGNED); 23317186Sdfr 234152652Srees *xidpp = tl; 235176224Sjhb *tl++ = txdr_unsigned(nfs_xid_gen()); 2361541Srgrimes *tl++ = rpc_call; 2371541Srgrimes *tl++ = rpc_vers; 23883651Speter *tl++ = txdr_unsigned(NFS_PROG); 23983651Speter if (nmflag & NFSMNT_NFSV3) { 24083651Speter *tl++ = txdr_unsigned(NFS_VER3); 24183651Speter *tl++ = txdr_unsigned(procid); 2421541Srgrimes } else { 24383651Speter *tl++ = txdr_unsigned(NFS_VER2); 24483651Speter *tl++ = txdr_unsigned(nfsv2_procid[procid]); 2451541Srgrimes } 2461541Srgrimes 2471541Srgrimes /* 2481541Srgrimes * And then the authorization cred. 2491541Srgrimes */ 2501541Srgrimes *tl++ = txdr_unsigned(auth_type); 2511541Srgrimes *tl = txdr_unsigned(authsiz); 2521541Srgrimes switch (auth_type) { 2531541Srgrimes case RPCAUTH_UNIX: 25484002Speter tl = nfsm_build(u_int32_t *, auth_len); 2551541Srgrimes *tl++ = 0; /* stamp ?? */ 2561541Srgrimes *tl++ = 0; /* NULL hostname */ 2571541Srgrimes *tl++ = txdr_unsigned(cr->cr_uid); 2581541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[0]); 2591541Srgrimes grpsiz = (auth_len >> 2) - 5; 2601541Srgrimes *tl++ = txdr_unsigned(grpsiz); 2611541Srgrimes for (i = 1; i <= grpsiz; i++) 2621541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[i]); 2631541Srgrimes break; 26483651Speter } 2659336Sdfr 2669336Sdfr /* 2679336Sdfr * And the verifier... 2689336Sdfr */ 26984002Speter tl = nfsm_build(u_int32_t *, 2 * NFSX_UNSIGNED); 27083651Speter *tl++ = txdr_unsigned(RPCAUTH_NULL); 27183651Speter *tl = 0; 2721541Srgrimes mb->m_next = mrest; 2739336Sdfr mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; 27499797Sdillon mreq->m_pkthdr.rcvif = NULL; 2751541Srgrimes *mbp = mb; 2761541Srgrimes return (mreq); 2771541Srgrimes} 2781541Srgrimes 2791541Srgrimes/* 28017186Sdfr * copies a uio scatter/gather list to an mbuf chain. 28117186Sdfr * NOTE: can ony handle iovcnt == 1 2821541Srgrimes */ 2831549Srgrimesint 28483651Speternfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos) 2851541Srgrimes{ 28683651Speter char *uiocp; 28783651Speter struct mbuf *mp, *mp2; 28883651Speter int xfer, left, mlen; 2891541Srgrimes int uiosiz, clflg, rem; 2901541Srgrimes char *cp; 2911541Srgrimes 29236519Speter#ifdef DIAGNOSTIC 29317186Sdfr if (uiop->uio_iovcnt != 1) 29417186Sdfr panic("nfsm_uiotombuf: iovcnt != 1"); 29536519Speter#endif 29617186Sdfr 2971541Srgrimes if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 2981541Srgrimes clflg = 1; 2991541Srgrimes else 3001541Srgrimes clflg = 0; 3011541Srgrimes rem = nfsm_rndup(siz)-siz; 3021541Srgrimes mp = mp2 = *mq; 3031541Srgrimes while (siz > 0) { 3041541Srgrimes left = uiop->uio_iov->iov_len; 3051541Srgrimes uiocp = uiop->uio_iov->iov_base; 3061541Srgrimes if (left > siz) 3071541Srgrimes left = siz; 3081541Srgrimes uiosiz = left; 3091541Srgrimes while (left > 0) { 3101541Srgrimes mlen = M_TRAILINGSPACE(mp); 3111541Srgrimes if (mlen == 0) { 312177599Sru MGET(mp, M_WAIT, MT_DATA); 3131541Srgrimes if (clflg) 314177599Sru MCLGET(mp, M_WAIT); 3151541Srgrimes mp->m_len = 0; 3161541Srgrimes mp2->m_next = mp; 3171541Srgrimes mp2 = mp; 3181541Srgrimes mlen = M_TRAILINGSPACE(mp); 3191541Srgrimes } 3201541Srgrimes xfer = (left > mlen) ? mlen : left; 3211541Srgrimes#ifdef notdef 3221541Srgrimes /* Not Yet.. */ 3231541Srgrimes if (uiop->uio_iov->iov_op != NULL) 3241541Srgrimes (*(uiop->uio_iov->iov_op)) 3251541Srgrimes (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 3261541Srgrimes else 3271541Srgrimes#endif 3281541Srgrimes if (uiop->uio_segflg == UIO_SYSSPACE) 3291541Srgrimes bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 3301541Srgrimes else 3311541Srgrimes copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 3321541Srgrimes mp->m_len += xfer; 3331541Srgrimes left -= xfer; 3341541Srgrimes uiocp += xfer; 3351541Srgrimes uiop->uio_offset += xfer; 3361541Srgrimes uiop->uio_resid -= xfer; 3371541Srgrimes } 338104908Smike uiop->uio_iov->iov_base = 339104908Smike (char *)uiop->uio_iov->iov_base + uiosiz; 34017186Sdfr uiop->uio_iov->iov_len -= uiosiz; 3411541Srgrimes siz -= uiosiz; 3421541Srgrimes } 3431541Srgrimes if (rem > 0) { 3441541Srgrimes if (rem > M_TRAILINGSPACE(mp)) { 345177599Sru MGET(mp, M_WAIT, MT_DATA); 3461541Srgrimes mp->m_len = 0; 3471541Srgrimes mp2->m_next = mp; 3481541Srgrimes } 3491541Srgrimes cp = mtod(mp, caddr_t)+mp->m_len; 3501541Srgrimes for (left = 0; left < rem; left++) 3511541Srgrimes *cp++ = '\0'; 3521541Srgrimes mp->m_len += rem; 3531541Srgrimes *bpos = cp; 3541541Srgrimes } else 3551541Srgrimes *bpos = mtod(mp, caddr_t)+mp->m_len; 3561541Srgrimes *mq = mp; 3571541Srgrimes return (0); 3581541Srgrimes} 3591541Srgrimes 3601541Srgrimes/* 3611541Srgrimes * Copy a string into mbufs for the hard cases... 3621541Srgrimes */ 3631549Srgrimesint 36483651Speternfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz) 3651541Srgrimes{ 36683651Speter struct mbuf *m1 = NULL, *m2; 3671541Srgrimes long left, xfer, len, tlen; 36836541Speter u_int32_t *tl; 3691541Srgrimes int putsize; 3701541Srgrimes 3711541Srgrimes putsize = 1; 3721541Srgrimes m2 = *mb; 3731541Srgrimes left = M_TRAILINGSPACE(m2); 3741541Srgrimes if (left > 0) { 37536541Speter tl = ((u_int32_t *)(*bpos)); 3761541Srgrimes *tl++ = txdr_unsigned(siz); 3771541Srgrimes putsize = 0; 3781541Srgrimes left -= NFSX_UNSIGNED; 3791541Srgrimes m2->m_len += NFSX_UNSIGNED; 3801541Srgrimes if (left > 0) { 3811541Srgrimes bcopy(cp, (caddr_t) tl, left); 3821541Srgrimes siz -= left; 3831541Srgrimes cp += left; 3841541Srgrimes m2->m_len += left; 3851541Srgrimes left = 0; 3861541Srgrimes } 3871541Srgrimes } 3881541Srgrimes /* Loop around adding mbufs */ 3891541Srgrimes while (siz > 0) { 390177599Sru MGET(m1, M_WAIT, MT_DATA); 3911541Srgrimes if (siz > MLEN) 392177599Sru MCLGET(m1, M_WAIT); 3931541Srgrimes m1->m_len = NFSMSIZ(m1); 3941541Srgrimes m2->m_next = m1; 3951541Srgrimes m2 = m1; 39636541Speter tl = mtod(m1, u_int32_t *); 3971541Srgrimes tlen = 0; 3981541Srgrimes if (putsize) { 3991541Srgrimes *tl++ = txdr_unsigned(siz); 4001541Srgrimes m1->m_len -= NFSX_UNSIGNED; 4011541Srgrimes tlen = NFSX_UNSIGNED; 4021541Srgrimes putsize = 0; 4031541Srgrimes } 4041541Srgrimes if (siz < m1->m_len) { 4051541Srgrimes len = nfsm_rndup(siz); 4061541Srgrimes xfer = siz; 4071541Srgrimes if (xfer < len) 4081541Srgrimes *(tl+(xfer>>2)) = 0; 4091541Srgrimes } else { 4101541Srgrimes xfer = len = m1->m_len; 4111541Srgrimes } 4121541Srgrimes bcopy(cp, (caddr_t) tl, xfer); 4131541Srgrimes m1->m_len = len+tlen; 4141541Srgrimes siz -= xfer; 4151541Srgrimes cp += xfer; 4161541Srgrimes } 4171541Srgrimes *mb = m1; 4181541Srgrimes *bpos = mtod(m1, caddr_t)+m1->m_len; 4191541Srgrimes return (0); 4201541Srgrimes} 4211541Srgrimes 4221541Srgrimes/* 4231541Srgrimes * Called once to initialize data structures... 4241541Srgrimes */ 4251549Srgrimesint 42683651Speternfs_init(struct vfsconf *vfsp) 4271541Srgrimes{ 42883651Speter int i; 4291541Srgrimes 43092783Sjeff nfsmount_zone = uma_zcreate("NFSMOUNT", sizeof(struct nfsmount), 43192783Sjeff NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 4321541Srgrimes rpc_vers = txdr_unsigned(RPC_VER2); 4331541Srgrimes rpc_call = txdr_unsigned(RPC_CALL); 4341541Srgrimes rpc_reply = txdr_unsigned(RPC_REPLY); 4351541Srgrimes rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 4361541Srgrimes rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 4371541Srgrimes rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 4381541Srgrimes rpc_autherr = txdr_unsigned(RPC_AUTHERR); 4391541Srgrimes rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 4401541Srgrimes nfs_true = txdr_unsigned(TRUE); 4411541Srgrimes nfs_false = txdr_unsigned(FALSE); 4423664Sphk nfs_xdrneg1 = txdr_unsigned(-1); 4439336Sdfr nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 4449336Sdfr if (nfs_ticks < 1) 4459336Sdfr nfs_ticks = 1; 4461541Srgrimes /* Ensure async daemons disabled */ 44719449Sdfr for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 44899797Sdillon nfs_iodwant[i] = NULL; 44999797Sdillon nfs_iodmount[i] = NULL; 45019449Sdfr } 4511541Srgrimes nfs_nhinit(); /* Init the nfsnode table */ 4521541Srgrimes 4531541Srgrimes /* 4541541Srgrimes * Initialize reply list and start timer 4551541Srgrimes */ 456184588Sdfr#ifdef NFS_LEGACYRPC 4573664Sphk TAILQ_INIT(&nfs_reqq); 458184588Sdfr mtx_init(&nfs_reqq_mtx, "NFS reqq lock", NULL, MTX_DEF); 459148162Sps callout_init(&nfs_callout, CALLOUT_MPSAFE); 460184588Sdfr#endif 461158739Smohans mtx_init(&nfs_iod_mtx, "NFS iod lock", NULL, MTX_DEF); 462172600Smohans mtx_init(&nfs_xid_mtx, "NFS xid lock", NULL, MTX_DEF); 46316365Sphk 46442957Sdillon nfs_pbuf_freecnt = nswbuf / 2 + 1; 46542957Sdillon 4661549Srgrimes return (0); 4671541Srgrimes} 4681541Srgrimes 46938894Sbdeint 47083651Speternfs_uninit(struct vfsconf *vfsp) 47138894Sbde{ 472128111Speadar int i; 47338894Sbde 474184588Sdfr#ifdef NFS_LEGACYRPC 475127421Srees callout_stop(&nfs_callout); 476128111Speadar 477128126Smarcel KASSERT(TAILQ_EMPTY(&nfs_reqq), 478128111Speadar ("nfs_uninit: request queue not empty")); 479184588Sdfr#endif 480128111Speadar 481128111Speadar /* 482128111Speadar * Tell all nfsiod processes to exit. Clear nfs_iodmax, and wakeup 483128111Speadar * any sleeping nfsiods so they check nfs_iodmax and exit. 484128111Speadar */ 485158739Smohans mtx_lock(&nfs_iod_mtx); 486128111Speadar nfs_iodmax = 0; 487128111Speadar for (i = 0; i < nfs_numasync; i++) 488128111Speadar if (nfs_iodwant[i]) 489128111Speadar wakeup(&nfs_iodwant[i]); 490128111Speadar /* The last nfsiod to exit will wake us up when nfs_numasync hits 0 */ 491128111Speadar while (nfs_numasync) 492158739Smohans msleep(&nfs_numasync, &nfs_iod_mtx, PWAIT, "ioddie", 0); 493158739Smohans mtx_unlock(&nfs_iod_mtx); 494128111Speadar nfs_nhuninit(); 495128111Speadar uma_zdestroy(nfsmount_zone); 49638894Sbde return (0); 49738894Sbde} 49838894Sbde 499158739Smohansvoid 500158739Smohansnfs_dircookie_lock(struct nfsnode *np) 501158739Smohans{ 502158739Smohans mtx_lock(&np->n_mtx); 503158739Smohans while (np->n_flag & NDIRCOOKIELK) 504158739Smohans (void) msleep(&np->n_flag, &np->n_mtx, PZERO, "nfsdirlk", 0); 505158739Smohans np->n_flag |= NDIRCOOKIELK; 506158739Smohans mtx_unlock(&np->n_mtx); 507158739Smohans} 508158739Smohans 509158739Smohansvoid 510158739Smohansnfs_dircookie_unlock(struct nfsnode *np) 511158739Smohans{ 512158739Smohans mtx_lock(&np->n_mtx); 513158739Smohans np->n_flag &= ~NDIRCOOKIELK; 514158739Smohans wakeup(&np->n_flag); 515158739Smohans mtx_unlock(&np->n_mtx); 516158739Smohans} 517158739Smohans 518158739Smohansint 519176134Sattilionfs_upgrade_vnlock(struct vnode *vp) 520158739Smohans{ 521158739Smohans int old_lock; 522158739Smohans 523176559Sattilio if ((old_lock = VOP_ISLOCKED(vp)) != LK_EXCLUSIVE) { 524158739Smohans if (old_lock == LK_SHARED) { 525158739Smohans /* Upgrade to exclusive lock, this might block */ 526175202Sattilio vn_lock(vp, LK_UPGRADE | LK_RETRY); 527158739Smohans } else { 528175202Sattilio vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 529158739Smohans } 530158739Smohans } 531158739Smohans return old_lock; 532158739Smohans} 533158739Smohans 534158739Smohansvoid 535176134Sattilionfs_downgrade_vnlock(struct vnode *vp, int old_lock) 536158739Smohans{ 537158739Smohans if (old_lock != LK_EXCLUSIVE) { 538158739Smohans if (old_lock == LK_SHARED) { 539158739Smohans /* Downgrade from exclusive lock, this might block */ 540175202Sattilio vn_lock(vp, LK_DOWNGRADE); 541158739Smohans } else { 542175294Sattilio VOP_UNLOCK(vp, 0); 543158739Smohans } 544158739Smohans } 545158739Smohans} 546158739Smohans 547158739Smohansvoid 548158739Smohansnfs_printf(const char *fmt, ...) 549158739Smohans{ 550158739Smohans va_list ap; 551158739Smohans 552158739Smohans mtx_lock(&Giant); 553158739Smohans va_start(ap, fmt); 554158739Smohans printf(fmt, ap); 555158739Smohans va_end(ap); 556158739Smohans mtx_unlock(&Giant); 557158739Smohans} 558158739Smohans 5591541Srgrimes/* 5601541Srgrimes * Attribute cache routines. 5611541Srgrimes * nfs_loadattrcache() - loads or updates the cache contents from attributes 5621541Srgrimes * that are on the mbuf list 5631541Srgrimes * nfs_getattrcache() - returns valid attributes if found in cache, returns 5641541Srgrimes * error otherwise 5651541Srgrimes */ 5661541Srgrimes 5671541Srgrimes/* 5681541Srgrimes * Load the attribute cache (that lives in the nfsnode entry) with 5691541Srgrimes * the values on the mbuf list and 5701541Srgrimes * Iff vap not NULL 5711541Srgrimes * copy the attributes to *vaper 5721541Srgrimes */ 5731549Srgrimesint 57483651Speternfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp, 575158739Smohans struct vattr *vaper, int dontshrink) 5761541Srgrimes{ 57783651Speter struct vnode *vp = *vpp; 57883651Speter struct vattr *vap; 57983651Speter struct nfs_fattr *fp; 580190380Srwatson struct nfsnode *np = NULL; 58183651Speter int32_t t1; 5829336Sdfr caddr_t cp2; 58384057Speter int rdev; 5841541Srgrimes struct mbuf *md; 5851541Srgrimes enum vtype vtyp; 5861541Srgrimes u_short vmode; 587171190Sjhb struct timespec mtime, mtime_save; 5889336Sdfr int v3 = NFS_ISV3(vp); 589167352Smohans struct thread *td = curthread; 590190380Srwatson int error = 0; 5911541Srgrimes 5921541Srgrimes md = *mdp; 5939336Sdfr t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 594177599Sru cp2 = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, M_WAIT); 595190380Srwatson if (cp2 == NULL) { 596190380Srwatson error = EBADRPC; 597190380Srwatson goto out; 598190380Srwatson } 5999336Sdfr fp = (struct nfs_fattr *)cp2; 6009336Sdfr if (v3) { 6019336Sdfr vtyp = nfsv3tov_type(fp->fa_type); 6029336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 603130640Sphk rdev = makedev(fxdr_unsigned(int, fp->fa3_rdev.specdata1), 60416634Sbde fxdr_unsigned(int, fp->fa3_rdev.specdata2)); 6059336Sdfr fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 6061541Srgrimes } else { 6079336Sdfr vtyp = nfsv2tov_type(fp->fa_type); 6089336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 6099336Sdfr /* 6109336Sdfr * XXX 6119336Sdfr * 6129336Sdfr * The duplicate information returned in fa_type and fa_mode 6139336Sdfr * is an ambiguity in the NFS version 2 protocol. 6149336Sdfr * 6159336Sdfr * VREG should be taken literally as a regular file. If a 6169336Sdfr * server intents to return some type information differently 6179336Sdfr * in the upper bits of the mode field (e.g. for sockets, or 6189336Sdfr * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we 6199336Sdfr * leave the examination of the mode bits even in the VREG 6209336Sdfr * case to avoid breakage for bogus servers, but we make sure 6219336Sdfr * that there are actually type bits set in the upper part of 6229336Sdfr * fa_mode (and failing that, trust the va_type field). 6239336Sdfr * 6249336Sdfr * NFSv3 cleared the issue, and requires fa_mode to not 6259336Sdfr * contain any type information (while also introduing sockets 6269336Sdfr * and FIFOs for fa_type). 6279336Sdfr */ 6289336Sdfr if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) 6299336Sdfr vtyp = IFTOVT(vmode); 63036541Speter rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); 6319336Sdfr fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 6329336Sdfr 6339336Sdfr /* 6349336Sdfr * Really ugly NFSv2 kludge. 6359336Sdfr */ 6369336Sdfr if (vtyp == VCHR && rdev == 0xffffffff) 6379336Sdfr vtyp = VFIFO; 6381541Srgrimes } 6399336Sdfr 6401541Srgrimes /* 6411541Srgrimes * If v_type == VNON it is a new node, so fill in the v_type, 6428876Srgrimes * n_mtime fields. Check to see if it represents a special 6431541Srgrimes * device, and if so, check for a possible alias. Once the 6441541Srgrimes * correct vnode has been obtained, fill in the rest of the 6451541Srgrimes * information. 6461541Srgrimes */ 6471541Srgrimes np = VTONFS(vp); 648158739Smohans mtx_lock(&np->n_mtx); 64910219Sdfr if (vp->v_type != vtyp) { 6509336Sdfr vp->v_type = vtyp; 651126851Sphk if (vp->v_type == VFIFO) 652138290Sphk vp->v_op = &nfs_fifoops; 653138473Sps np->n_mtime = mtime; 6541541Srgrimes } 6551541Srgrimes vap = &np->n_vattr; 6561541Srgrimes vap->va_type = vtyp; 6571541Srgrimes vap->va_mode = (vmode & 07777); 65847028Sphk vap->va_rdev = rdev; 659171190Sjhb mtime_save = vap->va_mtime; 6601541Srgrimes vap->va_mtime = mtime; 6611541Srgrimes vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 6629336Sdfr if (v3) { 6639336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 6649336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 6659336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 66647751Speter vap->va_size = fxdr_hyper(&fp->fa3_size); 6679336Sdfr vap->va_blocksize = NFS_FABLKSIZE; 66847751Speter vap->va_bytes = fxdr_hyper(&fp->fa3_used); 66936541Speter vap->va_fileid = fxdr_unsigned(int32_t, 67036541Speter fp->fa3_fileid.nfsuquad[1]); 6719336Sdfr fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 6729336Sdfr fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 6739336Sdfr vap->va_flags = 0; 6749336Sdfr vap->va_filerev = 0; 6751541Srgrimes } else { 6769336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 6779336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 6789336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 67936541Speter vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 68036541Speter vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 68147751Speter vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) 68236541Speter * NFS_FABLKSIZE; 68336541Speter vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); 6849336Sdfr fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 6851541Srgrimes vap->va_flags = 0; 68636541Speter vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, 68736541Speter fp->fa2_ctime.nfsv2_sec); 68818397Snate vap->va_ctime.tv_nsec = 0; 68983651Speter vap->va_gen = fxdr_unsigned(u_int32_t, fp->fa2_ctime.nfsv2_usec); 6901541Srgrimes vap->va_filerev = 0; 6911541Srgrimes } 69267486Sdwmalone np->n_attrstamp = time_second; 693167352Smohans /* Timestamp the NFS otw getattr fetch */ 694167352Smohans if (td->td_proc) { 695167352Smohans np->n_ac_ts_tid = td->td_tid; 696167352Smohans np->n_ac_ts_pid = td->td_proc->p_pid; 697167352Smohans np->n_ac_ts_syscalls = td->td_syscalls; 698167352Smohans } else 699167352Smohans bzero(&np->n_ac_ts, sizeof(struct nfs_attrcache_timestamp)); 700167352Smohans 7011541Srgrimes if (vap->va_size != np->n_size) { 7021541Srgrimes if (vap->va_type == VREG) { 70367486Sdwmalone if (dontshrink && vap->va_size < np->n_size) { 70467486Sdwmalone /* 70567486Sdwmalone * We've been told not to shrink the file; 70667486Sdwmalone * zero np->n_attrstamp to indicate that 70767486Sdwmalone * the attributes are stale. 70867486Sdwmalone */ 70967486Sdwmalone vap->va_size = np->n_size; 71067486Sdwmalone np->n_attrstamp = 0; 711190380Srwatson KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 71267486Sdwmalone } else if (np->n_flag & NMODIFIED) { 713128263Speadar /* 714128263Speadar * We've modified the file: Use the larger 715128263Speadar * of our size, and the server's size. 716128263Speadar */ 717128263Speadar if (vap->va_size < np->n_size) { 7181541Srgrimes vap->va_size = np->n_size; 719128263Speadar } else { 7201541Srgrimes np->n_size = vap->va_size; 721128263Speadar np->n_flag |= NSIZECHANGED; 722128263Speadar } 72354480Sdillon } else { 7241541Srgrimes np->n_size = vap->va_size; 725128263Speadar np->n_flag |= NSIZECHANGED; 72654480Sdillon } 72741026Speter vnode_pager_setsize(vp, np->n_size); 72854480Sdillon } else { 7291541Srgrimes np->n_size = vap->va_size; 73054480Sdillon } 7311541Srgrimes } 732171190Sjhb /* 733171190Sjhb * The following checks are added to prevent a race between (say) 734171190Sjhb * a READDIR+ and a WRITE. 735171190Sjhb * READDIR+, WRITE requests sent out. 736171190Sjhb * READDIR+ resp, WRITE resp received on client. 737171190Sjhb * However, the WRITE resp was handled before the READDIR+ resp 738171190Sjhb * causing the post op attrs from the write to be loaded first 739171190Sjhb * and the attrs from the READDIR+ to be loaded later. If this 740171190Sjhb * happens, we have stale attrs loaded into the attrcache. 741171190Sjhb * We detect this by for the mtime moving back. We invalidate the 742171190Sjhb * attrcache when this happens. 743171190Sjhb */ 744190380Srwatson if (timespeccmp(&mtime_save, &vap->va_mtime, >)) { 745171190Sjhb /* Size changed or mtime went backwards */ 746171190Sjhb np->n_attrstamp = 0; 747190380Srwatson KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 748190380Srwatson } 7491541Srgrimes if (vaper != NULL) { 7501541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 7511541Srgrimes if (np->n_flag & NCHG) { 7529336Sdfr if (np->n_flag & NACC) 7539336Sdfr vaper->va_atime = np->n_atim; 7549336Sdfr if (np->n_flag & NUPD) 7559336Sdfr vaper->va_mtime = np->n_mtim; 7561541Srgrimes } 7571541Srgrimes } 758158739Smohans mtx_unlock(&np->n_mtx); 759190380Srwatsonout: 760190380Srwatson#ifdef KDRACE_HOOKS 761190380Srwatson if (np != NULL) 762190380Srwatson KDTRACE_NFS_ATTRCACHE_LOAD_DONE(vp, error == 0 ? &np->n_vattr 763190380Srwatson : NULL, error); 764190380Srwatson#endif 765190380Srwatson return (error); 7661541Srgrimes} 7671541Srgrimes 76836176Speter#ifdef NFS_ACDEBUG 76936176Speter#include <sys/sysctl.h> 77044101SbdeSYSCTL_DECL(_vfs_nfs); 77136176Speterstatic int nfs_acdebug; 772184561StrhodesSYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, 773184561Strhodes "Toggle acdebug (access cache debug) flag"); 77436176Speter#endif 77536176Speter 7761541Srgrimes/* 7771541Srgrimes * Check the time stamp 7781541Srgrimes * If the cache is valid, copy contents to *vap and return 0 7791541Srgrimes * otherwise return an error 7801541Srgrimes */ 7811549Srgrimesint 78283651Speternfs_getattrcache(struct vnode *vp, struct vattr *vaper) 7831541Srgrimes{ 78483651Speter struct nfsnode *np; 78583651Speter struct vattr *vap; 78636176Speter struct nfsmount *nmp; 78736176Speter int timeo; 788158739Smohans 78936176Speter np = VTONFS(vp); 79036176Speter vap = &np->n_vattr; 79136176Speter nmp = VFSTONFS(vp->v_mount); 792158739Smohans#ifdef NFS_ACDEBUG 793158739Smohans mtx_lock(&Giant); /* nfs_printf() */ 794158739Smohans#endif 795158739Smohans mtx_lock(&np->n_mtx); 79636176Speter /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */ 797138473Sps timeo = (time_second - np->n_mtime.tv_sec) / 10; 79836176Speter 79936176Speter#ifdef NFS_ACDEBUG 80036176Speter if (nfs_acdebug>1) 801158739Smohans nfs_printf("nfs_getattrcache: initial timeo = %d\n", timeo); 80236176Speter#endif 80336176Speter 80436176Speter if (vap->va_type == VDIR) { 80536176Speter if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin) 80636176Speter timeo = nmp->nm_acdirmin; 80736176Speter else if (timeo > nmp->nm_acdirmax) 80836176Speter timeo = nmp->nm_acdirmax; 80936176Speter } else { 81036176Speter if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin) 81136176Speter timeo = nmp->nm_acregmin; 81236176Speter else if (timeo > nmp->nm_acregmax) 81336176Speter timeo = nmp->nm_acregmax; 81436176Speter } 81536176Speter 81636176Speter#ifdef NFS_ACDEBUG 81736176Speter if (nfs_acdebug > 2) 818158739Smohans nfs_printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n", 819158739Smohans nmp->nm_acregmin, nmp->nm_acregmax, 820158739Smohans nmp->nm_acdirmin, nmp->nm_acdirmax); 82136176Speter 82236176Speter if (nfs_acdebug) 823158739Smohans nfs_printf("nfs_getattrcache: age = %d; final timeo = %d\n", 824158739Smohans (time_second - np->n_attrstamp), timeo); 82536176Speter#endif 82636176Speter 82736176Speter if ((time_second - np->n_attrstamp) >= timeo) { 8281541Srgrimes nfsstats.attrcache_misses++; 829158739Smohans mtx_unlock(&np->n_mtx); 830190380Srwatson KDTRACE_NFS_ATTRCACHE_GET_MISS(vp); 831190380Srwatson return (ENOENT); 8321541Srgrimes } 8331541Srgrimes nfsstats.attrcache_hits++; 8341541Srgrimes if (vap->va_size != np->n_size) { 8351541Srgrimes if (vap->va_type == VREG) { 8361541Srgrimes if (np->n_flag & NMODIFIED) { 8371541Srgrimes if (vap->va_size < np->n_size) 8381541Srgrimes vap->va_size = np->n_size; 8391541Srgrimes else 8401541Srgrimes np->n_size = vap->va_size; 84154480Sdillon } else { 8421541Srgrimes np->n_size = vap->va_size; 84354480Sdillon } 84441026Speter vnode_pager_setsize(vp, np->n_size); 84554480Sdillon } else { 8461541Srgrimes np->n_size = vap->va_size; 84754480Sdillon } 8481541Srgrimes } 8491541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 8501541Srgrimes if (np->n_flag & NCHG) { 8519336Sdfr if (np->n_flag & NACC) 8529336Sdfr vaper->va_atime = np->n_atim; 8539336Sdfr if (np->n_flag & NUPD) 8549336Sdfr vaper->va_mtime = np->n_mtim; 8551541Srgrimes } 856158739Smohans mtx_unlock(&np->n_mtx); 857158739Smohans#ifdef NFS_ACDEBUG 858158739Smohans mtx_unlock(&Giant); /* nfs_printf() */ 859158739Smohans#endif 860190380Srwatson KDTRACE_NFS_ATTRCACHE_GET_HIT(vp, vap); 8611541Srgrimes return (0); 8621541Srgrimes} 8631541Srgrimes 86443305Sdillonstatic nfsuint64 nfs_nullcookie = { { 0, 0 } }; 8659336Sdfr/* 8669336Sdfr * This function finds the directory cookie that corresponds to the 8679336Sdfr * logical byte offset given. 8689336Sdfr */ 8699336Sdfrnfsuint64 * 87083651Speternfs_getcookie(struct nfsnode *np, off_t off, int add) 8719336Sdfr{ 87283651Speter struct nfsdmap *dp, *dp2; 87383651Speter int pos; 874158739Smohans nfsuint64 *retval = NULL; 875158739Smohans 87636979Sbde pos = (uoff_t)off / NFS_DIRBLKSIZ; 87736979Sbde if (pos == 0 || off < 0) { 8789336Sdfr#ifdef DIAGNOSTIC 8799336Sdfr if (add) 88036979Sbde panic("nfs getcookie add at <= 0"); 8819336Sdfr#endif 8829336Sdfr return (&nfs_nullcookie); 8839336Sdfr } 8849336Sdfr pos--; 88583651Speter dp = LIST_FIRST(&np->n_cookies); 8869336Sdfr if (!dp) { 8879336Sdfr if (add) { 888184205Sdes dp = malloc(sizeof (struct nfsdmap), 889111119Simp M_NFSDIROFF, M_WAITOK); 8909336Sdfr dp->ndm_eocookie = 0; 8919336Sdfr LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 8929336Sdfr } else 893158739Smohans goto out; 8949336Sdfr } 8959336Sdfr while (pos >= NFSNUMCOOKIES) { 8969336Sdfr pos -= NFSNUMCOOKIES; 89783651Speter if (LIST_NEXT(dp, ndm_list)) { 8989336Sdfr if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 899158739Smohans pos >= dp->ndm_eocookie) 900158739Smohans goto out; 90183651Speter dp = LIST_NEXT(dp, ndm_list); 9029336Sdfr } else if (add) { 903184205Sdes dp2 = malloc(sizeof (struct nfsdmap), 904111119Simp M_NFSDIROFF, M_WAITOK); 9059336Sdfr dp2->ndm_eocookie = 0; 9069336Sdfr LIST_INSERT_AFTER(dp, dp2, ndm_list); 9079336Sdfr dp = dp2; 9089336Sdfr } else 909158739Smohans goto out; 9109336Sdfr } 9119336Sdfr if (pos >= dp->ndm_eocookie) { 9129336Sdfr if (add) 9139336Sdfr dp->ndm_eocookie = pos + 1; 9149336Sdfr else 915158739Smohans goto out; 9169336Sdfr } 917158739Smohans retval = &dp->ndm_cookies[pos]; 918158739Smohansout: 919158739Smohans return (retval); 9209336Sdfr} 9219336Sdfr 9229336Sdfr/* 9239336Sdfr * Invalidate cached directory information, except for the actual directory 9249336Sdfr * blocks (which are invalidated separately). 9259336Sdfr * Done mainly to avoid the use of stale offset cookies. 9269336Sdfr */ 9279336Sdfrvoid 92883651Speternfs_invaldir(struct vnode *vp) 9299336Sdfr{ 93083651Speter struct nfsnode *np = VTONFS(vp); 9319336Sdfr 9329336Sdfr#ifdef DIAGNOSTIC 9339336Sdfr if (vp->v_type != VDIR) 9349336Sdfr panic("nfs: invaldir not dir"); 9359336Sdfr#endif 936158739Smohans nfs_dircookie_lock(np); 9379336Sdfr np->n_direofoffset = 0; 9389336Sdfr np->n_cookieverf.nfsuquad[0] = 0; 9399336Sdfr np->n_cookieverf.nfsuquad[1] = 0; 94083651Speter if (LIST_FIRST(&np->n_cookies)) 94183651Speter LIST_FIRST(&np->n_cookies)->ndm_eocookie = 0; 942158739Smohans nfs_dircookie_unlock(np); 9439336Sdfr} 9449336Sdfr 9459336Sdfr/* 9469336Sdfr * The write verifier has changed (probably due to a server reboot), so all 9479336Sdfr * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 9489336Sdfr * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 94954480Sdillon * and B_CLUSTEROK flags. Once done the new write verifier can be set for the 95054480Sdillon * mount point. 95154480Sdillon * 95283651Speter * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data 95354480Sdillon * writes are not clusterable. 9549336Sdfr */ 9559336Sdfrvoid 95683651Speternfs_clearcommit(struct mount *mp) 9579336Sdfr{ 95883651Speter struct vnode *vp, *nvp; 95983651Speter struct buf *bp, *nbp; 960177493Sjeff struct bufobj *bo; 9619336Sdfr 962122091Skan MNT_ILOCK(mp); 963131551Sphk MNT_VNODE_FOREACH(vp, mp, nvp) { 964177493Sjeff bo = &vp->v_bufobj; 965103939Sjeff VI_LOCK(vp); 966143510Sjeff if (vp->v_iflag & VI_DOOMED) { 967120787Sjeff VI_UNLOCK(vp); 968120787Sjeff continue; 969120787Sjeff } 970177493Sjeff vholdl(vp); 971177493Sjeff VI_UNLOCK(vp); 972122091Skan MNT_IUNLOCK(mp); 973177493Sjeff BO_LOCK(bo); 974177493Sjeff TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { 975175486Sattilio if (!BUF_ISLOCKED(bp) && 97648225Smckusick (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) 9779336Sdfr == (B_DELWRI | B_NEEDCOMMIT)) 97854480Sdillon bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); 9799336Sdfr } 980177493Sjeff BO_UNLOCK(bo); 981177493Sjeff vdrop(vp); 982122091Skan MNT_ILOCK(mp); 9839336Sdfr } 984122091Skan MNT_IUNLOCK(mp); 9859336Sdfr} 9869336Sdfr 9879336Sdfr/* 98883651Speter * Helper functions for former macros. Some of these should be 98983651Speter * moved to their callers. 9909336Sdfr */ 99183651Speter 9925455Sdgint 99383651Speternfsm_mtofh_xx(struct vnode *d, struct vnode **v, int v3, int *f, 99488091Siedowse struct mbuf **md, caddr_t *dpos) 9959336Sdfr{ 99683651Speter struct nfsnode *ttnp; 99783651Speter struct vnode *ttvp; 99883651Speter nfsfh_t *ttfhp; 99988091Siedowse u_int32_t *tl; 100083651Speter int ttfhsize; 100183651Speter int t1; 10029336Sdfr 100383651Speter if (v3) { 100488091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 100588091Siedowse if (tl == NULL) 100684057Speter return EBADRPC; 100788091Siedowse *f = fxdr_unsigned(int, *tl); 100883651Speter } else 100983651Speter *f = 1; 101083651Speter if (*f) { 101188091Siedowse t1 = nfsm_getfh_xx(&ttfhp, &ttfhsize, (v3), md, dpos); 101283651Speter if (t1 != 0) 101383651Speter return t1; 1014162288Smohans t1 = nfs_nget(d->v_mount, ttfhp, ttfhsize, &ttnp, LK_EXCLUSIVE); 101583651Speter if (t1 != 0) 101683651Speter return t1; 101783651Speter *v = NFSTOV(ttnp); 101883651Speter } 101983651Speter if (v3) { 102088091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 102188091Siedowse if (tl == NULL) 102284057Speter return EBADRPC; 102383651Speter if (*f) 102488091Siedowse *f = fxdr_unsigned(int, *tl); 102588091Siedowse else if (fxdr_unsigned(int, *tl)) 102688091Siedowse nfsm_adv_xx(NFSX_V3FATTR, md, dpos); 102783651Speter } 102883651Speter if (*f) { 102983651Speter ttvp = *v; 103099797Sdillon t1 = nfs_loadattrcache(&ttvp, md, dpos, NULL, 0); 103183651Speter if (t1) 103283651Speter return t1; 103383651Speter *v = ttvp; 103483651Speter } 103583651Speter return 0; 103683651Speter} 103783651Speter 103883651Speterint 103988091Siedowsenfsm_getfh_xx(nfsfh_t **f, int *s, int v3, struct mbuf **md, caddr_t *dpos) 104083651Speter{ 104188091Siedowse u_int32_t *tl; 104283651Speter 104383651Speter if (v3) { 104488091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 104588091Siedowse if (tl == NULL) 104684057Speter return EBADRPC; 104788091Siedowse *s = fxdr_unsigned(int, *tl); 104884057Speter if (*s <= 0 || *s > NFSX_V3FHMAX) 104983651Speter return EBADRPC; 105083651Speter } else 105183651Speter *s = NFSX_V2FH; 105284057Speter *f = nfsm_dissect_xx(nfsm_rndup(*s), md, dpos); 105384057Speter if (*f == NULL) 105484057Speter return EBADRPC; 105584057Speter else 105684057Speter return 0; 105783651Speter} 105883651Speter 105983651Speter 106083651Speterint 106188091Siedowsenfsm_loadattr_xx(struct vnode **v, struct vattr *va, struct mbuf **md, 1062158739Smohans caddr_t *dpos) 106383651Speter{ 106483651Speter int t1; 106583651Speter 106683651Speter struct vnode *ttvp = *v; 106783651Speter t1 = nfs_loadattrcache(&ttvp, md, dpos, va, 0); 106883651Speter if (t1 != 0) 106983651Speter return t1; 107083651Speter *v = ttvp; 107183651Speter return 0; 107283651Speter} 107383651Speter 107483651Speterint 107588091Siedowsenfsm_postop_attr_xx(struct vnode **v, int *f, struct mbuf **md, 1076158739Smohans caddr_t *dpos) 107783651Speter{ 107888091Siedowse u_int32_t *tl; 107983651Speter int t1; 108083651Speter 108183651Speter struct vnode *ttvp = *v; 108288091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 108388091Siedowse if (tl == NULL) 108484057Speter return EBADRPC; 108588091Siedowse *f = fxdr_unsigned(int, *tl); 108683914Siedowse if (*f != 0) { 108799797Sdillon t1 = nfs_loadattrcache(&ttvp, md, dpos, NULL, 1); 108883651Speter if (t1 != 0) { 108983651Speter *f = 0; 109083651Speter return t1; 109183651Speter } 109283651Speter *v = ttvp; 10939336Sdfr } 109483651Speter return 0; 10959336Sdfr} 10969336Sdfr 10979336Sdfrint 109888091Siedowsenfsm_wcc_data_xx(struct vnode **v, int *f, struct mbuf **md, caddr_t *dpos) 109931886Sbde{ 110088091Siedowse u_int32_t *tl; 110183651Speter int ttattrf, ttretf = 0; 110283651Speter int t1; 11035455Sdg 110488091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 110588091Siedowse if (tl == NULL) 110684057Speter return EBADRPC; 110788091Siedowse if (*tl == nfs_true) { 110888091Siedowse tl = nfsm_dissect_xx(6 * NFSX_UNSIGNED, md, dpos); 110988091Siedowse if (tl == NULL) 111084057Speter return EBADRPC; 1111158739Smohans mtx_lock(&(VTONFS(*v))->n_mtx); 111283651Speter if (*f) 1113138473Sps ttretf = (VTONFS(*v)->n_mtime.tv_sec == fxdr_unsigned(u_int32_t, *(tl + 2)) && 1114138473Sps VTONFS(*v)->n_mtime.tv_nsec == fxdr_unsigned(u_int32_t, *(tl + 3))); 1115158739Smohans mtx_unlock(&(VTONFS(*v))->n_mtx); 111683651Speter } 111788091Siedowse t1 = nfsm_postop_attr_xx(v, &ttattrf, md, dpos); 111883651Speter if (t1) 111983651Speter return t1; 112083651Speter if (*f) 112183651Speter *f = ttretf; 112283651Speter else 112383651Speter *f = ttattrf; 112483651Speter return 0; 11255455Sdg} 112636503Speter 112783651Speterint 112888091Siedowsenfsm_strtom_xx(const char *a, int s, int m, struct mbuf **mb, caddr_t *bpos) 112936503Speter{ 113088091Siedowse u_int32_t *tl; 113183651Speter int t1; 113236503Speter 113383651Speter if (s > m) 113483651Speter return ENAMETOOLONG; 113583651Speter t1 = nfsm_rndup(s) + NFSX_UNSIGNED; 113683651Speter if (t1 <= M_TRAILINGSPACE(*mb)) { 113788091Siedowse tl = nfsm_build_xx(t1, mb, bpos); 113888091Siedowse *tl++ = txdr_unsigned(s); 113988091Siedowse *(tl + ((t1 >> 2) - 2)) = 0; 114088091Siedowse bcopy(a, tl, s); 114183651Speter } else { 114283651Speter t1 = nfsm_strtmbuf(mb, bpos, a, s); 114383651Speter if (t1 != 0) 114483651Speter return t1; 114536503Speter } 114683651Speter return 0; 114736503Speter} 114836503Speter 114983651Speterint 115088091Siedowsenfsm_fhtom_xx(struct vnode *v, int v3, struct mbuf **mb, caddr_t *bpos) 115183651Speter{ 115288091Siedowse u_int32_t *tl; 115383651Speter int t1; 115483651Speter caddr_t cp; 115583651Speter 115683651Speter if (v3) { 115783651Speter t1 = nfsm_rndup(VTONFS(v)->n_fhsize) + NFSX_UNSIGNED; 115883651Speter if (t1 < M_TRAILINGSPACE(*mb)) { 115988091Siedowse tl = nfsm_build_xx(t1, mb, bpos); 116088091Siedowse *tl++ = txdr_unsigned(VTONFS(v)->n_fhsize); 116188091Siedowse *(tl + ((t1 >> 2) - 2)) = 0; 116288091Siedowse bcopy(VTONFS(v)->n_fhp, tl, VTONFS(v)->n_fhsize); 116383651Speter } else { 116483651Speter t1 = nfsm_strtmbuf(mb, bpos, 116583651Speter (const char *)VTONFS(v)->n_fhp, 116683651Speter VTONFS(v)->n_fhsize); 116783651Speter if (t1 != 0) 116883651Speter return t1; 116983651Speter } 117083651Speter } else { 117184002Speter cp = nfsm_build_xx(NFSX_V2FH, mb, bpos); 117283651Speter bcopy(VTONFS(v)->n_fhp, cp, NFSX_V2FH); 117383651Speter } 117483651Speter return 0; 117583651Speter} 117683651Speter 117736503Spetervoid 117888091Siedowsenfsm_v3attrbuild_xx(struct vattr *va, int full, struct mbuf **mb, 117988091Siedowse caddr_t *bpos) 118036503Speter{ 118188091Siedowse u_int32_t *tl; 118236503Speter 118383651Speter if (va->va_mode != (mode_t)VNOVAL) { 118488091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 118588091Siedowse *tl++ = nfs_true; 118688091Siedowse *tl = txdr_unsigned(va->va_mode); 118783651Speter } else { 118888091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 118988091Siedowse *tl = nfs_false; 119083651Speter } 119183651Speter if (full && va->va_uid != (uid_t)VNOVAL) { 119288091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 119388091Siedowse *tl++ = nfs_true; 119488091Siedowse *tl = txdr_unsigned(va->va_uid); 119583651Speter } else { 119688091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 119788091Siedowse *tl = nfs_false; 119883651Speter } 119983651Speter if (full && va->va_gid != (gid_t)VNOVAL) { 120088091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 120188091Siedowse *tl++ = nfs_true; 120288091Siedowse *tl = txdr_unsigned(va->va_gid); 120383651Speter } else { 120488091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 120588091Siedowse *tl = nfs_false; 120683651Speter } 120783651Speter if (full && va->va_size != VNOVAL) { 120888091Siedowse tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 120988091Siedowse *tl++ = nfs_true; 121088091Siedowse txdr_hyper(va->va_size, tl); 121183651Speter } else { 121288091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 121388091Siedowse *tl = nfs_false; 121483651Speter } 121583651Speter if (va->va_atime.tv_sec != VNOVAL) { 121683651Speter if (va->va_atime.tv_sec != time_second) { 121788091Siedowse tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 121888091Siedowse *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 121988091Siedowse txdr_nfsv3time(&va->va_atime, tl); 122083651Speter } else { 122188091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 122288091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 122383651Speter } 122483651Speter } else { 122588091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 122688091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 122783651Speter } 122883651Speter if (va->va_mtime.tv_sec != VNOVAL) { 122983651Speter if (va->va_mtime.tv_sec != time_second) { 123088091Siedowse tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 123188091Siedowse *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 123288091Siedowse txdr_nfsv3time(&va->va_mtime, tl); 123383651Speter } else { 123488091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 123588091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 123683651Speter } 123783651Speter } else { 123888091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 123988091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 124083651Speter } 124136503Speter} 1242