nfs_subs.c revision 88091
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 * 3. All advertising materials mentioning features or use of this software 171541Srgrimes * must display the following acknowledgement: 181541Srgrimes * This product includes software developed by the University of 191541Srgrimes * California, Berkeley and its contributors. 201541Srgrimes * 4. Neither the name of the University nor the names of its contributors 211541Srgrimes * may be used to endorse or promote products derived from this software 221541Srgrimes * without specific prior written permission. 231541Srgrimes * 241541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341541Srgrimes * SUCH DAMAGE. 351541Srgrimes * 3636503Speter * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 371541Srgrimes */ 381541Srgrimes 3983651Speter#include <sys/cdefs.h> 4083651Speter__FBSDID("$FreeBSD: head/sys/nfsclient/nfs_subs.c 88091 2001-12-18 01:22:09Z iedowse $"); 4183651Speter 421541Srgrimes/* 431541Srgrimes * These functions support the macros and help fiddle mbuf chains for 441541Srgrimes * the nfs op functions. They do things like create the rpc header and 451541Srgrimes * copy data between mbuf chains and uio lists. 461541Srgrimes */ 4783651Speter 481541Srgrimes#include <sys/param.h> 4948274Speter#include <sys/systm.h> 5048274Speter#include <sys/kernel.h> 5160041Sphk#include <sys/bio.h> 5231886Sbde#include <sys/buf.h> 531541Srgrimes#include <sys/proc.h> 541541Srgrimes#include <sys/mount.h> 551541Srgrimes#include <sys/vnode.h> 561541Srgrimes#include <sys/namei.h> 571541Srgrimes#include <sys/mbuf.h> 581541Srgrimes#include <sys/socket.h> 591541Srgrimes#include <sys/stat.h> 609336Sdfr#include <sys/malloc.h> 612997Swollman#include <sys/sysent.h> 622997Swollman#include <sys/syscall.h> 6383651Speter#include <sys/sysproto.h> 641541Srgrimes 653305Sphk#include <vm/vm.h> 6612662Sdg#include <vm/vm_object.h> 6712662Sdg#include <vm/vm_extern.h> 6832011Sbde#include <vm/vm_zone.h> 693305Sphk 701541Srgrimes#include <nfs/rpcv2.h> 719336Sdfr#include <nfs/nfsproto.h> 7283651Speter#include <nfsclient/nfs.h> 7383651Speter#include <nfsclient/nfsnode.h> 741541Srgrimes#include <nfs/xdr_subs.h> 7583651Speter#include <nfsclient/nfsm_subs.h> 7683651Speter#include <nfsclient/nfsmount.h> 771541Srgrimes 781541Srgrimes#include <netinet/in.h> 791541Srgrimes 801541Srgrimes/* 811541Srgrimes * Data items converted to xdr at startup, since they are constant 821541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps 831541Srgrimes */ 8483651Speteru_int32_t nfs_xdrneg1; 8583651Speteru_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 8683651Speter rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 8783651Speteru_int32_t nfs_true, nfs_false; 881541Srgrimes 891541Srgrimes/* And other global data */ 9036541Speterstatic u_int32_t nfs_xid = 0; 9112911Sphkstatic enum vtype nv2tov_type[8]= { 9283651Speter VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON 9312911Sphk}; 9412911Sphk 9583651Speterint nfs_ticks; 9683651Speterint nfs_pbuf_freecnt = -1; /* start out unlimited */ 979336Sdfr 9883651Speterstruct nfs_reqq nfs_reqq; 9983651Speterstruct nfs_bufq nfs_bufq; 1009759Sbde 10183651Speterstatic int nfs_prev_nfsclnt_sy_narg; 10283651Speterstatic sy_call_t *nfs_prev_nfsclnt_sy_call; 10338894Sbde 1049336Sdfr/* 1059336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers 1069336Sdfr */ 1079336Sdfrint nfsv2_procid[NFS_NPROCS] = { 1089336Sdfr NFSV2PROC_NULL, 1099336Sdfr NFSV2PROC_GETATTR, 1109336Sdfr NFSV2PROC_SETATTR, 1119336Sdfr NFSV2PROC_LOOKUP, 1129336Sdfr NFSV2PROC_NOOP, 1139336Sdfr NFSV2PROC_READLINK, 1149336Sdfr NFSV2PROC_READ, 1159336Sdfr NFSV2PROC_WRITE, 1169336Sdfr NFSV2PROC_CREATE, 1179336Sdfr NFSV2PROC_MKDIR, 1189336Sdfr NFSV2PROC_SYMLINK, 1199336Sdfr NFSV2PROC_CREATE, 1209336Sdfr NFSV2PROC_REMOVE, 1219336Sdfr NFSV2PROC_RMDIR, 1229336Sdfr NFSV2PROC_RENAME, 1239336Sdfr NFSV2PROC_LINK, 1249336Sdfr NFSV2PROC_READDIR, 1259336Sdfr NFSV2PROC_NOOP, 1269336Sdfr NFSV2PROC_STATFS, 1279336Sdfr NFSV2PROC_NOOP, 1289336Sdfr NFSV2PROC_NOOP, 1299336Sdfr NFSV2PROC_NOOP, 1309336Sdfr NFSV2PROC_NOOP, 1319336Sdfr}; 1329336Sdfr 13360938SjakeLIST_HEAD(nfsnodehashhead, nfsnode); 1343664Sphk 1351541Srgrimes/* 1361541Srgrimes * Create the header for an rpc request packet 1371541Srgrimes * The hsiz is the size of the rest of the nfs request header. 1381541Srgrimes * (just used to decide if a cluster is a good idea) 1391541Srgrimes */ 1401541Srgrimesstruct mbuf * 14183651Speternfsm_reqhead(struct vnode *vp, u_long procid, int hsiz) 1421541Srgrimes{ 14383651Speter struct mbuf *mb; 1441541Srgrimes 14570254Sbmilekic MGET(mb, M_TRYWAIT, MT_DATA); 1461541Srgrimes if (hsiz >= MINCLSIZE) 14770254Sbmilekic MCLGET(mb, M_TRYWAIT); 1481541Srgrimes mb->m_len = 0; 1491541Srgrimes return (mb); 1501541Srgrimes} 1511541Srgrimes 1521541Srgrimes/* 1531541Srgrimes * Build the RPC header and fill in the authorization info. 1541541Srgrimes * The authorization string argument is only used when the credentials 1551541Srgrimes * come from outside of the kernel. 1561541Srgrimes * Returns the head of the mbuf list. 1571541Srgrimes */ 1581541Srgrimesstruct mbuf * 15983651Speternfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type, 16083651Speter int auth_len, struct mbuf *mrest, int mrest_len, struct mbuf **mbp, 16183651Speter u_int32_t *xidp) 1621541Srgrimes{ 16383651Speter struct mbuf *mb; 16483651Speter u_int32_t *tl; 16583651Speter caddr_t bpos; 16683651Speter int i; 16783651Speter struct mbuf *mreq; 16883651Speter int grpsiz, authsiz; 1691541Srgrimes 1701541Srgrimes authsiz = nfsm_rndup(auth_len); 17170254Sbmilekic MGETHDR(mb, M_TRYWAIT, MT_DATA); 1729336Sdfr if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { 17370254Sbmilekic MCLGET(mb, M_TRYWAIT); 1749336Sdfr } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { 1759336Sdfr MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 1761541Srgrimes } else { 1779336Sdfr MH_ALIGN(mb, 8 * NFSX_UNSIGNED); 1781541Srgrimes } 1791541Srgrimes mb->m_len = 0; 1801541Srgrimes mreq = mb; 1811541Srgrimes bpos = mtod(mb, caddr_t); 1821541Srgrimes 1831541Srgrimes /* 1841541Srgrimes * First the RPC header. 1851541Srgrimes */ 18684002Speter tl = nfsm_build(u_int32_t *, 8 * NFSX_UNSIGNED); 18717186Sdfr 18835066Sphk /* Get a pretty random xid to start with */ 18983651Speter if (!nfs_xid) 19035066Sphk nfs_xid = random(); 19117186Sdfr /* 19217186Sdfr * Skip zero xid if it should ever happen. 19317186Sdfr */ 1941541Srgrimes if (++nfs_xid == 0) 1951541Srgrimes nfs_xid++; 19617186Sdfr 1971541Srgrimes *tl++ = *xidp = txdr_unsigned(nfs_xid); 1981541Srgrimes *tl++ = rpc_call; 1991541Srgrimes *tl++ = rpc_vers; 20083651Speter *tl++ = txdr_unsigned(NFS_PROG); 20183651Speter if (nmflag & NFSMNT_NFSV3) { 20283651Speter *tl++ = txdr_unsigned(NFS_VER3); 20383651Speter *tl++ = txdr_unsigned(procid); 2041541Srgrimes } else { 20583651Speter *tl++ = txdr_unsigned(NFS_VER2); 20683651Speter *tl++ = txdr_unsigned(nfsv2_procid[procid]); 2071541Srgrimes } 2081541Srgrimes 2091541Srgrimes /* 2101541Srgrimes * And then the authorization cred. 2111541Srgrimes */ 2121541Srgrimes *tl++ = txdr_unsigned(auth_type); 2131541Srgrimes *tl = txdr_unsigned(authsiz); 2141541Srgrimes switch (auth_type) { 2151541Srgrimes case RPCAUTH_UNIX: 21684002Speter tl = nfsm_build(u_int32_t *, auth_len); 2171541Srgrimes *tl++ = 0; /* stamp ?? */ 2181541Srgrimes *tl++ = 0; /* NULL hostname */ 2191541Srgrimes *tl++ = txdr_unsigned(cr->cr_uid); 2201541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[0]); 2211541Srgrimes grpsiz = (auth_len >> 2) - 5; 2221541Srgrimes *tl++ = txdr_unsigned(grpsiz); 2231541Srgrimes for (i = 1; i <= grpsiz; i++) 2241541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[i]); 2251541Srgrimes break; 22683651Speter } 2279336Sdfr 2289336Sdfr /* 2299336Sdfr * And the verifier... 2309336Sdfr */ 23184002Speter tl = nfsm_build(u_int32_t *, 2 * NFSX_UNSIGNED); 23283651Speter *tl++ = txdr_unsigned(RPCAUTH_NULL); 23383651Speter *tl = 0; 2341541Srgrimes mb->m_next = mrest; 2359336Sdfr mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; 2361541Srgrimes mreq->m_pkthdr.rcvif = (struct ifnet *)0; 2371541Srgrimes *mbp = mb; 2381541Srgrimes return (mreq); 2391541Srgrimes} 2401541Srgrimes 2411541Srgrimes/* 24217186Sdfr * copies a uio scatter/gather list to an mbuf chain. 24317186Sdfr * NOTE: can ony handle iovcnt == 1 2441541Srgrimes */ 2451549Srgrimesint 24683651Speternfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos) 2471541Srgrimes{ 24883651Speter char *uiocp; 24983651Speter struct mbuf *mp, *mp2; 25083651Speter int xfer, left, mlen; 2511541Srgrimes int uiosiz, clflg, rem; 2521541Srgrimes char *cp; 2531541Srgrimes 25436519Speter#ifdef DIAGNOSTIC 25517186Sdfr if (uiop->uio_iovcnt != 1) 25617186Sdfr panic("nfsm_uiotombuf: iovcnt != 1"); 25736519Speter#endif 25817186Sdfr 2591541Srgrimes if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 2601541Srgrimes clflg = 1; 2611541Srgrimes else 2621541Srgrimes clflg = 0; 2631541Srgrimes rem = nfsm_rndup(siz)-siz; 2641541Srgrimes mp = mp2 = *mq; 2651541Srgrimes while (siz > 0) { 2661541Srgrimes left = uiop->uio_iov->iov_len; 2671541Srgrimes uiocp = uiop->uio_iov->iov_base; 2681541Srgrimes if (left > siz) 2691541Srgrimes left = siz; 2701541Srgrimes uiosiz = left; 2711541Srgrimes while (left > 0) { 2721541Srgrimes mlen = M_TRAILINGSPACE(mp); 2731541Srgrimes if (mlen == 0) { 27470254Sbmilekic MGET(mp, M_TRYWAIT, MT_DATA); 2751541Srgrimes if (clflg) 27670254Sbmilekic MCLGET(mp, M_TRYWAIT); 2771541Srgrimes mp->m_len = 0; 2781541Srgrimes mp2->m_next = mp; 2791541Srgrimes mp2 = mp; 2801541Srgrimes mlen = M_TRAILINGSPACE(mp); 2811541Srgrimes } 2821541Srgrimes xfer = (left > mlen) ? mlen : left; 2831541Srgrimes#ifdef notdef 2841541Srgrimes /* Not Yet.. */ 2851541Srgrimes if (uiop->uio_iov->iov_op != NULL) 2861541Srgrimes (*(uiop->uio_iov->iov_op)) 2871541Srgrimes (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 2881541Srgrimes else 2891541Srgrimes#endif 2901541Srgrimes if (uiop->uio_segflg == UIO_SYSSPACE) 2911541Srgrimes bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 2921541Srgrimes else 2931541Srgrimes copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 2941541Srgrimes mp->m_len += xfer; 2951541Srgrimes left -= xfer; 2961541Srgrimes uiocp += xfer; 2971541Srgrimes uiop->uio_offset += xfer; 2981541Srgrimes uiop->uio_resid -= xfer; 2991541Srgrimes } 30017186Sdfr uiop->uio_iov->iov_base += uiosiz; 30117186Sdfr uiop->uio_iov->iov_len -= uiosiz; 3021541Srgrimes siz -= uiosiz; 3031541Srgrimes } 3041541Srgrimes if (rem > 0) { 3051541Srgrimes if (rem > M_TRAILINGSPACE(mp)) { 30670254Sbmilekic MGET(mp, M_TRYWAIT, MT_DATA); 3071541Srgrimes mp->m_len = 0; 3081541Srgrimes mp2->m_next = mp; 3091541Srgrimes } 3101541Srgrimes cp = mtod(mp, caddr_t)+mp->m_len; 3111541Srgrimes for (left = 0; left < rem; left++) 3121541Srgrimes *cp++ = '\0'; 3131541Srgrimes mp->m_len += rem; 3141541Srgrimes *bpos = cp; 3151541Srgrimes } else 3161541Srgrimes *bpos = mtod(mp, caddr_t)+mp->m_len; 3171541Srgrimes *mq = mp; 3181541Srgrimes return (0); 3191541Srgrimes} 3201541Srgrimes 3211541Srgrimes/* 3221541Srgrimes * Copy a string into mbufs for the hard cases... 3231541Srgrimes */ 3241549Srgrimesint 32583651Speternfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz) 3261541Srgrimes{ 32783651Speter struct mbuf *m1 = NULL, *m2; 3281541Srgrimes long left, xfer, len, tlen; 32936541Speter u_int32_t *tl; 3301541Srgrimes int putsize; 3311541Srgrimes 3321541Srgrimes putsize = 1; 3331541Srgrimes m2 = *mb; 3341541Srgrimes left = M_TRAILINGSPACE(m2); 3351541Srgrimes if (left > 0) { 33636541Speter tl = ((u_int32_t *)(*bpos)); 3371541Srgrimes *tl++ = txdr_unsigned(siz); 3381541Srgrimes putsize = 0; 3391541Srgrimes left -= NFSX_UNSIGNED; 3401541Srgrimes m2->m_len += NFSX_UNSIGNED; 3411541Srgrimes if (left > 0) { 3421541Srgrimes bcopy(cp, (caddr_t) tl, left); 3431541Srgrimes siz -= left; 3441541Srgrimes cp += left; 3451541Srgrimes m2->m_len += left; 3461541Srgrimes left = 0; 3471541Srgrimes } 3481541Srgrimes } 3491541Srgrimes /* Loop around adding mbufs */ 3501541Srgrimes while (siz > 0) { 35170254Sbmilekic MGET(m1, M_TRYWAIT, MT_DATA); 3521541Srgrimes if (siz > MLEN) 35370254Sbmilekic MCLGET(m1, M_TRYWAIT); 3541541Srgrimes m1->m_len = NFSMSIZ(m1); 3551541Srgrimes m2->m_next = m1; 3561541Srgrimes m2 = m1; 35736541Speter tl = mtod(m1, u_int32_t *); 3581541Srgrimes tlen = 0; 3591541Srgrimes if (putsize) { 3601541Srgrimes *tl++ = txdr_unsigned(siz); 3611541Srgrimes m1->m_len -= NFSX_UNSIGNED; 3621541Srgrimes tlen = NFSX_UNSIGNED; 3631541Srgrimes putsize = 0; 3641541Srgrimes } 3651541Srgrimes if (siz < m1->m_len) { 3661541Srgrimes len = nfsm_rndup(siz); 3671541Srgrimes xfer = siz; 3681541Srgrimes if (xfer < len) 3691541Srgrimes *(tl+(xfer>>2)) = 0; 3701541Srgrimes } else { 3711541Srgrimes xfer = len = m1->m_len; 3721541Srgrimes } 3731541Srgrimes bcopy(cp, (caddr_t) tl, xfer); 3741541Srgrimes m1->m_len = len+tlen; 3751541Srgrimes siz -= xfer; 3761541Srgrimes cp += xfer; 3771541Srgrimes } 3781541Srgrimes *mb = m1; 3791541Srgrimes *bpos = mtod(m1, caddr_t)+m1->m_len; 3801541Srgrimes return (0); 3811541Srgrimes} 3821541Srgrimes 3831541Srgrimes/* 3841541Srgrimes * Called once to initialize data structures... 3851541Srgrimes */ 3861549Srgrimesint 38783651Speternfs_init(struct vfsconf *vfsp) 3881541Srgrimes{ 38983651Speter int i; 3901541Srgrimes 39136329Speter nfsmount_zone = zinit("NFSMOUNT", sizeof(struct nfsmount), 0, 0, 1); 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++) { 4081541Srgrimes nfs_iodwant[i] = (struct proc *)0; 40919449Sdfr nfs_iodmount[i] = (struct nfsmount *)0; 41019449Sdfr } 4111541Srgrimes nfs_nhinit(); /* Init the nfsnode table */ 4121541Srgrimes 4131541Srgrimes /* 4141541Srgrimes * Initialize reply list and start timer 4151541Srgrimes */ 4163664Sphk TAILQ_INIT(&nfs_reqq); 41716365Sphk 4183305Sphk nfs_timer(0); 4191549Srgrimes 42083651Speter nfs_prev_nfsclnt_sy_narg = sysent[SYS_nfsclnt].sy_narg; 42183651Speter sysent[SYS_nfsclnt].sy_narg = 2; 42283651Speter nfs_prev_nfsclnt_sy_call = sysent[SYS_nfsclnt].sy_call; 42383651Speter sysent[SYS_nfsclnt].sy_call = (sy_call_t *)nfsclnt; 4242997Swollman 42542957Sdillon nfs_pbuf_freecnt = nswbuf / 2 + 1; 42642957Sdillon 4271549Srgrimes return (0); 4281541Srgrimes} 4291541Srgrimes 43038894Sbdeint 43183651Speternfs_uninit(struct vfsconf *vfsp) 43238894Sbde{ 43338894Sbde 43438894Sbde untimeout(nfs_timer, (void *)NULL, nfs_timer_handle); 43583651Speter sysent[SYS_nfsclnt].sy_narg = nfs_prev_nfsclnt_sy_narg; 43683651Speter sysent[SYS_nfsclnt].sy_call = nfs_prev_nfsclnt_sy_call; 43738894Sbde return (0); 43838894Sbde} 43938894Sbde 4401541Srgrimes/* 4411541Srgrimes * Attribute cache routines. 4421541Srgrimes * nfs_loadattrcache() - loads or updates the cache contents from attributes 4431541Srgrimes * that are on the mbuf list 4441541Srgrimes * nfs_getattrcache() - returns valid attributes if found in cache, returns 4451541Srgrimes * error otherwise 4461541Srgrimes */ 4471541Srgrimes 4481541Srgrimes/* 4491541Srgrimes * Load the attribute cache (that lives in the nfsnode entry) with 4501541Srgrimes * the values on the mbuf list and 4511541Srgrimes * Iff vap not NULL 4521541Srgrimes * copy the attributes to *vaper 4531541Srgrimes */ 4541549Srgrimesint 45583651Speternfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp, 45683651Speter struct vattr *vaper, int dontshrink) 4571541Srgrimes{ 45883651Speter struct vnode *vp = *vpp; 45983651Speter struct vattr *vap; 46083651Speter struct nfs_fattr *fp; 46183651Speter struct nfsnode *np; 46283651Speter int32_t t1; 4639336Sdfr caddr_t cp2; 46484057Speter int rdev; 4651541Srgrimes struct mbuf *md; 4661541Srgrimes enum vtype vtyp; 4671541Srgrimes u_short vmode; 4681541Srgrimes struct timespec mtime; 4699336Sdfr int v3 = NFS_ISV3(vp); 4701541Srgrimes 4711541Srgrimes md = *mdp; 4729336Sdfr t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 47384057Speter cp2 = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1); 47484057Speter if (cp2 == NULL) 47584057Speter return EBADRPC; 4769336Sdfr fp = (struct nfs_fattr *)cp2; 4779336Sdfr if (v3) { 4789336Sdfr vtyp = nfsv3tov_type(fp->fa_type); 4799336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 48048859Sphk rdev = makeudev(fxdr_unsigned(int, fp->fa3_rdev.specdata1), 48116634Sbde fxdr_unsigned(int, fp->fa3_rdev.specdata2)); 4829336Sdfr fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 4831541Srgrimes } else { 4849336Sdfr vtyp = nfsv2tov_type(fp->fa_type); 4859336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 4869336Sdfr /* 4879336Sdfr * XXX 4889336Sdfr * 4899336Sdfr * The duplicate information returned in fa_type and fa_mode 4909336Sdfr * is an ambiguity in the NFS version 2 protocol. 4919336Sdfr * 4929336Sdfr * VREG should be taken literally as a regular file. If a 4939336Sdfr * server intents to return some type information differently 4949336Sdfr * in the upper bits of the mode field (e.g. for sockets, or 4959336Sdfr * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we 4969336Sdfr * leave the examination of the mode bits even in the VREG 4979336Sdfr * case to avoid breakage for bogus servers, but we make sure 4989336Sdfr * that there are actually type bits set in the upper part of 4999336Sdfr * fa_mode (and failing that, trust the va_type field). 5009336Sdfr * 5019336Sdfr * NFSv3 cleared the issue, and requires fa_mode to not 5029336Sdfr * contain any type information (while also introduing sockets 5039336Sdfr * and FIFOs for fa_type). 5049336Sdfr */ 5059336Sdfr if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) 5069336Sdfr vtyp = IFTOVT(vmode); 50736541Speter rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); 5089336Sdfr fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 5099336Sdfr 5109336Sdfr /* 5119336Sdfr * Really ugly NFSv2 kludge. 5129336Sdfr */ 5139336Sdfr if (vtyp == VCHR && rdev == 0xffffffff) 5149336Sdfr vtyp = VFIFO; 5151541Srgrimes } 5169336Sdfr 5171541Srgrimes /* 5181541Srgrimes * If v_type == VNON it is a new node, so fill in the v_type, 5198876Srgrimes * n_mtime fields. Check to see if it represents a special 5201541Srgrimes * device, and if so, check for a possible alias. Once the 5211541Srgrimes * correct vnode has been obtained, fill in the rest of the 5221541Srgrimes * information. 5231541Srgrimes */ 5241541Srgrimes np = VTONFS(vp); 52510219Sdfr if (vp->v_type != vtyp) { 5269336Sdfr vp->v_type = vtyp; 5271541Srgrimes if (vp->v_type == VFIFO) { 5281541Srgrimes vp->v_op = fifo_nfsv2nodeop_p; 5291541Srgrimes } 5301541Srgrimes if (vp->v_type == VCHR || vp->v_type == VBLK) { 5311541Srgrimes vp->v_op = spec_nfsv2nodeop_p; 53263788Smckusick vp = addaliasu(vp, rdev); 53363788Smckusick np->n_vnode = vp; 5341541Srgrimes } 53518397Snate np->n_mtime = mtime.tv_sec; 5361541Srgrimes } 5371541Srgrimes vap = &np->n_vattr; 5381541Srgrimes vap->va_type = vtyp; 5391541Srgrimes vap->va_mode = (vmode & 07777); 54047028Sphk vap->va_rdev = rdev; 5411541Srgrimes vap->va_mtime = mtime; 5421541Srgrimes vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 5439336Sdfr if (v3) { 5449336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 5459336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 5469336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 54747751Speter vap->va_size = fxdr_hyper(&fp->fa3_size); 5489336Sdfr vap->va_blocksize = NFS_FABLKSIZE; 54947751Speter vap->va_bytes = fxdr_hyper(&fp->fa3_used); 55036541Speter vap->va_fileid = fxdr_unsigned(int32_t, 55136541Speter fp->fa3_fileid.nfsuquad[1]); 5529336Sdfr fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 5539336Sdfr fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 5549336Sdfr vap->va_flags = 0; 5559336Sdfr vap->va_filerev = 0; 5561541Srgrimes } else { 5579336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 5589336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 5599336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 56036541Speter vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 56136541Speter vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 56247751Speter vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) 56336541Speter * NFS_FABLKSIZE; 56436541Speter vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); 5659336Sdfr fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 5661541Srgrimes vap->va_flags = 0; 56736541Speter vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, 56836541Speter fp->fa2_ctime.nfsv2_sec); 56918397Snate vap->va_ctime.tv_nsec = 0; 57083651Speter vap->va_gen = fxdr_unsigned(u_int32_t, fp->fa2_ctime.nfsv2_usec); 5711541Srgrimes vap->va_filerev = 0; 5721541Srgrimes } 57367486Sdwmalone np->n_attrstamp = time_second; 5741541Srgrimes if (vap->va_size != np->n_size) { 5751541Srgrimes if (vap->va_type == VREG) { 57667486Sdwmalone if (dontshrink && vap->va_size < np->n_size) { 57767486Sdwmalone /* 57867486Sdwmalone * We've been told not to shrink the file; 57967486Sdwmalone * zero np->n_attrstamp to indicate that 58067486Sdwmalone * the attributes are stale. 58167486Sdwmalone */ 58267486Sdwmalone vap->va_size = np->n_size; 58367486Sdwmalone np->n_attrstamp = 0; 58467486Sdwmalone } else if (np->n_flag & NMODIFIED) { 5851541Srgrimes if (vap->va_size < np->n_size) 5861541Srgrimes vap->va_size = np->n_size; 5871541Srgrimes else 5881541Srgrimes np->n_size = vap->va_size; 58954480Sdillon } else { 5901541Srgrimes np->n_size = vap->va_size; 59154480Sdillon } 59241026Speter vnode_pager_setsize(vp, np->n_size); 59354480Sdillon } else { 5941541Srgrimes np->n_size = vap->va_size; 59554480Sdillon } 5961541Srgrimes } 5971541Srgrimes if (vaper != NULL) { 5981541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 5991541Srgrimes if (np->n_flag & NCHG) { 6009336Sdfr if (np->n_flag & NACC) 6019336Sdfr vaper->va_atime = np->n_atim; 6029336Sdfr if (np->n_flag & NUPD) 6039336Sdfr vaper->va_mtime = np->n_mtim; 6041541Srgrimes } 6051541Srgrimes } 6061541Srgrimes return (0); 6071541Srgrimes} 6081541Srgrimes 60936176Speter#ifdef NFS_ACDEBUG 61036176Speter#include <sys/sysctl.h> 61144101SbdeSYSCTL_DECL(_vfs_nfs); 61236176Speterstatic int nfs_acdebug; 61336176SpeterSYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, ""); 61436176Speter#endif 61536176Speter 6161541Srgrimes/* 6171541Srgrimes * Check the time stamp 6181541Srgrimes * If the cache is valid, copy contents to *vap and return 0 6191541Srgrimes * otherwise return an error 6201541Srgrimes */ 6211549Srgrimesint 62283651Speternfs_getattrcache(struct vnode *vp, struct vattr *vaper) 6231541Srgrimes{ 62483651Speter struct nfsnode *np; 62583651Speter struct vattr *vap; 62636176Speter struct nfsmount *nmp; 62736176Speter int timeo; 6281541Srgrimes 62936176Speter np = VTONFS(vp); 63036176Speter vap = &np->n_vattr; 63136176Speter nmp = VFSTONFS(vp->v_mount); 63236176Speter /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */ 63336176Speter timeo = (time_second - np->n_mtime) / 10; 63436176Speter 63536176Speter#ifdef NFS_ACDEBUG 63636176Speter if (nfs_acdebug>1) 63736176Speter printf("nfs_getattrcache: initial timeo = %d\n", timeo); 63836176Speter#endif 63936176Speter 64036176Speter if (vap->va_type == VDIR) { 64136176Speter if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin) 64236176Speter timeo = nmp->nm_acdirmin; 64336176Speter else if (timeo > nmp->nm_acdirmax) 64436176Speter timeo = nmp->nm_acdirmax; 64536176Speter } else { 64636176Speter if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin) 64736176Speter timeo = nmp->nm_acregmin; 64836176Speter else if (timeo > nmp->nm_acregmax) 64936176Speter timeo = nmp->nm_acregmax; 65036176Speter } 65136176Speter 65236176Speter#ifdef NFS_ACDEBUG 65336176Speter if (nfs_acdebug > 2) 65436176Speter printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n", 65536176Speter nmp->nm_acregmin, nmp->nm_acregmax, 65636176Speter nmp->nm_acdirmin, nmp->nm_acdirmax); 65736176Speter 65836176Speter if (nfs_acdebug) 65937089Sbde printf("nfs_getattrcache: age = %d; final timeo = %d\n", 66036176Speter (time_second - np->n_attrstamp), timeo); 66136176Speter#endif 66236176Speter 66336176Speter if ((time_second - np->n_attrstamp) >= timeo) { 6641541Srgrimes nfsstats.attrcache_misses++; 6651541Srgrimes return (ENOENT); 6661541Srgrimes } 6671541Srgrimes nfsstats.attrcache_hits++; 6681541Srgrimes if (vap->va_size != np->n_size) { 6691541Srgrimes if (vap->va_type == VREG) { 6701541Srgrimes if (np->n_flag & NMODIFIED) { 6711541Srgrimes if (vap->va_size < np->n_size) 6721541Srgrimes vap->va_size = np->n_size; 6731541Srgrimes else 6741541Srgrimes np->n_size = vap->va_size; 67554480Sdillon } else { 6761541Srgrimes np->n_size = vap->va_size; 67754480Sdillon } 67841026Speter vnode_pager_setsize(vp, np->n_size); 67954480Sdillon } else { 6801541Srgrimes np->n_size = vap->va_size; 68154480Sdillon } 6821541Srgrimes } 6831541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 6841541Srgrimes if (np->n_flag & NCHG) { 6859336Sdfr if (np->n_flag & NACC) 6869336Sdfr vaper->va_atime = np->n_atim; 6879336Sdfr if (np->n_flag & NUPD) 6889336Sdfr vaper->va_mtime = np->n_mtim; 6891541Srgrimes } 6901541Srgrimes return (0); 6911541Srgrimes} 6921541Srgrimes 69343305Sdillonstatic nfsuint64 nfs_nullcookie = { { 0, 0 } }; 6949336Sdfr/* 6959336Sdfr * This function finds the directory cookie that corresponds to the 6969336Sdfr * logical byte offset given. 6979336Sdfr */ 6989336Sdfrnfsuint64 * 69983651Speternfs_getcookie(struct nfsnode *np, off_t off, int add) 7009336Sdfr{ 70183651Speter struct nfsdmap *dp, *dp2; 70283651Speter int pos; 7039336Sdfr 70436979Sbde pos = (uoff_t)off / NFS_DIRBLKSIZ; 70536979Sbde if (pos == 0 || off < 0) { 7069336Sdfr#ifdef DIAGNOSTIC 7079336Sdfr if (add) 70836979Sbde panic("nfs getcookie add at <= 0"); 7099336Sdfr#endif 7109336Sdfr return (&nfs_nullcookie); 7119336Sdfr } 7129336Sdfr pos--; 71383651Speter dp = LIST_FIRST(&np->n_cookies); 7149336Sdfr if (!dp) { 7159336Sdfr if (add) { 7169336Sdfr MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 7179336Sdfr M_NFSDIROFF, M_WAITOK); 7189336Sdfr dp->ndm_eocookie = 0; 7199336Sdfr LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 7209336Sdfr } else 7219336Sdfr return ((nfsuint64 *)0); 7229336Sdfr } 7239336Sdfr while (pos >= NFSNUMCOOKIES) { 7249336Sdfr pos -= NFSNUMCOOKIES; 72583651Speter if (LIST_NEXT(dp, ndm_list)) { 7269336Sdfr if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 7279336Sdfr pos >= dp->ndm_eocookie) 7289336Sdfr return ((nfsuint64 *)0); 72983651Speter dp = LIST_NEXT(dp, ndm_list); 7309336Sdfr } else if (add) { 7319336Sdfr MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 7329336Sdfr M_NFSDIROFF, M_WAITOK); 7339336Sdfr dp2->ndm_eocookie = 0; 7349336Sdfr LIST_INSERT_AFTER(dp, dp2, ndm_list); 7359336Sdfr dp = dp2; 7369336Sdfr } else 7379336Sdfr return ((nfsuint64 *)0); 7389336Sdfr } 7399336Sdfr if (pos >= dp->ndm_eocookie) { 7409336Sdfr if (add) 7419336Sdfr dp->ndm_eocookie = pos + 1; 7429336Sdfr else 7439336Sdfr return ((nfsuint64 *)0); 7449336Sdfr } 7459336Sdfr return (&dp->ndm_cookies[pos]); 7469336Sdfr} 7479336Sdfr 7489336Sdfr/* 7499336Sdfr * Invalidate cached directory information, except for the actual directory 7509336Sdfr * blocks (which are invalidated separately). 7519336Sdfr * Done mainly to avoid the use of stale offset cookies. 7529336Sdfr */ 7539336Sdfrvoid 75483651Speternfs_invaldir(struct vnode *vp) 7559336Sdfr{ 75683651Speter struct nfsnode *np = VTONFS(vp); 7579336Sdfr 7589336Sdfr#ifdef DIAGNOSTIC 7599336Sdfr if (vp->v_type != VDIR) 7609336Sdfr panic("nfs: invaldir not dir"); 7619336Sdfr#endif 7629336Sdfr np->n_direofoffset = 0; 7639336Sdfr np->n_cookieverf.nfsuquad[0] = 0; 7649336Sdfr np->n_cookieverf.nfsuquad[1] = 0; 76583651Speter if (LIST_FIRST(&np->n_cookies)) 76683651Speter LIST_FIRST(&np->n_cookies)->ndm_eocookie = 0; 7679336Sdfr} 7689336Sdfr 7699336Sdfr/* 7709336Sdfr * The write verifier has changed (probably due to a server reboot), so all 7719336Sdfr * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 7729336Sdfr * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 77354480Sdillon * and B_CLUSTEROK flags. Once done the new write verifier can be set for the 77454480Sdillon * mount point. 77554480Sdillon * 77683651Speter * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data 77754480Sdillon * writes are not clusterable. 7789336Sdfr */ 7799336Sdfrvoid 78083651Speternfs_clearcommit(struct mount *mp) 7819336Sdfr{ 78283651Speter struct vnode *vp, *nvp; 78383651Speter struct buf *bp, *nbp; 7849336Sdfr int s; 7859336Sdfr 78679224Sdillon GIANT_REQUIRED; 78779224Sdillon 7889336Sdfr s = splbio(); 78978911Sjhb mtx_lock(&mntvnode_mtx); 7909336Sdfrloop: 79185339Sdillon for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp; vp = nvp) { 7929336Sdfr if (vp->v_mount != mp) /* Paranoia */ 7939336Sdfr goto loop; 79485339Sdillon nvp = TAILQ_NEXT(vp, v_nmntvnodes); 79540790Speter for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 79640790Speter nbp = TAILQ_NEXT(bp, b_vnbufs); 79748225Smckusick if (BUF_REFCNT(bp) == 0 && 79848225Smckusick (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) 7999336Sdfr == (B_DELWRI | B_NEEDCOMMIT)) 80054480Sdillon bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); 8019336Sdfr } 8029336Sdfr } 80378911Sjhb mtx_unlock(&mntvnode_mtx); 8049336Sdfr splx(s); 8059336Sdfr} 8069336Sdfr 8079336Sdfr/* 80883651Speter * Helper functions for former macros. Some of these should be 80983651Speter * moved to their callers. 8109336Sdfr */ 81183651Speter 8125455Sdgint 81383651Speternfsm_mtofh_xx(struct vnode *d, struct vnode **v, int v3, int *f, 81488091Siedowse struct mbuf **md, caddr_t *dpos) 8159336Sdfr{ 81683651Speter struct nfsnode *ttnp; 81783651Speter struct vnode *ttvp; 81883651Speter nfsfh_t *ttfhp; 81988091Siedowse u_int32_t *tl; 82083651Speter int ttfhsize; 82183651Speter int t1; 8229336Sdfr 82383651Speter if (v3) { 82488091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 82588091Siedowse if (tl == NULL) 82684057Speter return EBADRPC; 82788091Siedowse *f = fxdr_unsigned(int, *tl); 82883651Speter } else 82983651Speter *f = 1; 83083651Speter if (*f) { 83188091Siedowse t1 = nfsm_getfh_xx(&ttfhp, &ttfhsize, (v3), md, dpos); 83283651Speter if (t1 != 0) 83383651Speter return t1; 83483651Speter t1 = nfs_nget(d->v_mount, ttfhp, ttfhsize, &ttnp); 83583651Speter if (t1 != 0) 83683651Speter return t1; 83783651Speter *v = NFSTOV(ttnp); 83883651Speter } 83983651Speter if (v3) { 84088091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 84188091Siedowse if (tl == NULL) 84284057Speter return EBADRPC; 84383651Speter if (*f) 84488091Siedowse *f = fxdr_unsigned(int, *tl); 84588091Siedowse else if (fxdr_unsigned(int, *tl)) 84688091Siedowse nfsm_adv_xx(NFSX_V3FATTR, md, dpos); 84783651Speter } 84883651Speter if (*f) { 84983651Speter ttvp = *v; 85083651Speter t1 = nfs_loadattrcache(&ttvp, md, dpos, (struct vattr *)0, 0); 85183651Speter if (t1) 85283651Speter return t1; 85383651Speter *v = ttvp; 85483651Speter } 85583651Speter return 0; 85683651Speter} 85783651Speter 85883651Speterint 85988091Siedowsenfsm_getfh_xx(nfsfh_t **f, int *s, int v3, struct mbuf **md, caddr_t *dpos) 86083651Speter{ 86188091Siedowse u_int32_t *tl; 86283651Speter 86383651Speter if (v3) { 86488091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 86588091Siedowse if (tl == NULL) 86684057Speter return EBADRPC; 86788091Siedowse *s = fxdr_unsigned(int, *tl); 86884057Speter if (*s <= 0 || *s > NFSX_V3FHMAX) 86983651Speter return EBADRPC; 87083651Speter } else 87183651Speter *s = NFSX_V2FH; 87284057Speter *f = nfsm_dissect_xx(nfsm_rndup(*s), md, dpos); 87384057Speter if (*f == NULL) 87484057Speter return EBADRPC; 87584057Speter else 87684057Speter return 0; 87783651Speter} 87883651Speter 87983651Speter 88083651Speterint 88188091Siedowsenfsm_loadattr_xx(struct vnode **v, struct vattr *va, struct mbuf **md, 88288091Siedowse caddr_t *dpos) 88383651Speter{ 88483651Speter int t1; 88583651Speter 88683651Speter struct vnode *ttvp = *v; 88783651Speter t1 = nfs_loadattrcache(&ttvp, md, dpos, va, 0); 88883651Speter if (t1 != 0) 88983651Speter return t1; 89083651Speter *v = ttvp; 89183651Speter return 0; 89283651Speter} 89383651Speter 89483651Speterint 89588091Siedowsenfsm_postop_attr_xx(struct vnode **v, int *f, struct mbuf **md, 89688091Siedowse caddr_t *dpos) 89783651Speter{ 89888091Siedowse u_int32_t *tl; 89983651Speter int t1; 90083651Speter 90183651Speter struct vnode *ttvp = *v; 90288091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 90388091Siedowse if (tl == NULL) 90484057Speter return EBADRPC; 90588091Siedowse *f = fxdr_unsigned(int, *tl); 90683914Siedowse if (*f != 0) { 90783651Speter t1 = nfs_loadattrcache(&ttvp, md, dpos, (struct vattr *)0, 1); 90883651Speter if (t1 != 0) { 90983651Speter *f = 0; 91083651Speter return t1; 91183651Speter } 91283651Speter *v = ttvp; 9139336Sdfr } 91483651Speter return 0; 9159336Sdfr} 9169336Sdfr 9179336Sdfrint 91888091Siedowsenfsm_wcc_data_xx(struct vnode **v, int *f, struct mbuf **md, caddr_t *dpos) 91931886Sbde{ 92088091Siedowse u_int32_t *tl; 92183651Speter int ttattrf, ttretf = 0; 92283651Speter int t1; 9235455Sdg 92488091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 92588091Siedowse if (tl == NULL) 92684057Speter return EBADRPC; 92788091Siedowse if (*tl == nfs_true) { 92888091Siedowse tl = nfsm_dissect_xx(6 * NFSX_UNSIGNED, md, dpos); 92988091Siedowse if (tl == NULL) 93084057Speter return EBADRPC; 93183651Speter if (*f) 93283651Speter ttretf = (VTONFS(*v)->n_mtime == 93388091Siedowse fxdr_unsigned(u_int32_t, *(tl + 2))); 93483651Speter } 93588091Siedowse t1 = nfsm_postop_attr_xx(v, &ttattrf, md, dpos); 93683651Speter if (t1) 93783651Speter return t1; 93883651Speter if (*f) 93983651Speter *f = ttretf; 94083651Speter else 94183651Speter *f = ttattrf; 94283651Speter return 0; 9435455Sdg} 94436503Speter 94583651Speterint 94688091Siedowsenfsm_strtom_xx(const char *a, int s, int m, struct mbuf **mb, caddr_t *bpos) 94736503Speter{ 94888091Siedowse u_int32_t *tl; 94983651Speter int t1; 95036503Speter 95183651Speter if (s > m) 95283651Speter return ENAMETOOLONG; 95383651Speter t1 = nfsm_rndup(s) + NFSX_UNSIGNED; 95483651Speter if (t1 <= M_TRAILINGSPACE(*mb)) { 95588091Siedowse tl = nfsm_build_xx(t1, mb, bpos); 95688091Siedowse *tl++ = txdr_unsigned(s); 95788091Siedowse *(tl + ((t1 >> 2) - 2)) = 0; 95888091Siedowse bcopy(a, tl, s); 95983651Speter } else { 96083651Speter t1 = nfsm_strtmbuf(mb, bpos, a, s); 96183651Speter if (t1 != 0) 96283651Speter return t1; 96336503Speter } 96483651Speter return 0; 96536503Speter} 96636503Speter 96783651Speterint 96888091Siedowsenfsm_fhtom_xx(struct vnode *v, int v3, struct mbuf **mb, caddr_t *bpos) 96983651Speter{ 97088091Siedowse u_int32_t *tl; 97183651Speter int t1; 97283651Speter caddr_t cp; 97383651Speter 97483651Speter if (v3) { 97583651Speter t1 = nfsm_rndup(VTONFS(v)->n_fhsize) + NFSX_UNSIGNED; 97683651Speter if (t1 < M_TRAILINGSPACE(*mb)) { 97788091Siedowse tl = nfsm_build_xx(t1, mb, bpos); 97888091Siedowse *tl++ = txdr_unsigned(VTONFS(v)->n_fhsize); 97988091Siedowse *(tl + ((t1 >> 2) - 2)) = 0; 98088091Siedowse bcopy(VTONFS(v)->n_fhp, tl, VTONFS(v)->n_fhsize); 98183651Speter } else { 98283651Speter t1 = nfsm_strtmbuf(mb, bpos, 98383651Speter (const char *)VTONFS(v)->n_fhp, 98483651Speter VTONFS(v)->n_fhsize); 98583651Speter if (t1 != 0) 98683651Speter return t1; 98783651Speter } 98883651Speter } else { 98984002Speter cp = nfsm_build_xx(NFSX_V2FH, mb, bpos); 99083651Speter bcopy(VTONFS(v)->n_fhp, cp, NFSX_V2FH); 99183651Speter } 99283651Speter return 0; 99383651Speter} 99483651Speter 99536503Spetervoid 99688091Siedowsenfsm_v3attrbuild_xx(struct vattr *va, int full, struct mbuf **mb, 99788091Siedowse caddr_t *bpos) 99836503Speter{ 99988091Siedowse u_int32_t *tl; 100036503Speter 100183651Speter if (va->va_mode != (mode_t)VNOVAL) { 100288091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 100388091Siedowse *tl++ = nfs_true; 100488091Siedowse *tl = txdr_unsigned(va->va_mode); 100583651Speter } else { 100688091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 100788091Siedowse *tl = nfs_false; 100883651Speter } 100983651Speter if (full && va->va_uid != (uid_t)VNOVAL) { 101088091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 101188091Siedowse *tl++ = nfs_true; 101288091Siedowse *tl = txdr_unsigned(va->va_uid); 101383651Speter } else { 101488091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 101588091Siedowse *tl = nfs_false; 101683651Speter } 101783651Speter if (full && va->va_gid != (gid_t)VNOVAL) { 101888091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 101988091Siedowse *tl++ = nfs_true; 102088091Siedowse *tl = txdr_unsigned(va->va_gid); 102183651Speter } else { 102288091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 102388091Siedowse *tl = nfs_false; 102483651Speter } 102583651Speter if (full && va->va_size != VNOVAL) { 102688091Siedowse tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 102788091Siedowse *tl++ = nfs_true; 102888091Siedowse txdr_hyper(va->va_size, tl); 102983651Speter } else { 103088091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 103188091Siedowse *tl = nfs_false; 103283651Speter } 103383651Speter if (va->va_atime.tv_sec != VNOVAL) { 103483651Speter if (va->va_atime.tv_sec != time_second) { 103588091Siedowse tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 103688091Siedowse *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 103788091Siedowse txdr_nfsv3time(&va->va_atime, tl); 103883651Speter } else { 103988091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 104088091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 104183651Speter } 104283651Speter } else { 104388091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 104488091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 104583651Speter } 104683651Speter if (va->va_mtime.tv_sec != VNOVAL) { 104783651Speter if (va->va_mtime.tv_sec != time_second) { 104888091Siedowse tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 104988091Siedowse *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 105088091Siedowse txdr_nfsv3time(&va->va_mtime, tl); 105183651Speter } else { 105288091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 105388091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 105483651Speter } 105583651Speter } else { 105688091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 105788091Siedowse *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 105883651Speter } 105936503Speter} 1060