nfs_subs.c revision 177599
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 177599 2008-03-25 09:39:02Z ru $"); 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 441541Srgrimes#include <sys/param.h> 4548274Speter#include <sys/systm.h> 4648274Speter#include <sys/kernel.h> 4760041Sphk#include <sys/bio.h> 4831886Sbde#include <sys/buf.h> 491541Srgrimes#include <sys/proc.h> 501541Srgrimes#include <sys/mount.h> 511541Srgrimes#include <sys/vnode.h> 521541Srgrimes#include <sys/namei.h> 531541Srgrimes#include <sys/mbuf.h> 541541Srgrimes#include <sys/socket.h> 551541Srgrimes#include <sys/stat.h> 569336Sdfr#include <sys/malloc.h> 572997Swollman#include <sys/sysent.h> 582997Swollman#include <sys/syscall.h> 5983651Speter#include <sys/sysproto.h> 601541Srgrimes 613305Sphk#include <vm/vm.h> 6212662Sdg#include <vm/vm_object.h> 6312662Sdg#include <vm/vm_extern.h> 6492783Sjeff#include <vm/uma.h> 653305Sphk 66122698Salfred#include <rpc/rpcclnt.h> 67122698Salfred 681541Srgrimes#include <nfs/rpcv2.h> 699336Sdfr#include <nfs/nfsproto.h> 7083651Speter#include <nfsclient/nfs.h> 7183651Speter#include <nfsclient/nfsnode.h> 721541Srgrimes#include <nfs/xdr_subs.h> 7383651Speter#include <nfsclient/nfsm_subs.h> 7483651Speter#include <nfsclient/nfsmount.h> 751541Srgrimes 761541Srgrimes#include <netinet/in.h> 771541Srgrimes 781541Srgrimes/* 79158739Smohans * Note that stdarg.h and the ANSI style va_start macro is used for both 80158739Smohans * ANSI and traditional C compilers. 81158739Smohans */ 82158739Smohans#include <machine/stdarg.h> 83158739Smohans 84158739Smohans/* 851541Srgrimes * Data items converted to xdr at startup, since they are constant 861541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps 871541Srgrimes */ 8883651Speteru_int32_t nfs_xdrneg1; 8983651Speteru_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 9083651Speter rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 9183651Speteru_int32_t nfs_true, nfs_false; 921541Srgrimes 931541Srgrimes/* And other global data */ 94176224Sjhbstatic u_int32_t nfs_xid = 0; 9512911Sphkstatic enum vtype nv2tov_type[8]= { 9683651Speter VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON 9712911Sphk}; 9812911Sphk 9983651Speterint nfs_ticks; 10083651Speterint nfs_pbuf_freecnt = -1; /* start out unlimited */ 1019336Sdfr 10283651Speterstruct nfs_reqq nfs_reqq; 103138496Spsstruct mtx nfs_reqq_mtx; 10483651Speterstruct nfs_bufq nfs_bufq; 105176224Sjhbstatic struct mtx nfs_xid_mtx; 1069759Sbde 1079336Sdfr/* 1089336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers 1099336Sdfr */ 1109336Sdfrint nfsv2_procid[NFS_NPROCS] = { 1119336Sdfr NFSV2PROC_NULL, 1129336Sdfr NFSV2PROC_GETATTR, 1139336Sdfr NFSV2PROC_SETATTR, 1149336Sdfr NFSV2PROC_LOOKUP, 1159336Sdfr NFSV2PROC_NOOP, 1169336Sdfr NFSV2PROC_READLINK, 1179336Sdfr NFSV2PROC_READ, 1189336Sdfr NFSV2PROC_WRITE, 1199336Sdfr NFSV2PROC_CREATE, 1209336Sdfr NFSV2PROC_MKDIR, 1219336Sdfr NFSV2PROC_SYMLINK, 1229336Sdfr NFSV2PROC_CREATE, 1239336Sdfr NFSV2PROC_REMOVE, 1249336Sdfr NFSV2PROC_RMDIR, 1259336Sdfr NFSV2PROC_RENAME, 1269336Sdfr NFSV2PROC_LINK, 1279336Sdfr NFSV2PROC_READDIR, 1289336Sdfr NFSV2PROC_NOOP, 1299336Sdfr NFSV2PROC_STATFS, 1309336Sdfr NFSV2PROC_NOOP, 1319336Sdfr NFSV2PROC_NOOP, 1329336Sdfr NFSV2PROC_NOOP, 1339336Sdfr NFSV2PROC_NOOP, 1349336Sdfr}; 1359336Sdfr 13660938SjakeLIST_HEAD(nfsnodehashhead, nfsnode); 1373664Sphk 138176224Sjhbu_int32_t 139176224Sjhbnfs_xid_gen(void) 140176224Sjhb{ 141176224Sjhb uint32_t xid; 142176224Sjhb 143176224Sjhb mtx_lock(&nfs_xid_mtx); 144176224Sjhb 145176224Sjhb /* Get a pretty random xid to start with */ 146176224Sjhb if (!nfs_xid) 147176224Sjhb nfs_xid = random(); 148176224Sjhb /* 149176224Sjhb * Skip zero xid if it should ever happen. 150176224Sjhb */ 151176224Sjhb if (++nfs_xid == 0) 152176224Sjhb nfs_xid++; 153176224Sjhb xid = nfs_xid; 154176224Sjhb mtx_unlock(&nfs_xid_mtx); 155176224Sjhb return xid; 156176224Sjhb} 157176224Sjhb 1581541Srgrimes/* 1591541Srgrimes * Create the header for an rpc request packet 1601541Srgrimes * The hsiz is the size of the rest of the nfs request header. 1611541Srgrimes * (just used to decide if a cluster is a good idea) 1621541Srgrimes */ 1631541Srgrimesstruct mbuf * 16483651Speternfsm_reqhead(struct vnode *vp, u_long procid, int hsiz) 1651541Srgrimes{ 16683651Speter struct mbuf *mb; 1671541Srgrimes 168177599Sru MGET(mb, M_WAIT, MT_DATA); 1691541Srgrimes if (hsiz >= MINCLSIZE) 170177599Sru MCLGET(mb, M_WAIT); 1711541Srgrimes mb->m_len = 0; 1721541Srgrimes return (mb); 1731541Srgrimes} 1741541Srgrimes 1751541Srgrimes/* 1761541Srgrimes * Build the RPC header and fill in the authorization info. 1771541Srgrimes * The authorization string argument is only used when the credentials 1781541Srgrimes * come from outside of the kernel. 1791541Srgrimes * Returns the head of the mbuf list. 1801541Srgrimes */ 1811541Srgrimesstruct mbuf * 18283651Speternfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type, 18383651Speter int auth_len, struct mbuf *mrest, int mrest_len, struct mbuf **mbp, 184152652Srees u_int32_t **xidpp) 1851541Srgrimes{ 18683651Speter struct mbuf *mb; 18783651Speter u_int32_t *tl; 18883651Speter caddr_t bpos; 18983651Speter int i; 19083651Speter struct mbuf *mreq; 19183651Speter int grpsiz, authsiz; 1921541Srgrimes 1931541Srgrimes authsiz = nfsm_rndup(auth_len); 194177599Sru MGETHDR(mb, M_WAIT, MT_DATA); 1959336Sdfr if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { 196177599Sru MCLGET(mb, M_WAIT); 1979336Sdfr } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { 1989336Sdfr MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 1991541Srgrimes } else { 2009336Sdfr MH_ALIGN(mb, 8 * NFSX_UNSIGNED); 2011541Srgrimes } 2021541Srgrimes mb->m_len = 0; 2031541Srgrimes mreq = mb; 2041541Srgrimes bpos = mtod(mb, caddr_t); 2051541Srgrimes 2061541Srgrimes /* 2071541Srgrimes * First the RPC header. 2081541Srgrimes */ 20984002Speter tl = nfsm_build(u_int32_t *, 8 * NFSX_UNSIGNED); 21017186Sdfr 211152652Srees *xidpp = tl; 212176224Sjhb *tl++ = txdr_unsigned(nfs_xid_gen()); 2131541Srgrimes *tl++ = rpc_call; 2141541Srgrimes *tl++ = rpc_vers; 21583651Speter *tl++ = txdr_unsigned(NFS_PROG); 21683651Speter if (nmflag & NFSMNT_NFSV3) { 21783651Speter *tl++ = txdr_unsigned(NFS_VER3); 21883651Speter *tl++ = txdr_unsigned(procid); 2191541Srgrimes } else { 22083651Speter *tl++ = txdr_unsigned(NFS_VER2); 22183651Speter *tl++ = txdr_unsigned(nfsv2_procid[procid]); 2221541Srgrimes } 2231541Srgrimes 2241541Srgrimes /* 2251541Srgrimes * And then the authorization cred. 2261541Srgrimes */ 2271541Srgrimes *tl++ = txdr_unsigned(auth_type); 2281541Srgrimes *tl = txdr_unsigned(authsiz); 2291541Srgrimes switch (auth_type) { 2301541Srgrimes case RPCAUTH_UNIX: 23184002Speter tl = nfsm_build(u_int32_t *, auth_len); 2321541Srgrimes *tl++ = 0; /* stamp ?? */ 2331541Srgrimes *tl++ = 0; /* NULL hostname */ 2341541Srgrimes *tl++ = txdr_unsigned(cr->cr_uid); 2351541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[0]); 2361541Srgrimes grpsiz = (auth_len >> 2) - 5; 2371541Srgrimes *tl++ = txdr_unsigned(grpsiz); 2381541Srgrimes for (i = 1; i <= grpsiz; i++) 2391541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[i]); 2401541Srgrimes break; 24183651Speter } 2429336Sdfr 2439336Sdfr /* 2449336Sdfr * And the verifier... 2459336Sdfr */ 24684002Speter tl = nfsm_build(u_int32_t *, 2 * NFSX_UNSIGNED); 24783651Speter *tl++ = txdr_unsigned(RPCAUTH_NULL); 24883651Speter *tl = 0; 2491541Srgrimes mb->m_next = mrest; 2509336Sdfr mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; 25199797Sdillon mreq->m_pkthdr.rcvif = NULL; 2521541Srgrimes *mbp = mb; 2531541Srgrimes return (mreq); 2541541Srgrimes} 2551541Srgrimes 2561541Srgrimes/* 25717186Sdfr * copies a uio scatter/gather list to an mbuf chain. 25817186Sdfr * NOTE: can ony handle iovcnt == 1 2591541Srgrimes */ 2601549Srgrimesint 26183651Speternfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos) 2621541Srgrimes{ 26383651Speter char *uiocp; 26483651Speter struct mbuf *mp, *mp2; 26583651Speter int xfer, left, mlen; 2661541Srgrimes int uiosiz, clflg, rem; 2671541Srgrimes char *cp; 2681541Srgrimes 26936519Speter#ifdef DIAGNOSTIC 27017186Sdfr if (uiop->uio_iovcnt != 1) 27117186Sdfr panic("nfsm_uiotombuf: iovcnt != 1"); 27236519Speter#endif 27317186Sdfr 2741541Srgrimes if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 2751541Srgrimes clflg = 1; 2761541Srgrimes else 2771541Srgrimes clflg = 0; 2781541Srgrimes rem = nfsm_rndup(siz)-siz; 2791541Srgrimes mp = mp2 = *mq; 2801541Srgrimes while (siz > 0) { 2811541Srgrimes left = uiop->uio_iov->iov_len; 2821541Srgrimes uiocp = uiop->uio_iov->iov_base; 2831541Srgrimes if (left > siz) 2841541Srgrimes left = siz; 2851541Srgrimes uiosiz = left; 2861541Srgrimes while (left > 0) { 2871541Srgrimes mlen = M_TRAILINGSPACE(mp); 2881541Srgrimes if (mlen == 0) { 289177599Sru MGET(mp, M_WAIT, MT_DATA); 2901541Srgrimes if (clflg) 291177599Sru MCLGET(mp, M_WAIT); 2921541Srgrimes mp->m_len = 0; 2931541Srgrimes mp2->m_next = mp; 2941541Srgrimes mp2 = mp; 2951541Srgrimes mlen = M_TRAILINGSPACE(mp); 2961541Srgrimes } 2971541Srgrimes xfer = (left > mlen) ? mlen : left; 2981541Srgrimes#ifdef notdef 2991541Srgrimes /* Not Yet.. */ 3001541Srgrimes if (uiop->uio_iov->iov_op != NULL) 3011541Srgrimes (*(uiop->uio_iov->iov_op)) 3021541Srgrimes (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 3031541Srgrimes else 3041541Srgrimes#endif 3051541Srgrimes if (uiop->uio_segflg == UIO_SYSSPACE) 3061541Srgrimes bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 3071541Srgrimes else 3081541Srgrimes copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 3091541Srgrimes mp->m_len += xfer; 3101541Srgrimes left -= xfer; 3111541Srgrimes uiocp += xfer; 3121541Srgrimes uiop->uio_offset += xfer; 3131541Srgrimes uiop->uio_resid -= xfer; 3141541Srgrimes } 315104908Smike uiop->uio_iov->iov_base = 316104908Smike (char *)uiop->uio_iov->iov_base + uiosiz; 31717186Sdfr uiop->uio_iov->iov_len -= uiosiz; 3181541Srgrimes siz -= uiosiz; 3191541Srgrimes } 3201541Srgrimes if (rem > 0) { 3211541Srgrimes if (rem > M_TRAILINGSPACE(mp)) { 322177599Sru MGET(mp, M_WAIT, MT_DATA); 3231541Srgrimes mp->m_len = 0; 3241541Srgrimes mp2->m_next = mp; 3251541Srgrimes } 3261541Srgrimes cp = mtod(mp, caddr_t)+mp->m_len; 3271541Srgrimes for (left = 0; left < rem; left++) 3281541Srgrimes *cp++ = '\0'; 3291541Srgrimes mp->m_len += rem; 3301541Srgrimes *bpos = cp; 3311541Srgrimes } else 3321541Srgrimes *bpos = mtod(mp, caddr_t)+mp->m_len; 3331541Srgrimes *mq = mp; 3341541Srgrimes return (0); 3351541Srgrimes} 3361541Srgrimes 3371541Srgrimes/* 3381541Srgrimes * Copy a string into mbufs for the hard cases... 3391541Srgrimes */ 3401549Srgrimesint 34183651Speternfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz) 3421541Srgrimes{ 34383651Speter struct mbuf *m1 = NULL, *m2; 3441541Srgrimes long left, xfer, len, tlen; 34536541Speter u_int32_t *tl; 3461541Srgrimes int putsize; 3471541Srgrimes 3481541Srgrimes putsize = 1; 3491541Srgrimes m2 = *mb; 3501541Srgrimes left = M_TRAILINGSPACE(m2); 3511541Srgrimes if (left > 0) { 35236541Speter tl = ((u_int32_t *)(*bpos)); 3531541Srgrimes *tl++ = txdr_unsigned(siz); 3541541Srgrimes putsize = 0; 3551541Srgrimes left -= NFSX_UNSIGNED; 3561541Srgrimes m2->m_len += NFSX_UNSIGNED; 3571541Srgrimes if (left > 0) { 3581541Srgrimes bcopy(cp, (caddr_t) tl, left); 3591541Srgrimes siz -= left; 3601541Srgrimes cp += left; 3611541Srgrimes m2->m_len += left; 3621541Srgrimes left = 0; 3631541Srgrimes } 3641541Srgrimes } 3651541Srgrimes /* Loop around adding mbufs */ 3661541Srgrimes while (siz > 0) { 367177599Sru MGET(m1, M_WAIT, MT_DATA); 3681541Srgrimes if (siz > MLEN) 369177599Sru MCLGET(m1, M_WAIT); 3701541Srgrimes m1->m_len = NFSMSIZ(m1); 3711541Srgrimes m2->m_next = m1; 3721541Srgrimes m2 = m1; 37336541Speter tl = mtod(m1, u_int32_t *); 3741541Srgrimes tlen = 0; 3751541Srgrimes if (putsize) { 3761541Srgrimes *tl++ = txdr_unsigned(siz); 3771541Srgrimes m1->m_len -= NFSX_UNSIGNED; 3781541Srgrimes tlen = NFSX_UNSIGNED; 3791541Srgrimes putsize = 0; 3801541Srgrimes } 3811541Srgrimes if (siz < m1->m_len) { 3821541Srgrimes len = nfsm_rndup(siz); 3831541Srgrimes xfer = siz; 3841541Srgrimes if (xfer < len) 3851541Srgrimes *(tl+(xfer>>2)) = 0; 3861541Srgrimes } else { 3871541Srgrimes xfer = len = m1->m_len; 3881541Srgrimes } 3891541Srgrimes bcopy(cp, (caddr_t) tl, xfer); 3901541Srgrimes m1->m_len = len+tlen; 3911541Srgrimes siz -= xfer; 3921541Srgrimes cp += xfer; 3931541Srgrimes } 3941541Srgrimes *mb = m1; 3951541Srgrimes *bpos = mtod(m1, caddr_t)+m1->m_len; 3961541Srgrimes return (0); 3971541Srgrimes} 3981541Srgrimes 3991541Srgrimes/* 4001541Srgrimes * Called once to initialize data structures... 4011541Srgrimes */ 4021549Srgrimesint 40383651Speternfs_init(struct vfsconf *vfsp) 4041541Srgrimes{ 40583651Speter int i; 4061541Srgrimes 40792783Sjeff nfsmount_zone = uma_zcreate("NFSMOUNT", sizeof(struct nfsmount), 40892783Sjeff NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 4091541Srgrimes rpc_vers = txdr_unsigned(RPC_VER2); 4101541Srgrimes rpc_call = txdr_unsigned(RPC_CALL); 4111541Srgrimes rpc_reply = txdr_unsigned(RPC_REPLY); 4121541Srgrimes rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 4131541Srgrimes rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 4141541Srgrimes rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 4151541Srgrimes rpc_autherr = txdr_unsigned(RPC_AUTHERR); 4161541Srgrimes rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 4171541Srgrimes nfs_true = txdr_unsigned(TRUE); 4181541Srgrimes nfs_false = txdr_unsigned(FALSE); 4193664Sphk nfs_xdrneg1 = txdr_unsigned(-1); 4209336Sdfr nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 4219336Sdfr if (nfs_ticks < 1) 4229336Sdfr nfs_ticks = 1; 4231541Srgrimes /* Ensure async daemons disabled */ 42419449Sdfr for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 42599797Sdillon nfs_iodwant[i] = NULL; 42699797Sdillon nfs_iodmount[i] = NULL; 42719449Sdfr } 4281541Srgrimes nfs_nhinit(); /* Init the nfsnode table */ 4291541Srgrimes 4301541Srgrimes /* 4311541Srgrimes * Initialize reply list and start timer 4321541Srgrimes */ 4333664Sphk TAILQ_INIT(&nfs_reqq); 434148162Sps callout_init(&nfs_callout, CALLOUT_MPSAFE); 435138496Sps mtx_init(&nfs_reqq_mtx, "NFS reqq lock", NULL, MTX_DEF); 436158739Smohans mtx_init(&nfs_iod_mtx, "NFS iod lock", NULL, MTX_DEF); 437172600Smohans mtx_init(&nfs_xid_mtx, "NFS xid lock", NULL, MTX_DEF); 43816365Sphk 43942957Sdillon nfs_pbuf_freecnt = nswbuf / 2 + 1; 44042957Sdillon 4411549Srgrimes return (0); 4421541Srgrimes} 4431541Srgrimes 44438894Sbdeint 44583651Speternfs_uninit(struct vfsconf *vfsp) 44638894Sbde{ 447128111Speadar int i; 44838894Sbde 449127421Srees callout_stop(&nfs_callout); 450128111Speadar 451128126Smarcel KASSERT(TAILQ_EMPTY(&nfs_reqq), 452128111Speadar ("nfs_uninit: request queue not empty")); 453128111Speadar 454128111Speadar /* 455128111Speadar * Tell all nfsiod processes to exit. Clear nfs_iodmax, and wakeup 456128111Speadar * any sleeping nfsiods so they check nfs_iodmax and exit. 457128111Speadar */ 458158739Smohans mtx_lock(&nfs_iod_mtx); 459128111Speadar nfs_iodmax = 0; 460128111Speadar for (i = 0; i < nfs_numasync; i++) 461128111Speadar if (nfs_iodwant[i]) 462128111Speadar wakeup(&nfs_iodwant[i]); 463128111Speadar /* The last nfsiod to exit will wake us up when nfs_numasync hits 0 */ 464128111Speadar while (nfs_numasync) 465158739Smohans msleep(&nfs_numasync, &nfs_iod_mtx, PWAIT, "ioddie", 0); 466158739Smohans mtx_unlock(&nfs_iod_mtx); 467128111Speadar nfs_nhuninit(); 468128111Speadar uma_zdestroy(nfsmount_zone); 46938894Sbde return (0); 47038894Sbde} 47138894Sbde 472158739Smohansvoid 473158739Smohansnfs_dircookie_lock(struct nfsnode *np) 474158739Smohans{ 475158739Smohans mtx_lock(&np->n_mtx); 476158739Smohans while (np->n_flag & NDIRCOOKIELK) 477158739Smohans (void) msleep(&np->n_flag, &np->n_mtx, PZERO, "nfsdirlk", 0); 478158739Smohans np->n_flag |= NDIRCOOKIELK; 479158739Smohans mtx_unlock(&np->n_mtx); 480158739Smohans} 481158739Smohans 482158739Smohansvoid 483158739Smohansnfs_dircookie_unlock(struct nfsnode *np) 484158739Smohans{ 485158739Smohans mtx_lock(&np->n_mtx); 486158739Smohans np->n_flag &= ~NDIRCOOKIELK; 487158739Smohans wakeup(&np->n_flag); 488158739Smohans mtx_unlock(&np->n_mtx); 489158739Smohans} 490158739Smohans 491158739Smohansint 492176134Sattilionfs_upgrade_vnlock(struct vnode *vp) 493158739Smohans{ 494158739Smohans int old_lock; 495158739Smohans 496176559Sattilio if ((old_lock = VOP_ISLOCKED(vp)) != LK_EXCLUSIVE) { 497158739Smohans if (old_lock == LK_SHARED) { 498158739Smohans /* Upgrade to exclusive lock, this might block */ 499175202Sattilio vn_lock(vp, LK_UPGRADE | LK_RETRY); 500158739Smohans } else { 501175202Sattilio vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 502158739Smohans } 503158739Smohans } 504158739Smohans return old_lock; 505158739Smohans} 506158739Smohans 507158739Smohansvoid 508176134Sattilionfs_downgrade_vnlock(struct vnode *vp, int old_lock) 509158739Smohans{ 510158739Smohans if (old_lock != LK_EXCLUSIVE) { 511158739Smohans if (old_lock == LK_SHARED) { 512158739Smohans /* Downgrade from exclusive lock, this might block */ 513175202Sattilio vn_lock(vp, LK_DOWNGRADE); 514158739Smohans } else { 515175294Sattilio VOP_UNLOCK(vp, 0); 516158739Smohans } 517158739Smohans } 518158739Smohans} 519158739Smohans 520158739Smohansvoid 521158739Smohansnfs_printf(const char *fmt, ...) 522158739Smohans{ 523158739Smohans va_list ap; 524158739Smohans 525158739Smohans mtx_lock(&Giant); 526158739Smohans va_start(ap, fmt); 527158739Smohans printf(fmt, ap); 528158739Smohans va_end(ap); 529158739Smohans mtx_unlock(&Giant); 530158739Smohans} 531158739Smohans 5321541Srgrimes/* 5331541Srgrimes * Attribute cache routines. 5341541Srgrimes * nfs_loadattrcache() - loads or updates the cache contents from attributes 5351541Srgrimes * that are on the mbuf list 5361541Srgrimes * nfs_getattrcache() - returns valid attributes if found in cache, returns 5371541Srgrimes * error otherwise 5381541Srgrimes */ 5391541Srgrimes 5401541Srgrimes/* 5411541Srgrimes * Load the attribute cache (that lives in the nfsnode entry) with 5421541Srgrimes * the values on the mbuf list and 5431541Srgrimes * Iff vap not NULL 5441541Srgrimes * copy the attributes to *vaper 5451541Srgrimes */ 5461549Srgrimesint 54783651Speternfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp, 548158739Smohans struct vattr *vaper, int dontshrink) 5491541Srgrimes{ 55083651Speter struct vnode *vp = *vpp; 55183651Speter struct vattr *vap; 55283651Speter struct nfs_fattr *fp; 55383651Speter struct nfsnode *np; 55483651Speter int32_t t1; 5559336Sdfr caddr_t cp2; 55684057Speter int rdev; 5571541Srgrimes struct mbuf *md; 5581541Srgrimes enum vtype vtyp; 5591541Srgrimes u_short vmode; 560171190Sjhb struct timespec mtime, mtime_save; 5619336Sdfr int v3 = NFS_ISV3(vp); 562167352Smohans struct thread *td = curthread; 5631541Srgrimes 5641541Srgrimes md = *mdp; 5659336Sdfr t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 566177599Sru cp2 = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, M_WAIT); 56784057Speter if (cp2 == NULL) 56884057Speter return EBADRPC; 5699336Sdfr fp = (struct nfs_fattr *)cp2; 5709336Sdfr if (v3) { 5719336Sdfr vtyp = nfsv3tov_type(fp->fa_type); 5729336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 573130640Sphk rdev = makedev(fxdr_unsigned(int, fp->fa3_rdev.specdata1), 57416634Sbde fxdr_unsigned(int, fp->fa3_rdev.specdata2)); 5759336Sdfr fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 5761541Srgrimes } else { 5779336Sdfr vtyp = nfsv2tov_type(fp->fa_type); 5789336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 5799336Sdfr /* 5809336Sdfr * XXX 5819336Sdfr * 5829336Sdfr * The duplicate information returned in fa_type and fa_mode 5839336Sdfr * is an ambiguity in the NFS version 2 protocol. 5849336Sdfr * 5859336Sdfr * VREG should be taken literally as a regular file. If a 5869336Sdfr * server intents to return some type information differently 5879336Sdfr * in the upper bits of the mode field (e.g. for sockets, or 5889336Sdfr * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we 5899336Sdfr * leave the examination of the mode bits even in the VREG 5909336Sdfr * case to avoid breakage for bogus servers, but we make sure 5919336Sdfr * that there are actually type bits set in the upper part of 5929336Sdfr * fa_mode (and failing that, trust the va_type field). 5939336Sdfr * 5949336Sdfr * NFSv3 cleared the issue, and requires fa_mode to not 5959336Sdfr * contain any type information (while also introduing sockets 5969336Sdfr * and FIFOs for fa_type). 5979336Sdfr */ 5989336Sdfr if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) 5999336Sdfr vtyp = IFTOVT(vmode); 60036541Speter rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); 6019336Sdfr fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 6029336Sdfr 6039336Sdfr /* 6049336Sdfr * Really ugly NFSv2 kludge. 6059336Sdfr */ 6069336Sdfr if (vtyp == VCHR && rdev == 0xffffffff) 6079336Sdfr vtyp = VFIFO; 6081541Srgrimes } 6099336Sdfr 6101541Srgrimes /* 6111541Srgrimes * If v_type == VNON it is a new node, so fill in the v_type, 6128876Srgrimes * n_mtime fields. Check to see if it represents a special 6131541Srgrimes * device, and if so, check for a possible alias. Once the 6141541Srgrimes * correct vnode has been obtained, fill in the rest of the 6151541Srgrimes * information. 6161541Srgrimes */ 6171541Srgrimes np = VTONFS(vp); 618158739Smohans mtx_lock(&np->n_mtx); 61910219Sdfr if (vp->v_type != vtyp) { 6209336Sdfr vp->v_type = vtyp; 621126851Sphk if (vp->v_type == VFIFO) 622138290Sphk vp->v_op = &nfs_fifoops; 623138473Sps np->n_mtime = mtime; 6241541Srgrimes } 6251541Srgrimes vap = &np->n_vattr; 6261541Srgrimes vap->va_type = vtyp; 6271541Srgrimes vap->va_mode = (vmode & 07777); 62847028Sphk vap->va_rdev = rdev; 629171190Sjhb mtime_save = vap->va_mtime; 6301541Srgrimes vap->va_mtime = mtime; 6311541Srgrimes vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 6329336Sdfr if (v3) { 6339336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 6349336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 6359336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 63647751Speter vap->va_size = fxdr_hyper(&fp->fa3_size); 6379336Sdfr vap->va_blocksize = NFS_FABLKSIZE; 63847751Speter vap->va_bytes = fxdr_hyper(&fp->fa3_used); 63936541Speter vap->va_fileid = fxdr_unsigned(int32_t, 64036541Speter fp->fa3_fileid.nfsuquad[1]); 6419336Sdfr fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 6429336Sdfr fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 6439336Sdfr vap->va_flags = 0; 6449336Sdfr vap->va_filerev = 0; 6451541Srgrimes } else { 6469336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 6479336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 6489336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 64936541Speter vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 65036541Speter vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 65147751Speter vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) 65236541Speter * NFS_FABLKSIZE; 65336541Speter vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); 6549336Sdfr fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 6551541Srgrimes vap->va_flags = 0; 65636541Speter vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, 65736541Speter fp->fa2_ctime.nfsv2_sec); 65818397Snate vap->va_ctime.tv_nsec = 0; 65983651Speter vap->va_gen = fxdr_unsigned(u_int32_t, fp->fa2_ctime.nfsv2_usec); 6601541Srgrimes vap->va_filerev = 0; 6611541Srgrimes } 66267486Sdwmalone np->n_attrstamp = time_second; 663167352Smohans /* Timestamp the NFS otw getattr fetch */ 664167352Smohans if (td->td_proc) { 665167352Smohans np->n_ac_ts_tid = td->td_tid; 666167352Smohans np->n_ac_ts_pid = td->td_proc->p_pid; 667167352Smohans np->n_ac_ts_syscalls = td->td_syscalls; 668167352Smohans } else 669167352Smohans bzero(&np->n_ac_ts, sizeof(struct nfs_attrcache_timestamp)); 670167352Smohans 6711541Srgrimes if (vap->va_size != np->n_size) { 6721541Srgrimes if (vap->va_type == VREG) { 67367486Sdwmalone if (dontshrink && vap->va_size < np->n_size) { 67467486Sdwmalone /* 67567486Sdwmalone * We've been told not to shrink the file; 67667486Sdwmalone * zero np->n_attrstamp to indicate that 67767486Sdwmalone * the attributes are stale. 67867486Sdwmalone */ 67967486Sdwmalone vap->va_size = np->n_size; 68067486Sdwmalone np->n_attrstamp = 0; 68167486Sdwmalone } else if (np->n_flag & NMODIFIED) { 682128263Speadar /* 683128263Speadar * We've modified the file: Use the larger 684128263Speadar * of our size, and the server's size. 685128263Speadar */ 686128263Speadar if (vap->va_size < np->n_size) { 6871541Srgrimes vap->va_size = np->n_size; 688128263Speadar } else { 6891541Srgrimes np->n_size = vap->va_size; 690128263Speadar np->n_flag |= NSIZECHANGED; 691128263Speadar } 69254480Sdillon } else { 6931541Srgrimes np->n_size = vap->va_size; 694128263Speadar np->n_flag |= NSIZECHANGED; 69554480Sdillon } 69641026Speter vnode_pager_setsize(vp, np->n_size); 69754480Sdillon } else { 6981541Srgrimes np->n_size = vap->va_size; 69954480Sdillon } 7001541Srgrimes } 701171190Sjhb /* 702171190Sjhb * The following checks are added to prevent a race between (say) 703171190Sjhb * a READDIR+ and a WRITE. 704171190Sjhb * READDIR+, WRITE requests sent out. 705171190Sjhb * READDIR+ resp, WRITE resp received on client. 706171190Sjhb * However, the WRITE resp was handled before the READDIR+ resp 707171190Sjhb * causing the post op attrs from the write to be loaded first 708171190Sjhb * and the attrs from the READDIR+ to be loaded later. If this 709171190Sjhb * happens, we have stale attrs loaded into the attrcache. 710171190Sjhb * We detect this by for the mtime moving back. We invalidate the 711171190Sjhb * attrcache when this happens. 712171190Sjhb */ 713171190Sjhb if (timespeccmp(&mtime_save, &vap->va_mtime, >)) 714171190Sjhb /* Size changed or mtime went backwards */ 715171190Sjhb np->n_attrstamp = 0; 7161541Srgrimes if (vaper != NULL) { 7171541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 7181541Srgrimes if (np->n_flag & NCHG) { 7199336Sdfr if (np->n_flag & NACC) 7209336Sdfr vaper->va_atime = np->n_atim; 7219336Sdfr if (np->n_flag & NUPD) 7229336Sdfr vaper->va_mtime = np->n_mtim; 7231541Srgrimes } 7241541Srgrimes } 725158739Smohans mtx_unlock(&np->n_mtx); 7261541Srgrimes return (0); 7271541Srgrimes} 7281541Srgrimes 72936176Speter#ifdef NFS_ACDEBUG 73036176Speter#include <sys/sysctl.h> 73144101SbdeSYSCTL_DECL(_vfs_nfs); 73236176Speterstatic int nfs_acdebug; 73336176SpeterSYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, ""); 73436176Speter#endif 73536176Speter 7361541Srgrimes/* 7371541Srgrimes * Check the time stamp 7381541Srgrimes * If the cache is valid, copy contents to *vap and return 0 7391541Srgrimes * otherwise return an error 7401541Srgrimes */ 7411549Srgrimesint 74283651Speternfs_getattrcache(struct vnode *vp, struct vattr *vaper) 7431541Srgrimes{ 74483651Speter struct nfsnode *np; 74583651Speter struct vattr *vap; 74636176Speter struct nfsmount *nmp; 74736176Speter int timeo; 748158739Smohans 74936176Speter np = VTONFS(vp); 75036176Speter vap = &np->n_vattr; 75136176Speter nmp = VFSTONFS(vp->v_mount); 752158739Smohans#ifdef NFS_ACDEBUG 753158739Smohans mtx_lock(&Giant); /* nfs_printf() */ 754158739Smohans#endif 755158739Smohans mtx_lock(&np->n_mtx); 75636176Speter /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */ 757138473Sps timeo = (time_second - np->n_mtime.tv_sec) / 10; 75836176Speter 75936176Speter#ifdef NFS_ACDEBUG 76036176Speter if (nfs_acdebug>1) 761158739Smohans nfs_printf("nfs_getattrcache: initial timeo = %d\n", timeo); 76236176Speter#endif 76336176Speter 76436176Speter if (vap->va_type == VDIR) { 76536176Speter if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin) 76636176Speter timeo = nmp->nm_acdirmin; 76736176Speter else if (timeo > nmp->nm_acdirmax) 76836176Speter timeo = nmp->nm_acdirmax; 76936176Speter } else { 77036176Speter if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin) 77136176Speter timeo = nmp->nm_acregmin; 77236176Speter else if (timeo > nmp->nm_acregmax) 77336176Speter timeo = nmp->nm_acregmax; 77436176Speter } 77536176Speter 77636176Speter#ifdef NFS_ACDEBUG 77736176Speter if (nfs_acdebug > 2) 778158739Smohans nfs_printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n", 779158739Smohans nmp->nm_acregmin, nmp->nm_acregmax, 780158739Smohans nmp->nm_acdirmin, nmp->nm_acdirmax); 78136176Speter 78236176Speter if (nfs_acdebug) 783158739Smohans nfs_printf("nfs_getattrcache: age = %d; final timeo = %d\n", 784158739Smohans (time_second - np->n_attrstamp), timeo); 78536176Speter#endif 78636176Speter 78736176Speter if ((time_second - np->n_attrstamp) >= timeo) { 7881541Srgrimes nfsstats.attrcache_misses++; 789158739Smohans mtx_unlock(&np->n_mtx); 790158739Smohans return( ENOENT); 7911541Srgrimes } 7921541Srgrimes nfsstats.attrcache_hits++; 7931541Srgrimes if (vap->va_size != np->n_size) { 7941541Srgrimes if (vap->va_type == VREG) { 7951541Srgrimes if (np->n_flag & NMODIFIED) { 7961541Srgrimes if (vap->va_size < np->n_size) 7971541Srgrimes vap->va_size = np->n_size; 7981541Srgrimes else 7991541Srgrimes np->n_size = vap->va_size; 80054480Sdillon } else { 8011541Srgrimes np->n_size = vap->va_size; 80254480Sdillon } 80341026Speter vnode_pager_setsize(vp, np->n_size); 80454480Sdillon } else { 8051541Srgrimes np->n_size = vap->va_size; 80654480Sdillon } 8071541Srgrimes } 8081541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 8091541Srgrimes if (np->n_flag & NCHG) { 8109336Sdfr if (np->n_flag & NACC) 8119336Sdfr vaper->va_atime = np->n_atim; 8129336Sdfr if (np->n_flag & NUPD) 8139336Sdfr vaper->va_mtime = np->n_mtim; 8141541Srgrimes } 815158739Smohans mtx_unlock(&np->n_mtx); 816158739Smohans#ifdef NFS_ACDEBUG 817158739Smohans mtx_unlock(&Giant); /* nfs_printf() */ 818158739Smohans#endif 8191541Srgrimes return (0); 8201541Srgrimes} 8211541Srgrimes 82243305Sdillonstatic nfsuint64 nfs_nullcookie = { { 0, 0 } }; 8239336Sdfr/* 8249336Sdfr * This function finds the directory cookie that corresponds to the 8259336Sdfr * logical byte offset given. 8269336Sdfr */ 8279336Sdfrnfsuint64 * 82883651Speternfs_getcookie(struct nfsnode *np, off_t off, int add) 8299336Sdfr{ 83083651Speter struct nfsdmap *dp, *dp2; 83183651Speter int pos; 832158739Smohans nfsuint64 *retval = NULL; 833158739Smohans 83436979Sbde pos = (uoff_t)off / NFS_DIRBLKSIZ; 83536979Sbde if (pos == 0 || off < 0) { 8369336Sdfr#ifdef DIAGNOSTIC 8379336Sdfr if (add) 83836979Sbde panic("nfs getcookie add at <= 0"); 8399336Sdfr#endif 8409336Sdfr return (&nfs_nullcookie); 8419336Sdfr } 8429336Sdfr pos--; 84383651Speter dp = LIST_FIRST(&np->n_cookies); 8449336Sdfr if (!dp) { 8459336Sdfr if (add) { 8469336Sdfr MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 847111119Simp M_NFSDIROFF, M_WAITOK); 8489336Sdfr dp->ndm_eocookie = 0; 8499336Sdfr LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 8509336Sdfr } else 851158739Smohans goto out; 8529336Sdfr } 8539336Sdfr while (pos >= NFSNUMCOOKIES) { 8549336Sdfr pos -= NFSNUMCOOKIES; 85583651Speter if (LIST_NEXT(dp, ndm_list)) { 8569336Sdfr if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 857158739Smohans pos >= dp->ndm_eocookie) 858158739Smohans goto out; 85983651Speter dp = LIST_NEXT(dp, ndm_list); 8609336Sdfr } else if (add) { 8619336Sdfr MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 862111119Simp M_NFSDIROFF, M_WAITOK); 8639336Sdfr dp2->ndm_eocookie = 0; 8649336Sdfr LIST_INSERT_AFTER(dp, dp2, ndm_list); 8659336Sdfr dp = dp2; 8669336Sdfr } else 867158739Smohans goto out; 8689336Sdfr } 8699336Sdfr if (pos >= dp->ndm_eocookie) { 8709336Sdfr if (add) 8719336Sdfr dp->ndm_eocookie = pos + 1; 8729336Sdfr else 873158739Smohans goto out; 8749336Sdfr } 875158739Smohans retval = &dp->ndm_cookies[pos]; 876158739Smohansout: 877158739Smohans return (retval); 8789336Sdfr} 8799336Sdfr 8809336Sdfr/* 8819336Sdfr * Invalidate cached directory information, except for the actual directory 8829336Sdfr * blocks (which are invalidated separately). 8839336Sdfr * Done mainly to avoid the use of stale offset cookies. 8849336Sdfr */ 8859336Sdfrvoid 88683651Speternfs_invaldir(struct vnode *vp) 8879336Sdfr{ 88883651Speter struct nfsnode *np = VTONFS(vp); 8899336Sdfr 8909336Sdfr#ifdef DIAGNOSTIC 8919336Sdfr if (vp->v_type != VDIR) 8929336Sdfr panic("nfs: invaldir not dir"); 8939336Sdfr#endif 894158739Smohans nfs_dircookie_lock(np); 8959336Sdfr np->n_direofoffset = 0; 8969336Sdfr np->n_cookieverf.nfsuquad[0] = 0; 8979336Sdfr np->n_cookieverf.nfsuquad[1] = 0; 89883651Speter if (LIST_FIRST(&np->n_cookies)) 89983651Speter LIST_FIRST(&np->n_cookies)->ndm_eocookie = 0; 900158739Smohans nfs_dircookie_unlock(np); 9019336Sdfr} 9029336Sdfr 9039336Sdfr/* 9049336Sdfr * The write verifier has changed (probably due to a server reboot), so all 9059336Sdfr * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 9069336Sdfr * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 90754480Sdillon * and B_CLUSTEROK flags. Once done the new write verifier can be set for the 90854480Sdillon * mount point. 90954480Sdillon * 91083651Speter * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data 91154480Sdillon * writes are not clusterable. 9129336Sdfr */ 9139336Sdfrvoid 91483651Speternfs_clearcommit(struct mount *mp) 9159336Sdfr{ 91683651Speter struct vnode *vp, *nvp; 91783651Speter struct buf *bp, *nbp; 918177493Sjeff struct bufobj *bo; 9199336Sdfr 920122091Skan MNT_ILOCK(mp); 921131551Sphk MNT_VNODE_FOREACH(vp, mp, nvp) { 922177493Sjeff bo = &vp->v_bufobj; 923103939Sjeff VI_LOCK(vp); 924143510Sjeff if (vp->v_iflag & VI_DOOMED) { 925120787Sjeff VI_UNLOCK(vp); 926120787Sjeff continue; 927120787Sjeff } 928177493Sjeff vholdl(vp); 929177493Sjeff VI_UNLOCK(vp); 930122091Skan MNT_IUNLOCK(mp); 931177493Sjeff BO_LOCK(bo); 932177493Sjeff TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { 933175486Sattilio if (!BUF_ISLOCKED(bp) && 93448225Smckusick (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) 9359336Sdfr == (B_DELWRI | B_NEEDCOMMIT)) 93654480Sdillon bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); 9379336Sdfr } 938177493Sjeff BO_UNLOCK(bo); 939177493Sjeff vdrop(vp); 940122091Skan MNT_ILOCK(mp); 9419336Sdfr } 942122091Skan MNT_IUNLOCK(mp); 9439336Sdfr} 9449336Sdfr 9459336Sdfr/* 94683651Speter * Helper functions for former macros. Some of these should be 94783651Speter * moved to their callers. 9489336Sdfr */ 94983651Speter 9505455Sdgint 95183651Speternfsm_mtofh_xx(struct vnode *d, struct vnode **v, int v3, int *f, 95288091Siedowse struct mbuf **md, caddr_t *dpos) 9539336Sdfr{ 95483651Speter struct nfsnode *ttnp; 95583651Speter struct vnode *ttvp; 95683651Speter nfsfh_t *ttfhp; 95788091Siedowse u_int32_t *tl; 95883651Speter int ttfhsize; 95983651Speter int t1; 9609336Sdfr 96183651Speter if (v3) { 96288091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 96388091Siedowse if (tl == NULL) 96484057Speter return EBADRPC; 96588091Siedowse *f = fxdr_unsigned(int, *tl); 96683651Speter } else 96783651Speter *f = 1; 96883651Speter if (*f) { 96988091Siedowse t1 = nfsm_getfh_xx(&ttfhp, &ttfhsize, (v3), md, dpos); 97083651Speter if (t1 != 0) 97183651Speter return t1; 972162288Smohans t1 = nfs_nget(d->v_mount, ttfhp, ttfhsize, &ttnp, LK_EXCLUSIVE); 97383651Speter if (t1 != 0) 97483651Speter return t1; 97583651Speter *v = NFSTOV(ttnp); 97683651Speter } 97783651Speter if (v3) { 97888091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 97988091Siedowse if (tl == NULL) 98084057Speter return EBADRPC; 98183651Speter if (*f) 98288091Siedowse *f = fxdr_unsigned(int, *tl); 98388091Siedowse else if (fxdr_unsigned(int, *tl)) 98488091Siedowse nfsm_adv_xx(NFSX_V3FATTR, md, dpos); 98583651Speter } 98683651Speter if (*f) { 98783651Speter ttvp = *v; 98899797Sdillon t1 = nfs_loadattrcache(&ttvp, md, dpos, NULL, 0); 98983651Speter if (t1) 99083651Speter return t1; 99183651Speter *v = ttvp; 99283651Speter } 99383651Speter return 0; 99483651Speter} 99583651Speter 99683651Speterint 99788091Siedowsenfsm_getfh_xx(nfsfh_t **f, int *s, int v3, struct mbuf **md, caddr_t *dpos) 99883651Speter{ 99988091Siedowse u_int32_t *tl; 100083651Speter 100183651Speter if (v3) { 100288091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 100388091Siedowse if (tl == NULL) 100484057Speter return EBADRPC; 100588091Siedowse *s = fxdr_unsigned(int, *tl); 100684057Speter if (*s <= 0 || *s > NFSX_V3FHMAX) 100783651Speter return EBADRPC; 100883651Speter } else 100983651Speter *s = NFSX_V2FH; 101084057Speter *f = nfsm_dissect_xx(nfsm_rndup(*s), md, dpos); 101184057Speter if (*f == NULL) 101284057Speter return EBADRPC; 101384057Speter else 101484057Speter return 0; 101583651Speter} 101683651Speter 101783651Speter 101883651Speterint 101988091Siedowsenfsm_loadattr_xx(struct vnode **v, struct vattr *va, struct mbuf **md, 1020158739Smohans caddr_t *dpos) 102183651Speter{ 102283651Speter int t1; 102383651Speter 102483651Speter struct vnode *ttvp = *v; 102583651Speter t1 = nfs_loadattrcache(&ttvp, md, dpos, va, 0); 102683651Speter if (t1 != 0) 102783651Speter return t1; 102883651Speter *v = ttvp; 102983651Speter return 0; 103083651Speter} 103183651Speter 103283651Speterint 103388091Siedowsenfsm_postop_attr_xx(struct vnode **v, int *f, struct mbuf **md, 1034158739Smohans caddr_t *dpos) 103583651Speter{ 103688091Siedowse u_int32_t *tl; 103783651Speter int t1; 103883651Speter 103983651Speter struct vnode *ttvp = *v; 104088091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 104188091Siedowse if (tl == NULL) 104284057Speter return EBADRPC; 104388091Siedowse *f = fxdr_unsigned(int, *tl); 104483914Siedowse if (*f != 0) { 104599797Sdillon t1 = nfs_loadattrcache(&ttvp, md, dpos, NULL, 1); 104683651Speter if (t1 != 0) { 104783651Speter *f = 0; 104883651Speter return t1; 104983651Speter } 105083651Speter *v = ttvp; 10519336Sdfr } 105283651Speter return 0; 10539336Sdfr} 10549336Sdfr 10559336Sdfrint 105688091Siedowsenfsm_wcc_data_xx(struct vnode **v, int *f, struct mbuf **md, caddr_t *dpos) 105731886Sbde{ 105888091Siedowse u_int32_t *tl; 105983651Speter int ttattrf, ttretf = 0; 106083651Speter int t1; 10615455Sdg 106288091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 106388091Siedowse if (tl == NULL) 106484057Speter return EBADRPC; 106588091Siedowse if (*tl == nfs_true) { 106688091Siedowse tl = nfsm_dissect_xx(6 * NFSX_UNSIGNED, md, dpos); 106788091Siedowse if (tl == NULL) 106884057Speter return EBADRPC; 1069158739Smohans mtx_lock(&(VTONFS(*v))->n_mtx); 107083651Speter if (*f) 1071138473Sps ttretf = (VTONFS(*v)->n_mtime.tv_sec == fxdr_unsigned(u_int32_t, *(tl + 2)) && 1072138473Sps VTONFS(*v)->n_mtime.tv_nsec == fxdr_unsigned(u_int32_t, *(tl + 3))); 1073158739Smohans mtx_unlock(&(VTONFS(*v))->n_mtx); 107483651Speter } 107588091Siedowse t1 = nfsm_postop_attr_xx(v, &ttattrf, md, dpos); 107683651Speter if (t1) 107783651Speter return t1; 107883651Speter if (*f) 107983651Speter *f = ttretf; 108083651Speter else 108183651Speter *f = ttattrf; 108283651Speter return 0; 10835455Sdg} 108436503Speter 108583651Speterint 108688091Siedowsenfsm_strtom_xx(const char *a, int s, int m, struct mbuf **mb, caddr_t *bpos) 108736503Speter{ 108888091Siedowse u_int32_t *tl; 108983651Speter int t1; 109036503Speter 109183651Speter if (s > m) 109283651Speter return ENAMETOOLONG; 109383651Speter t1 = nfsm_rndup(s) + NFSX_UNSIGNED; 109483651Speter if (t1 <= M_TRAILINGSPACE(*mb)) { 109588091Siedowse tl = nfsm_build_xx(t1, mb, bpos); 109688091Siedowse *tl++ = txdr_unsigned(s); 109788091Siedowse *(tl + ((t1 >> 2) - 2)) = 0; 109888091Siedowse bcopy(a, tl, s); 109983651Speter } else { 110083651Speter t1 = nfsm_strtmbuf(mb, bpos, a, s); 110183651Speter if (t1 != 0) 110283651Speter return t1; 110336503Speter } 110483651Speter return 0; 110536503Speter} 110636503Speter 110783651Speterint 110888091Siedowsenfsm_fhtom_xx(struct vnode *v, int v3, struct mbuf **mb, caddr_t *bpos) 110983651Speter{ 111088091Siedowse u_int32_t *tl; 111183651Speter int t1; 111283651Speter caddr_t cp; 111383651Speter 111483651Speter if (v3) { 111583651Speter t1 = nfsm_rndup(VTONFS(v)->n_fhsize) + NFSX_UNSIGNED; 111683651Speter if (t1 < M_TRAILINGSPACE(*mb)) { 111788091Siedowse tl = nfsm_build_xx(t1, mb, bpos); 111888091Siedowse *tl++ = txdr_unsigned(VTONFS(v)->n_fhsize); 111988091Siedowse *(tl + ((t1 >> 2) - 2)) = 0; 112088091Siedowse bcopy(VTONFS(v)->n_fhp, tl, VTONFS(v)->n_fhsize); 112183651Speter } else { 112283651Speter t1 = nfsm_strtmbuf(mb, bpos, 112383651Speter (const char *)VTONFS(v)->n_fhp, 112483651Speter VTONFS(v)->n_fhsize); 112583651Speter if (t1 != 0) 112683651Speter return t1; 112783651Speter } 112883651Speter } else { 112984002Speter cp = nfsm_build_xx(NFSX_V2FH, mb, bpos); 113083651Speter bcopy(VTONFS(v)->n_fhp, cp, NFSX_V2FH); 113183651Speter } 113283651Speter return 0; 113383651Speter} 113483651Speter 113536503Spetervoid 113688091Siedowsenfsm_v3attrbuild_xx(struct vattr *va, int full, struct mbuf **mb, 113788091Siedowse caddr_t *bpos) 113836503Speter{ 113988091Siedowse u_int32_t *tl; 114036503Speter 114183651Speter if (va->va_mode != (mode_t)VNOVAL) { 114288091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 114388091Siedowse *tl++ = nfs_true; 114488091Siedowse *tl = txdr_unsigned(va->va_mode); 114583651Speter } else { 114688091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 114788091Siedowse *tl = nfs_false; 114883651Speter } 114983651Speter if (full && va->va_uid != (uid_t)VNOVAL) { 115088091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 115188091Siedowse *tl++ = nfs_true; 115288091Siedowse *tl = txdr_unsigned(va->va_uid); 115383651Speter } else { 115488091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 115588091Siedowse *tl = nfs_false; 115683651Speter } 115783651Speter if (full && va->va_gid != (gid_t)VNOVAL) { 115888091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 115988091Siedowse *tl++ = nfs_true; 116088091Siedowse *tl = txdr_unsigned(va->va_gid); 116183651Speter } else { 116288091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 116388091Siedowse *tl = nfs_false; 116483651Speter } 116583651Speter if (full && va->va_size != VNOVAL) { 116688091Siedowse tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 116788091Siedowse *tl++ = nfs_true; 116888091Siedowse txdr_hyper(va->va_size, tl); 116983651Speter } else { 117088091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 117188091Siedowse *tl = nfs_false; 117283651Speter } 117383651Speter if (va->va_atime.tv_sec != VNOVAL) { 117483651Speter if (va->va_atime.tv_sec != time_second) { 117588091Siedowse tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 117688091Siedowse *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 117788091Siedowse txdr_nfsv3time(&va->va_atime, tl); 117883651Speter } else { 117988091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 118088091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 118183651Speter } 118283651Speter } else { 118388091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 118488091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 118583651Speter } 118683651Speter if (va->va_mtime.tv_sec != VNOVAL) { 118783651Speter if (va->va_mtime.tv_sec != time_second) { 118888091Siedowse tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 118988091Siedowse *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 119088091Siedowse txdr_nfsv3time(&va->va_mtime, tl); 119183651Speter } else { 119288091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 119388091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 119483651Speter } 119583651Speter } else { 119688091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 119788091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 119883651Speter } 119936503Speter} 1200