nfs_subs.c revision 138290
11541Srgrimes/* 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 138290 2004-12-01 23:16:38Z phk $"); 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/* 791541Srgrimes * Data items converted to xdr at startup, since they are constant 801541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps 811541Srgrimes */ 8283651Speteru_int32_t nfs_xdrneg1; 8383651Speteru_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 8483651Speter rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 8583651Speteru_int32_t nfs_true, nfs_false; 861541Srgrimes 871541Srgrimes/* And other global data */ 8836541Speterstatic u_int32_t nfs_xid = 0; 8912911Sphkstatic enum vtype nv2tov_type[8]= { 9083651Speter VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON 9112911Sphk}; 9212911Sphk 9383651Speterint nfs_ticks; 9483651Speterint nfs_pbuf_freecnt = -1; /* start out unlimited */ 959336Sdfr 9683651Speterstruct nfs_reqq nfs_reqq; 9783651Speterstruct nfs_bufq nfs_bufq; 989759Sbde 9983651Speterstatic int nfs_prev_nfsclnt_sy_narg; 10083651Speterstatic sy_call_t *nfs_prev_nfsclnt_sy_call; 10138894Sbde 1029336Sdfr/* 1039336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers 1049336Sdfr */ 1059336Sdfrint nfsv2_procid[NFS_NPROCS] = { 1069336Sdfr NFSV2PROC_NULL, 1079336Sdfr NFSV2PROC_GETATTR, 1089336Sdfr NFSV2PROC_SETATTR, 1099336Sdfr NFSV2PROC_LOOKUP, 1109336Sdfr NFSV2PROC_NOOP, 1119336Sdfr NFSV2PROC_READLINK, 1129336Sdfr NFSV2PROC_READ, 1139336Sdfr NFSV2PROC_WRITE, 1149336Sdfr NFSV2PROC_CREATE, 1159336Sdfr NFSV2PROC_MKDIR, 1169336Sdfr NFSV2PROC_SYMLINK, 1179336Sdfr NFSV2PROC_CREATE, 1189336Sdfr NFSV2PROC_REMOVE, 1199336Sdfr NFSV2PROC_RMDIR, 1209336Sdfr NFSV2PROC_RENAME, 1219336Sdfr NFSV2PROC_LINK, 1229336Sdfr NFSV2PROC_READDIR, 1239336Sdfr NFSV2PROC_NOOP, 1249336Sdfr NFSV2PROC_STATFS, 1259336Sdfr NFSV2PROC_NOOP, 1269336Sdfr NFSV2PROC_NOOP, 1279336Sdfr NFSV2PROC_NOOP, 1289336Sdfr NFSV2PROC_NOOP, 1299336Sdfr}; 1309336Sdfr 13160938SjakeLIST_HEAD(nfsnodehashhead, nfsnode); 1323664Sphk 1331541Srgrimes/* 1341541Srgrimes * Create the header for an rpc request packet 1351541Srgrimes * The hsiz is the size of the rest of the nfs request header. 1361541Srgrimes * (just used to decide if a cluster is a good idea) 1371541Srgrimes */ 1381541Srgrimesstruct mbuf * 13983651Speternfsm_reqhead(struct vnode *vp, u_long procid, int hsiz) 1401541Srgrimes{ 14183651Speter struct mbuf *mb; 1421541Srgrimes 143111119Simp MGET(mb, M_TRYWAIT, MT_DATA); 1441541Srgrimes if (hsiz >= MINCLSIZE) 145111119Simp MCLGET(mb, M_TRYWAIT); 1461541Srgrimes mb->m_len = 0; 1471541Srgrimes return (mb); 1481541Srgrimes} 1491541Srgrimes 1501541Srgrimes/* 1511541Srgrimes * Build the RPC header and fill in the authorization info. 1521541Srgrimes * The authorization string argument is only used when the credentials 1531541Srgrimes * come from outside of the kernel. 1541541Srgrimes * Returns the head of the mbuf list. 1551541Srgrimes */ 1561541Srgrimesstruct mbuf * 15783651Speternfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type, 15883651Speter int auth_len, struct mbuf *mrest, int mrest_len, struct mbuf **mbp, 15983651Speter u_int32_t *xidp) 1601541Srgrimes{ 16183651Speter struct mbuf *mb; 16283651Speter u_int32_t *tl; 16383651Speter caddr_t bpos; 16483651Speter int i; 16583651Speter struct mbuf *mreq; 16683651Speter int grpsiz, authsiz; 1671541Srgrimes 1681541Srgrimes authsiz = nfsm_rndup(auth_len); 169111119Simp MGETHDR(mb, M_TRYWAIT, MT_DATA); 1709336Sdfr if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { 171111119Simp MCLGET(mb, M_TRYWAIT); 1729336Sdfr } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { 1739336Sdfr MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 1741541Srgrimes } else { 1759336Sdfr MH_ALIGN(mb, 8 * NFSX_UNSIGNED); 1761541Srgrimes } 1771541Srgrimes mb->m_len = 0; 1781541Srgrimes mreq = mb; 1791541Srgrimes bpos = mtod(mb, caddr_t); 1801541Srgrimes 1811541Srgrimes /* 1821541Srgrimes * First the RPC header. 1831541Srgrimes */ 18484002Speter tl = nfsm_build(u_int32_t *, 8 * NFSX_UNSIGNED); 18517186Sdfr 18635066Sphk /* Get a pretty random xid to start with */ 18783651Speter if (!nfs_xid) 18835066Sphk nfs_xid = random(); 18917186Sdfr /* 19017186Sdfr * Skip zero xid if it should ever happen. 19117186Sdfr */ 1921541Srgrimes if (++nfs_xid == 0) 1931541Srgrimes nfs_xid++; 19417186Sdfr 1951541Srgrimes *tl++ = *xidp = txdr_unsigned(nfs_xid); 1961541Srgrimes *tl++ = rpc_call; 1971541Srgrimes *tl++ = rpc_vers; 19883651Speter *tl++ = txdr_unsigned(NFS_PROG); 19983651Speter if (nmflag & NFSMNT_NFSV3) { 20083651Speter *tl++ = txdr_unsigned(NFS_VER3); 20183651Speter *tl++ = txdr_unsigned(procid); 2021541Srgrimes } else { 20383651Speter *tl++ = txdr_unsigned(NFS_VER2); 20483651Speter *tl++ = txdr_unsigned(nfsv2_procid[procid]); 2051541Srgrimes } 2061541Srgrimes 2071541Srgrimes /* 2081541Srgrimes * And then the authorization cred. 2091541Srgrimes */ 2101541Srgrimes *tl++ = txdr_unsigned(auth_type); 2111541Srgrimes *tl = txdr_unsigned(authsiz); 2121541Srgrimes switch (auth_type) { 2131541Srgrimes case RPCAUTH_UNIX: 21484002Speter tl = nfsm_build(u_int32_t *, auth_len); 2151541Srgrimes *tl++ = 0; /* stamp ?? */ 2161541Srgrimes *tl++ = 0; /* NULL hostname */ 2171541Srgrimes *tl++ = txdr_unsigned(cr->cr_uid); 2181541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[0]); 2191541Srgrimes grpsiz = (auth_len >> 2) - 5; 2201541Srgrimes *tl++ = txdr_unsigned(grpsiz); 2211541Srgrimes for (i = 1; i <= grpsiz; i++) 2221541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[i]); 2231541Srgrimes break; 22483651Speter } 2259336Sdfr 2269336Sdfr /* 2279336Sdfr * And the verifier... 2289336Sdfr */ 22984002Speter tl = nfsm_build(u_int32_t *, 2 * NFSX_UNSIGNED); 23083651Speter *tl++ = txdr_unsigned(RPCAUTH_NULL); 23183651Speter *tl = 0; 2321541Srgrimes mb->m_next = mrest; 2339336Sdfr mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; 23499797Sdillon mreq->m_pkthdr.rcvif = NULL; 2351541Srgrimes *mbp = mb; 2361541Srgrimes return (mreq); 2371541Srgrimes} 2381541Srgrimes 2391541Srgrimes/* 24017186Sdfr * copies a uio scatter/gather list to an mbuf chain. 24117186Sdfr * NOTE: can ony handle iovcnt == 1 2421541Srgrimes */ 2431549Srgrimesint 24483651Speternfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos) 2451541Srgrimes{ 24683651Speter char *uiocp; 24783651Speter struct mbuf *mp, *mp2; 24883651Speter int xfer, left, mlen; 2491541Srgrimes int uiosiz, clflg, rem; 2501541Srgrimes char *cp; 2511541Srgrimes 25236519Speter#ifdef DIAGNOSTIC 25317186Sdfr if (uiop->uio_iovcnt != 1) 25417186Sdfr panic("nfsm_uiotombuf: iovcnt != 1"); 25536519Speter#endif 25617186Sdfr 2571541Srgrimes if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 2581541Srgrimes clflg = 1; 2591541Srgrimes else 2601541Srgrimes clflg = 0; 2611541Srgrimes rem = nfsm_rndup(siz)-siz; 2621541Srgrimes mp = mp2 = *mq; 2631541Srgrimes while (siz > 0) { 2641541Srgrimes left = uiop->uio_iov->iov_len; 2651541Srgrimes uiocp = uiop->uio_iov->iov_base; 2661541Srgrimes if (left > siz) 2671541Srgrimes left = siz; 2681541Srgrimes uiosiz = left; 2691541Srgrimes while (left > 0) { 2701541Srgrimes mlen = M_TRAILINGSPACE(mp); 2711541Srgrimes if (mlen == 0) { 272111119Simp MGET(mp, M_TRYWAIT, MT_DATA); 2731541Srgrimes if (clflg) 274111119Simp MCLGET(mp, M_TRYWAIT); 2751541Srgrimes mp->m_len = 0; 2761541Srgrimes mp2->m_next = mp; 2771541Srgrimes mp2 = mp; 2781541Srgrimes mlen = M_TRAILINGSPACE(mp); 2791541Srgrimes } 2801541Srgrimes xfer = (left > mlen) ? mlen : left; 2811541Srgrimes#ifdef notdef 2821541Srgrimes /* Not Yet.. */ 2831541Srgrimes if (uiop->uio_iov->iov_op != NULL) 2841541Srgrimes (*(uiop->uio_iov->iov_op)) 2851541Srgrimes (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 2861541Srgrimes else 2871541Srgrimes#endif 2881541Srgrimes if (uiop->uio_segflg == UIO_SYSSPACE) 2891541Srgrimes bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 2901541Srgrimes else 2911541Srgrimes copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 2921541Srgrimes mp->m_len += xfer; 2931541Srgrimes left -= xfer; 2941541Srgrimes uiocp += xfer; 2951541Srgrimes uiop->uio_offset += xfer; 2961541Srgrimes uiop->uio_resid -= xfer; 2971541Srgrimes } 298104908Smike uiop->uio_iov->iov_base = 299104908Smike (char *)uiop->uio_iov->iov_base + uiosiz; 30017186Sdfr uiop->uio_iov->iov_len -= uiosiz; 3011541Srgrimes siz -= uiosiz; 3021541Srgrimes } 3031541Srgrimes if (rem > 0) { 3041541Srgrimes if (rem > M_TRAILINGSPACE(mp)) { 305111119Simp MGET(mp, M_TRYWAIT, MT_DATA); 3061541Srgrimes mp->m_len = 0; 3071541Srgrimes mp2->m_next = mp; 3081541Srgrimes } 3091541Srgrimes cp = mtod(mp, caddr_t)+mp->m_len; 3101541Srgrimes for (left = 0; left < rem; left++) 3111541Srgrimes *cp++ = '\0'; 3121541Srgrimes mp->m_len += rem; 3131541Srgrimes *bpos = cp; 3141541Srgrimes } else 3151541Srgrimes *bpos = mtod(mp, caddr_t)+mp->m_len; 3161541Srgrimes *mq = mp; 3171541Srgrimes return (0); 3181541Srgrimes} 3191541Srgrimes 3201541Srgrimes/* 3211541Srgrimes * Copy a string into mbufs for the hard cases... 3221541Srgrimes */ 3231549Srgrimesint 32483651Speternfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz) 3251541Srgrimes{ 32683651Speter struct mbuf *m1 = NULL, *m2; 3271541Srgrimes long left, xfer, len, tlen; 32836541Speter u_int32_t *tl; 3291541Srgrimes int putsize; 3301541Srgrimes 3311541Srgrimes putsize = 1; 3321541Srgrimes m2 = *mb; 3331541Srgrimes left = M_TRAILINGSPACE(m2); 3341541Srgrimes if (left > 0) { 33536541Speter tl = ((u_int32_t *)(*bpos)); 3361541Srgrimes *tl++ = txdr_unsigned(siz); 3371541Srgrimes putsize = 0; 3381541Srgrimes left -= NFSX_UNSIGNED; 3391541Srgrimes m2->m_len += NFSX_UNSIGNED; 3401541Srgrimes if (left > 0) { 3411541Srgrimes bcopy(cp, (caddr_t) tl, left); 3421541Srgrimes siz -= left; 3431541Srgrimes cp += left; 3441541Srgrimes m2->m_len += left; 3451541Srgrimes left = 0; 3461541Srgrimes } 3471541Srgrimes } 3481541Srgrimes /* Loop around adding mbufs */ 3491541Srgrimes while (siz > 0) { 350111119Simp MGET(m1, M_TRYWAIT, MT_DATA); 3511541Srgrimes if (siz > MLEN) 352111119Simp MCLGET(m1, M_TRYWAIT); 3531541Srgrimes m1->m_len = NFSMSIZ(m1); 3541541Srgrimes m2->m_next = m1; 3551541Srgrimes m2 = m1; 35636541Speter tl = mtod(m1, u_int32_t *); 3571541Srgrimes tlen = 0; 3581541Srgrimes if (putsize) { 3591541Srgrimes *tl++ = txdr_unsigned(siz); 3601541Srgrimes m1->m_len -= NFSX_UNSIGNED; 3611541Srgrimes tlen = NFSX_UNSIGNED; 3621541Srgrimes putsize = 0; 3631541Srgrimes } 3641541Srgrimes if (siz < m1->m_len) { 3651541Srgrimes len = nfsm_rndup(siz); 3661541Srgrimes xfer = siz; 3671541Srgrimes if (xfer < len) 3681541Srgrimes *(tl+(xfer>>2)) = 0; 3691541Srgrimes } else { 3701541Srgrimes xfer = len = m1->m_len; 3711541Srgrimes } 3721541Srgrimes bcopy(cp, (caddr_t) tl, xfer); 3731541Srgrimes m1->m_len = len+tlen; 3741541Srgrimes siz -= xfer; 3751541Srgrimes cp += xfer; 3761541Srgrimes } 3771541Srgrimes *mb = m1; 3781541Srgrimes *bpos = mtod(m1, caddr_t)+m1->m_len; 3791541Srgrimes return (0); 3801541Srgrimes} 3811541Srgrimes 3821541Srgrimes/* 3831541Srgrimes * Called once to initialize data structures... 3841541Srgrimes */ 3851549Srgrimesint 38683651Speternfs_init(struct vfsconf *vfsp) 3871541Srgrimes{ 38883651Speter int i; 3891541Srgrimes 39092783Sjeff nfsmount_zone = uma_zcreate("NFSMOUNT", sizeof(struct nfsmount), 39192783Sjeff NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 3921541Srgrimes rpc_vers = txdr_unsigned(RPC_VER2); 3931541Srgrimes rpc_call = txdr_unsigned(RPC_CALL); 3941541Srgrimes rpc_reply = txdr_unsigned(RPC_REPLY); 3951541Srgrimes rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 3961541Srgrimes rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 3971541Srgrimes rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 3981541Srgrimes rpc_autherr = txdr_unsigned(RPC_AUTHERR); 3991541Srgrimes rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 4001541Srgrimes nfs_true = txdr_unsigned(TRUE); 4011541Srgrimes nfs_false = txdr_unsigned(FALSE); 4023664Sphk nfs_xdrneg1 = txdr_unsigned(-1); 4039336Sdfr nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 4049336Sdfr if (nfs_ticks < 1) 4059336Sdfr nfs_ticks = 1; 4061541Srgrimes /* Ensure async daemons disabled */ 40719449Sdfr for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 40899797Sdillon nfs_iodwant[i] = NULL; 40999797Sdillon nfs_iodmount[i] = NULL; 41019449Sdfr } 4111541Srgrimes nfs_nhinit(); /* Init the nfsnode table */ 4121541Srgrimes 4131541Srgrimes /* 4141541Srgrimes * Initialize reply list and start timer 4151541Srgrimes */ 4163664Sphk TAILQ_INIT(&nfs_reqq); 417127421Srees callout_init(&nfs_callout, 0); 41816365Sphk 41983651Speter nfs_prev_nfsclnt_sy_narg = sysent[SYS_nfsclnt].sy_narg; 42083651Speter sysent[SYS_nfsclnt].sy_narg = 2; 42183651Speter nfs_prev_nfsclnt_sy_call = sysent[SYS_nfsclnt].sy_call; 42283651Speter sysent[SYS_nfsclnt].sy_call = (sy_call_t *)nfsclnt; 4232997Swollman 42442957Sdillon nfs_pbuf_freecnt = nswbuf / 2 + 1; 42542957Sdillon 4261549Srgrimes return (0); 4271541Srgrimes} 4281541Srgrimes 42938894Sbdeint 43083651Speternfs_uninit(struct vfsconf *vfsp) 43138894Sbde{ 432128111Speadar int i; 43338894Sbde 434127421Srees callout_stop(&nfs_callout); 43583651Speter sysent[SYS_nfsclnt].sy_narg = nfs_prev_nfsclnt_sy_narg; 43683651Speter sysent[SYS_nfsclnt].sy_call = nfs_prev_nfsclnt_sy_call; 437128111Speadar 438128126Smarcel KASSERT(TAILQ_EMPTY(&nfs_reqq), 439128111Speadar ("nfs_uninit: request queue not empty")); 440128111Speadar 441128111Speadar /* 442128111Speadar * Tell all nfsiod processes to exit. Clear nfs_iodmax, and wakeup 443128111Speadar * any sleeping nfsiods so they check nfs_iodmax and exit. 444128111Speadar */ 445128111Speadar nfs_iodmax = 0; 446128111Speadar for (i = 0; i < nfs_numasync; i++) 447128111Speadar if (nfs_iodwant[i]) 448128111Speadar wakeup(&nfs_iodwant[i]); 449128111Speadar /* The last nfsiod to exit will wake us up when nfs_numasync hits 0 */ 450128111Speadar while (nfs_numasync) 451128111Speadar tsleep(&nfs_numasync, PWAIT, "ioddie", 0); 452128111Speadar 453128111Speadar nfs_nhuninit(); 454128111Speadar uma_zdestroy(nfsmount_zone); 45538894Sbde return (0); 45638894Sbde} 45738894Sbde 4581541Srgrimes/* 4591541Srgrimes * Attribute cache routines. 4601541Srgrimes * nfs_loadattrcache() - loads or updates the cache contents from attributes 4611541Srgrimes * that are on the mbuf list 4621541Srgrimes * nfs_getattrcache() - returns valid attributes if found in cache, returns 4631541Srgrimes * error otherwise 4641541Srgrimes */ 4651541Srgrimes 4661541Srgrimes/* 4671541Srgrimes * Load the attribute cache (that lives in the nfsnode entry) with 4681541Srgrimes * the values on the mbuf list and 4691541Srgrimes * Iff vap not NULL 4701541Srgrimes * copy the attributes to *vaper 4711541Srgrimes */ 4721549Srgrimesint 47383651Speternfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp, 47483651Speter struct vattr *vaper, int dontshrink) 4751541Srgrimes{ 47683651Speter struct vnode *vp = *vpp; 47783651Speter struct vattr *vap; 47883651Speter struct nfs_fattr *fp; 47983651Speter struct nfsnode *np; 48083651Speter int32_t t1; 4819336Sdfr caddr_t cp2; 48284057Speter int rdev; 4831541Srgrimes struct mbuf *md; 4841541Srgrimes enum vtype vtyp; 4851541Srgrimes u_short vmode; 4861541Srgrimes struct timespec mtime; 4879336Sdfr int v3 = NFS_ISV3(vp); 4881541Srgrimes 4891541Srgrimes md = *mdp; 4909336Sdfr t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 49184057Speter cp2 = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1); 49284057Speter if (cp2 == NULL) 49384057Speter return EBADRPC; 4949336Sdfr fp = (struct nfs_fattr *)cp2; 4959336Sdfr if (v3) { 4969336Sdfr vtyp = nfsv3tov_type(fp->fa_type); 4979336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 498130640Sphk rdev = makedev(fxdr_unsigned(int, fp->fa3_rdev.specdata1), 49916634Sbde fxdr_unsigned(int, fp->fa3_rdev.specdata2)); 5009336Sdfr fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 5011541Srgrimes } else { 5029336Sdfr vtyp = nfsv2tov_type(fp->fa_type); 5039336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 5049336Sdfr /* 5059336Sdfr * XXX 5069336Sdfr * 5079336Sdfr * The duplicate information returned in fa_type and fa_mode 5089336Sdfr * is an ambiguity in the NFS version 2 protocol. 5099336Sdfr * 5109336Sdfr * VREG should be taken literally as a regular file. If a 5119336Sdfr * server intents to return some type information differently 5129336Sdfr * in the upper bits of the mode field (e.g. for sockets, or 5139336Sdfr * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we 5149336Sdfr * leave the examination of the mode bits even in the VREG 5159336Sdfr * case to avoid breakage for bogus servers, but we make sure 5169336Sdfr * that there are actually type bits set in the upper part of 5179336Sdfr * fa_mode (and failing that, trust the va_type field). 5189336Sdfr * 5199336Sdfr * NFSv3 cleared the issue, and requires fa_mode to not 5209336Sdfr * contain any type information (while also introduing sockets 5219336Sdfr * and FIFOs for fa_type). 5229336Sdfr */ 5239336Sdfr if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) 5249336Sdfr vtyp = IFTOVT(vmode); 52536541Speter rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); 5269336Sdfr fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 5279336Sdfr 5289336Sdfr /* 5299336Sdfr * Really ugly NFSv2 kludge. 5309336Sdfr */ 5319336Sdfr if (vtyp == VCHR && rdev == 0xffffffff) 5329336Sdfr vtyp = VFIFO; 5331541Srgrimes } 5349336Sdfr 5351541Srgrimes /* 5361541Srgrimes * If v_type == VNON it is a new node, so fill in the v_type, 5378876Srgrimes * n_mtime fields. Check to see if it represents a special 5381541Srgrimes * device, and if so, check for a possible alias. Once the 5391541Srgrimes * correct vnode has been obtained, fill in the rest of the 5401541Srgrimes * information. 5411541Srgrimes */ 5421541Srgrimes np = VTONFS(vp); 54310219Sdfr if (vp->v_type != vtyp) { 5449336Sdfr vp->v_type = vtyp; 545126851Sphk if (vp->v_type == VFIFO) 546138290Sphk vp->v_op = &nfs_fifoops; 54718397Snate np->n_mtime = mtime.tv_sec; 5481541Srgrimes } 5491541Srgrimes vap = &np->n_vattr; 5501541Srgrimes vap->va_type = vtyp; 5511541Srgrimes vap->va_mode = (vmode & 07777); 55247028Sphk vap->va_rdev = rdev; 5531541Srgrimes vap->va_mtime = mtime; 5541541Srgrimes vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 5559336Sdfr if (v3) { 5569336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 5579336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 5589336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 55947751Speter vap->va_size = fxdr_hyper(&fp->fa3_size); 5609336Sdfr vap->va_blocksize = NFS_FABLKSIZE; 56147751Speter vap->va_bytes = fxdr_hyper(&fp->fa3_used); 56236541Speter vap->va_fileid = fxdr_unsigned(int32_t, 56336541Speter fp->fa3_fileid.nfsuquad[1]); 5649336Sdfr fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 5659336Sdfr fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 5669336Sdfr vap->va_flags = 0; 5679336Sdfr vap->va_filerev = 0; 5681541Srgrimes } else { 5699336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 5709336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 5719336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 57236541Speter vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 57336541Speter vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 57447751Speter vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) 57536541Speter * NFS_FABLKSIZE; 57636541Speter vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); 5779336Sdfr fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 5781541Srgrimes vap->va_flags = 0; 57936541Speter vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, 58036541Speter fp->fa2_ctime.nfsv2_sec); 58118397Snate vap->va_ctime.tv_nsec = 0; 58283651Speter vap->va_gen = fxdr_unsigned(u_int32_t, fp->fa2_ctime.nfsv2_usec); 5831541Srgrimes vap->va_filerev = 0; 5841541Srgrimes } 58567486Sdwmalone np->n_attrstamp = time_second; 5861541Srgrimes if (vap->va_size != np->n_size) { 5871541Srgrimes if (vap->va_type == VREG) { 58867486Sdwmalone if (dontshrink && vap->va_size < np->n_size) { 58967486Sdwmalone /* 59067486Sdwmalone * We've been told not to shrink the file; 59167486Sdwmalone * zero np->n_attrstamp to indicate that 59267486Sdwmalone * the attributes are stale. 59367486Sdwmalone */ 59467486Sdwmalone vap->va_size = np->n_size; 59567486Sdwmalone np->n_attrstamp = 0; 59667486Sdwmalone } else if (np->n_flag & NMODIFIED) { 597128263Speadar /* 598128263Speadar * We've modified the file: Use the larger 599128263Speadar * of our size, and the server's size. 600128263Speadar */ 601128263Speadar if (vap->va_size < np->n_size) { 6021541Srgrimes vap->va_size = np->n_size; 603128263Speadar } else { 6041541Srgrimes np->n_size = vap->va_size; 605128263Speadar np->n_flag |= NSIZECHANGED; 606128263Speadar } 60754480Sdillon } else { 6081541Srgrimes np->n_size = vap->va_size; 609128263Speadar np->n_flag |= NSIZECHANGED; 61054480Sdillon } 61141026Speter vnode_pager_setsize(vp, np->n_size); 61254480Sdillon } else { 6131541Srgrimes np->n_size = vap->va_size; 61454480Sdillon } 6151541Srgrimes } 6161541Srgrimes if (vaper != NULL) { 6171541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 6181541Srgrimes if (np->n_flag & NCHG) { 6199336Sdfr if (np->n_flag & NACC) 6209336Sdfr vaper->va_atime = np->n_atim; 6219336Sdfr if (np->n_flag & NUPD) 6229336Sdfr vaper->va_mtime = np->n_mtim; 6231541Srgrimes } 6241541Srgrimes } 6251541Srgrimes return (0); 6261541Srgrimes} 6271541Srgrimes 62836176Speter#ifdef NFS_ACDEBUG 62936176Speter#include <sys/sysctl.h> 63044101SbdeSYSCTL_DECL(_vfs_nfs); 63136176Speterstatic int nfs_acdebug; 63236176SpeterSYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, ""); 63336176Speter#endif 63436176Speter 6351541Srgrimes/* 6361541Srgrimes * Check the time stamp 6371541Srgrimes * If the cache is valid, copy contents to *vap and return 0 6381541Srgrimes * otherwise return an error 6391541Srgrimes */ 6401549Srgrimesint 64183651Speternfs_getattrcache(struct vnode *vp, struct vattr *vaper) 6421541Srgrimes{ 64383651Speter struct nfsnode *np; 64483651Speter struct vattr *vap; 64536176Speter struct nfsmount *nmp; 64636176Speter int timeo; 6471541Srgrimes 64836176Speter np = VTONFS(vp); 64936176Speter vap = &np->n_vattr; 65036176Speter nmp = VFSTONFS(vp->v_mount); 65136176Speter /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */ 65236176Speter timeo = (time_second - np->n_mtime) / 10; 65336176Speter 65436176Speter#ifdef NFS_ACDEBUG 65536176Speter if (nfs_acdebug>1) 65636176Speter printf("nfs_getattrcache: initial timeo = %d\n", timeo); 65736176Speter#endif 65836176Speter 65936176Speter if (vap->va_type == VDIR) { 66036176Speter if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin) 66136176Speter timeo = nmp->nm_acdirmin; 66236176Speter else if (timeo > nmp->nm_acdirmax) 66336176Speter timeo = nmp->nm_acdirmax; 66436176Speter } else { 66536176Speter if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin) 66636176Speter timeo = nmp->nm_acregmin; 66736176Speter else if (timeo > nmp->nm_acregmax) 66836176Speter timeo = nmp->nm_acregmax; 66936176Speter } 67036176Speter 67136176Speter#ifdef NFS_ACDEBUG 67236176Speter if (nfs_acdebug > 2) 67336176Speter printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n", 67436176Speter nmp->nm_acregmin, nmp->nm_acregmax, 67536176Speter nmp->nm_acdirmin, nmp->nm_acdirmax); 67636176Speter 67736176Speter if (nfs_acdebug) 67837089Sbde printf("nfs_getattrcache: age = %d; final timeo = %d\n", 67936176Speter (time_second - np->n_attrstamp), timeo); 68036176Speter#endif 68136176Speter 68236176Speter if ((time_second - np->n_attrstamp) >= timeo) { 6831541Srgrimes nfsstats.attrcache_misses++; 6841541Srgrimes return (ENOENT); 6851541Srgrimes } 6861541Srgrimes nfsstats.attrcache_hits++; 6871541Srgrimes if (vap->va_size != np->n_size) { 6881541Srgrimes if (vap->va_type == VREG) { 6891541Srgrimes if (np->n_flag & NMODIFIED) { 6901541Srgrimes if (vap->va_size < np->n_size) 6911541Srgrimes vap->va_size = np->n_size; 6921541Srgrimes else 6931541Srgrimes np->n_size = vap->va_size; 69454480Sdillon } else { 6951541Srgrimes np->n_size = vap->va_size; 69654480Sdillon } 69741026Speter vnode_pager_setsize(vp, np->n_size); 69854480Sdillon } else { 6991541Srgrimes np->n_size = vap->va_size; 70054480Sdillon } 7011541Srgrimes } 7021541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 7031541Srgrimes if (np->n_flag & NCHG) { 7049336Sdfr if (np->n_flag & NACC) 7059336Sdfr vaper->va_atime = np->n_atim; 7069336Sdfr if (np->n_flag & NUPD) 7079336Sdfr vaper->va_mtime = np->n_mtim; 7081541Srgrimes } 7091541Srgrimes return (0); 7101541Srgrimes} 7111541Srgrimes 71243305Sdillonstatic nfsuint64 nfs_nullcookie = { { 0, 0 } }; 7139336Sdfr/* 7149336Sdfr * This function finds the directory cookie that corresponds to the 7159336Sdfr * logical byte offset given. 7169336Sdfr */ 7179336Sdfrnfsuint64 * 71883651Speternfs_getcookie(struct nfsnode *np, off_t off, int add) 7199336Sdfr{ 72083651Speter struct nfsdmap *dp, *dp2; 72183651Speter int pos; 7229336Sdfr 72336979Sbde pos = (uoff_t)off / NFS_DIRBLKSIZ; 72436979Sbde if (pos == 0 || off < 0) { 7259336Sdfr#ifdef DIAGNOSTIC 7269336Sdfr if (add) 72736979Sbde panic("nfs getcookie add at <= 0"); 7289336Sdfr#endif 7299336Sdfr return (&nfs_nullcookie); 7309336Sdfr } 7319336Sdfr pos--; 73283651Speter dp = LIST_FIRST(&np->n_cookies); 7339336Sdfr if (!dp) { 7349336Sdfr if (add) { 7359336Sdfr MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 736111119Simp M_NFSDIROFF, M_WAITOK); 7379336Sdfr dp->ndm_eocookie = 0; 7389336Sdfr LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 7399336Sdfr } else 74099797Sdillon return (NULL); 7419336Sdfr } 7429336Sdfr while (pos >= NFSNUMCOOKIES) { 7439336Sdfr pos -= NFSNUMCOOKIES; 74483651Speter if (LIST_NEXT(dp, ndm_list)) { 7459336Sdfr if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 7469336Sdfr pos >= dp->ndm_eocookie) 74799797Sdillon return (NULL); 74883651Speter dp = LIST_NEXT(dp, ndm_list); 7499336Sdfr } else if (add) { 7509336Sdfr MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 751111119Simp M_NFSDIROFF, M_WAITOK); 7529336Sdfr dp2->ndm_eocookie = 0; 7539336Sdfr LIST_INSERT_AFTER(dp, dp2, ndm_list); 7549336Sdfr dp = dp2; 7559336Sdfr } else 75699797Sdillon return (NULL); 7579336Sdfr } 7589336Sdfr if (pos >= dp->ndm_eocookie) { 7599336Sdfr if (add) 7609336Sdfr dp->ndm_eocookie = pos + 1; 7619336Sdfr else 76299797Sdillon return (NULL); 7639336Sdfr } 7649336Sdfr return (&dp->ndm_cookies[pos]); 7659336Sdfr} 7669336Sdfr 7679336Sdfr/* 7689336Sdfr * Invalidate cached directory information, except for the actual directory 7699336Sdfr * blocks (which are invalidated separately). 7709336Sdfr * Done mainly to avoid the use of stale offset cookies. 7719336Sdfr */ 7729336Sdfrvoid 77383651Speternfs_invaldir(struct vnode *vp) 7749336Sdfr{ 77583651Speter struct nfsnode *np = VTONFS(vp); 7769336Sdfr 7779336Sdfr#ifdef DIAGNOSTIC 7789336Sdfr if (vp->v_type != VDIR) 7799336Sdfr panic("nfs: invaldir not dir"); 7809336Sdfr#endif 7819336Sdfr np->n_direofoffset = 0; 7829336Sdfr np->n_cookieverf.nfsuquad[0] = 0; 7839336Sdfr np->n_cookieverf.nfsuquad[1] = 0; 78483651Speter if (LIST_FIRST(&np->n_cookies)) 78583651Speter LIST_FIRST(&np->n_cookies)->ndm_eocookie = 0; 7869336Sdfr} 7879336Sdfr 7889336Sdfr/* 7899336Sdfr * The write verifier has changed (probably due to a server reboot), so all 7909336Sdfr * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 7919336Sdfr * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 79254480Sdillon * and B_CLUSTEROK flags. Once done the new write verifier can be set for the 79354480Sdillon * mount point. 79454480Sdillon * 79583651Speter * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data 79654480Sdillon * writes are not clusterable. 7979336Sdfr */ 7989336Sdfrvoid 79983651Speternfs_clearcommit(struct mount *mp) 8009336Sdfr{ 80183651Speter struct vnode *vp, *nvp; 80283651Speter struct buf *bp, *nbp; 8039336Sdfr int s; 8049336Sdfr 80579224Sdillon GIANT_REQUIRED; 80679224Sdillon 8079336Sdfr s = splbio(); 808122091Skan MNT_ILOCK(mp); 809131551Sphk MNT_VNODE_FOREACH(vp, mp, nvp) { 810103939Sjeff VI_LOCK(vp); 811120787Sjeff if (vp->v_iflag & VI_XLOCK) { 812120787Sjeff VI_UNLOCK(vp); 813120787Sjeff continue; 814120787Sjeff } 815122091Skan MNT_IUNLOCK(mp); 816136767Sphk TAILQ_FOREACH_SAFE(bp, &vp->v_bufobj.bo_dirty.bv_hd, b_bobufs, nbp) { 81748225Smckusick if (BUF_REFCNT(bp) == 0 && 81848225Smckusick (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) 8199336Sdfr == (B_DELWRI | B_NEEDCOMMIT)) 82054480Sdillon bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); 8219336Sdfr } 822103939Sjeff VI_UNLOCK(vp); 823122091Skan MNT_ILOCK(mp); 8249336Sdfr } 825122091Skan MNT_IUNLOCK(mp); 8269336Sdfr splx(s); 8279336Sdfr} 8289336Sdfr 8299336Sdfr/* 83083651Speter * Helper functions for former macros. Some of these should be 83183651Speter * moved to their callers. 8329336Sdfr */ 83383651Speter 8345455Sdgint 83583651Speternfsm_mtofh_xx(struct vnode *d, struct vnode **v, int v3, int *f, 83688091Siedowse struct mbuf **md, caddr_t *dpos) 8379336Sdfr{ 83883651Speter struct nfsnode *ttnp; 83983651Speter struct vnode *ttvp; 84083651Speter nfsfh_t *ttfhp; 84188091Siedowse u_int32_t *tl; 84283651Speter int ttfhsize; 84383651Speter int t1; 8449336Sdfr 84583651Speter if (v3) { 84688091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 84788091Siedowse if (tl == NULL) 84884057Speter return EBADRPC; 84988091Siedowse *f = fxdr_unsigned(int, *tl); 85083651Speter } else 85183651Speter *f = 1; 85283651Speter if (*f) { 85388091Siedowse t1 = nfsm_getfh_xx(&ttfhp, &ttfhsize, (v3), md, dpos); 85483651Speter if (t1 != 0) 85583651Speter return t1; 85683651Speter t1 = nfs_nget(d->v_mount, ttfhp, ttfhsize, &ttnp); 85783651Speter if (t1 != 0) 85883651Speter return t1; 85983651Speter *v = NFSTOV(ttnp); 86083651Speter } 86183651Speter if (v3) { 86288091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 86388091Siedowse if (tl == NULL) 86484057Speter return EBADRPC; 86583651Speter if (*f) 86688091Siedowse *f = fxdr_unsigned(int, *tl); 86788091Siedowse else if (fxdr_unsigned(int, *tl)) 86888091Siedowse nfsm_adv_xx(NFSX_V3FATTR, md, dpos); 86983651Speter } 87083651Speter if (*f) { 87183651Speter ttvp = *v; 87299797Sdillon t1 = nfs_loadattrcache(&ttvp, md, dpos, NULL, 0); 87383651Speter if (t1) 87483651Speter return t1; 87583651Speter *v = ttvp; 87683651Speter } 87783651Speter return 0; 87883651Speter} 87983651Speter 88083651Speterint 88188091Siedowsenfsm_getfh_xx(nfsfh_t **f, int *s, int v3, struct mbuf **md, caddr_t *dpos) 88283651Speter{ 88388091Siedowse u_int32_t *tl; 88483651Speter 88583651Speter if (v3) { 88688091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 88788091Siedowse if (tl == NULL) 88884057Speter return EBADRPC; 88988091Siedowse *s = fxdr_unsigned(int, *tl); 89084057Speter if (*s <= 0 || *s > NFSX_V3FHMAX) 89183651Speter return EBADRPC; 89283651Speter } else 89383651Speter *s = NFSX_V2FH; 89484057Speter *f = nfsm_dissect_xx(nfsm_rndup(*s), md, dpos); 89584057Speter if (*f == NULL) 89684057Speter return EBADRPC; 89784057Speter else 89884057Speter return 0; 89983651Speter} 90083651Speter 90183651Speter 90283651Speterint 90388091Siedowsenfsm_loadattr_xx(struct vnode **v, struct vattr *va, struct mbuf **md, 90488091Siedowse caddr_t *dpos) 90583651Speter{ 90683651Speter int t1; 90783651Speter 90883651Speter struct vnode *ttvp = *v; 90983651Speter t1 = nfs_loadattrcache(&ttvp, md, dpos, va, 0); 91083651Speter if (t1 != 0) 91183651Speter return t1; 91283651Speter *v = ttvp; 91383651Speter return 0; 91483651Speter} 91583651Speter 91683651Speterint 91788091Siedowsenfsm_postop_attr_xx(struct vnode **v, int *f, struct mbuf **md, 91888091Siedowse caddr_t *dpos) 91983651Speter{ 92088091Siedowse u_int32_t *tl; 92183651Speter int t1; 92283651Speter 92383651Speter struct vnode *ttvp = *v; 92488091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 92588091Siedowse if (tl == NULL) 92684057Speter return EBADRPC; 92788091Siedowse *f = fxdr_unsigned(int, *tl); 92883914Siedowse if (*f != 0) { 92999797Sdillon t1 = nfs_loadattrcache(&ttvp, md, dpos, NULL, 1); 93083651Speter if (t1 != 0) { 93183651Speter *f = 0; 93283651Speter return t1; 93383651Speter } 93483651Speter *v = ttvp; 9359336Sdfr } 93683651Speter return 0; 9379336Sdfr} 9389336Sdfr 9399336Sdfrint 94088091Siedowsenfsm_wcc_data_xx(struct vnode **v, int *f, struct mbuf **md, caddr_t *dpos) 94131886Sbde{ 94288091Siedowse u_int32_t *tl; 94383651Speter int ttattrf, ttretf = 0; 94483651Speter int t1; 9455455Sdg 94688091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 94788091Siedowse if (tl == NULL) 94884057Speter return EBADRPC; 94988091Siedowse if (*tl == nfs_true) { 95088091Siedowse tl = nfsm_dissect_xx(6 * NFSX_UNSIGNED, md, dpos); 95188091Siedowse if (tl == NULL) 95284057Speter return EBADRPC; 95383651Speter if (*f) 95483651Speter ttretf = (VTONFS(*v)->n_mtime == 95588091Siedowse fxdr_unsigned(u_int32_t, *(tl + 2))); 95683651Speter } 95788091Siedowse t1 = nfsm_postop_attr_xx(v, &ttattrf, md, dpos); 95883651Speter if (t1) 95983651Speter return t1; 96083651Speter if (*f) 96183651Speter *f = ttretf; 96283651Speter else 96383651Speter *f = ttattrf; 96483651Speter return 0; 9655455Sdg} 96636503Speter 96783651Speterint 96888091Siedowsenfsm_strtom_xx(const char *a, int s, int m, struct mbuf **mb, caddr_t *bpos) 96936503Speter{ 97088091Siedowse u_int32_t *tl; 97183651Speter int t1; 97236503Speter 97383651Speter if (s > m) 97483651Speter return ENAMETOOLONG; 97583651Speter t1 = nfsm_rndup(s) + NFSX_UNSIGNED; 97683651Speter if (t1 <= M_TRAILINGSPACE(*mb)) { 97788091Siedowse tl = nfsm_build_xx(t1, mb, bpos); 97888091Siedowse *tl++ = txdr_unsigned(s); 97988091Siedowse *(tl + ((t1 >> 2) - 2)) = 0; 98088091Siedowse bcopy(a, tl, s); 98183651Speter } else { 98283651Speter t1 = nfsm_strtmbuf(mb, bpos, a, s); 98383651Speter if (t1 != 0) 98483651Speter return t1; 98536503Speter } 98683651Speter return 0; 98736503Speter} 98836503Speter 98983651Speterint 99088091Siedowsenfsm_fhtom_xx(struct vnode *v, int v3, struct mbuf **mb, caddr_t *bpos) 99183651Speter{ 99288091Siedowse u_int32_t *tl; 99383651Speter int t1; 99483651Speter caddr_t cp; 99583651Speter 99683651Speter if (v3) { 99783651Speter t1 = nfsm_rndup(VTONFS(v)->n_fhsize) + NFSX_UNSIGNED; 99883651Speter if (t1 < M_TRAILINGSPACE(*mb)) { 99988091Siedowse tl = nfsm_build_xx(t1, mb, bpos); 100088091Siedowse *tl++ = txdr_unsigned(VTONFS(v)->n_fhsize); 100188091Siedowse *(tl + ((t1 >> 2) - 2)) = 0; 100288091Siedowse bcopy(VTONFS(v)->n_fhp, tl, VTONFS(v)->n_fhsize); 100383651Speter } else { 100483651Speter t1 = nfsm_strtmbuf(mb, bpos, 100583651Speter (const char *)VTONFS(v)->n_fhp, 100683651Speter VTONFS(v)->n_fhsize); 100783651Speter if (t1 != 0) 100883651Speter return t1; 100983651Speter } 101083651Speter } else { 101184002Speter cp = nfsm_build_xx(NFSX_V2FH, mb, bpos); 101283651Speter bcopy(VTONFS(v)->n_fhp, cp, NFSX_V2FH); 101383651Speter } 101483651Speter return 0; 101583651Speter} 101683651Speter 101736503Spetervoid 101888091Siedowsenfsm_v3attrbuild_xx(struct vattr *va, int full, struct mbuf **mb, 101988091Siedowse caddr_t *bpos) 102036503Speter{ 102188091Siedowse u_int32_t *tl; 102236503Speter 102383651Speter if (va->va_mode != (mode_t)VNOVAL) { 102488091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 102588091Siedowse *tl++ = nfs_true; 102688091Siedowse *tl = txdr_unsigned(va->va_mode); 102783651Speter } else { 102888091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 102988091Siedowse *tl = nfs_false; 103083651Speter } 103183651Speter if (full && va->va_uid != (uid_t)VNOVAL) { 103288091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 103388091Siedowse *tl++ = nfs_true; 103488091Siedowse *tl = txdr_unsigned(va->va_uid); 103583651Speter } else { 103688091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 103788091Siedowse *tl = nfs_false; 103883651Speter } 103983651Speter if (full && va->va_gid != (gid_t)VNOVAL) { 104088091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 104188091Siedowse *tl++ = nfs_true; 104288091Siedowse *tl = txdr_unsigned(va->va_gid); 104383651Speter } else { 104488091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 104588091Siedowse *tl = nfs_false; 104683651Speter } 104783651Speter if (full && va->va_size != VNOVAL) { 104888091Siedowse tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 104988091Siedowse *tl++ = nfs_true; 105088091Siedowse txdr_hyper(va->va_size, tl); 105183651Speter } else { 105288091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 105388091Siedowse *tl = nfs_false; 105483651Speter } 105583651Speter if (va->va_atime.tv_sec != VNOVAL) { 105683651Speter if (va->va_atime.tv_sec != time_second) { 105788091Siedowse tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 105888091Siedowse *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 105988091Siedowse txdr_nfsv3time(&va->va_atime, tl); 106083651Speter } else { 106188091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 106288091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 106383651Speter } 106483651Speter } else { 106588091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 106688091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 106783651Speter } 106883651Speter if (va->va_mtime.tv_sec != VNOVAL) { 106983651Speter if (va->va_mtime.tv_sec != time_second) { 107088091Siedowse tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 107188091Siedowse *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 107288091Siedowse txdr_nfsv3time(&va->va_mtime, tl); 107383651Speter } else { 107488091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 107588091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 107683651Speter } 107783651Speter } else { 107888091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 107988091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 108083651Speter } 108136503Speter} 1082