Home | History | Annotate | Line # | Download | only in client
nfs_clrpcops.c revision 1.3
      1  1.3    andvar /*	$NetBSD: nfs_clrpcops.c,v 1.3 2024/02/08 20:51:25 andvar Exp $	*/
      2  1.1  dholland /*-
      3  1.1  dholland  * Copyright (c) 1989, 1993
      4  1.1  dholland  *	The Regents of the University of California.  All rights reserved.
      5  1.1  dholland  *
      6  1.1  dholland  * This code is derived from software contributed to Berkeley by
      7  1.1  dholland  * Rick Macklem at The University of Guelph.
      8  1.1  dholland  *
      9  1.1  dholland  * Redistribution and use in source and binary forms, with or without
     10  1.1  dholland  * modification, are permitted provided that the following conditions
     11  1.1  dholland  * are met:
     12  1.1  dholland  * 1. Redistributions of source code must retain the above copyright
     13  1.1  dholland  *    notice, this list of conditions and the following disclaimer.
     14  1.1  dholland  * 2. Redistributions in binary form must reproduce the above copyright
     15  1.1  dholland  *    notice, this list of conditions and the following disclaimer in the
     16  1.1  dholland  *    documentation and/or other materials provided with the distribution.
     17  1.1  dholland  * 4. Neither the name of the University nor the names of its contributors
     18  1.1  dholland  *    may be used to endorse or promote products derived from this software
     19  1.1  dholland  *    without specific prior written permission.
     20  1.1  dholland  *
     21  1.1  dholland  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  1.1  dholland  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  1.1  dholland  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  1.1  dholland  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  1.1  dholland  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  1.1  dholland  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  1.1  dholland  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  1.1  dholland  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  1.1  dholland  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  1.1  dholland  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  1.1  dholland  * SUCH DAMAGE.
     32  1.1  dholland  *
     33  1.1  dholland  */
     34  1.1  dholland 
     35  1.1  dholland #include <sys/cdefs.h>
     36  1.2  pgoyette /* __FBSDID("FreeBSD: head/sys/fs/nfsclient/nfs_clrpcops.c 298788 2016-04-29 16:07:25Z pfg "); */
     37  1.3    andvar __RCSID("$NetBSD: nfs_clrpcops.c,v 1.3 2024/02/08 20:51:25 andvar Exp $");
     38  1.1  dholland 
     39  1.1  dholland /*
     40  1.1  dholland  * Rpc op calls, generally called from the vnode op calls or through the
     41  1.1  dholland  * buffer cache, for NFS v2, 3 and 4.
     42  1.1  dholland  * These do not normally make any changes to vnode arguments or use
     43  1.1  dholland  * structures that might change between the VFS variants. The returned
     44  1.1  dholland  * arguments are all at the end, after the NFSPROC_T *p one.
     45  1.1  dholland  */
     46  1.1  dholland 
     47  1.1  dholland #ifndef APPLEKEXT
     48  1.2  pgoyette #ifdef _KERNEL_OPT
     49  1.1  dholland #include "opt_inet6.h"
     50  1.2  pgoyette #endif
     51  1.2  pgoyette 
     52  1.2  pgoyette #include <fs/nfs/common/nfsport.h>
     53  1.2  pgoyette #include <sys/sysctl.h>
     54  1.2  pgoyette 
     55  1.2  pgoyette SYSCTL_DECL(_vfs_nfs);
     56  1.1  dholland 
     57  1.2  pgoyette static int	nfsignore_eexist = 0;
     58  1.2  pgoyette SYSCTL_INT(_vfs_nfs, OID_AUTO, ignore_eexist, CTLFLAG_RW,
     59  1.2  pgoyette     &nfsignore_eexist, 0, "NFS ignore EEXIST replies for mkdir/symlink");
     60  1.1  dholland 
     61  1.1  dholland /*
     62  1.1  dholland  * Global variables
     63  1.1  dholland  */
     64  1.1  dholland extern int nfs_numnfscbd;
     65  1.1  dholland extern struct timeval nfsboottime;
     66  1.1  dholland extern u_int32_t newnfs_false, newnfs_true;
     67  1.1  dholland extern nfstype nfsv34_type[9];
     68  1.1  dholland extern int nfsrv_useacl;
     69  1.1  dholland extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN];
     70  1.1  dholland extern int nfscl_debuglevel;
     71  1.1  dholland NFSCLSTATEMUTEX;
     72  1.1  dholland int nfstest_outofseq = 0;
     73  1.1  dholland int nfscl_assumeposixlocks = 1;
     74  1.1  dholland int nfscl_enablecallb = 0;
     75  1.1  dholland short nfsv4_cbport = NFSV4_CBPORT;
     76  1.1  dholland int nfstest_openallsetattr = 0;
     77  1.1  dholland #endif	/* !APPLEKEXT */
     78  1.1  dholland 
     79  1.1  dholland #define	DIRHDSIZ	(sizeof (struct dirent) - (MAXNAMLEN + 1))
     80  1.1  dholland 
     81  1.1  dholland /*
     82  1.1  dholland  * nfscl_getsameserver() can return one of three values:
     83  1.1  dholland  * NFSDSP_USETHISSESSION - Use this session for the DS.
     84  1.1  dholland  * NFSDSP_SEQTHISSESSION - Use the nfsclds_sequence field of this dsp for new
     85  1.1  dholland  *     session.
     86  1.1  dholland  * NFSDSP_NOTFOUND - No matching server was found.
     87  1.1  dholland  */
     88  1.1  dholland enum nfsclds_state {
     89  1.1  dholland 	NFSDSP_USETHISSESSION = 0,
     90  1.1  dholland 	NFSDSP_SEQTHISSESSION = 1,
     91  1.1  dholland 	NFSDSP_NOTFOUND = 2,
     92  1.1  dholland };
     93  1.1  dholland 
     94  1.1  dholland static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *,
     95  1.1  dholland     struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *);
     96  1.1  dholland static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *,
     97  1.1  dholland     nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, void *);
     98  1.1  dholland static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *,
     99  1.1  dholland     struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *,
    100  1.1  dholland     void *);
    101  1.1  dholland static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *,
    102  1.1  dholland     nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *,
    103  1.1  dholland     struct nfsvattr *, struct nfsfh **, int *, int *, void *);
    104  1.1  dholland static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *,
    105  1.1  dholland     nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *,
    106  1.1  dholland     NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *,
    107  1.1  dholland     int *, void *, int *);
    108  1.1  dholland static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *,
    109  1.1  dholland     struct nfscllockowner *, u_int64_t, u_int64_t,
    110  1.1  dholland     u_int32_t, struct ucred *, NFSPROC_T *, int);
    111  1.1  dholland static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *,
    112  1.1  dholland     struct acl *, nfsv4stateid_t *, void *);
    113  1.1  dholland static int nfsrpc_getlayout(struct nfsmount *, vnode_t, struct nfsfh *, int,
    114  1.1  dholland     uint32_t *, nfsv4stateid_t *, uint64_t, struct nfscllayout **,
    115  1.1  dholland     struct ucred *, NFSPROC_T *);
    116  1.1  dholland static int nfsrpc_fillsa(struct nfsmount *, struct sockaddr_storage *,
    117  1.1  dholland     struct nfsclds **, NFSPROC_T *);
    118  1.1  dholland static void nfscl_initsessionslots(struct nfsclsession *);
    119  1.1  dholland static int nfscl_doflayoutio(vnode_t, struct uio *, int *, int *, int *,
    120  1.1  dholland     nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
    121  1.1  dholland     struct nfsclflayout *, uint64_t, uint64_t, struct ucred *, NFSPROC_T *);
    122  1.1  dholland static int nfsrpc_readds(vnode_t, struct uio *, nfsv4stateid_t *, int *,
    123  1.1  dholland     struct nfsclds *, uint64_t, int, struct nfsfh *, struct ucred *,
    124  1.1  dholland     NFSPROC_T *);
    125  1.1  dholland static int nfsrpc_writeds(vnode_t, struct uio *, int *, int *,
    126  1.1  dholland     nfsv4stateid_t *, struct nfsclds *, uint64_t, int,
    127  1.1  dholland     struct nfsfh *, int, struct ucred *, NFSPROC_T *);
    128  1.1  dholland static enum nfsclds_state nfscl_getsameserver(struct nfsmount *,
    129  1.1  dholland     struct nfsclds *, struct nfsclds **);
    130  1.1  dholland #ifdef notyet
    131  1.1  dholland static int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *,
    132  1.1  dholland     struct nfsfh *, struct ucred *, NFSPROC_T *, void *);
    133  1.1  dholland #endif
    134  1.1  dholland 
    135  1.1  dholland /*
    136  1.1  dholland  * nfs null call from vfs.
    137  1.1  dholland  */
    138  1.1  dholland APPLESTATIC int
    139  1.1  dholland nfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p)
    140  1.1  dholland {
    141  1.1  dholland 	int error;
    142  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
    143  1.1  dholland 
    144  1.1  dholland 	NFSCL_REQSTART(nd, NFSPROC_NULL, vp);
    145  1.1  dholland 	error = nfscl_request(nd, vp, p, cred, NULL);
    146  1.1  dholland 	if (nd->nd_repstat && !error)
    147  1.1  dholland 		error = nd->nd_repstat;
    148  1.1  dholland 	mbuf_freem(nd->nd_mrep);
    149  1.1  dholland 	return (error);
    150  1.1  dholland }
    151  1.1  dholland 
    152  1.1  dholland /*
    153  1.1  dholland  * nfs access rpc op.
    154  1.1  dholland  * For nfs version 3 and 4, use the access rpc to check accessibility. If file
    155  1.1  dholland  * modes are changed on the server, accesses might still fail later.
    156  1.1  dholland  */
    157  1.1  dholland APPLESTATIC int
    158  1.1  dholland nfsrpc_access(vnode_t vp, int acmode, struct ucred *cred,
    159  1.1  dholland     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
    160  1.1  dholland {
    161  1.1  dholland 	int error;
    162  1.1  dholland 	u_int32_t mode, rmode;
    163  1.1  dholland 
    164  1.1  dholland 	if (acmode & VREAD)
    165  1.1  dholland 		mode = NFSACCESS_READ;
    166  1.1  dholland 	else
    167  1.1  dholland 		mode = 0;
    168  1.1  dholland 	if (vnode_vtype(vp) == VDIR) {
    169  1.1  dholland 		if (acmode & VWRITE)
    170  1.1  dholland 			mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND |
    171  1.1  dholland 				 NFSACCESS_DELETE);
    172  1.1  dholland 		if (acmode & VEXEC)
    173  1.1  dholland 			mode |= NFSACCESS_LOOKUP;
    174  1.1  dholland 	} else {
    175  1.1  dholland 		if (acmode & VWRITE)
    176  1.1  dholland 			mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND);
    177  1.1  dholland 		if (acmode & VEXEC)
    178  1.1  dholland 			mode |= NFSACCESS_EXECUTE;
    179  1.1  dholland 	}
    180  1.1  dholland 
    181  1.1  dholland 	/*
    182  1.1  dholland 	 * Now, just call nfsrpc_accessrpc() to do the actual RPC.
    183  1.1  dholland 	 */
    184  1.1  dholland 	error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode,
    185  1.1  dholland 	    NULL);
    186  1.1  dholland 
    187  1.1  dholland 	/*
    188  1.1  dholland 	 * The NFS V3 spec does not clarify whether or not
    189  1.1  dholland 	 * the returned access bits can be a superset of
    190  1.1  dholland 	 * the ones requested, so...
    191  1.1  dholland 	 */
    192  1.1  dholland 	if (!error && (rmode & mode) != mode)
    193  1.1  dholland 		error = EACCES;
    194  1.1  dholland 	return (error);
    195  1.1  dholland }
    196  1.1  dholland 
    197  1.1  dholland /*
    198  1.1  dholland  * The actual rpc, separated out for Darwin.
    199  1.1  dholland  */
    200  1.1  dholland APPLESTATIC int
    201  1.1  dholland nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred,
    202  1.1  dholland     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep,
    203  1.1  dholland     void *stuff)
    204  1.1  dholland {
    205  1.1  dholland 	u_int32_t *tl;
    206  1.1  dholland 	u_int32_t supported, rmode;
    207  1.1  dholland 	int error;
    208  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
    209  1.1  dholland 	nfsattrbit_t attrbits;
    210  1.1  dholland 
    211  1.1  dholland 	*attrflagp = 0;
    212  1.1  dholland 	supported = mode;
    213  1.1  dholland 	NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp);
    214  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
    215  1.1  dholland 	*tl = txdr_unsigned(mode);
    216  1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
    217  1.1  dholland 		/*
    218  1.1  dholland 		 * And do a Getattr op.
    219  1.1  dholland 		 */
    220  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
    221  1.1  dholland 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
    222  1.1  dholland 		NFSGETATTR_ATTRBIT(&attrbits);
    223  1.1  dholland 		(void) nfsrv_putattrbit(nd, &attrbits);
    224  1.1  dholland 	}
    225  1.1  dholland 	error = nfscl_request(nd, vp, p, cred, stuff);
    226  1.1  dholland 	if (error)
    227  1.1  dholland 		return (error);
    228  1.1  dholland 	if (nd->nd_flag & ND_NFSV3) {
    229  1.1  dholland 		error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
    230  1.1  dholland 		if (error)
    231  1.1  dholland 			goto nfsmout;
    232  1.1  dholland 	}
    233  1.1  dholland 	if (!nd->nd_repstat) {
    234  1.1  dholland 		if (nd->nd_flag & ND_NFSV4) {
    235  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
    236  1.1  dholland 			supported = fxdr_unsigned(u_int32_t, *tl++);
    237  1.1  dholland 		} else {
    238  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
    239  1.1  dholland 		}
    240  1.1  dholland 		rmode = fxdr_unsigned(u_int32_t, *tl);
    241  1.1  dholland 		if (nd->nd_flag & ND_NFSV4)
    242  1.1  dholland 			error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
    243  1.1  dholland 
    244  1.1  dholland 		/*
    245  1.1  dholland 		 * It's not obvious what should be done about
    246  1.1  dholland 		 * unsupported access modes. For now, be paranoid
    247  1.1  dholland 		 * and clear the unsupported ones.
    248  1.1  dholland 		 */
    249  1.1  dholland 		rmode &= supported;
    250  1.1  dholland 		*rmodep = rmode;
    251  1.1  dholland 	} else
    252  1.1  dholland 		error = nd->nd_repstat;
    253  1.1  dholland nfsmout:
    254  1.1  dholland 	mbuf_freem(nd->nd_mrep);
    255  1.1  dholland 	return (error);
    256  1.1  dholland }
    257  1.1  dholland 
    258  1.1  dholland /*
    259  1.1  dholland  * nfs open rpc
    260  1.1  dholland  */
    261  1.1  dholland APPLESTATIC int
    262  1.1  dholland nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p)
    263  1.1  dholland {
    264  1.1  dholland 	struct nfsclopen *op;
    265  1.1  dholland 	struct nfscldeleg *dp;
    266  1.1  dholland 	struct nfsfh *nfhp;
    267  1.1  dholland 	struct nfsnode *np = VTONFS(vp);
    268  1.1  dholland 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
    269  1.1  dholland 	u_int32_t mode, clidrev;
    270  1.1  dholland 	int ret, newone, error, expireret = 0, retrycnt;
    271  1.1  dholland 
    272  1.1  dholland 	/*
    273  1.1  dholland 	 * For NFSv4, Open Ops are only done on Regular Files.
    274  1.1  dholland 	 */
    275  1.1  dholland 	if (vnode_vtype(vp) != VREG)
    276  1.1  dholland 		return (0);
    277  1.1  dholland 	mode = 0;
    278  1.1  dholland 	if (amode & FREAD)
    279  1.1  dholland 		mode |= NFSV4OPEN_ACCESSREAD;
    280  1.1  dholland 	if (amode & FWRITE)
    281  1.1  dholland 		mode |= NFSV4OPEN_ACCESSWRITE;
    282  1.1  dholland 	nfhp = np->n_fhp;
    283  1.1  dholland 
    284  1.1  dholland 	retrycnt = 0;
    285  1.1  dholland #ifdef notdef
    286  1.1  dholland { char name[100]; int namel;
    287  1.1  dholland namel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99;
    288  1.1  dholland bcopy(NFS4NODENAME(np->n_v4), name, namel);
    289  1.1  dholland name[namel] = '\0';
    290  1.1  dholland printf("rpcopen p=0x%x name=%s",p->p_pid,name);
    291  1.1  dholland if (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]);
    292  1.1  dholland else printf(" fhl=0\n");
    293  1.1  dholland }
    294  1.1  dholland #endif
    295  1.1  dholland 	do {
    296  1.1  dholland 	    dp = NULL;
    297  1.1  dholland 	    error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1,
    298  1.1  dholland 		cred, p, NULL, &op, &newone, &ret, 1);
    299  1.1  dholland 	    if (error) {
    300  1.1  dholland 		return (error);
    301  1.1  dholland 	    }
    302  1.1  dholland 	    if (nmp->nm_clp != NULL)
    303  1.1  dholland 		clidrev = nmp->nm_clp->nfsc_clientidrev;
    304  1.1  dholland 	    else
    305  1.1  dholland 		clidrev = 0;
    306  1.1  dholland 	    if (ret == NFSCLOPEN_DOOPEN) {
    307  1.1  dholland 		if (np->n_v4 != NULL) {
    308  1.1  dholland 			error = nfsrpc_openrpc(nmp, vp, np->n_v4->n4_data,
    309  1.1  dholland 			   np->n_v4->n4_fhlen, np->n_fhp->nfh_fh,
    310  1.1  dholland 			   np->n_fhp->nfh_len, mode, op,
    311  1.1  dholland 			   NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, &dp,
    312  1.1  dholland 			   0, 0x0, cred, p, 0, 0);
    313  1.1  dholland 			if (dp != NULL) {
    314  1.1  dholland #ifdef APPLE
    315  1.1  dholland 				OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag);
    316  1.1  dholland #else
    317  1.1  dholland 				NFSLOCKNODE(np);
    318  1.1  dholland 				np->n_flag &= ~NDELEGMOD;
    319  1.1  dholland 				/*
    320  1.1  dholland 				 * Invalidate the attribute cache, so that
    321  1.1  dholland 				 * attributes that pre-date the issue of a
    322  1.1  dholland 				 * delegation are not cached, since the
    323  1.1  dholland 				 * cached attributes will remain valid while
    324  1.1  dholland 				 * the delegation is held.
    325  1.1  dholland 				 */
    326  1.1  dholland 				NFSINVALATTRCACHE(np);
    327  1.1  dholland 				NFSUNLOCKNODE(np);
    328  1.1  dholland #endif
    329  1.1  dholland 				(void) nfscl_deleg(nmp->nm_mountp,
    330  1.1  dholland 				    op->nfso_own->nfsow_clp,
    331  1.1  dholland 				    nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp);
    332  1.1  dholland 			}
    333  1.1  dholland 		} else {
    334  1.1  dholland 			error = EIO;
    335  1.1  dholland 		}
    336  1.1  dholland 		newnfs_copyincred(cred, &op->nfso_cred);
    337  1.1  dholland 	    } else if (ret == NFSCLOPEN_SETCRED)
    338  1.1  dholland 		/*
    339  1.1  dholland 		 * This is a new local open on a delegation. It needs
    340  1.1  dholland 		 * to have credentials so that an open can be done
    341  1.1  dholland 		 * against the server during recovery.
    342  1.1  dholland 		 */
    343  1.1  dholland 		newnfs_copyincred(cred, &op->nfso_cred);
    344  1.1  dholland 
    345  1.1  dholland 	    /*
    346  1.1  dholland 	     * nfso_opencnt is the count of how many VOP_OPEN()s have
    347  1.1  dholland 	     * been done on this Open successfully and a VOP_CLOSE()
    348  1.1  dholland 	     * is expected for each of these.
    349  1.1  dholland 	     * If error is non-zero, don't increment it, since the Open
    350  1.1  dholland 	     * hasn't succeeded yet.
    351  1.1  dholland 	     */
    352  1.1  dholland 	    if (!error)
    353  1.1  dholland 		op->nfso_opencnt++;
    354  1.1  dholland 	    nfscl_openrelease(op, error, newone);
    355  1.1  dholland 	    if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
    356  1.1  dholland 		error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
    357  1.1  dholland 		error == NFSERR_BADSESSION) {
    358  1.1  dholland 		(void) nfs_catnap(PZERO, error, "nfs_open");
    359  1.1  dholland 	    } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
    360  1.1  dholland 		&& clidrev != 0) {
    361  1.1  dholland 		expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
    362  1.1  dholland 		retrycnt++;
    363  1.1  dholland 	    }
    364  1.1  dholland 	} while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
    365  1.1  dholland 	    error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
    366  1.1  dholland 	    error == NFSERR_BADSESSION ||
    367  1.1  dholland 	    ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
    368  1.1  dholland 	     expireret == 0 && clidrev != 0 && retrycnt < 4));
    369  1.1  dholland 	if (error && retrycnt >= 4)
    370  1.1  dholland 		error = EIO;
    371  1.1  dholland 	return (error);
    372  1.1  dholland }
    373  1.1  dholland 
    374  1.1  dholland /*
    375  1.1  dholland  * the actual open rpc
    376  1.1  dholland  */
    377  1.1  dholland APPLESTATIC int
    378  1.1  dholland nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
    379  1.1  dholland     u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op,
    380  1.1  dholland     u_int8_t *name, int namelen, struct nfscldeleg **dpp,
    381  1.1  dholland     int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p,
    382  1.1  dholland     int syscred, int recursed)
    383  1.1  dholland {
    384  1.1  dholland 	u_int32_t *tl;
    385  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
    386  1.1  dholland 	struct nfscldeleg *dp, *ndp = NULL;
    387  1.1  dholland 	struct nfsvattr nfsva;
    388  1.1  dholland 	u_int32_t rflags, deleg;
    389  1.1  dholland 	nfsattrbit_t attrbits;
    390  1.1  dholland 	int error, ret, acesize, limitby;
    391  1.1  dholland 
    392  1.1  dholland 	dp = *dpp;
    393  1.1  dholland 	*dpp = NULL;
    394  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL, NULL);
    395  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
    396  1.1  dholland 	*tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
    397  1.1  dholland 	*tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
    398  1.1  dholland 	*tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
    399  1.1  dholland 	*tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
    400  1.1  dholland 	*tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
    401  1.1  dholland 	(void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
    402  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
    403  1.1  dholland 	*tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
    404  1.1  dholland 	if (reclaim) {
    405  1.1  dholland 		*tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS);
    406  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
    407  1.1  dholland 		*tl = txdr_unsigned(delegtype);
    408  1.1  dholland 	} else {
    409  1.1  dholland 		if (dp != NULL) {
    410  1.1  dholland 			*tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR);
    411  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
    412  1.1  dholland 			if (NFSHASNFSV4N(nmp))
    413  1.1  dholland 				*tl++ = 0;
    414  1.1  dholland 			else
    415  1.1  dholland 				*tl++ = dp->nfsdl_stateid.seqid;
    416  1.1  dholland 			*tl++ = dp->nfsdl_stateid.other[0];
    417  1.1  dholland 			*tl++ = dp->nfsdl_stateid.other[1];
    418  1.1  dholland 			*tl = dp->nfsdl_stateid.other[2];
    419  1.1  dholland 		} else {
    420  1.1  dholland 			*tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
    421  1.1  dholland 		}
    422  1.1  dholland 		(void) nfsm_strtom(nd, name, namelen);
    423  1.1  dholland 	}
    424  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
    425  1.1  dholland 	*tl = txdr_unsigned(NFSV4OP_GETATTR);
    426  1.1  dholland 	NFSZERO_ATTRBIT(&attrbits);
    427  1.1  dholland 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
    428  1.1  dholland 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
    429  1.1  dholland 	(void) nfsrv_putattrbit(nd, &attrbits);
    430  1.1  dholland 	if (syscred)
    431  1.1  dholland 		nd->nd_flag |= ND_USEGSSNAME;
    432  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
    433  1.1  dholland 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
    434  1.1  dholland 	if (error)
    435  1.1  dholland 		return (error);
    436  1.1  dholland 	NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
    437  1.1  dholland 	if (!nd->nd_repstat) {
    438  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
    439  1.1  dholland 		    6 * NFSX_UNSIGNED);
    440  1.1  dholland 		op->nfso_stateid.seqid = *tl++;
    441  1.1  dholland 		op->nfso_stateid.other[0] = *tl++;
    442  1.1  dholland 		op->nfso_stateid.other[1] = *tl++;
    443  1.1  dholland 		op->nfso_stateid.other[2] = *tl;
    444  1.1  dholland 		rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
    445  1.1  dholland 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
    446  1.1  dholland 		if (error)
    447  1.1  dholland 			goto nfsmout;
    448  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
    449  1.1  dholland 		deleg = fxdr_unsigned(u_int32_t, *tl);
    450  1.1  dholland 		if (deleg == NFSV4OPEN_DELEGATEREAD ||
    451  1.1  dholland 		    deleg == NFSV4OPEN_DELEGATEWRITE) {
    452  1.1  dholland 			if (!(op->nfso_own->nfsow_clp->nfsc_flags &
    453  1.1  dholland 			      NFSCLFLAGS_FIRSTDELEG))
    454  1.1  dholland 				op->nfso_own->nfsow_clp->nfsc_flags |=
    455  1.1  dholland 				  (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
    456  1.1  dholland 			MALLOC(ndp, struct nfscldeleg *,
    457  1.1  dholland 			    sizeof (struct nfscldeleg) + newfhlen,
    458  1.1  dholland 			    M_NFSCLDELEG, M_WAITOK);
    459  1.1  dholland 			LIST_INIT(&ndp->nfsdl_owner);
    460  1.1  dholland 			LIST_INIT(&ndp->nfsdl_lock);
    461  1.1  dholland 			ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
    462  1.1  dholland 			ndp->nfsdl_fhlen = newfhlen;
    463  1.1  dholland 			NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
    464  1.1  dholland 			newnfs_copyincred(cred, &ndp->nfsdl_cred);
    465  1.1  dholland 			nfscl_lockinit(&ndp->nfsdl_rwlock);
    466  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
    467  1.1  dholland 			    NFSX_UNSIGNED);
    468  1.1  dholland 			ndp->nfsdl_stateid.seqid = *tl++;
    469  1.1  dholland 			ndp->nfsdl_stateid.other[0] = *tl++;
    470  1.1  dholland 			ndp->nfsdl_stateid.other[1] = *tl++;
    471  1.1  dholland 			ndp->nfsdl_stateid.other[2] = *tl++;
    472  1.1  dholland 			ret = fxdr_unsigned(int, *tl);
    473  1.1  dholland 			if (deleg == NFSV4OPEN_DELEGATEWRITE) {
    474  1.1  dholland 				ndp->nfsdl_flags = NFSCLDL_WRITE;
    475  1.1  dholland 				/*
    476  1.1  dholland 				 * Indicates how much the file can grow.
    477  1.1  dholland 				 */
    478  1.1  dholland 				NFSM_DISSECT(tl, u_int32_t *,
    479  1.1  dholland 				    3 * NFSX_UNSIGNED);
    480  1.1  dholland 				limitby = fxdr_unsigned(int, *tl++);
    481  1.1  dholland 				switch (limitby) {
    482  1.1  dholland 				case NFSV4OPEN_LIMITSIZE:
    483  1.1  dholland 					ndp->nfsdl_sizelimit = fxdr_hyper(tl);
    484  1.1  dholland 					break;
    485  1.1  dholland 				case NFSV4OPEN_LIMITBLOCKS:
    486  1.1  dholland 					ndp->nfsdl_sizelimit =
    487  1.1  dholland 					    fxdr_unsigned(u_int64_t, *tl++);
    488  1.1  dholland 					ndp->nfsdl_sizelimit *=
    489  1.1  dholland 					    fxdr_unsigned(u_int64_t, *tl);
    490  1.1  dholland 					break;
    491  1.1  dholland 				default:
    492  1.1  dholland 					error = NFSERR_BADXDR;
    493  1.1  dholland 					goto nfsmout;
    494  1.2  pgoyette 				}
    495  1.1  dholland 			} else {
    496  1.1  dholland 				ndp->nfsdl_flags = NFSCLDL_READ;
    497  1.1  dholland 			}
    498  1.1  dholland 			if (ret)
    499  1.1  dholland 				ndp->nfsdl_flags |= NFSCLDL_RECALL;
    500  1.1  dholland 			error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret,
    501  1.1  dholland 			    &acesize, p);
    502  1.1  dholland 			if (error)
    503  1.1  dholland 				goto nfsmout;
    504  1.1  dholland 		} else if (deleg != NFSV4OPEN_DELEGATENONE) {
    505  1.1  dholland 			error = NFSERR_BADXDR;
    506  1.1  dholland 			goto nfsmout;
    507  1.1  dholland 		}
    508  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
    509  1.1  dholland 		error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
    510  1.1  dholland 		    NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
    511  1.1  dholland 		    NULL, NULL, NULL, p, cred);
    512  1.1  dholland 		if (error)
    513  1.1  dholland 			goto nfsmout;
    514  1.1  dholland 		if (ndp != NULL) {
    515  1.1  dholland 			ndp->nfsdl_change = nfsva.na_filerev;
    516  1.1  dholland 			ndp->nfsdl_modtime = nfsva.na_mtime;
    517  1.1  dholland 			ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
    518  1.1  dholland 		}
    519  1.1  dholland 		if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) {
    520  1.1  dholland 		    do {
    521  1.1  dholland 			ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op,
    522  1.1  dholland 			    cred, p);
    523  1.1  dholland 			if (ret == NFSERR_DELAY)
    524  1.1  dholland 			    (void) nfs_catnap(PZERO, ret, "nfs_open");
    525  1.1  dholland 		    } while (ret == NFSERR_DELAY);
    526  1.1  dholland 		    error = ret;
    527  1.1  dholland 		}
    528  1.1  dholland 		if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) ||
    529  1.1  dholland 		    nfscl_assumeposixlocks)
    530  1.1  dholland 		    op->nfso_posixlock = 1;
    531  1.1  dholland 		else
    532  1.1  dholland 		    op->nfso_posixlock = 0;
    533  1.1  dholland 
    534  1.1  dholland 		/*
    535  1.1  dholland 		 * If the server is handing out delegations, but we didn't
    536  1.1  dholland 		 * get one because an OpenConfirm was required, try the
    537  1.1  dholland 		 * Open again, to get a delegation. This is a harmless no-op,
    538  1.1  dholland 		 * from a server's point of view.
    539  1.1  dholland 		 */
    540  1.1  dholland 		if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) &&
    541  1.1  dholland 		    (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG)
    542  1.1  dholland 		    && !error && dp == NULL && ndp == NULL && !recursed) {
    543  1.1  dholland 		    do {
    544  1.1  dholland 			ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp,
    545  1.1  dholland 			    newfhlen, mode, op, name, namelen, &ndp, 0, 0x0,
    546  1.1  dholland 			    cred, p, syscred, 1);
    547  1.1  dholland 			if (ret == NFSERR_DELAY)
    548  1.1  dholland 			    (void) nfs_catnap(PZERO, ret, "nfs_open2");
    549  1.1  dholland 		    } while (ret == NFSERR_DELAY);
    550  1.1  dholland 		    if (ret) {
    551  1.2  pgoyette 			if (ndp != NULL) {
    552  1.1  dholland 				FREE((caddr_t)ndp, M_NFSCLDELEG);
    553  1.2  pgoyette 				ndp = NULL;
    554  1.2  pgoyette 			}
    555  1.1  dholland 			if (ret == NFSERR_STALECLIENTID ||
    556  1.1  dholland 			    ret == NFSERR_STALEDONTRECOVER ||
    557  1.1  dholland 			    ret == NFSERR_BADSESSION)
    558  1.1  dholland 				error = ret;
    559  1.1  dholland 		    }
    560  1.1  dholland 		}
    561  1.1  dholland 	}
    562  1.1  dholland 	if (nd->nd_repstat != 0 && error == 0)
    563  1.1  dholland 		error = nd->nd_repstat;
    564  1.1  dholland 	if (error == NFSERR_STALECLIENTID || error == NFSERR_BADSESSION)
    565  1.1  dholland 		nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
    566  1.1  dholland nfsmout:
    567  1.1  dholland 	if (!error)
    568  1.1  dholland 		*dpp = ndp;
    569  1.1  dholland 	else if (ndp != NULL)
    570  1.1  dholland 		FREE((caddr_t)ndp, M_NFSCLDELEG);
    571  1.1  dholland 	mbuf_freem(nd->nd_mrep);
    572  1.1  dholland 	return (error);
    573  1.1  dholland }
    574  1.1  dholland 
    575  1.1  dholland /*
    576  1.1  dholland  * open downgrade rpc
    577  1.1  dholland  */
    578  1.1  dholland APPLESTATIC int
    579  1.1  dholland nfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op,
    580  1.1  dholland     struct ucred *cred, NFSPROC_T *p)
    581  1.1  dholland {
    582  1.1  dholland 	u_int32_t *tl;
    583  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
    584  1.1  dholland 	int error;
    585  1.1  dholland 
    586  1.1  dholland 	NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp);
    587  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
    588  1.1  dholland 	if (NFSHASNFSV4N(VFSTONFS(vnode_mount(vp))))
    589  1.1  dholland 		*tl++ = 0;
    590  1.1  dholland 	else
    591  1.1  dholland 		*tl++ = op->nfso_stateid.seqid;
    592  1.1  dholland 	*tl++ = op->nfso_stateid.other[0];
    593  1.1  dholland 	*tl++ = op->nfso_stateid.other[1];
    594  1.1  dholland 	*tl++ = op->nfso_stateid.other[2];
    595  1.1  dholland 	*tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
    596  1.1  dholland 	*tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
    597  1.1  dholland 	*tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
    598  1.1  dholland 	error = nfscl_request(nd, vp, p, cred, NULL);
    599  1.1  dholland 	if (error)
    600  1.1  dholland 		return (error);
    601  1.1  dholland 	NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
    602  1.1  dholland 	if (!nd->nd_repstat) {
    603  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
    604  1.1  dholland 		op->nfso_stateid.seqid = *tl++;
    605  1.1  dholland 		op->nfso_stateid.other[0] = *tl++;
    606  1.1  dholland 		op->nfso_stateid.other[1] = *tl++;
    607  1.1  dholland 		op->nfso_stateid.other[2] = *tl;
    608  1.1  dholland 	}
    609  1.1  dholland 	if (nd->nd_repstat && error == 0)
    610  1.1  dholland 		error = nd->nd_repstat;
    611  1.1  dholland 	if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION)
    612  1.1  dholland 		nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
    613  1.1  dholland nfsmout:
    614  1.1  dholland 	mbuf_freem(nd->nd_mrep);
    615  1.1  dholland 	return (error);
    616  1.1  dholland }
    617  1.1  dholland 
    618  1.1  dholland /*
    619  1.1  dholland  * V4 Close operation.
    620  1.1  dholland  */
    621  1.1  dholland APPLESTATIC int
    622  1.1  dholland nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p)
    623  1.1  dholland {
    624  1.1  dholland 	struct nfsclclient *clp;
    625  1.1  dholland 	int error;
    626  1.1  dholland 
    627  1.1  dholland 	if (vnode_vtype(vp) != VREG)
    628  1.1  dholland 		return (0);
    629  1.1  dholland 	if (doclose)
    630  1.1  dholland 		error = nfscl_doclose(vp, &clp, p);
    631  1.1  dholland 	else
    632  1.1  dholland 		error = nfscl_getclose(vp, &clp);
    633  1.1  dholland 	if (error)
    634  1.1  dholland 		return (error);
    635  1.1  dholland 
    636  1.1  dholland 	nfscl_clientrelease(clp);
    637  1.1  dholland 	return (0);
    638  1.1  dholland }
    639  1.1  dholland 
    640  1.1  dholland /*
    641  1.1  dholland  * Close the open.
    642  1.1  dholland  */
    643  1.1  dholland APPLESTATIC void
    644  1.1  dholland nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p)
    645  1.1  dholland {
    646  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
    647  1.1  dholland 	struct nfscllockowner *lp, *nlp;
    648  1.1  dholland 	struct nfscllock *lop, *nlop;
    649  1.1  dholland 	struct ucred *tcred;
    650  1.1  dholland 	u_int64_t off = 0, len = 0;
    651  1.1  dholland 	u_int32_t type = NFSV4LOCKT_READ;
    652  1.1  dholland 	int error, do_unlock, trycnt;
    653  1.1  dholland 
    654  1.1  dholland 	tcred = newnfs_getcred();
    655  1.1  dholland 	newnfs_copycred(&op->nfso_cred, tcred);
    656  1.1  dholland 	/*
    657  1.1  dholland 	 * (Theoretically this could be done in the same
    658  1.1  dholland 	 *  compound as the close, but having multiple
    659  1.1  dholland 	 *  sequenced Ops in the same compound might be
    660  1.1  dholland 	 *  too scary for some servers.)
    661  1.1  dholland 	 */
    662  1.1  dholland 	if (op->nfso_posixlock) {
    663  1.1  dholland 		off = 0;
    664  1.1  dholland 		len = NFS64BITSSET;
    665  1.1  dholland 		type = NFSV4LOCKT_READ;
    666  1.1  dholland 	}
    667  1.1  dholland 
    668  1.1  dholland 	/*
    669  1.1  dholland 	 * Since this function is only called from VOP_INACTIVE(), no
    670  1.1  dholland 	 * other thread will be manipulating this Open. As such, the
    671  1.1  dholland 	 * lock lists are not being changed by other threads, so it should
    672  1.1  dholland 	 * be safe to do this without locking.
    673  1.1  dholland 	 */
    674  1.1  dholland 	LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
    675  1.1  dholland 		do_unlock = 1;
    676  1.1  dholland 		LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) {
    677  1.1  dholland 			if (op->nfso_posixlock == 0) {
    678  1.1  dholland 				off = lop->nfslo_first;
    679  1.1  dholland 				len = lop->nfslo_end - lop->nfslo_first;
    680  1.1  dholland 				if (lop->nfslo_type == F_WRLCK)
    681  1.1  dholland 					type = NFSV4LOCKT_WRITE;
    682  1.1  dholland 				else
    683  1.1  dholland 					type = NFSV4LOCKT_READ;
    684  1.1  dholland 			}
    685  1.1  dholland 			if (do_unlock) {
    686  1.1  dholland 				trycnt = 0;
    687  1.1  dholland 				do {
    688  1.1  dholland 					error = nfsrpc_locku(nd, nmp, lp, off,
    689  1.1  dholland 					    len, type, tcred, p, 0);
    690  1.1  dholland 					if ((nd->nd_repstat == NFSERR_GRACE ||
    691  1.1  dholland 					    nd->nd_repstat == NFSERR_DELAY) &&
    692  1.1  dholland 					    error == 0)
    693  1.1  dholland 						(void) nfs_catnap(PZERO,
    694  1.1  dholland 						    (int)nd->nd_repstat,
    695  1.1  dholland 						    "nfs_close");
    696  1.1  dholland 				} while ((nd->nd_repstat == NFSERR_GRACE ||
    697  1.1  dholland 				    nd->nd_repstat == NFSERR_DELAY) &&
    698  1.1  dholland 				    error == 0 && trycnt++ < 5);
    699  1.1  dholland 				if (op->nfso_posixlock)
    700  1.1  dholland 					do_unlock = 0;
    701  1.1  dholland 			}
    702  1.1  dholland 			nfscl_freelock(lop, 0);
    703  1.1  dholland 		}
    704  1.1  dholland 		/*
    705  1.1  dholland 		 * Do a ReleaseLockOwner.
    706  1.1  dholland 		 * The lock owner name nfsl_owner may be used by other opens for
    707  1.1  dholland 		 * other files but the lock_owner4 name that nfsrpc_rellockown()
    708  1.1  dholland 		 * puts on the wire has the file handle for this file appended
    709  1.1  dholland 		 * to it, so it can be done now.
    710  1.1  dholland 		 */
    711  1.1  dholland 		(void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh,
    712  1.1  dholland 		    lp->nfsl_open->nfso_fhlen, tcred, p);
    713  1.1  dholland 	}
    714  1.1  dholland 
    715  1.1  dholland 	/*
    716  1.1  dholland 	 * There could be other Opens for different files on the same
    717  1.1  dholland 	 * OpenOwner, so locking is required.
    718  1.1  dholland 	 */
    719  1.1  dholland 	NFSLOCKCLSTATE();
    720  1.1  dholland 	nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
    721  1.1  dholland 	NFSUNLOCKCLSTATE();
    722  1.1  dholland 	do {
    723  1.1  dholland 		error = nfscl_tryclose(op, tcred, nmp, p);
    724  1.1  dholland 		if (error == NFSERR_GRACE)
    725  1.1  dholland 			(void) nfs_catnap(PZERO, error, "nfs_close");
    726  1.1  dholland 	} while (error == NFSERR_GRACE);
    727  1.1  dholland 	NFSLOCKCLSTATE();
    728  1.1  dholland 	nfscl_lockunlock(&op->nfso_own->nfsow_rwlock);
    729  1.1  dholland 
    730  1.1  dholland 	LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp)
    731  1.1  dholland 		nfscl_freelockowner(lp, 0);
    732  1.1  dholland 	nfscl_freeopen(op, 0);
    733  1.1  dholland 	NFSUNLOCKCLSTATE();
    734  1.1  dholland 	NFSFREECRED(tcred);
    735  1.1  dholland }
    736  1.1  dholland 
    737  1.1  dholland /*
    738  1.1  dholland  * The actual Close RPC.
    739  1.1  dholland  */
    740  1.1  dholland APPLESTATIC int
    741  1.1  dholland nfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp,
    742  1.1  dholland     struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p,
    743  1.1  dholland     int syscred)
    744  1.1  dholland {
    745  1.1  dholland 	u_int32_t *tl;
    746  1.1  dholland 	int error;
    747  1.1  dholland 
    748  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh,
    749  1.1  dholland 	    op->nfso_fhlen, NULL, NULL);
    750  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
    751  1.1  dholland 	*tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
    752  1.1  dholland 	if (NFSHASNFSV4N(nmp))
    753  1.1  dholland 		*tl++ = 0;
    754  1.1  dholland 	else
    755  1.1  dholland 		*tl++ = op->nfso_stateid.seqid;
    756  1.1  dholland 	*tl++ = op->nfso_stateid.other[0];
    757  1.1  dholland 	*tl++ = op->nfso_stateid.other[1];
    758  1.1  dholland 	*tl = op->nfso_stateid.other[2];
    759  1.1  dholland 	if (syscred)
    760  1.1  dholland 		nd->nd_flag |= ND_USEGSSNAME;
    761  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
    762  1.1  dholland 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
    763  1.1  dholland 	if (error)
    764  1.1  dholland 		return (error);
    765  1.1  dholland 	NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
    766  1.1  dholland 	if (nd->nd_repstat == 0)
    767  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
    768  1.1  dholland 	error = nd->nd_repstat;
    769  1.1  dholland 	if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION)
    770  1.1  dholland 		nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
    771  1.1  dholland nfsmout:
    772  1.1  dholland 	mbuf_freem(nd->nd_mrep);
    773  1.1  dholland 	return (error);
    774  1.1  dholland }
    775  1.1  dholland 
    776  1.1  dholland /*
    777  1.1  dholland  * V4 Open Confirm RPC.
    778  1.1  dholland  */
    779  1.1  dholland APPLESTATIC int
    780  1.1  dholland nfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen,
    781  1.1  dholland     struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p)
    782  1.1  dholland {
    783  1.1  dholland 	u_int32_t *tl;
    784  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
    785  1.1  dholland 	struct nfsmount *nmp;
    786  1.1  dholland 	int error;
    787  1.1  dholland 
    788  1.1  dholland 	nmp = VFSTONFS(vnode_mount(vp));
    789  1.1  dholland 	if (NFSHASNFSV4N(nmp))
    790  1.1  dholland 		return (0);		/* No confirmation for NFSv4.1. */
    791  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, nmp, nfhp, fhlen, NULL, NULL);
    792  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
    793  1.1  dholland 	*tl++ = op->nfso_stateid.seqid;
    794  1.1  dholland 	*tl++ = op->nfso_stateid.other[0];
    795  1.1  dholland 	*tl++ = op->nfso_stateid.other[1];
    796  1.1  dholland 	*tl++ = op->nfso_stateid.other[2];
    797  1.1  dholland 	*tl = txdr_unsigned(op->nfso_own->nfsow_seqid);
    798  1.1  dholland 	error = nfscl_request(nd, vp, p, cred, NULL);
    799  1.1  dholland 	if (error)
    800  1.1  dholland 		return (error);
    801  1.1  dholland 	NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
    802  1.1  dholland 	if (!nd->nd_repstat) {
    803  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
    804  1.1  dholland 		op->nfso_stateid.seqid = *tl++;
    805  1.1  dholland 		op->nfso_stateid.other[0] = *tl++;
    806  1.1  dholland 		op->nfso_stateid.other[1] = *tl++;
    807  1.1  dholland 		op->nfso_stateid.other[2] = *tl;
    808  1.1  dholland 	}
    809  1.1  dholland 	error = nd->nd_repstat;
    810  1.1  dholland 	if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION)
    811  1.1  dholland 		nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
    812  1.1  dholland nfsmout:
    813  1.1  dholland 	mbuf_freem(nd->nd_mrep);
    814  1.1  dholland 	return (error);
    815  1.1  dholland }
    816  1.1  dholland 
    817  1.1  dholland /*
    818  1.1  dholland  * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs()
    819  1.1  dholland  * when a mount has just occurred and when the server replies NFSERR_EXPIRED.
    820  1.1  dholland  */
    821  1.1  dholland APPLESTATIC int
    822  1.1  dholland nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp, int reclaim,
    823  1.1  dholland     struct ucred *cred, NFSPROC_T *p)
    824  1.1  dholland {
    825  1.1  dholland 	u_int32_t *tl;
    826  1.1  dholland 	struct nfsrv_descript nfsd;
    827  1.1  dholland 	struct nfsrv_descript *nd = &nfsd;
    828  1.1  dholland 	nfsattrbit_t attrbits;
    829  1.1  dholland 	u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9];
    830  1.1  dholland 	u_short port;
    831  1.1  dholland 	int error, isinet6 = 0, callblen;
    832  1.1  dholland 	nfsquad_t confirm;
    833  1.1  dholland 	u_int32_t lease;
    834  1.1  dholland 	static u_int32_t rev = 0;
    835  1.1  dholland 	struct nfsclds *dsp, *ndsp, *tdsp;
    836  1.2  pgoyette 	struct in6_addr a6;
    837  1.1  dholland 
    838  1.1  dholland 	if (nfsboottime.tv_sec == 0)
    839  1.1  dholland 		NFSSETBOOTTIME(nfsboottime);
    840  1.1  dholland 	clp->nfsc_rev = rev++;
    841  1.1  dholland 	if (NFSHASNFSV4N(nmp)) {
    842  1.1  dholland 		error = nfsrpc_exchangeid(nmp, clp, &nmp->nm_sockreq,
    843  1.1  dholland 		    NFSV4EXCH_USEPNFSMDS | NFSV4EXCH_USENONPNFS, &dsp, cred, p);
    844  1.1  dholland 		NFSCL_DEBUG(1, "aft exch=%d\n", error);
    845  1.1  dholland 		if (error == 0) {
    846  1.1  dholland 			error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
    847  1.1  dholland 			    &nmp->nm_sockreq,
    848  1.1  dholland 			    dsp->nfsclds_sess.nfsess_sequenceid, 1, cred, p);
    849  1.1  dholland 			if (error == 0) {
    850  1.1  dholland 				NFSLOCKMNT(nmp);
    851  1.1  dholland 				TAILQ_FOREACH_SAFE(tdsp, &nmp->nm_sess,
    852  1.1  dholland 				    nfsclds_list, ndsp)
    853  1.1  dholland 					nfscl_freenfsclds(tdsp);
    854  1.1  dholland 				TAILQ_INIT(&nmp->nm_sess);
    855  1.1  dholland 				TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp,
    856  1.1  dholland 				    nfsclds_list);
    857  1.1  dholland 				NFSUNLOCKMNT(nmp);
    858  1.1  dholland 			} else
    859  1.1  dholland 				nfscl_freenfsclds(dsp);
    860  1.1  dholland 			NFSCL_DEBUG(1, "aft createsess=%d\n", error);
    861  1.1  dholland 		}
    862  1.1  dholland 		if (error == 0 && reclaim == 0) {
    863  1.1  dholland 			error = nfsrpc_reclaimcomplete(nmp, cred, p);
    864  1.1  dholland 			NFSCL_DEBUG(1, "aft reclaimcomp=%d\n", error);
    865  1.1  dholland 			if (error == NFSERR_COMPLETEALREADY ||
    866  1.1  dholland 			    error == NFSERR_NOTSUPP)
    867  1.1  dholland 				/* Ignore this error. */
    868  1.1  dholland 				error = 0;
    869  1.1  dholland 		}
    870  1.1  dholland 		return (error);
    871  1.1  dholland 	}
    872  1.1  dholland 
    873  1.1  dholland 	/*
    874  1.1  dholland 	 * Allocate a single session structure for NFSv4.0, because some of
    875  1.1  dholland 	 * the fields are used by NFSv4.0 although it doesn't do a session.
    876  1.1  dholland 	 */
    877  1.1  dholland 	dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, M_WAITOK | M_ZERO);
    878  1.1  dholland 	mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
    879  1.1  dholland 	mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", NULL, MTX_DEF);
    880  1.1  dholland 	NFSLOCKMNT(nmp);
    881  1.1  dholland 	TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, nfsclds_list);
    882  1.1  dholland 	NFSUNLOCKMNT(nmp);
    883  1.1  dholland 
    884  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL, NULL);
    885  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
    886  1.1  dholland 	*tl++ = txdr_unsigned(nfsboottime.tv_sec);
    887  1.1  dholland 	*tl = txdr_unsigned(clp->nfsc_rev);
    888  1.1  dholland 	(void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
    889  1.1  dholland 
    890  1.1  dholland 	/*
    891  1.1  dholland 	 * set up the callback address
    892  1.1  dholland 	 */
    893  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
    894  1.1  dholland 	*tl = txdr_unsigned(NFS_CALLBCKPROG);
    895  1.1  dholland 	callblen = strlen(nfsv4_callbackaddr);
    896  1.1  dholland 	if (callblen == 0)
    897  1.2  pgoyette 		cp = nfscl_getmyip(nmp, &a6, &isinet6);
    898  1.1  dholland 	if (nfscl_enablecallb && nfs_numnfscbd > 0 &&
    899  1.1  dholland 	    (callblen > 0 || cp != NULL)) {
    900  1.1  dholland 		port = htons(nfsv4_cbport);
    901  1.1  dholland 		cp2 = (u_int8_t *)&port;
    902  1.1  dholland #ifdef INET6
    903  1.1  dholland 		if ((callblen > 0 &&
    904  1.1  dholland 		     strchr(nfsv4_callbackaddr, ':')) || isinet6) {
    905  1.1  dholland 			char ip6buf[INET6_ADDRSTRLEN], *ip6add;
    906  1.1  dholland 
    907  1.1  dholland 			(void) nfsm_strtom(nd, "tcp6", 4);
    908  1.1  dholland 			if (callblen == 0) {
    909  1.1  dholland 				ip6_sprintf(ip6buf, (struct in6_addr *)cp);
    910  1.1  dholland 				ip6add = ip6buf;
    911  1.1  dholland 			} else {
    912  1.1  dholland 				ip6add = nfsv4_callbackaddr;
    913  1.1  dholland 			}
    914  1.1  dholland 			snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d",
    915  1.1  dholland 			    ip6add, cp2[0], cp2[1]);
    916  1.1  dholland 		} else
    917  1.1  dholland #endif
    918  1.1  dholland 		{
    919  1.1  dholland 			(void) nfsm_strtom(nd, "tcp", 3);
    920  1.1  dholland 			if (callblen == 0)
    921  1.1  dholland 				snprintf(addr, INET6_ADDRSTRLEN + 9,
    922  1.1  dholland 				    "%d.%d.%d.%d.%d.%d", cp[0], cp[1],
    923  1.1  dholland 				    cp[2], cp[3], cp2[0], cp2[1]);
    924  1.1  dholland 			else
    925  1.1  dholland 				snprintf(addr, INET6_ADDRSTRLEN + 9,
    926  1.1  dholland 				    "%s.%d.%d", nfsv4_callbackaddr,
    927  1.1  dholland 				    cp2[0], cp2[1]);
    928  1.1  dholland 		}
    929  1.1  dholland 		(void) nfsm_strtom(nd, addr, strlen(addr));
    930  1.1  dholland 	} else {
    931  1.1  dholland 		(void) nfsm_strtom(nd, "tcp", 3);
    932  1.1  dholland 		(void) nfsm_strtom(nd, "0.0.0.0.0.0", 11);
    933  1.1  dholland 	}
    934  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
    935  1.1  dholland 	*tl = txdr_unsigned(clp->nfsc_cbident);
    936  1.1  dholland 	nd->nd_flag |= ND_USEGSSNAME;
    937  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
    938  1.1  dholland 		NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
    939  1.1  dholland 	if (error)
    940  1.1  dholland 		return (error);
    941  1.1  dholland 	if (nd->nd_repstat == 0) {
    942  1.1  dholland 	    NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
    943  1.1  dholland 	    NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0] = *tl++;
    944  1.1  dholland 	    NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1] = *tl++;
    945  1.1  dholland 	    confirm.lval[0] = *tl++;
    946  1.1  dholland 	    confirm.lval[1] = *tl;
    947  1.1  dholland 	    mbuf_freem(nd->nd_mrep);
    948  1.1  dholland 	    nd->nd_mrep = NULL;
    949  1.1  dholland 
    950  1.1  dholland 	    /*
    951  1.1  dholland 	     * and confirm it.
    952  1.1  dholland 	     */
    953  1.1  dholland 	    nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL,
    954  1.1  dholland 		NULL);
    955  1.1  dholland 	    NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
    956  1.1  dholland 	    *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
    957  1.1  dholland 	    *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
    958  1.1  dholland 	    *tl++ = confirm.lval[0];
    959  1.1  dholland 	    *tl = confirm.lval[1];
    960  1.1  dholland 	    nd->nd_flag |= ND_USEGSSNAME;
    961  1.1  dholland 	    error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
    962  1.1  dholland 		cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
    963  1.1  dholland 	    if (error)
    964  1.1  dholland 		return (error);
    965  1.1  dholland 	    mbuf_freem(nd->nd_mrep);
    966  1.1  dholland 	    nd->nd_mrep = NULL;
    967  1.1  dholland 	    if (nd->nd_repstat == 0) {
    968  1.1  dholland 		nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, nmp->nm_fh,
    969  1.1  dholland 		    nmp->nm_fhsize, NULL, NULL);
    970  1.1  dholland 		NFSZERO_ATTRBIT(&attrbits);
    971  1.1  dholland 		NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
    972  1.1  dholland 		(void) nfsrv_putattrbit(nd, &attrbits);
    973  1.1  dholland 		nd->nd_flag |= ND_USEGSSNAME;
    974  1.1  dholland 		error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
    975  1.1  dholland 		    cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
    976  1.1  dholland 		if (error)
    977  1.1  dholland 		    return (error);
    978  1.1  dholland 		if (nd->nd_repstat == 0) {
    979  1.1  dholland 		    error = nfsv4_loadattr(nd, NULL, NULL, NULL, NULL, 0, NULL,
    980  1.1  dholland 			NULL, NULL, NULL, NULL, 0, NULL, &lease, NULL, p, cred);
    981  1.1  dholland 		    if (error)
    982  1.1  dholland 			goto nfsmout;
    983  1.1  dholland 		    clp->nfsc_renew = NFSCL_RENEW(lease);
    984  1.1  dholland 		    clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
    985  1.1  dholland 		    clp->nfsc_clientidrev++;
    986  1.1  dholland 		    if (clp->nfsc_clientidrev == 0)
    987  1.1  dholland 			clp->nfsc_clientidrev++;
    988  1.1  dholland 		}
    989  1.1  dholland 	    }
    990  1.1  dholland 	}
    991  1.1  dholland 	error = nd->nd_repstat;
    992  1.1  dholland nfsmout:
    993  1.1  dholland 	mbuf_freem(nd->nd_mrep);
    994  1.1  dholland 	return (error);
    995  1.1  dholland }
    996  1.1  dholland 
    997  1.1  dholland /*
    998  1.1  dholland  * nfs getattr call.
    999  1.1  dholland  */
   1000  1.1  dholland APPLESTATIC int
   1001  1.1  dholland nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
   1002  1.1  dholland     struct nfsvattr *nap, void *stuff)
   1003  1.1  dholland {
   1004  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   1005  1.1  dholland 	int error;
   1006  1.1  dholland 	nfsattrbit_t attrbits;
   1007  1.1  dholland 
   1008  1.1  dholland 	NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
   1009  1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
   1010  1.1  dholland 		NFSGETATTR_ATTRBIT(&attrbits);
   1011  1.1  dholland 		(void) nfsrv_putattrbit(nd, &attrbits);
   1012  1.1  dholland 	}
   1013  1.1  dholland 	error = nfscl_request(nd, vp, p, cred, stuff);
   1014  1.1  dholland 	if (error)
   1015  1.1  dholland 		return (error);
   1016  1.1  dholland 	if (!nd->nd_repstat)
   1017  1.1  dholland 		error = nfsm_loadattr(nd, nap);
   1018  1.1  dholland 	else
   1019  1.1  dholland 		error = nd->nd_repstat;
   1020  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   1021  1.1  dholland 	return (error);
   1022  1.1  dholland }
   1023  1.1  dholland 
   1024  1.1  dholland /*
   1025  1.3    andvar  * nfs getattr call with non-vnode arguments.
   1026  1.1  dholland  */
   1027  1.1  dholland APPLESTATIC int
   1028  1.1  dholland nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred,
   1029  1.1  dholland     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp,
   1030  1.1  dholland     uint32_t *leasep)
   1031  1.1  dholland {
   1032  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   1033  1.1  dholland 	int error, vers = NFS_VER2;
   1034  1.1  dholland 	nfsattrbit_t attrbits;
   1035  1.1  dholland 
   1036  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL, NULL);
   1037  1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
   1038  1.1  dholland 		vers = NFS_VER4;
   1039  1.1  dholland 		NFSGETATTR_ATTRBIT(&attrbits);
   1040  1.1  dholland 		NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
   1041  1.1  dholland 		(void) nfsrv_putattrbit(nd, &attrbits);
   1042  1.1  dholland 	} else if (nd->nd_flag & ND_NFSV3) {
   1043  1.1  dholland 		vers = NFS_VER3;
   1044  1.1  dholland 	}
   1045  1.1  dholland 	if (syscred)
   1046  1.1  dholland 		nd->nd_flag |= ND_USEGSSNAME;
   1047  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
   1048  1.1  dholland 	    NFS_PROG, vers, NULL, 1, xidp, NULL);
   1049  1.1  dholland 	if (error)
   1050  1.1  dholland 		return (error);
   1051  1.1  dholland 	if (nd->nd_repstat == 0) {
   1052  1.1  dholland 		if ((nd->nd_flag & ND_NFSV4) != 0)
   1053  1.1  dholland 			error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
   1054  1.1  dholland 			    NULL, NULL, NULL, NULL, NULL, 0, NULL, leasep, NULL,
   1055  1.1  dholland 			    NULL, NULL);
   1056  1.1  dholland 		else
   1057  1.1  dholland 			error = nfsm_loadattr(nd, nap);
   1058  1.1  dholland 	} else
   1059  1.1  dholland 		error = nd->nd_repstat;
   1060  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   1061  1.1  dholland 	return (error);
   1062  1.1  dholland }
   1063  1.1  dholland 
   1064  1.1  dholland /*
   1065  1.1  dholland  * Do an nfs setattr operation.
   1066  1.1  dholland  */
   1067  1.1  dholland APPLESTATIC int
   1068  1.1  dholland nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp,
   1069  1.1  dholland     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp,
   1070  1.1  dholland     void *stuff)
   1071  1.1  dholland {
   1072  1.1  dholland 	int error, expireret = 0, openerr, retrycnt;
   1073  1.1  dholland 	u_int32_t clidrev = 0, mode;
   1074  1.1  dholland 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
   1075  1.1  dholland 	struct nfsfh *nfhp;
   1076  1.1  dholland 	nfsv4stateid_t stateid;
   1077  1.1  dholland 	void *lckp;
   1078  1.1  dholland 
   1079  1.1  dholland 	if (nmp->nm_clp != NULL)
   1080  1.1  dholland 		clidrev = nmp->nm_clp->nfsc_clientidrev;
   1081  1.1  dholland 	if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size))
   1082  1.1  dholland 		mode = NFSV4OPEN_ACCESSWRITE;
   1083  1.1  dholland 	else
   1084  1.1  dholland 		mode = NFSV4OPEN_ACCESSREAD;
   1085  1.1  dholland 	retrycnt = 0;
   1086  1.1  dholland 	do {
   1087  1.1  dholland 		lckp = NULL;
   1088  1.1  dholland 		openerr = 1;
   1089  1.1  dholland 		if (NFSHASNFSV4(nmp)) {
   1090  1.1  dholland 			nfhp = VTONFS(vp)->n_fhp;
   1091  1.1  dholland 			error = nfscl_getstateid(vp, nfhp->nfh_fh,
   1092  1.1  dholland 			    nfhp->nfh_len, mode, 0, cred, p, &stateid, &lckp);
   1093  1.1  dholland 			if (error && vnode_vtype(vp) == VREG &&
   1094  1.1  dholland 			    (mode == NFSV4OPEN_ACCESSWRITE ||
   1095  1.1  dholland 			     nfstest_openallsetattr)) {
   1096  1.1  dholland 				/*
   1097  1.1  dholland 				 * No Open stateid, so try and open the file
   1098  1.1  dholland 				 * now.
   1099  1.1  dholland 				 */
   1100  1.1  dholland 				if (mode == NFSV4OPEN_ACCESSWRITE)
   1101  1.1  dholland 					openerr = nfsrpc_open(vp, FWRITE, cred,
   1102  1.1  dholland 					    p);
   1103  1.1  dholland 				else
   1104  1.1  dholland 					openerr = nfsrpc_open(vp, FREAD, cred,
   1105  1.1  dholland 					    p);
   1106  1.1  dholland 				if (!openerr)
   1107  1.1  dholland 					(void) nfscl_getstateid(vp,
   1108  1.1  dholland 					    nfhp->nfh_fh, nfhp->nfh_len,
   1109  1.1  dholland 					    mode, 0, cred, p, &stateid, &lckp);
   1110  1.1  dholland 			}
   1111  1.1  dholland 		}
   1112  1.1  dholland 		if (vap != NULL)
   1113  1.1  dholland 			error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p,
   1114  1.1  dholland 			    rnap, attrflagp, stuff);
   1115  1.1  dholland 		else
   1116  1.1  dholland 			error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid,
   1117  1.1  dholland 			    stuff);
   1118  1.1  dholland 		if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION)
   1119  1.1  dholland 			nfscl_initiate_recovery(nmp->nm_clp);
   1120  1.1  dholland 		if (lckp != NULL)
   1121  1.1  dholland 			nfscl_lockderef(lckp);
   1122  1.1  dholland 		if (!openerr)
   1123  1.1  dholland 			(void) nfsrpc_close(vp, 0, p);
   1124  1.1  dholland 		if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
   1125  1.1  dholland 		    error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
   1126  1.1  dholland 		    error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
   1127  1.1  dholland 			(void) nfs_catnap(PZERO, error, "nfs_setattr");
   1128  1.1  dholland 		} else if ((error == NFSERR_EXPIRED ||
   1129  1.1  dholland 		    error == NFSERR_BADSTATEID) && clidrev != 0) {
   1130  1.1  dholland 			expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
   1131  1.1  dholland 		}
   1132  1.1  dholland 		retrycnt++;
   1133  1.1  dholland 	} while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
   1134  1.1  dholland 	    error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
   1135  1.1  dholland 	    error == NFSERR_BADSESSION ||
   1136  1.1  dholland 	    (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
   1137  1.1  dholland 	    ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
   1138  1.1  dholland 	     expireret == 0 && clidrev != 0 && retrycnt < 4));
   1139  1.1  dholland 	if (error && retrycnt >= 4)
   1140  1.1  dholland 		error = EIO;
   1141  1.1  dholland 	return (error);
   1142  1.1  dholland }
   1143  1.1  dholland 
   1144  1.1  dholland static int
   1145  1.1  dholland nfsrpc_setattrrpc(vnode_t vp, struct vattr *vap,
   1146  1.1  dholland     nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p,
   1147  1.1  dholland     struct nfsvattr *rnap, int *attrflagp, void *stuff)
   1148  1.1  dholland {
   1149  1.1  dholland 	u_int32_t *tl;
   1150  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   1151  1.1  dholland 	int error;
   1152  1.1  dholland 	nfsattrbit_t attrbits;
   1153  1.1  dholland 
   1154  1.1  dholland 	*attrflagp = 0;
   1155  1.1  dholland 	NFSCL_REQSTART(nd, NFSPROC_SETATTR, vp);
   1156  1.1  dholland 	if (nd->nd_flag & ND_NFSV4)
   1157  1.1  dholland 		nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
   1158  1.1  dholland 	vap->va_type = vnode_vtype(vp);
   1159  1.1  dholland 	nfscl_fillsattr(nd, vap, vp, NFSSATTR_FULL, 0);
   1160  1.1  dholland 	if (nd->nd_flag & ND_NFSV3) {
   1161  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   1162  1.1  dholland 		*tl = newnfs_false;
   1163  1.1  dholland 	} else if (nd->nd_flag & ND_NFSV4) {
   1164  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   1165  1.1  dholland 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
   1166  1.1  dholland 		NFSGETATTR_ATTRBIT(&attrbits);
   1167  1.1  dholland 		(void) nfsrv_putattrbit(nd, &attrbits);
   1168  1.1  dholland 	}
   1169  1.1  dholland 	error = nfscl_request(nd, vp, p, cred, stuff);
   1170  1.1  dholland 	if (error)
   1171  1.1  dholland 		return (error);
   1172  1.1  dholland 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
   1173  1.1  dholland 		error = nfscl_wcc_data(nd, vp, rnap, attrflagp, NULL, stuff);
   1174  1.1  dholland 	if ((nd->nd_flag & ND_NFSV4) && !error)
   1175  1.1  dholland 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
   1176  1.1  dholland 	if (!(nd->nd_flag & ND_NFSV3) && !nd->nd_repstat && !error)
   1177  1.1  dholland 		error = nfscl_postop_attr(nd, rnap, attrflagp, stuff);
   1178  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   1179  1.1  dholland 	if (nd->nd_repstat && !error)
   1180  1.1  dholland 		error = nd->nd_repstat;
   1181  1.1  dholland 	return (error);
   1182  1.1  dholland }
   1183  1.1  dholland 
   1184  1.1  dholland /*
   1185  1.1  dholland  * nfs lookup rpc
   1186  1.1  dholland  */
   1187  1.1  dholland APPLESTATIC int
   1188  1.1  dholland nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred,
   1189  1.1  dholland     NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap,
   1190  1.1  dholland     struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, void *stuff)
   1191  1.1  dholland {
   1192  1.1  dholland 	u_int32_t *tl;
   1193  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   1194  1.1  dholland 	struct nfsmount *nmp;
   1195  1.1  dholland 	struct nfsnode *np;
   1196  1.1  dholland 	struct nfsfh *nfhp;
   1197  1.1  dholland 	nfsattrbit_t attrbits;
   1198  1.1  dholland 	int error = 0, lookupp = 0;
   1199  1.1  dholland 
   1200  1.1  dholland 	*attrflagp = 0;
   1201  1.1  dholland 	*dattrflagp = 0;
   1202  1.1  dholland 	if (vnode_vtype(dvp) != VDIR)
   1203  1.1  dholland 		return (ENOTDIR);
   1204  1.1  dholland 	nmp = VFSTONFS(vnode_mount(dvp));
   1205  1.1  dholland 	if (len > NFS_MAXNAMLEN)
   1206  1.1  dholland 		return (ENAMETOOLONG);
   1207  1.1  dholland 	if (NFSHASNFSV4(nmp) && len == 1 &&
   1208  1.1  dholland 		name[0] == '.') {
   1209  1.1  dholland 		/*
   1210  1.1  dholland 		 * Just return the current dir's fh.
   1211  1.1  dholland 		 */
   1212  1.1  dholland 		np = VTONFS(dvp);
   1213  1.1  dholland 		MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) +
   1214  1.1  dholland 			np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
   1215  1.1  dholland 		nfhp->nfh_len = np->n_fhp->nfh_len;
   1216  1.1  dholland 		NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
   1217  1.1  dholland 		*nfhpp = nfhp;
   1218  1.1  dholland 		return (0);
   1219  1.1  dholland 	}
   1220  1.1  dholland 	if (NFSHASNFSV4(nmp) && len == 2 &&
   1221  1.1  dholland 		name[0] == '.' && name[1] == '.') {
   1222  1.1  dholland 		lookupp = 1;
   1223  1.1  dholland 		NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp);
   1224  1.1  dholland 	} else {
   1225  1.1  dholland 		NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp);
   1226  1.1  dholland 		(void) nfsm_strtom(nd, name, len);
   1227  1.1  dholland 	}
   1228  1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
   1229  1.1  dholland 		NFSGETATTR_ATTRBIT(&attrbits);
   1230  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   1231  1.1  dholland 		*tl++ = txdr_unsigned(NFSV4OP_GETFH);
   1232  1.1  dholland 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
   1233  1.1  dholland 		(void) nfsrv_putattrbit(nd, &attrbits);
   1234  1.1  dholland 	}
   1235  1.1  dholland 	error = nfscl_request(nd, dvp, p, cred, stuff);
   1236  1.1  dholland 	if (error)
   1237  1.1  dholland 		return (error);
   1238  1.1  dholland 	if (nd->nd_repstat) {
   1239  1.1  dholland 		/*
   1240  1.1  dholland 		 * When an NFSv4 Lookupp returns ENOENT, it means that
   1241  1.1  dholland 		 * the lookup is at the root of an fs, so return this dir.
   1242  1.1  dholland 		 */
   1243  1.1  dholland 		if (nd->nd_repstat == NFSERR_NOENT && lookupp) {
   1244  1.1  dholland 		    np = VTONFS(dvp);
   1245  1.1  dholland 		    MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) +
   1246  1.1  dholland 			np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
   1247  1.1  dholland 		    nfhp->nfh_len = np->n_fhp->nfh_len;
   1248  1.1  dholland 		    NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
   1249  1.1  dholland 		    *nfhpp = nfhp;
   1250  1.1  dholland 		    mbuf_freem(nd->nd_mrep);
   1251  1.1  dholland 		    return (0);
   1252  1.1  dholland 		}
   1253  1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
   1254  1.1  dholland 		    error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
   1255  1.2  pgoyette 		else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
   1256  1.2  pgoyette 		    ND_NFSV4) {
   1257  1.2  pgoyette 			/* Load the directory attributes. */
   1258  1.2  pgoyette 			error = nfsm_loadattr(nd, dnap);
   1259  1.2  pgoyette 			if (error == 0)
   1260  1.2  pgoyette 				*dattrflagp = 1;
   1261  1.2  pgoyette 		}
   1262  1.1  dholland 		goto nfsmout;
   1263  1.1  dholland 	}
   1264  1.1  dholland 	if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
   1265  1.2  pgoyette 		/* Load the directory attributes. */
   1266  1.2  pgoyette 		error = nfsm_loadattr(nd, dnap);
   1267  1.2  pgoyette 		if (error != 0)
   1268  1.1  dholland 			goto nfsmout;
   1269  1.2  pgoyette 		*dattrflagp = 1;
   1270  1.2  pgoyette 		/* Skip over the Lookup and GetFH operation status values. */
   1271  1.2  pgoyette 		NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
   1272  1.1  dholland 	}
   1273  1.1  dholland 	error = nfsm_getfh(nd, nfhpp);
   1274  1.1  dholland 	if (error)
   1275  1.1  dholland 		goto nfsmout;
   1276  1.1  dholland 
   1277  1.1  dholland 	error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
   1278  1.1  dholland 	if ((nd->nd_flag & ND_NFSV3) && !error)
   1279  1.1  dholland 		error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
   1280  1.1  dholland nfsmout:
   1281  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   1282  1.1  dholland 	if (!error && nd->nd_repstat)
   1283  1.1  dholland 		error = nd->nd_repstat;
   1284  1.1  dholland 	return (error);
   1285  1.1  dholland }
   1286  1.1  dholland 
   1287  1.1  dholland /*
   1288  1.1  dholland  * Do a readlink rpc.
   1289  1.1  dholland  */
   1290  1.1  dholland APPLESTATIC int
   1291  1.1  dholland nfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred,
   1292  1.1  dholland     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
   1293  1.1  dholland {
   1294  1.1  dholland 	u_int32_t *tl;
   1295  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   1296  1.1  dholland 	struct nfsnode *np = VTONFS(vp);
   1297  1.1  dholland 	nfsattrbit_t attrbits;
   1298  1.1  dholland 	int error, len, cangetattr = 1;
   1299  1.1  dholland 
   1300  1.1  dholland 	*attrflagp = 0;
   1301  1.1  dholland 	NFSCL_REQSTART(nd, NFSPROC_READLINK, vp);
   1302  1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
   1303  1.1  dholland 		/*
   1304  1.1  dholland 		 * And do a Getattr op.
   1305  1.1  dholland 		 */
   1306  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   1307  1.1  dholland 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
   1308  1.1  dholland 		NFSGETATTR_ATTRBIT(&attrbits);
   1309  1.1  dholland 		(void) nfsrv_putattrbit(nd, &attrbits);
   1310  1.1  dholland 	}
   1311  1.1  dholland 	error = nfscl_request(nd, vp, p, cred, stuff);
   1312  1.1  dholland 	if (error)
   1313  1.1  dholland 		return (error);
   1314  1.1  dholland 	if (nd->nd_flag & ND_NFSV3)
   1315  1.1  dholland 		error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
   1316  1.1  dholland 	if (!nd->nd_repstat && !error) {
   1317  1.1  dholland 		NFSM_STRSIZ(len, NFS_MAXPATHLEN);
   1318  1.1  dholland 		/*
   1319  1.1  dholland 		 * This seems weird to me, but must have been added to
   1320  1.1  dholland 		 * FreeBSD for some reason. The only thing I can think of
   1321  1.1  dholland 		 * is that there was/is some server that replies with
   1322  1.1  dholland 		 * more link data than it should?
   1323  1.1  dholland 		 */
   1324  1.1  dholland 		if (len == NFS_MAXPATHLEN) {
   1325  1.1  dholland 			NFSLOCKNODE(np);
   1326  1.1  dholland 			if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) {
   1327  1.1  dholland 				len = np->n_size;
   1328  1.1  dholland 				cangetattr = 0;
   1329  1.1  dholland 			}
   1330  1.1  dholland 			NFSUNLOCKNODE(np);
   1331  1.1  dholland 		}
   1332  1.1  dholland 		error = nfsm_mbufuio(nd, uiop, len);
   1333  1.1  dholland 		if ((nd->nd_flag & ND_NFSV4) && !error && cangetattr)
   1334  1.1  dholland 			error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
   1335  1.1  dholland 	}
   1336  1.1  dholland 	if (nd->nd_repstat && !error)
   1337  1.1  dholland 		error = nd->nd_repstat;
   1338  1.1  dholland nfsmout:
   1339  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   1340  1.1  dholland 	return (error);
   1341  1.1  dholland }
   1342  1.1  dholland 
   1343  1.1  dholland /*
   1344  1.1  dholland  * Read operation.
   1345  1.1  dholland  */
   1346  1.1  dholland APPLESTATIC int
   1347  1.1  dholland nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred,
   1348  1.1  dholland     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
   1349  1.1  dholland {
   1350  1.1  dholland 	int error, expireret = 0, retrycnt;
   1351  1.1  dholland 	u_int32_t clidrev = 0;
   1352  1.1  dholland 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
   1353  1.1  dholland 	struct nfsnode *np = VTONFS(vp);
   1354  1.1  dholland 	struct ucred *newcred;
   1355  1.1  dholland 	struct nfsfh *nfhp = NULL;
   1356  1.1  dholland 	nfsv4stateid_t stateid;
   1357  1.1  dholland 	void *lckp;
   1358  1.1  dholland 
   1359  1.1  dholland 	if (nmp->nm_clp != NULL)
   1360  1.1  dholland 		clidrev = nmp->nm_clp->nfsc_clientidrev;
   1361  1.1  dholland 	newcred = cred;
   1362  1.1  dholland 	if (NFSHASNFSV4(nmp)) {
   1363  1.1  dholland 		nfhp = np->n_fhp;
   1364  1.1  dholland 		newcred = NFSNEWCRED(cred);
   1365  1.1  dholland 	}
   1366  1.1  dholland 	retrycnt = 0;
   1367  1.1  dholland 	do {
   1368  1.1  dholland 		lckp = NULL;
   1369  1.1  dholland 		if (NFSHASNFSV4(nmp))
   1370  1.1  dholland 			(void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
   1371  1.1  dholland 			    NFSV4OPEN_ACCESSREAD, 0, newcred, p, &stateid,
   1372  1.1  dholland 			    &lckp);
   1373  1.1  dholland 		error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap,
   1374  1.1  dholland 		    attrflagp, stuff);
   1375  1.1  dholland 		if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION)
   1376  1.1  dholland 			nfscl_initiate_recovery(nmp->nm_clp);
   1377  1.1  dholland 		if (lckp != NULL)
   1378  1.1  dholland 			nfscl_lockderef(lckp);
   1379  1.1  dholland 		if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
   1380  1.1  dholland 		    error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
   1381  1.1  dholland 		    error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
   1382  1.1  dholland 			(void) nfs_catnap(PZERO, error, "nfs_read");
   1383  1.1  dholland 		} else if ((error == NFSERR_EXPIRED ||
   1384  1.1  dholland 		    error == NFSERR_BADSTATEID) && clidrev != 0) {
   1385  1.1  dholland 			expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
   1386  1.1  dholland 		}
   1387  1.1  dholland 		retrycnt++;
   1388  1.1  dholland 	} while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
   1389  1.1  dholland 	    error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
   1390  1.1  dholland 	    error == NFSERR_BADSESSION ||
   1391  1.1  dholland 	    (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
   1392  1.1  dholland 	    ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
   1393  1.1  dholland 	     expireret == 0 && clidrev != 0 && retrycnt < 4));
   1394  1.1  dholland 	if (error && retrycnt >= 4)
   1395  1.1  dholland 		error = EIO;
   1396  1.1  dholland 	if (NFSHASNFSV4(nmp))
   1397  1.1  dholland 		NFSFREECRED(newcred);
   1398  1.1  dholland 	return (error);
   1399  1.1  dholland }
   1400  1.1  dholland 
   1401  1.1  dholland /*
   1402  1.1  dholland  * The actual read RPC.
   1403  1.1  dholland  */
   1404  1.1  dholland static int
   1405  1.1  dholland nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred,
   1406  1.1  dholland     nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap,
   1407  1.1  dholland     int *attrflagp, void *stuff)
   1408  1.1  dholland {
   1409  1.1  dholland 	u_int32_t *tl;
   1410  1.1  dholland 	int error = 0, len, retlen, tsiz, eof = 0;
   1411  1.1  dholland 	struct nfsrv_descript nfsd;
   1412  1.1  dholland 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
   1413  1.1  dholland 	struct nfsrv_descript *nd = &nfsd;
   1414  1.1  dholland 	int rsize;
   1415  1.1  dholland 	off_t tmp_off;
   1416  1.1  dholland 
   1417  1.1  dholland 	*attrflagp = 0;
   1418  1.1  dholland 	tsiz = uio_uio_resid(uiop);
   1419  1.1  dholland 	tmp_off = uiop->uio_offset + tsiz;
   1420  1.1  dholland 	NFSLOCKMNT(nmp);
   1421  1.1  dholland 	if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
   1422  1.1  dholland 		NFSUNLOCKMNT(nmp);
   1423  1.1  dholland 		return (EFBIG);
   1424  1.1  dholland 	}
   1425  1.1  dholland 	rsize = nmp->nm_rsize;
   1426  1.1  dholland 	NFSUNLOCKMNT(nmp);
   1427  1.1  dholland 	nd->nd_mrep = NULL;
   1428  1.1  dholland 	while (tsiz > 0) {
   1429  1.1  dholland 		*attrflagp = 0;
   1430  1.1  dholland 		len = (tsiz > rsize) ? rsize : tsiz;
   1431  1.1  dholland 		NFSCL_REQSTART(nd, NFSPROC_READ, vp);
   1432  1.1  dholland 		if (nd->nd_flag & ND_NFSV4)
   1433  1.1  dholland 			nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
   1434  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3);
   1435  1.1  dholland 		if (nd->nd_flag & ND_NFSV2) {
   1436  1.1  dholland 			*tl++ = txdr_unsigned(uiop->uio_offset);
   1437  1.1  dholland 			*tl++ = txdr_unsigned(len);
   1438  1.1  dholland 			*tl = 0;
   1439  1.1  dholland 		} else {
   1440  1.1  dholland 			txdr_hyper(uiop->uio_offset, tl);
   1441  1.1  dholland 			*(tl + 2) = txdr_unsigned(len);
   1442  1.1  dholland 		}
   1443  1.1  dholland 		/*
   1444  1.1  dholland 		 * Since I can't do a Getattr for NFSv4 for Write, there
   1445  1.1  dholland 		 * doesn't seem any point in doing one here, either.
   1446  1.1  dholland 		 * (See the comment in nfsrpc_writerpc() for more info.)
   1447  1.1  dholland 		 */
   1448  1.1  dholland 		error = nfscl_request(nd, vp, p, cred, stuff);
   1449  1.1  dholland 		if (error)
   1450  1.1  dholland 			return (error);
   1451  1.1  dholland 		if (nd->nd_flag & ND_NFSV3) {
   1452  1.1  dholland 			error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
   1453  1.1  dholland 		} else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
   1454  1.1  dholland 			error = nfsm_loadattr(nd, nap);
   1455  1.1  dholland 			if (!error)
   1456  1.1  dholland 				*attrflagp = 1;
   1457  1.1  dholland 		}
   1458  1.1  dholland 		if (nd->nd_repstat || error) {
   1459  1.1  dholland 			if (!error)
   1460  1.1  dholland 				error = nd->nd_repstat;
   1461  1.1  dholland 			goto nfsmout;
   1462  1.1  dholland 		}
   1463  1.1  dholland 		if (nd->nd_flag & ND_NFSV3) {
   1464  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   1465  1.1  dholland 			eof = fxdr_unsigned(int, *(tl + 1));
   1466  1.1  dholland 		} else if (nd->nd_flag & ND_NFSV4) {
   1467  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1468  1.1  dholland 			eof = fxdr_unsigned(int, *tl);
   1469  1.1  dholland 		}
   1470  1.1  dholland 		NFSM_STRSIZ(retlen, len);
   1471  1.1  dholland 		error = nfsm_mbufuio(nd, uiop, retlen);
   1472  1.1  dholland 		if (error)
   1473  1.1  dholland 			goto nfsmout;
   1474  1.1  dholland 		mbuf_freem(nd->nd_mrep);
   1475  1.1  dholland 		nd->nd_mrep = NULL;
   1476  1.1  dholland 		tsiz -= retlen;
   1477  1.1  dholland 		if (!(nd->nd_flag & ND_NFSV2)) {
   1478  1.1  dholland 			if (eof || retlen == 0)
   1479  1.1  dholland 				tsiz = 0;
   1480  1.1  dholland 		} else if (retlen < len)
   1481  1.1  dholland 			tsiz = 0;
   1482  1.1  dholland 	}
   1483  1.1  dholland 	return (0);
   1484  1.1  dholland nfsmout:
   1485  1.1  dholland 	if (nd->nd_mrep != NULL)
   1486  1.1  dholland 		mbuf_freem(nd->nd_mrep);
   1487  1.1  dholland 	return (error);
   1488  1.1  dholland }
   1489  1.1  dholland 
   1490  1.1  dholland /*
   1491  1.1  dholland  * nfs write operation
   1492  1.1  dholland  * When called_from_strategy != 0, it should return EIO for an error that
   1493  1.1  dholland  * indicates recovery is in progress, so that the buffer will be left
   1494  1.1  dholland  * dirty and be written back to the server later. If it loops around,
   1495  1.1  dholland  * the recovery thread could get stuck waiting for the buffer and recovery
   1496  1.1  dholland  * will then deadlock.
   1497  1.1  dholland  */
   1498  1.1  dholland APPLESTATIC int
   1499  1.1  dholland nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
   1500  1.1  dholland     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
   1501  1.1  dholland     void *stuff, int called_from_strategy)
   1502  1.1  dholland {
   1503  1.1  dholland 	int error, expireret = 0, retrycnt, nostateid;
   1504  1.1  dholland 	u_int32_t clidrev = 0;
   1505  1.1  dholland 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
   1506  1.1  dholland 	struct nfsnode *np = VTONFS(vp);
   1507  1.1  dholland 	struct ucred *newcred;
   1508  1.1  dholland 	struct nfsfh *nfhp = NULL;
   1509  1.1  dholland 	nfsv4stateid_t stateid;
   1510  1.1  dholland 	void *lckp;
   1511  1.1  dholland 
   1512  1.1  dholland 	*must_commit = 0;
   1513  1.1  dholland 	if (nmp->nm_clp != NULL)
   1514  1.1  dholland 		clidrev = nmp->nm_clp->nfsc_clientidrev;
   1515  1.1  dholland 	newcred = cred;
   1516  1.1  dholland 	if (NFSHASNFSV4(nmp)) {
   1517  1.1  dholland 		newcred = NFSNEWCRED(cred);
   1518  1.1  dholland 		nfhp = np->n_fhp;
   1519  1.1  dholland 	}
   1520  1.1  dholland 	retrycnt = 0;
   1521  1.1  dholland 	do {
   1522  1.1  dholland 		lckp = NULL;
   1523  1.1  dholland 		nostateid = 0;
   1524  1.1  dholland 		if (NFSHASNFSV4(nmp)) {
   1525  1.1  dholland 			(void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
   1526  1.1  dholland 			    NFSV4OPEN_ACCESSWRITE, 0, newcred, p, &stateid,
   1527  1.1  dholland 			    &lckp);
   1528  1.1  dholland 			if (stateid.other[0] == 0 && stateid.other[1] == 0 &&
   1529  1.1  dholland 			    stateid.other[2] == 0) {
   1530  1.1  dholland 				nostateid = 1;
   1531  1.1  dholland 				NFSCL_DEBUG(1, "stateid0 in write\n");
   1532  1.1  dholland 			}
   1533  1.1  dholland 		}
   1534  1.1  dholland 
   1535  1.1  dholland 		/*
   1536  1.1  dholland 		 * If there is no stateid for NFSv4, it means this is an
   1537  1.1  dholland 		 * extraneous write after close. Basically a poorly
   1538  1.1  dholland 		 * implemented buffer cache. Just don't do the write.
   1539  1.1  dholland 		 */
   1540  1.1  dholland 		if (nostateid)
   1541  1.1  dholland 			error = 0;
   1542  1.1  dholland 		else
   1543  1.1  dholland 			error = nfsrpc_writerpc(vp, uiop, iomode, must_commit,
   1544  1.1  dholland 			    newcred, &stateid, p, nap, attrflagp, stuff);
   1545  1.1  dholland 		if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION)
   1546  1.1  dholland 			nfscl_initiate_recovery(nmp->nm_clp);
   1547  1.1  dholland 		if (lckp != NULL)
   1548  1.1  dholland 			nfscl_lockderef(lckp);
   1549  1.1  dholland 		if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
   1550  1.1  dholland 		    error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
   1551  1.1  dholland 		    error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
   1552  1.1  dholland 			(void) nfs_catnap(PZERO, error, "nfs_write");
   1553  1.1  dholland 		} else if ((error == NFSERR_EXPIRED ||
   1554  1.1  dholland 		    error == NFSERR_BADSTATEID) && clidrev != 0) {
   1555  1.1  dholland 			expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
   1556  1.1  dholland 		}
   1557  1.1  dholland 		retrycnt++;
   1558  1.1  dholland 	} while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
   1559  1.1  dholland 	    ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
   1560  1.1  dholland 	      error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) ||
   1561  1.1  dholland 	    (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
   1562  1.1  dholland 	    ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
   1563  1.1  dholland 	     expireret == 0 && clidrev != 0 && retrycnt < 4));
   1564  1.1  dholland 	if (error != 0 && (retrycnt >= 4 ||
   1565  1.1  dholland 	    ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
   1566  1.1  dholland 	      error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0)))
   1567  1.1  dholland 		error = EIO;
   1568  1.1  dholland 	if (NFSHASNFSV4(nmp))
   1569  1.1  dholland 		NFSFREECRED(newcred);
   1570  1.1  dholland 	return (error);
   1571  1.1  dholland }
   1572  1.1  dholland 
   1573  1.1  dholland /*
   1574  1.1  dholland  * The actual write RPC.
   1575  1.1  dholland  */
   1576  1.1  dholland static int
   1577  1.1  dholland nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
   1578  1.1  dholland     int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp,
   1579  1.1  dholland     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
   1580  1.1  dholland {
   1581  1.1  dholland 	u_int32_t *tl;
   1582  1.1  dholland 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
   1583  1.1  dholland 	struct nfsnode *np = VTONFS(vp);
   1584  1.1  dholland 	int error = 0, len, tsiz, rlen, commit, committed = NFSWRITE_FILESYNC;
   1585  1.1  dholland 	int wccflag = 0, wsize;
   1586  1.1  dholland 	int32_t backup;
   1587  1.1  dholland 	struct nfsrv_descript nfsd;
   1588  1.1  dholland 	struct nfsrv_descript *nd = &nfsd;
   1589  1.1  dholland 	nfsattrbit_t attrbits;
   1590  1.1  dholland 	off_t tmp_off;
   1591  1.1  dholland 
   1592  1.1  dholland 	KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
   1593  1.1  dholland 	*attrflagp = 0;
   1594  1.1  dholland 	tsiz = uio_uio_resid(uiop);
   1595  1.1  dholland 	tmp_off = uiop->uio_offset + tsiz;
   1596  1.1  dholland 	NFSLOCKMNT(nmp);
   1597  1.1  dholland 	if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
   1598  1.1  dholland 		NFSUNLOCKMNT(nmp);
   1599  1.1  dholland 		return (EFBIG);
   1600  1.1  dholland 	}
   1601  1.1  dholland 	wsize = nmp->nm_wsize;
   1602  1.1  dholland 	NFSUNLOCKMNT(nmp);
   1603  1.1  dholland 	nd->nd_mrep = NULL;	/* NFSv2 sometimes does a write with */
   1604  1.1  dholland 	nd->nd_repstat = 0;	/* uio_resid == 0, so the while is not done */
   1605  1.1  dholland 	while (tsiz > 0) {
   1606  1.1  dholland 		*attrflagp = 0;
   1607  1.1  dholland 		len = (tsiz > wsize) ? wsize : tsiz;
   1608  1.1  dholland 		NFSCL_REQSTART(nd, NFSPROC_WRITE, vp);
   1609  1.1  dholland 		if (nd->nd_flag & ND_NFSV4) {
   1610  1.1  dholland 			nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
   1611  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED);
   1612  1.1  dholland 			txdr_hyper(uiop->uio_offset, tl);
   1613  1.1  dholland 			tl += 2;
   1614  1.1  dholland 			*tl++ = txdr_unsigned(*iomode);
   1615  1.1  dholland 			*tl = txdr_unsigned(len);
   1616  1.1  dholland 		} else if (nd->nd_flag & ND_NFSV3) {
   1617  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED);
   1618  1.1  dholland 			txdr_hyper(uiop->uio_offset, tl);
   1619  1.1  dholland 			tl += 2;
   1620  1.1  dholland 			*tl++ = txdr_unsigned(len);
   1621  1.1  dholland 			*tl++ = txdr_unsigned(*iomode);
   1622  1.1  dholland 			*tl = txdr_unsigned(len);
   1623  1.1  dholland 		} else {
   1624  1.1  dholland 			u_int32_t x;
   1625  1.1  dholland 
   1626  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
   1627  1.1  dholland 			/*
   1628  1.1  dholland 			 * Not sure why someone changed this, since the
   1629  1.1  dholland 			 * RFC clearly states that "beginoffset" and
   1630  1.1  dholland 			 * "totalcount" are ignored, but it wouldn't
   1631  1.1  dholland 			 * surprise me if there's a busted server out there.
   1632  1.1  dholland 			 */
   1633  1.1  dholland 			/* Set both "begin" and "current" to non-garbage. */
   1634  1.1  dholland 			x = txdr_unsigned((u_int32_t)uiop->uio_offset);
   1635  1.1  dholland 			*tl++ = x;      /* "begin offset" */
   1636  1.1  dholland 			*tl++ = x;      /* "current offset" */
   1637  1.1  dholland 			x = txdr_unsigned(len);
   1638  1.1  dholland 			*tl++ = x;      /* total to this offset */
   1639  1.1  dholland 			*tl = x;        /* size of this write */
   1640  1.1  dholland 
   1641  1.1  dholland 		}
   1642  1.1  dholland 		nfsm_uiombuf(nd, uiop, len);
   1643  1.1  dholland 		/*
   1644  1.1  dholland 		 * Although it is tempting to do a normal Getattr Op in the
   1645  1.1  dholland 		 * NFSv4 compound, the result can be a nearly hung client
   1646  1.1  dholland 		 * system if the Getattr asks for Owner and/or OwnerGroup.
   1647  1.1  dholland 		 * It occurs when the client can't map either the Owner or
   1648  1.1  dholland 		 * Owner_group name in the Getattr reply to a uid/gid. When
   1649  1.1  dholland 		 * there is a cache miss, the kernel does an upcall to the
   1650  1.1  dholland 		 * nfsuserd. Then, it can try and read the local /etc/passwd
   1651  1.1  dholland 		 * or /etc/group file. It can then block in getnewbuf(),
   1652  1.1  dholland 		 * waiting for dirty writes to be pushed to the NFS server.
   1653  1.1  dholland 		 * The only reason this doesn't result in a complete
   1654  1.1  dholland 		 * deadlock, is that the upcall times out and allows
   1655  1.1  dholland 		 * the write to complete. However, progress is so slow
   1656  1.1  dholland 		 * that it might just as well be deadlocked.
   1657  1.1  dholland 		 * As such, we get the rest of the attributes, but not
   1658  1.1  dholland 		 * Owner or Owner_group.
   1659  1.1  dholland 		 * nb: nfscl_loadattrcache() needs to be told that these
   1660  1.1  dholland 		 *     partial attributes from a write rpc are being
   1661  1.1  dholland 		 *     passed in, via a argument flag.
   1662  1.1  dholland 		 */
   1663  1.1  dholland 		if (nd->nd_flag & ND_NFSV4) {
   1664  1.1  dholland 			NFSWRITEGETATTR_ATTRBIT(&attrbits);
   1665  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   1666  1.1  dholland 			*tl = txdr_unsigned(NFSV4OP_GETATTR);
   1667  1.1  dholland 			(void) nfsrv_putattrbit(nd, &attrbits);
   1668  1.1  dholland 		}
   1669  1.1  dholland 		error = nfscl_request(nd, vp, p, cred, stuff);
   1670  1.1  dholland 		if (error)
   1671  1.1  dholland 			return (error);
   1672  1.1  dholland 		if (nd->nd_repstat) {
   1673  1.1  dholland 			/*
   1674  1.1  dholland 			 * In case the rpc gets retried, roll
   1675  1.1  dholland 			 * the uio fileds changed by nfsm_uiombuf()
   1676  1.1  dholland 			 * back.
   1677  1.1  dholland 			 */
   1678  1.1  dholland 			uiop->uio_offset -= len;
   1679  1.1  dholland 			uio_uio_resid_add(uiop, len);
   1680  1.1  dholland 			uio_iov_base_add(uiop, -len);
   1681  1.1  dholland 			uio_iov_len_add(uiop, len);
   1682  1.1  dholland 		}
   1683  1.1  dholland 		if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
   1684  1.1  dholland 			error = nfscl_wcc_data(nd, vp, nap, attrflagp,
   1685  1.1  dholland 			    &wccflag, stuff);
   1686  1.1  dholland 			if (error)
   1687  1.1  dholland 				goto nfsmout;
   1688  1.1  dholland 		}
   1689  1.1  dholland 		if (!nd->nd_repstat) {
   1690  1.1  dholland 			if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
   1691  1.1  dholland 				NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED
   1692  1.1  dholland 					+ NFSX_VERF);
   1693  1.1  dholland 				rlen = fxdr_unsigned(int, *tl++);
   1694  1.1  dholland 				if (rlen == 0) {
   1695  1.1  dholland 					error = NFSERR_IO;
   1696  1.1  dholland 					goto nfsmout;
   1697  1.1  dholland 				} else if (rlen < len) {
   1698  1.1  dholland 					backup = len - rlen;
   1699  1.1  dholland 					uio_iov_base_add(uiop, -(backup));
   1700  1.1  dholland 					uio_iov_len_add(uiop, backup);
   1701  1.1  dholland 					uiop->uio_offset -= backup;
   1702  1.1  dholland 					uio_uio_resid_add(uiop, backup);
   1703  1.1  dholland 					len = rlen;
   1704  1.1  dholland 				}
   1705  1.1  dholland 				commit = fxdr_unsigned(int, *tl++);
   1706  1.1  dholland 
   1707  1.1  dholland 				/*
   1708  1.2  pgoyette 				 * Return the lowest commitment level
   1709  1.1  dholland 				 * obtained by any of the RPCs.
   1710  1.1  dholland 				 */
   1711  1.1  dholland 				if (committed == NFSWRITE_FILESYNC)
   1712  1.1  dholland 					committed = commit;
   1713  1.1  dholland 				else if (committed == NFSWRITE_DATASYNC &&
   1714  1.1  dholland 					commit == NFSWRITE_UNSTABLE)
   1715  1.1  dholland 					committed = commit;
   1716  1.1  dholland 				NFSLOCKMNT(nmp);
   1717  1.1  dholland 				if (!NFSHASWRITEVERF(nmp)) {
   1718  1.1  dholland 					NFSBCOPY((caddr_t)tl,
   1719  1.1  dholland 					    (caddr_t)&nmp->nm_verf[0],
   1720  1.1  dholland 					    NFSX_VERF);
   1721  1.1  dholland 					NFSSETWRITEVERF(nmp);
   1722  1.1  dholland 	    			} else if (NFSBCMP(tl, nmp->nm_verf,
   1723  1.1  dholland 				    NFSX_VERF)) {
   1724  1.1  dholland 					*must_commit = 1;
   1725  1.1  dholland 					NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
   1726  1.1  dholland 				}
   1727  1.1  dholland 				NFSUNLOCKMNT(nmp);
   1728  1.1  dholland 			}
   1729  1.1  dholland 			if (nd->nd_flag & ND_NFSV4)
   1730  1.1  dholland 				NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   1731  1.1  dholland 			if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) {
   1732  1.1  dholland 				error = nfsm_loadattr(nd, nap);
   1733  1.1  dholland 				if (!error)
   1734  1.1  dholland 					*attrflagp = NFS_LATTR_NOSHRINK;
   1735  1.1  dholland 			}
   1736  1.1  dholland 		} else {
   1737  1.1  dholland 			error = nd->nd_repstat;
   1738  1.1  dholland 		}
   1739  1.1  dholland 		if (error)
   1740  1.1  dholland 			goto nfsmout;
   1741  1.2  pgoyette 		NFSWRITERPC_SETTIME(wccflag, np, nap, (nd->nd_flag & ND_NFSV4));
   1742  1.1  dholland 		mbuf_freem(nd->nd_mrep);
   1743  1.1  dholland 		nd->nd_mrep = NULL;
   1744  1.1  dholland 		tsiz -= len;
   1745  1.1  dholland 	}
   1746  1.1  dholland nfsmout:
   1747  1.1  dholland 	if (nd->nd_mrep != NULL)
   1748  1.1  dholland 		mbuf_freem(nd->nd_mrep);
   1749  1.1  dholland 	*iomode = committed;
   1750  1.1  dholland 	if (nd->nd_repstat && !error)
   1751  1.1  dholland 		error = nd->nd_repstat;
   1752  1.1  dholland 	return (error);
   1753  1.1  dholland }
   1754  1.1  dholland 
   1755  1.1  dholland /*
   1756  1.1  dholland  * nfs mknod rpc
   1757  1.1  dholland  * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
   1758  1.1  dholland  * mode set to specify the file type and the size field for rdev.
   1759  1.1  dholland  */
   1760  1.1  dholland APPLESTATIC int
   1761  1.1  dholland nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap,
   1762  1.1  dholland     u_int32_t rdev, enum vtype vtyp, struct ucred *cred, NFSPROC_T *p,
   1763  1.1  dholland     struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
   1764  1.1  dholland     int *attrflagp, int *dattrflagp, void *dstuff)
   1765  1.1  dholland {
   1766  1.1  dholland 	u_int32_t *tl;
   1767  1.1  dholland 	int error = 0;
   1768  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   1769  1.1  dholland 	nfsattrbit_t attrbits;
   1770  1.1  dholland 
   1771  1.1  dholland 	*nfhpp = NULL;
   1772  1.1  dholland 	*attrflagp = 0;
   1773  1.1  dholland 	*dattrflagp = 0;
   1774  1.1  dholland 	if (namelen > NFS_MAXNAMLEN)
   1775  1.1  dholland 		return (ENAMETOOLONG);
   1776  1.1  dholland 	NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp);
   1777  1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
   1778  1.1  dholland 		if (vtyp == VBLK || vtyp == VCHR) {
   1779  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   1780  1.1  dholland 			*tl++ = vtonfsv34_type(vtyp);
   1781  1.1  dholland 			*tl++ = txdr_unsigned(NFSMAJOR(rdev));
   1782  1.1  dholland 			*tl = txdr_unsigned(NFSMINOR(rdev));
   1783  1.1  dholland 		} else {
   1784  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   1785  1.1  dholland 			*tl = vtonfsv34_type(vtyp);
   1786  1.1  dholland 		}
   1787  1.1  dholland 	}
   1788  1.1  dholland 	(void) nfsm_strtom(nd, name, namelen);
   1789  1.1  dholland 	if (nd->nd_flag & ND_NFSV3) {
   1790  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   1791  1.1  dholland 		*tl = vtonfsv34_type(vtyp);
   1792  1.1  dholland 	}
   1793  1.1  dholland 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
   1794  1.1  dholland 		nfscl_fillsattr(nd, vap, dvp, 0, 0);
   1795  1.1  dholland 	if ((nd->nd_flag & ND_NFSV3) &&
   1796  1.1  dholland 	    (vtyp == VCHR || vtyp == VBLK)) {
   1797  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   1798  1.1  dholland 		*tl++ = txdr_unsigned(NFSMAJOR(rdev));
   1799  1.1  dholland 		*tl = txdr_unsigned(NFSMINOR(rdev));
   1800  1.1  dholland 	}
   1801  1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
   1802  1.1  dholland 		NFSGETATTR_ATTRBIT(&attrbits);
   1803  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   1804  1.1  dholland 		*tl++ = txdr_unsigned(NFSV4OP_GETFH);
   1805  1.1  dholland 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
   1806  1.1  dholland 		(void) nfsrv_putattrbit(nd, &attrbits);
   1807  1.1  dholland 	}
   1808  1.1  dholland 	if (nd->nd_flag & ND_NFSV2)
   1809  1.1  dholland 		nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev);
   1810  1.1  dholland 	error = nfscl_request(nd, dvp, p, cred, dstuff);
   1811  1.1  dholland 	if (error)
   1812  1.1  dholland 		return (error);
   1813  1.1  dholland 	if (nd->nd_flag & ND_NFSV4)
   1814  1.1  dholland 		error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
   1815  1.1  dholland 	if (!nd->nd_repstat) {
   1816  1.1  dholland 		if (nd->nd_flag & ND_NFSV4) {
   1817  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
   1818  1.1  dholland 			error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
   1819  1.1  dholland 			if (error)
   1820  1.1  dholland 				goto nfsmout;
   1821  1.1  dholland 		}
   1822  1.1  dholland 		error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
   1823  1.1  dholland 		if (error)
   1824  1.1  dholland 			goto nfsmout;
   1825  1.1  dholland 	}
   1826  1.1  dholland 	if (nd->nd_flag & ND_NFSV3)
   1827  1.1  dholland 		error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
   1828  1.1  dholland 	if (!error && nd->nd_repstat)
   1829  1.1  dholland 		error = nd->nd_repstat;
   1830  1.1  dholland nfsmout:
   1831  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   1832  1.1  dholland 	return (error);
   1833  1.1  dholland }
   1834  1.1  dholland 
   1835  1.1  dholland /*
   1836  1.1  dholland  * nfs file create call
   1837  1.1  dholland  * Mostly just call the approriate routine. (I separated out v4, so that
   1838  1.1  dholland  * error recovery wouldn't be as difficult.)
   1839  1.1  dholland  */
   1840  1.1  dholland APPLESTATIC int
   1841  1.1  dholland nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap,
   1842  1.1  dholland     nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
   1843  1.1  dholland     struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
   1844  1.1  dholland     int *attrflagp, int *dattrflagp, void *dstuff)
   1845  1.1  dholland {
   1846  1.1  dholland 	int error = 0, newone, expireret = 0, retrycnt, unlocked;
   1847  1.1  dholland 	struct nfsclowner *owp;
   1848  1.1  dholland 	struct nfscldeleg *dp;
   1849  1.1  dholland 	struct nfsmount *nmp = VFSTONFS(vnode_mount(dvp));
   1850  1.1  dholland 	u_int32_t clidrev;
   1851  1.1  dholland 
   1852  1.1  dholland 	if (NFSHASNFSV4(nmp)) {
   1853  1.1  dholland 	    retrycnt = 0;
   1854  1.1  dholland 	    do {
   1855  1.1  dholland 		dp = NULL;
   1856  1.1  dholland 		error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE |
   1857  1.1  dholland 		    NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone,
   1858  1.1  dholland 		    NULL, 1);
   1859  1.1  dholland 		if (error)
   1860  1.1  dholland 			return (error);
   1861  1.1  dholland 		if (nmp->nm_clp != NULL)
   1862  1.1  dholland 			clidrev = nmp->nm_clp->nfsc_clientidrev;
   1863  1.1  dholland 		else
   1864  1.1  dholland 			clidrev = 0;
   1865  1.1  dholland 		error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, fmode,
   1866  1.1  dholland 		  owp, &dp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
   1867  1.1  dholland 		  dstuff, &unlocked);
   1868  1.1  dholland 		/*
   1869  1.1  dholland 		 * There is no need to invalidate cached attributes here,
   1870  1.1  dholland 		 * since new post-delegation issue attributes are always
   1871  1.1  dholland 		 * returned by nfsrpc_createv4() and these will update the
   1872  1.1  dholland 		 * attribute cache.
   1873  1.1  dholland 		 */
   1874  1.1  dholland 		if (dp != NULL)
   1875  1.1  dholland 			(void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp,
   1876  1.1  dholland 			    (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp);
   1877  1.1  dholland 		nfscl_ownerrelease(owp, error, newone, unlocked);
   1878  1.1  dholland 		if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
   1879  1.1  dholland 		    error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
   1880  1.1  dholland 		    error == NFSERR_BADSESSION) {
   1881  1.1  dholland 			(void) nfs_catnap(PZERO, error, "nfs_open");
   1882  1.1  dholland 		} else if ((error == NFSERR_EXPIRED ||
   1883  1.1  dholland 		    error == NFSERR_BADSTATEID) && clidrev != 0) {
   1884  1.1  dholland 			expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
   1885  1.1  dholland 			retrycnt++;
   1886  1.1  dholland 		}
   1887  1.1  dholland 	    } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
   1888  1.1  dholland 		error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
   1889  1.1  dholland 		error == NFSERR_BADSESSION ||
   1890  1.1  dholland 		((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
   1891  1.1  dholland 		 expireret == 0 && clidrev != 0 && retrycnt < 4));
   1892  1.1  dholland 	    if (error && retrycnt >= 4)
   1893  1.1  dholland 		    error = EIO;
   1894  1.1  dholland 	} else {
   1895  1.1  dholland 		error = nfsrpc_createv23(dvp, name, namelen, vap, cverf,
   1896  1.1  dholland 		    fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
   1897  1.1  dholland 		    dstuff);
   1898  1.1  dholland 	}
   1899  1.1  dholland 	return (error);
   1900  1.1  dholland }
   1901  1.1  dholland 
   1902  1.1  dholland /*
   1903  1.1  dholland  * The create rpc for v2 and 3.
   1904  1.1  dholland  */
   1905  1.1  dholland static int
   1906  1.1  dholland nfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap,
   1907  1.1  dholland     nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
   1908  1.1  dholland     struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
   1909  1.1  dholland     int *attrflagp, int *dattrflagp, void *dstuff)
   1910  1.1  dholland {
   1911  1.1  dholland 	u_int32_t *tl;
   1912  1.1  dholland 	int error = 0;
   1913  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   1914  1.1  dholland 
   1915  1.1  dholland 	*nfhpp = NULL;
   1916  1.1  dholland 	*attrflagp = 0;
   1917  1.1  dholland 	*dattrflagp = 0;
   1918  1.1  dholland 	if (namelen > NFS_MAXNAMLEN)
   1919  1.1  dholland 		return (ENAMETOOLONG);
   1920  1.1  dholland 	NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
   1921  1.1  dholland 	(void) nfsm_strtom(nd, name, namelen);
   1922  1.1  dholland 	if (nd->nd_flag & ND_NFSV3) {
   1923  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   1924  1.1  dholland 		if (fmode & O_EXCL) {
   1925  1.1  dholland 			*tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
   1926  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
   1927  1.1  dholland 			*tl++ = cverf.lval[0];
   1928  1.1  dholland 			*tl = cverf.lval[1];
   1929  1.1  dholland 		} else {
   1930  1.1  dholland 			*tl = txdr_unsigned(NFSCREATE_UNCHECKED);
   1931  1.1  dholland 			nfscl_fillsattr(nd, vap, dvp, 0, 0);
   1932  1.1  dholland 		}
   1933  1.1  dholland 	} else {
   1934  1.1  dholland 		nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0);
   1935  1.1  dholland 	}
   1936  1.1  dholland 	error = nfscl_request(nd, dvp, p, cred, dstuff);
   1937  1.1  dholland 	if (error)
   1938  1.1  dholland 		return (error);
   1939  1.1  dholland 	if (nd->nd_repstat == 0) {
   1940  1.1  dholland 		error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
   1941  1.1  dholland 		if (error)
   1942  1.1  dholland 			goto nfsmout;
   1943  1.1  dholland 	}
   1944  1.1  dholland 	if (nd->nd_flag & ND_NFSV3)
   1945  1.1  dholland 		error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
   1946  1.1  dholland 	if (nd->nd_repstat != 0 && error == 0)
   1947  1.1  dholland 		error = nd->nd_repstat;
   1948  1.1  dholland nfsmout:
   1949  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   1950  1.1  dholland 	return (error);
   1951  1.1  dholland }
   1952  1.1  dholland 
   1953  1.1  dholland static int
   1954  1.1  dholland nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap,
   1955  1.1  dholland     nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
   1956  1.1  dholland     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
   1957  1.1  dholland     struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
   1958  1.1  dholland     int *dattrflagp, void *dstuff, int *unlockedp)
   1959  1.1  dholland {
   1960  1.1  dholland 	u_int32_t *tl;
   1961  1.1  dholland 	int error = 0, deleg, newone, ret, acesize, limitby;
   1962  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   1963  1.1  dholland 	struct nfsclopen *op;
   1964  1.1  dholland 	struct nfscldeleg *dp = NULL;
   1965  1.1  dholland 	struct nfsnode *np;
   1966  1.1  dholland 	struct nfsfh *nfhp;
   1967  1.1  dholland 	nfsattrbit_t attrbits;
   1968  1.1  dholland 	nfsv4stateid_t stateid;
   1969  1.1  dholland 	u_int32_t rflags;
   1970  1.1  dholland 	struct nfsmount *nmp;
   1971  1.1  dholland 
   1972  1.1  dholland 	nmp = VFSTONFS(dvp->v_mount);
   1973  1.2  pgoyette 	np = VTONFS(dvp);
   1974  1.1  dholland 	*unlockedp = 0;
   1975  1.1  dholland 	*nfhpp = NULL;
   1976  1.1  dholland 	*dpp = NULL;
   1977  1.1  dholland 	*attrflagp = 0;
   1978  1.1  dholland 	*dattrflagp = 0;
   1979  1.1  dholland 	if (namelen > NFS_MAXNAMLEN)
   1980  1.1  dholland 		return (ENAMETOOLONG);
   1981  1.1  dholland 	NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
   1982  1.1  dholland 	/*
   1983  1.1  dholland 	 * For V4, this is actually an Open op.
   1984  1.1  dholland 	 */
   1985  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
   1986  1.1  dholland 	*tl++ = txdr_unsigned(owp->nfsow_seqid);
   1987  1.1  dholland 	*tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
   1988  1.1  dholland 	    NFSV4OPEN_ACCESSREAD);
   1989  1.1  dholland 	*tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
   1990  1.1  dholland 	*tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
   1991  1.1  dholland 	*tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
   1992  1.1  dholland 	(void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
   1993  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   1994  1.1  dholland 	*tl++ = txdr_unsigned(NFSV4OPEN_CREATE);
   1995  1.1  dholland 	if (fmode & O_EXCL) {
   1996  1.1  dholland 		if (NFSHASNFSV4N(nmp)) {
   1997  1.1  dholland 			if (NFSHASSESSPERSIST(nmp)) {
   1998  1.1  dholland 				/* Use GUARDED for persistent sessions. */
   1999  1.1  dholland 				*tl = txdr_unsigned(NFSCREATE_GUARDED);
   2000  1.1  dholland 				nfscl_fillsattr(nd, vap, dvp, 0, 0);
   2001  1.1  dholland 			} else {
   2002  1.1  dholland 				/* Otherwise, use EXCLUSIVE4_1. */
   2003  1.1  dholland 				*tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41);
   2004  1.1  dholland 				NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
   2005  1.1  dholland 				*tl++ = cverf.lval[0];
   2006  1.1  dholland 				*tl = cverf.lval[1];
   2007  1.1  dholland 				nfscl_fillsattr(nd, vap, dvp, 0, 0);
   2008  1.1  dholland 			}
   2009  1.1  dholland 		} else {
   2010  1.1  dholland 			/* NFSv4.0 */
   2011  1.1  dholland 			*tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
   2012  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
   2013  1.1  dholland 			*tl++ = cverf.lval[0];
   2014  1.1  dholland 			*tl = cverf.lval[1];
   2015  1.1  dholland 		}
   2016  1.1  dholland 	} else {
   2017  1.1  dholland 		*tl = txdr_unsigned(NFSCREATE_UNCHECKED);
   2018  1.1  dholland 		nfscl_fillsattr(nd, vap, dvp, 0, 0);
   2019  1.1  dholland 	}
   2020  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2021  1.1  dholland 	*tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
   2022  1.1  dholland 	(void) nfsm_strtom(nd, name, namelen);
   2023  1.2  pgoyette 	/* Get the new file's handle and attributes. */
   2024  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2025  1.1  dholland 	*tl++ = txdr_unsigned(NFSV4OP_GETFH);
   2026  1.1  dholland 	*tl = txdr_unsigned(NFSV4OP_GETATTR);
   2027  1.1  dholland 	NFSGETATTR_ATTRBIT(&attrbits);
   2028  1.1  dholland 	(void) nfsrv_putattrbit(nd, &attrbits);
   2029  1.2  pgoyette 	/* Get the directory's post-op attributes. */
   2030  1.2  pgoyette 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2031  1.2  pgoyette 	*tl = txdr_unsigned(NFSV4OP_PUTFH);
   2032  1.2  pgoyette 	(void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
   2033  1.2  pgoyette 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2034  1.2  pgoyette 	*tl = txdr_unsigned(NFSV4OP_GETATTR);
   2035  1.2  pgoyette 	(void) nfsrv_putattrbit(nd, &attrbits);
   2036  1.1  dholland 	error = nfscl_request(nd, dvp, p, cred, dstuff);
   2037  1.1  dholland 	if (error)
   2038  1.1  dholland 		return (error);
   2039  1.1  dholland 	NFSCL_INCRSEQID(owp->nfsow_seqid, nd);
   2040  1.1  dholland 	if (nd->nd_repstat == 0) {
   2041  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
   2042  1.1  dholland 		    6 * NFSX_UNSIGNED);
   2043  1.1  dholland 		stateid.seqid = *tl++;
   2044  1.1  dholland 		stateid.other[0] = *tl++;
   2045  1.1  dholland 		stateid.other[1] = *tl++;
   2046  1.1  dholland 		stateid.other[2] = *tl;
   2047  1.1  dholland 		rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
   2048  1.1  dholland 		(void) nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
   2049  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2050  1.1  dholland 		deleg = fxdr_unsigned(int, *tl);
   2051  1.1  dholland 		if (deleg == NFSV4OPEN_DELEGATEREAD ||
   2052  1.1  dholland 		    deleg == NFSV4OPEN_DELEGATEWRITE) {
   2053  1.1  dholland 			if (!(owp->nfsow_clp->nfsc_flags &
   2054  1.1  dholland 			      NFSCLFLAGS_FIRSTDELEG))
   2055  1.1  dholland 				owp->nfsow_clp->nfsc_flags |=
   2056  1.1  dholland 				  (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
   2057  1.1  dholland 			MALLOC(dp, struct nfscldeleg *,
   2058  1.1  dholland 			    sizeof (struct nfscldeleg) + NFSX_V4FHMAX,
   2059  1.1  dholland 			    M_NFSCLDELEG, M_WAITOK);
   2060  1.1  dholland 			LIST_INIT(&dp->nfsdl_owner);
   2061  1.1  dholland 			LIST_INIT(&dp->nfsdl_lock);
   2062  1.1  dholland 			dp->nfsdl_clp = owp->nfsow_clp;
   2063  1.1  dholland 			newnfs_copyincred(cred, &dp->nfsdl_cred);
   2064  1.1  dholland 			nfscl_lockinit(&dp->nfsdl_rwlock);
   2065  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
   2066  1.1  dholland 			    NFSX_UNSIGNED);
   2067  1.1  dholland 			dp->nfsdl_stateid.seqid = *tl++;
   2068  1.1  dholland 			dp->nfsdl_stateid.other[0] = *tl++;
   2069  1.1  dholland 			dp->nfsdl_stateid.other[1] = *tl++;
   2070  1.1  dholland 			dp->nfsdl_stateid.other[2] = *tl++;
   2071  1.1  dholland 			ret = fxdr_unsigned(int, *tl);
   2072  1.1  dholland 			if (deleg == NFSV4OPEN_DELEGATEWRITE) {
   2073  1.1  dholland 				dp->nfsdl_flags = NFSCLDL_WRITE;
   2074  1.1  dholland 				/*
   2075  1.1  dholland 				 * Indicates how much the file can grow.
   2076  1.1  dholland 				 */
   2077  1.1  dholland 				NFSM_DISSECT(tl, u_int32_t *,
   2078  1.1  dholland 				    3 * NFSX_UNSIGNED);
   2079  1.1  dholland 				limitby = fxdr_unsigned(int, *tl++);
   2080  1.1  dholland 				switch (limitby) {
   2081  1.1  dholland 				case NFSV4OPEN_LIMITSIZE:
   2082  1.1  dholland 					dp->nfsdl_sizelimit = fxdr_hyper(tl);
   2083  1.1  dholland 					break;
   2084  1.1  dholland 				case NFSV4OPEN_LIMITBLOCKS:
   2085  1.1  dholland 					dp->nfsdl_sizelimit =
   2086  1.1  dholland 					    fxdr_unsigned(u_int64_t, *tl++);
   2087  1.1  dholland 					dp->nfsdl_sizelimit *=
   2088  1.1  dholland 					    fxdr_unsigned(u_int64_t, *tl);
   2089  1.1  dholland 					break;
   2090  1.1  dholland 				default:
   2091  1.1  dholland 					error = NFSERR_BADXDR;
   2092  1.1  dholland 					goto nfsmout;
   2093  1.2  pgoyette 				}
   2094  1.1  dholland 			} else {
   2095  1.1  dholland 				dp->nfsdl_flags = NFSCLDL_READ;
   2096  1.1  dholland 			}
   2097  1.1  dholland 			if (ret)
   2098  1.1  dholland 				dp->nfsdl_flags |= NFSCLDL_RECALL;
   2099  1.1  dholland 			error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret,
   2100  1.1  dholland 			    &acesize, p);
   2101  1.1  dholland 			if (error)
   2102  1.1  dholland 				goto nfsmout;
   2103  1.1  dholland 		} else if (deleg != NFSV4OPEN_DELEGATENONE) {
   2104  1.1  dholland 			error = NFSERR_BADXDR;
   2105  1.1  dholland 			goto nfsmout;
   2106  1.1  dholland 		}
   2107  1.1  dholland 		error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
   2108  1.1  dholland 		if (error)
   2109  1.1  dholland 			goto nfsmout;
   2110  1.2  pgoyette 		/* Get rid of the PutFH and Getattr status values. */
   2111  1.2  pgoyette 		NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
   2112  1.2  pgoyette 		/* Load the directory attributes. */
   2113  1.2  pgoyette 		error = nfsm_loadattr(nd, dnap);
   2114  1.2  pgoyette 		if (error)
   2115  1.2  pgoyette 			goto nfsmout;
   2116  1.2  pgoyette 		*dattrflagp = 1;
   2117  1.1  dholland 		if (dp != NULL && *attrflagp) {
   2118  1.1  dholland 			dp->nfsdl_change = nnap->na_filerev;
   2119  1.1  dholland 			dp->nfsdl_modtime = nnap->na_mtime;
   2120  1.1  dholland 			dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
   2121  1.1  dholland 		}
   2122  1.1  dholland 		/*
   2123  1.1  dholland 		 * We can now complete the Open state.
   2124  1.1  dholland 		 */
   2125  1.1  dholland 		nfhp = *nfhpp;
   2126  1.1  dholland 		if (dp != NULL) {
   2127  1.1  dholland 			dp->nfsdl_fhlen = nfhp->nfh_len;
   2128  1.1  dholland 			NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len);
   2129  1.1  dholland 		}
   2130  1.1  dholland 		/*
   2131  1.1  dholland 		 * Get an Open structure that will be
   2132  1.1  dholland 		 * attached to the OpenOwner, acquired already.
   2133  1.1  dholland 		 */
   2134  1.1  dholland 		error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len,
   2135  1.1  dholland 		    (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0,
   2136  1.1  dholland 		    cred, p, NULL, &op, &newone, NULL, 0);
   2137  1.1  dholland 		if (error)
   2138  1.1  dholland 			goto nfsmout;
   2139  1.1  dholland 		op->nfso_stateid = stateid;
   2140  1.1  dholland 		newnfs_copyincred(cred, &op->nfso_cred);
   2141  1.1  dholland 		if ((rflags & NFSV4OPEN_RESULTCONFIRM)) {
   2142  1.1  dholland 		    do {
   2143  1.1  dholland 			ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh,
   2144  1.1  dholland 			    nfhp->nfh_len, op, cred, p);
   2145  1.1  dholland 			if (ret == NFSERR_DELAY)
   2146  1.1  dholland 			    (void) nfs_catnap(PZERO, ret, "nfs_create");
   2147  1.1  dholland 		    } while (ret == NFSERR_DELAY);
   2148  1.1  dholland 		    error = ret;
   2149  1.1  dholland 		}
   2150  1.1  dholland 
   2151  1.1  dholland 		/*
   2152  1.1  dholland 		 * If the server is handing out delegations, but we didn't
   2153  1.1  dholland 		 * get one because an OpenConfirm was required, try the
   2154  1.1  dholland 		 * Open again, to get a delegation. This is a harmless no-op,
   2155  1.1  dholland 		 * from a server's point of view.
   2156  1.1  dholland 		 */
   2157  1.1  dholland 		if ((rflags & NFSV4OPEN_RESULTCONFIRM) &&
   2158  1.1  dholland 		    (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) &&
   2159  1.1  dholland 		    !error && dp == NULL) {
   2160  1.1  dholland 		    do {
   2161  1.1  dholland 			ret = nfsrpc_openrpc(VFSTONFS(vnode_mount(dvp)), dvp,
   2162  1.1  dholland 			    np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
   2163  1.1  dholland 			    nfhp->nfh_fh, nfhp->nfh_len,
   2164  1.1  dholland 			    (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op,
   2165  1.1  dholland 			    name, namelen, &dp, 0, 0x0, cred, p, 0, 1);
   2166  1.1  dholland 			if (ret == NFSERR_DELAY)
   2167  1.1  dholland 			    (void) nfs_catnap(PZERO, ret, "nfs_crt2");
   2168  1.1  dholland 		    } while (ret == NFSERR_DELAY);
   2169  1.1  dholland 		    if (ret) {
   2170  1.2  pgoyette 			if (dp != NULL) {
   2171  1.1  dholland 				FREE((caddr_t)dp, M_NFSCLDELEG);
   2172  1.2  pgoyette 				dp = NULL;
   2173  1.2  pgoyette 			}
   2174  1.1  dholland 			if (ret == NFSERR_STALECLIENTID ||
   2175  1.1  dholland 			    ret == NFSERR_STALEDONTRECOVER ||
   2176  1.1  dholland 			    ret == NFSERR_BADSESSION)
   2177  1.1  dholland 				error = ret;
   2178  1.1  dholland 		    }
   2179  1.1  dholland 		}
   2180  1.1  dholland 		nfscl_openrelease(op, error, newone);
   2181  1.1  dholland 		*unlockedp = 1;
   2182  1.1  dholland 	}
   2183  1.1  dholland 	if (nd->nd_repstat != 0 && error == 0)
   2184  1.1  dholland 		error = nd->nd_repstat;
   2185  1.1  dholland 	if (error == NFSERR_STALECLIENTID || error == NFSERR_BADSESSION)
   2186  1.1  dholland 		nfscl_initiate_recovery(owp->nfsow_clp);
   2187  1.1  dholland nfsmout:
   2188  1.1  dholland 	if (!error)
   2189  1.1  dholland 		*dpp = dp;
   2190  1.1  dholland 	else if (dp != NULL)
   2191  1.1  dholland 		FREE((caddr_t)dp, M_NFSCLDELEG);
   2192  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   2193  1.1  dholland 	return (error);
   2194  1.1  dholland }
   2195  1.1  dholland 
   2196  1.1  dholland /*
   2197  1.1  dholland  * Nfs remove rpc
   2198  1.1  dholland  */
   2199  1.1  dholland APPLESTATIC int
   2200  1.1  dholland nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp,
   2201  1.1  dholland     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp,
   2202  1.1  dholland     void *dstuff)
   2203  1.1  dholland {
   2204  1.1  dholland 	u_int32_t *tl;
   2205  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   2206  1.1  dholland 	struct nfsnode *np;
   2207  1.1  dholland 	struct nfsmount *nmp;
   2208  1.1  dholland 	nfsv4stateid_t dstateid;
   2209  1.1  dholland 	int error, ret = 0, i;
   2210  1.1  dholland 
   2211  1.1  dholland 	*dattrflagp = 0;
   2212  1.1  dholland 	if (namelen > NFS_MAXNAMLEN)
   2213  1.1  dholland 		return (ENAMETOOLONG);
   2214  1.1  dholland 	nmp = VFSTONFS(vnode_mount(dvp));
   2215  1.1  dholland tryagain:
   2216  1.1  dholland 	if (NFSHASNFSV4(nmp) && ret == 0) {
   2217  1.1  dholland 		ret = nfscl_removedeleg(vp, p, &dstateid);
   2218  1.1  dholland 		if (ret == 1) {
   2219  1.1  dholland 			NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp);
   2220  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
   2221  1.1  dholland 			    NFSX_UNSIGNED);
   2222  1.1  dholland 			if (NFSHASNFSV4N(nmp))
   2223  1.1  dholland 				*tl++ = 0;
   2224  1.1  dholland 			else
   2225  1.1  dholland 				*tl++ = dstateid.seqid;
   2226  1.1  dholland 			*tl++ = dstateid.other[0];
   2227  1.1  dholland 			*tl++ = dstateid.other[1];
   2228  1.1  dholland 			*tl++ = dstateid.other[2];
   2229  1.1  dholland 			*tl = txdr_unsigned(NFSV4OP_PUTFH);
   2230  1.1  dholland 			np = VTONFS(dvp);
   2231  1.1  dholland 			(void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
   2232  1.1  dholland 			    np->n_fhp->nfh_len, 0);
   2233  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2234  1.1  dholland 			*tl = txdr_unsigned(NFSV4OP_REMOVE);
   2235  1.1  dholland 		}
   2236  1.1  dholland 	} else {
   2237  1.1  dholland 		ret = 0;
   2238  1.1  dholland 	}
   2239  1.1  dholland 	if (ret == 0)
   2240  1.1  dholland 		NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp);
   2241  1.1  dholland 	(void) nfsm_strtom(nd, name, namelen);
   2242  1.1  dholland 	error = nfscl_request(nd, dvp, p, cred, dstuff);
   2243  1.1  dholland 	if (error)
   2244  1.1  dholland 		return (error);
   2245  1.1  dholland 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
   2246  1.1  dholland 		/* For NFSv4, parse out any Delereturn replies. */
   2247  1.1  dholland 		if (ret > 0 && nd->nd_repstat != 0 &&
   2248  1.1  dholland 		    (nd->nd_flag & ND_NOMOREDATA)) {
   2249  1.1  dholland 			/*
   2250  1.1  dholland 			 * If the Delegreturn failed, try again without
   2251  1.1  dholland 			 * it. The server will Recall, as required.
   2252  1.1  dholland 			 */
   2253  1.1  dholland 			mbuf_freem(nd->nd_mrep);
   2254  1.1  dholland 			goto tryagain;
   2255  1.1  dholland 		}
   2256  1.1  dholland 		for (i = 0; i < (ret * 2); i++) {
   2257  1.1  dholland 			if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
   2258  1.1  dholland 			    ND_NFSV4) {
   2259  1.1  dholland 			    NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2260  1.1  dholland 			    if (*(tl + 1))
   2261  1.1  dholland 				nd->nd_flag |= ND_NOMOREDATA;
   2262  1.1  dholland 			}
   2263  1.1  dholland 		}
   2264  1.1  dholland 		error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
   2265  1.1  dholland 	}
   2266  1.1  dholland 	if (nd->nd_repstat && !error)
   2267  1.1  dholland 		error = nd->nd_repstat;
   2268  1.1  dholland nfsmout:
   2269  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   2270  1.1  dholland 	return (error);
   2271  1.1  dholland }
   2272  1.1  dholland 
   2273  1.1  dholland /*
   2274  1.1  dholland  * Do an nfs rename rpc.
   2275  1.1  dholland  */
   2276  1.1  dholland APPLESTATIC int
   2277  1.1  dholland nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen,
   2278  1.1  dholland     vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred,
   2279  1.1  dholland     NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap,
   2280  1.1  dholland     int *fattrflagp, int *tattrflagp, void *fstuff, void *tstuff)
   2281  1.1  dholland {
   2282  1.1  dholland 	u_int32_t *tl;
   2283  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   2284  1.1  dholland 	struct nfsmount *nmp;
   2285  1.1  dholland 	struct nfsnode *np;
   2286  1.1  dholland 	nfsattrbit_t attrbits;
   2287  1.1  dholland 	nfsv4stateid_t fdstateid, tdstateid;
   2288  1.1  dholland 	int error = 0, ret = 0, gottd = 0, gotfd = 0, i;
   2289  1.1  dholland 
   2290  1.1  dholland 	*fattrflagp = 0;
   2291  1.1  dholland 	*tattrflagp = 0;
   2292  1.1  dholland 	nmp = VFSTONFS(vnode_mount(fdvp));
   2293  1.1  dholland 	if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN)
   2294  1.1  dholland 		return (ENAMETOOLONG);
   2295  1.1  dholland tryagain:
   2296  1.1  dholland 	if (NFSHASNFSV4(nmp) && ret == 0) {
   2297  1.1  dholland 		ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp,
   2298  1.1  dholland 		    &tdstateid, &gottd, p);
   2299  1.1  dholland 		if (gotfd && gottd) {
   2300  1.1  dholland 			NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp);
   2301  1.1  dholland 		} else if (gotfd) {
   2302  1.1  dholland 			NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp);
   2303  1.1  dholland 		} else if (gottd) {
   2304  1.1  dholland 			NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp);
   2305  1.1  dholland 		}
   2306  1.1  dholland 		if (gotfd) {
   2307  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
   2308  1.1  dholland 			if (NFSHASNFSV4N(nmp))
   2309  1.1  dholland 				*tl++ = 0;
   2310  1.1  dholland 			else
   2311  1.1  dholland 				*tl++ = fdstateid.seqid;
   2312  1.1  dholland 			*tl++ = fdstateid.other[0];
   2313  1.1  dholland 			*tl++ = fdstateid.other[1];
   2314  1.1  dholland 			*tl = fdstateid.other[2];
   2315  1.1  dholland 			if (gottd) {
   2316  1.1  dholland 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2317  1.1  dholland 				*tl = txdr_unsigned(NFSV4OP_PUTFH);
   2318  1.1  dholland 				np = VTONFS(tvp);
   2319  1.1  dholland 				(void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
   2320  1.1  dholland 				    np->n_fhp->nfh_len, 0);
   2321  1.1  dholland 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2322  1.1  dholland 				*tl = txdr_unsigned(NFSV4OP_DELEGRETURN);
   2323  1.1  dholland 			}
   2324  1.1  dholland 		}
   2325  1.1  dholland 		if (gottd) {
   2326  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
   2327  1.1  dholland 			if (NFSHASNFSV4N(nmp))
   2328  1.1  dholland 				*tl++ = 0;
   2329  1.1  dholland 			else
   2330  1.1  dholland 				*tl++ = tdstateid.seqid;
   2331  1.1  dholland 			*tl++ = tdstateid.other[0];
   2332  1.1  dholland 			*tl++ = tdstateid.other[1];
   2333  1.1  dholland 			*tl = tdstateid.other[2];
   2334  1.1  dholland 		}
   2335  1.1  dholland 		if (ret > 0) {
   2336  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2337  1.1  dholland 			*tl = txdr_unsigned(NFSV4OP_PUTFH);
   2338  1.1  dholland 			np = VTONFS(fdvp);
   2339  1.1  dholland 			(void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
   2340  1.1  dholland 			    np->n_fhp->nfh_len, 0);
   2341  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2342  1.1  dholland 			*tl = txdr_unsigned(NFSV4OP_SAVEFH);
   2343  1.1  dholland 		}
   2344  1.1  dholland 	} else {
   2345  1.1  dholland 		ret = 0;
   2346  1.1  dholland 	}
   2347  1.1  dholland 	if (ret == 0)
   2348  1.1  dholland 		NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp);
   2349  1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
   2350  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2351  1.1  dholland 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
   2352  1.1  dholland 		NFSWCCATTR_ATTRBIT(&attrbits);
   2353  1.1  dholland 		(void) nfsrv_putattrbit(nd, &attrbits);
   2354  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2355  1.1  dholland 		*tl = txdr_unsigned(NFSV4OP_PUTFH);
   2356  1.1  dholland 		(void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
   2357  1.1  dholland 		    VTONFS(tdvp)->n_fhp->nfh_len, 0);
   2358  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2359  1.1  dholland 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
   2360  1.1  dholland 		(void) nfsrv_putattrbit(nd, &attrbits);
   2361  1.1  dholland 		nd->nd_flag |= ND_V4WCCATTR;
   2362  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2363  1.1  dholland 		*tl = txdr_unsigned(NFSV4OP_RENAME);
   2364  1.1  dholland 	}
   2365  1.1  dholland 	(void) nfsm_strtom(nd, fnameptr, fnamelen);
   2366  1.1  dholland 	if (!(nd->nd_flag & ND_NFSV4))
   2367  1.1  dholland 		(void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
   2368  1.1  dholland 			VTONFS(tdvp)->n_fhp->nfh_len, 0);
   2369  1.1  dholland 	(void) nfsm_strtom(nd, tnameptr, tnamelen);
   2370  1.1  dholland 	error = nfscl_request(nd, fdvp, p, cred, fstuff);
   2371  1.1  dholland 	if (error)
   2372  1.1  dholland 		return (error);
   2373  1.1  dholland 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
   2374  1.1  dholland 		/* For NFSv4, parse out any Delereturn replies. */
   2375  1.1  dholland 		if (ret > 0 && nd->nd_repstat != 0 &&
   2376  1.1  dholland 		    (nd->nd_flag & ND_NOMOREDATA)) {
   2377  1.1  dholland 			/*
   2378  1.1  dholland 			 * If the Delegreturn failed, try again without
   2379  1.1  dholland 			 * it. The server will Recall, as required.
   2380  1.1  dholland 			 */
   2381  1.1  dholland 			mbuf_freem(nd->nd_mrep);
   2382  1.1  dholland 			goto tryagain;
   2383  1.1  dholland 		}
   2384  1.1  dholland 		for (i = 0; i < (ret * 2); i++) {
   2385  1.1  dholland 			if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
   2386  1.1  dholland 			    ND_NFSV4) {
   2387  1.1  dholland 			    NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2388  1.1  dholland 			    if (*(tl + 1)) {
   2389  1.1  dholland 				if (i == 0 && ret > 1) {
   2390  1.1  dholland 				    /*
   2391  1.1  dholland 				     * If the Delegreturn failed, try again
   2392  1.1  dholland 				     * without it. The server will Recall, as
   2393  1.1  dholland 				     * required.
   2394  1.1  dholland 				     * If ret > 1, the first iteration of this
   2395  1.1  dholland 				     * loop is the second DelegReturn result.
   2396  1.1  dholland 				     */
   2397  1.1  dholland 				    mbuf_freem(nd->nd_mrep);
   2398  1.1  dholland 				    goto tryagain;
   2399  1.1  dholland 				} else {
   2400  1.1  dholland 				    nd->nd_flag |= ND_NOMOREDATA;
   2401  1.1  dholland 				}
   2402  1.1  dholland 			    }
   2403  1.1  dholland 			}
   2404  1.1  dholland 		}
   2405  1.1  dholland 		/* Now, the first wcc attribute reply. */
   2406  1.1  dholland 		if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
   2407  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2408  1.1  dholland 			if (*(tl + 1))
   2409  1.1  dholland 				nd->nd_flag |= ND_NOMOREDATA;
   2410  1.1  dholland 		}
   2411  1.1  dholland 		error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL,
   2412  1.1  dholland 		    fstuff);
   2413  1.1  dholland 		/* and the second wcc attribute reply. */
   2414  1.1  dholland 		if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 &&
   2415  1.1  dholland 		    !error) {
   2416  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2417  1.1  dholland 			if (*(tl + 1))
   2418  1.1  dholland 				nd->nd_flag |= ND_NOMOREDATA;
   2419  1.1  dholland 		}
   2420  1.1  dholland 		if (!error)
   2421  1.1  dholland 			error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp,
   2422  1.1  dholland 			    NULL, tstuff);
   2423  1.1  dholland 	}
   2424  1.1  dholland 	if (nd->nd_repstat && !error)
   2425  1.1  dholland 		error = nd->nd_repstat;
   2426  1.1  dholland nfsmout:
   2427  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   2428  1.1  dholland 	return (error);
   2429  1.1  dholland }
   2430  1.1  dholland 
   2431  1.1  dholland /*
   2432  1.1  dholland  * nfs hard link create rpc
   2433  1.1  dholland  */
   2434  1.1  dholland APPLESTATIC int
   2435  1.1  dholland nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen,
   2436  1.1  dholland     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
   2437  1.1  dholland     struct nfsvattr *nap, int *attrflagp, int *dattrflagp, void *dstuff)
   2438  1.1  dholland {
   2439  1.1  dholland 	u_int32_t *tl;
   2440  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   2441  1.1  dholland 	nfsattrbit_t attrbits;
   2442  1.1  dholland 	int error = 0;
   2443  1.1  dholland 
   2444  1.1  dholland 	*attrflagp = 0;
   2445  1.1  dholland 	*dattrflagp = 0;
   2446  1.1  dholland 	if (namelen > NFS_MAXNAMLEN)
   2447  1.1  dholland 		return (ENAMETOOLONG);
   2448  1.1  dholland 	NFSCL_REQSTART(nd, NFSPROC_LINK, vp);
   2449  1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
   2450  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2451  1.1  dholland 		*tl = txdr_unsigned(NFSV4OP_PUTFH);
   2452  1.1  dholland 	}
   2453  1.1  dholland 	(void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh,
   2454  1.1  dholland 		VTONFS(dvp)->n_fhp->nfh_len, 0);
   2455  1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
   2456  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2457  1.1  dholland 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
   2458  1.1  dholland 		NFSWCCATTR_ATTRBIT(&attrbits);
   2459  1.1  dholland 		(void) nfsrv_putattrbit(nd, &attrbits);
   2460  1.1  dholland 		nd->nd_flag |= ND_V4WCCATTR;
   2461  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2462  1.1  dholland 		*tl = txdr_unsigned(NFSV4OP_LINK);
   2463  1.1  dholland 	}
   2464  1.1  dholland 	(void) nfsm_strtom(nd, name, namelen);
   2465  1.1  dholland 	error = nfscl_request(nd, vp, p, cred, dstuff);
   2466  1.1  dholland 	if (error)
   2467  1.1  dholland 		return (error);
   2468  1.1  dholland 	if (nd->nd_flag & ND_NFSV3) {
   2469  1.1  dholland 		error = nfscl_postop_attr(nd, nap, attrflagp, dstuff);
   2470  1.1  dholland 		if (!error)
   2471  1.1  dholland 			error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
   2472  1.1  dholland 			    NULL, dstuff);
   2473  1.1  dholland 	} else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
   2474  1.1  dholland 		/*
   2475  1.1  dholland 		 * First, parse out the PutFH and Getattr result.
   2476  1.1  dholland 		 */
   2477  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2478  1.1  dholland 		if (!(*(tl + 1)))
   2479  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2480  1.1  dholland 		if (*(tl + 1))
   2481  1.1  dholland 			nd->nd_flag |= ND_NOMOREDATA;
   2482  1.1  dholland 		/*
   2483  1.1  dholland 		 * Get the pre-op attributes.
   2484  1.1  dholland 		 */
   2485  1.1  dholland 		error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
   2486  1.1  dholland 	}
   2487  1.1  dholland 	if (nd->nd_repstat && !error)
   2488  1.1  dholland 		error = nd->nd_repstat;
   2489  1.1  dholland nfsmout:
   2490  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   2491  1.1  dholland 	return (error);
   2492  1.1  dholland }
   2493  1.1  dholland 
   2494  1.1  dholland /*
   2495  1.1  dholland  * nfs symbolic link create rpc
   2496  1.1  dholland  */
   2497  1.1  dholland APPLESTATIC int
   2498  1.1  dholland nfsrpc_symlink(vnode_t dvp, char *name, int namelen, char *target,
   2499  1.1  dholland     struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
   2500  1.1  dholland     struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
   2501  1.1  dholland     int *dattrflagp, void *dstuff)
   2502  1.1  dholland {
   2503  1.1  dholland 	u_int32_t *tl;
   2504  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   2505  1.1  dholland 	struct nfsmount *nmp;
   2506  1.1  dholland 	int slen, error = 0;
   2507  1.1  dholland 
   2508  1.1  dholland 	*nfhpp = NULL;
   2509  1.1  dholland 	*attrflagp = 0;
   2510  1.1  dholland 	*dattrflagp = 0;
   2511  1.1  dholland 	nmp = VFSTONFS(vnode_mount(dvp));
   2512  1.1  dholland 	slen = strlen(target);
   2513  1.1  dholland 	if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN)
   2514  1.1  dholland 		return (ENAMETOOLONG);
   2515  1.1  dholland 	NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp);
   2516  1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
   2517  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2518  1.1  dholland 		*tl = txdr_unsigned(NFLNK);
   2519  1.1  dholland 		(void) nfsm_strtom(nd, target, slen);
   2520  1.1  dholland 	}
   2521  1.1  dholland 	(void) nfsm_strtom(nd, name, namelen);
   2522  1.1  dholland 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
   2523  1.1  dholland 		nfscl_fillsattr(nd, vap, dvp, 0, 0);
   2524  1.1  dholland 	if (!(nd->nd_flag & ND_NFSV4))
   2525  1.1  dholland 		(void) nfsm_strtom(nd, target, slen);
   2526  1.1  dholland 	if (nd->nd_flag & ND_NFSV2)
   2527  1.1  dholland 		nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
   2528  1.1  dholland 	error = nfscl_request(nd, dvp, p, cred, dstuff);
   2529  1.1  dholland 	if (error)
   2530  1.1  dholland 		return (error);
   2531  1.1  dholland 	if (nd->nd_flag & ND_NFSV4)
   2532  1.1  dholland 		error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
   2533  1.1  dholland 	if ((nd->nd_flag & ND_NFSV3) && !error) {
   2534  1.1  dholland 		if (!nd->nd_repstat)
   2535  1.1  dholland 			error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
   2536  1.1  dholland 		if (!error)
   2537  1.1  dholland 			error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
   2538  1.1  dholland 			    NULL, dstuff);
   2539  1.1  dholland 	}
   2540  1.1  dholland 	if (nd->nd_repstat && !error)
   2541  1.1  dholland 		error = nd->nd_repstat;
   2542  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   2543  1.1  dholland 	/*
   2544  1.1  dholland 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
   2545  1.2  pgoyette 	 * Only do this if vfs.nfs.ignore_eexist is set.
   2546  1.2  pgoyette 	 * Never do this for NFSv4.1 or later minor versions, since sessions
   2547  1.2  pgoyette 	 * should guarantee "exactly once" RPC semantics.
   2548  1.1  dholland 	 */
   2549  1.2  pgoyette 	if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
   2550  1.2  pgoyette 	    nmp->nm_minorvers == 0))
   2551  1.1  dholland 		error = 0;
   2552  1.1  dholland 	return (error);
   2553  1.1  dholland }
   2554  1.1  dholland 
   2555  1.1  dholland /*
   2556  1.1  dholland  * nfs make dir rpc
   2557  1.1  dholland  */
   2558  1.1  dholland APPLESTATIC int
   2559  1.1  dholland nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap,
   2560  1.1  dholland     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
   2561  1.1  dholland     struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
   2562  1.1  dholland     int *dattrflagp, void *dstuff)
   2563  1.1  dholland {
   2564  1.1  dholland 	u_int32_t *tl;
   2565  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   2566  1.1  dholland 	nfsattrbit_t attrbits;
   2567  1.1  dholland 	int error = 0;
   2568  1.2  pgoyette 	struct nfsfh *fhp;
   2569  1.2  pgoyette 	struct nfsmount *nmp;
   2570  1.1  dholland 
   2571  1.1  dholland 	*nfhpp = NULL;
   2572  1.1  dholland 	*attrflagp = 0;
   2573  1.1  dholland 	*dattrflagp = 0;
   2574  1.2  pgoyette 	nmp = VFSTONFS(vnode_mount(dvp));
   2575  1.2  pgoyette 	fhp = VTONFS(dvp)->n_fhp;
   2576  1.1  dholland 	if (namelen > NFS_MAXNAMLEN)
   2577  1.1  dholland 		return (ENAMETOOLONG);
   2578  1.1  dholland 	NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp);
   2579  1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
   2580  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2581  1.1  dholland 		*tl = txdr_unsigned(NFDIR);
   2582  1.1  dholland 	}
   2583  1.1  dholland 	(void) nfsm_strtom(nd, name, namelen);
   2584  1.1  dholland 	nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
   2585  1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
   2586  1.1  dholland 		NFSGETATTR_ATTRBIT(&attrbits);
   2587  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2588  1.1  dholland 		*tl++ = txdr_unsigned(NFSV4OP_GETFH);
   2589  1.1  dholland 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
   2590  1.1  dholland 		(void) nfsrv_putattrbit(nd, &attrbits);
   2591  1.2  pgoyette 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2592  1.2  pgoyette 		*tl = txdr_unsigned(NFSV4OP_PUTFH);
   2593  1.2  pgoyette 		(void) nfsm_fhtom(nd, fhp->nfh_fh, fhp->nfh_len, 0);
   2594  1.2  pgoyette 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2595  1.2  pgoyette 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
   2596  1.2  pgoyette 		(void) nfsrv_putattrbit(nd, &attrbits);
   2597  1.1  dholland 	}
   2598  1.1  dholland 	error = nfscl_request(nd, dvp, p, cred, dstuff);
   2599  1.1  dholland 	if (error)
   2600  1.1  dholland 		return (error);
   2601  1.1  dholland 	if (nd->nd_flag & ND_NFSV4)
   2602  1.1  dholland 		error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
   2603  1.1  dholland 	if (!nd->nd_repstat && !error) {
   2604  1.1  dholland 		if (nd->nd_flag & ND_NFSV4) {
   2605  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
   2606  1.1  dholland 			error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
   2607  1.1  dholland 		}
   2608  1.1  dholland 		if (!error)
   2609  1.1  dholland 			error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
   2610  1.2  pgoyette 		if (error == 0 && (nd->nd_flag & ND_NFSV4) != 0) {
   2611  1.2  pgoyette 			/* Get rid of the PutFH and Getattr status values. */
   2612  1.2  pgoyette 			NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
   2613  1.2  pgoyette 			/* Load the directory attributes. */
   2614  1.2  pgoyette 			error = nfsm_loadattr(nd, dnap);
   2615  1.2  pgoyette 			if (error == 0)
   2616  1.2  pgoyette 				*dattrflagp = 1;
   2617  1.2  pgoyette 		}
   2618  1.1  dholland 	}
   2619  1.1  dholland 	if ((nd->nd_flag & ND_NFSV3) && !error)
   2620  1.1  dholland 		error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
   2621  1.1  dholland 	if (nd->nd_repstat && !error)
   2622  1.1  dholland 		error = nd->nd_repstat;
   2623  1.1  dholland nfsmout:
   2624  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   2625  1.1  dholland 	/*
   2626  1.2  pgoyette 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
   2627  1.2  pgoyette 	 * Only do this if vfs.nfs.ignore_eexist is set.
   2628  1.2  pgoyette 	 * Never do this for NFSv4.1 or later minor versions, since sessions
   2629  1.2  pgoyette 	 * should guarantee "exactly once" RPC semantics.
   2630  1.1  dholland 	 */
   2631  1.2  pgoyette 	if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
   2632  1.2  pgoyette 	    nmp->nm_minorvers == 0))
   2633  1.1  dholland 		error = 0;
   2634  1.1  dholland 	return (error);
   2635  1.1  dholland }
   2636  1.1  dholland 
   2637  1.1  dholland /*
   2638  1.1  dholland  * nfs remove directory call
   2639  1.1  dholland  */
   2640  1.1  dholland APPLESTATIC int
   2641  1.1  dholland nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred,
   2642  1.1  dholland     NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, void *dstuff)
   2643  1.1  dholland {
   2644  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   2645  1.1  dholland 	int error = 0;
   2646  1.1  dholland 
   2647  1.1  dholland 	*dattrflagp = 0;
   2648  1.1  dholland 	if (namelen > NFS_MAXNAMLEN)
   2649  1.1  dholland 		return (ENAMETOOLONG);
   2650  1.1  dholland 	NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp);
   2651  1.1  dholland 	(void) nfsm_strtom(nd, name, namelen);
   2652  1.1  dholland 	error = nfscl_request(nd, dvp, p, cred, dstuff);
   2653  1.1  dholland 	if (error)
   2654  1.1  dholland 		return (error);
   2655  1.1  dholland 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
   2656  1.1  dholland 		error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
   2657  1.1  dholland 	if (nd->nd_repstat && !error)
   2658  1.1  dholland 		error = nd->nd_repstat;
   2659  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   2660  1.1  dholland 	/*
   2661  1.1  dholland 	 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
   2662  1.1  dholland 	 */
   2663  1.1  dholland 	if (error == ENOENT)
   2664  1.1  dholland 		error = 0;
   2665  1.1  dholland 	return (error);
   2666  1.1  dholland }
   2667  1.1  dholland 
   2668  1.1  dholland /*
   2669  1.1  dholland  * Readdir rpc.
   2670  1.1  dholland  * Always returns with either uio_resid unchanged, if you are at the
   2671  1.1  dholland  * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks
   2672  1.1  dholland  * filled in.
   2673  1.1  dholland  * I felt this would allow caching of directory blocks more easily
   2674  1.1  dholland  * than returning a pertially filled block.
   2675  1.1  dholland  * Directory offset cookies:
   2676  1.1  dholland  * Oh my, what to do with them...
   2677  1.1  dholland  * I can think of three ways to deal with them:
   2678  1.1  dholland  * 1 - have the layer above these RPCs maintain a map between logical
   2679  1.1  dholland  *     directory byte offsets and the NFS directory offset cookies
   2680  1.1  dholland  * 2 - pass the opaque directory offset cookies up into userland
   2681  1.1  dholland  *     and let the libc functions deal with them, via the system call
   2682  1.1  dholland  * 3 - return them to userland in the "struct dirent", so future versions
   2683  1.2  pgoyette  *     of libc can use them and do whatever is necessary to make things work
   2684  1.1  dholland  *     above these rpc calls, in the meantime
   2685  1.1  dholland  * For now, I do #3 by "hiding" the directory offset cookies after the
   2686  1.1  dholland  * d_name field in struct dirent. This is space inside d_reclen that
   2687  1.1  dholland  * will be ignored by anything that doesn't know about them.
   2688  1.1  dholland  * The directory offset cookies are filled in as the last 8 bytes of
   2689  1.1  dholland  * each directory entry, after d_name. Someday, the userland libc
   2690  1.1  dholland  * functions may be able to use these. In the meantime, it satisfies
   2691  1.1  dholland  * OpenBSD's requirements for cookies being returned.
   2692  1.1  dholland  * If expects the directory offset cookie for the read to be in uio_offset
   2693  1.1  dholland  * and returns the one for the next entry after this directory block in
   2694  1.1  dholland  * there, as well.
   2695  1.1  dholland  */
   2696  1.1  dholland APPLESTATIC int
   2697  1.1  dholland nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
   2698  1.1  dholland     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
   2699  1.1  dholland     int *eofp, void *stuff)
   2700  1.1  dholland {
   2701  1.1  dholland 	int len, left;
   2702  1.1  dholland 	struct dirent *dp = NULL;
   2703  1.1  dholland 	u_int32_t *tl;
   2704  1.1  dholland 	nfsquad_t cookie, ncookie;
   2705  1.1  dholland 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
   2706  1.1  dholland 	struct nfsnode *dnp = VTONFS(vp);
   2707  1.1  dholland 	struct nfsvattr nfsva;
   2708  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   2709  1.1  dholland 	int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
   2710  1.1  dholland 	int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0;
   2711  1.1  dholland 	long dotfileid, dotdotfileid = 0;
   2712  1.1  dholland 	u_int32_t fakefileno = 0xffffffff, rderr;
   2713  1.1  dholland 	char *cp;
   2714  1.1  dholland 	nfsattrbit_t attrbits, dattrbits;
   2715  1.1  dholland 	u_int32_t *tl2 = NULL;
   2716  1.1  dholland 	size_t tresid;
   2717  1.1  dholland 
   2718  1.1  dholland 	KASSERT(uiop->uio_iovcnt == 1 &&
   2719  1.1  dholland 	    (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
   2720  1.1  dholland 	    ("nfs readdirrpc bad uio"));
   2721  1.1  dholland 
   2722  1.1  dholland 	/*
   2723  1.1  dholland 	 * There is no point in reading a lot more than uio_resid, however
   2724  1.1  dholland 	 * adding one additional DIRBLKSIZ makes sense. Since uio_resid
   2725  1.1  dholland 	 * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this
   2726  1.1  dholland 	 * will never make readsize > nm_readdirsize.
   2727  1.1  dholland 	 */
   2728  1.1  dholland 	readsize = nmp->nm_readdirsize;
   2729  1.1  dholland 	if (readsize > uio_uio_resid(uiop))
   2730  1.1  dholland 		readsize = uio_uio_resid(uiop) + DIRBLKSIZ;
   2731  1.1  dholland 
   2732  1.1  dholland 	*attrflagp = 0;
   2733  1.1  dholland 	if (eofp)
   2734  1.1  dholland 		*eofp = 0;
   2735  1.1  dholland 	tresid = uio_uio_resid(uiop);
   2736  1.1  dholland 	cookie.lval[0] = cookiep->nfsuquad[0];
   2737  1.1  dholland 	cookie.lval[1] = cookiep->nfsuquad[1];
   2738  1.1  dholland 	nd->nd_mrep = NULL;
   2739  1.1  dholland 
   2740  1.1  dholland 	/*
   2741  1.1  dholland 	 * For NFSv4, first create the "." and ".." entries.
   2742  1.1  dholland 	 */
   2743  1.1  dholland 	if (NFSHASNFSV4(nmp)) {
   2744  1.1  dholland 		reqsize = 6 * NFSX_UNSIGNED;
   2745  1.1  dholland 		NFSGETATTR_ATTRBIT(&dattrbits);
   2746  1.1  dholland 		NFSZERO_ATTRBIT(&attrbits);
   2747  1.1  dholland 		NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
   2748  1.1  dholland 		NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE);
   2749  1.1  dholland 		if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
   2750  1.1  dholland 		    NFSATTRBIT_MOUNTEDONFILEID)) {
   2751  1.1  dholland 			NFSSETBIT_ATTRBIT(&attrbits,
   2752  1.1  dholland 			    NFSATTRBIT_MOUNTEDONFILEID);
   2753  1.1  dholland 			gotmnton = 1;
   2754  1.1  dholland 		} else {
   2755  1.1  dholland 			/*
   2756  1.1  dholland 			 * Must fake it. Use the fileno, except when the
   2757  1.1  dholland 			 * fsid is != to that of the directory. For that
   2758  1.1  dholland 			 * case, generate a fake fileno that is not the same.
   2759  1.1  dholland 			 */
   2760  1.1  dholland 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
   2761  1.1  dholland 			gotmnton = 0;
   2762  1.1  dholland 		}
   2763  1.1  dholland 
   2764  1.1  dholland 		/*
   2765  1.1  dholland 		 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
   2766  1.1  dholland 		 */
   2767  1.1  dholland 		if (uiop->uio_offset == 0) {
   2768  1.1  dholland 			NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
   2769  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2770  1.1  dholland 			*tl++ = txdr_unsigned(NFSV4OP_GETFH);
   2771  1.1  dholland 			*tl = txdr_unsigned(NFSV4OP_GETATTR);
   2772  1.1  dholland 			(void) nfsrv_putattrbit(nd, &attrbits);
   2773  1.1  dholland 			error = nfscl_request(nd, vp, p, cred, stuff);
   2774  1.1  dholland 			if (error)
   2775  1.1  dholland 			    return (error);
   2776  1.2  pgoyette 			dotfileid = 0;	/* Fake out the compiler. */
   2777  1.2  pgoyette 			if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
   2778  1.2  pgoyette 			    error = nfsm_loadattr(nd, &nfsva);
   2779  1.2  pgoyette 			    if (error != 0)
   2780  1.2  pgoyette 				goto nfsmout;
   2781  1.2  pgoyette 			    dotfileid = nfsva.na_fileid;
   2782  1.2  pgoyette 			}
   2783  1.1  dholland 			if (nd->nd_repstat == 0) {
   2784  1.2  pgoyette 			    NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
   2785  1.2  pgoyette 			    len = fxdr_unsigned(int, *(tl + 4));
   2786  1.1  dholland 			    if (len > 0 && len <= NFSX_V4FHMAX)
   2787  1.1  dholland 				error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
   2788  1.1  dholland 			    else
   2789  1.1  dholland 				error = EPERM;
   2790  1.1  dholland 			    if (!error) {
   2791  1.1  dholland 				NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
   2792  1.1  dholland 				nfsva.na_mntonfileno = 0xffffffff;
   2793  1.1  dholland 				error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
   2794  1.1  dholland 				    NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
   2795  1.1  dholland 				    NULL, NULL, NULL, p, cred);
   2796  1.1  dholland 				if (error) {
   2797  1.1  dholland 				    dotdotfileid = dotfileid;
   2798  1.1  dholland 				} else if (gotmnton) {
   2799  1.1  dholland 				    if (nfsva.na_mntonfileno != 0xffffffff)
   2800  1.1  dholland 					dotdotfileid = nfsva.na_mntonfileno;
   2801  1.1  dholland 				    else
   2802  1.1  dholland 					dotdotfileid = nfsva.na_fileid;
   2803  1.1  dholland 				} else if (nfsva.na_filesid[0] ==
   2804  1.1  dholland 				    dnp->n_vattr.na_filesid[0] &&
   2805  1.1  dholland 				    nfsva.na_filesid[1] ==
   2806  1.1  dholland 				    dnp->n_vattr.na_filesid[1]) {
   2807  1.1  dholland 				    dotdotfileid = nfsva.na_fileid;
   2808  1.1  dholland 				} else {
   2809  1.1  dholland 				    do {
   2810  1.1  dholland 					fakefileno--;
   2811  1.1  dholland 				    } while (fakefileno ==
   2812  1.1  dholland 					nfsva.na_fileid);
   2813  1.1  dholland 				    dotdotfileid = fakefileno;
   2814  1.1  dholland 				}
   2815  1.1  dholland 			    }
   2816  1.1  dholland 			} else if (nd->nd_repstat == NFSERR_NOENT) {
   2817  1.1  dholland 			    /*
   2818  1.1  dholland 			     * Lookupp returns NFSERR_NOENT when we are
   2819  1.1  dholland 			     * at the root, so just use the current dir.
   2820  1.1  dholland 			     */
   2821  1.1  dholland 			    nd->nd_repstat = 0;
   2822  1.1  dholland 			    dotdotfileid = dotfileid;
   2823  1.1  dholland 			} else {
   2824  1.1  dholland 			    error = nd->nd_repstat;
   2825  1.1  dholland 			}
   2826  1.1  dholland 			mbuf_freem(nd->nd_mrep);
   2827  1.1  dholland 			if (error)
   2828  1.1  dholland 			    return (error);
   2829  1.1  dholland 			nd->nd_mrep = NULL;
   2830  1.1  dholland 			dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
   2831  1.1  dholland 			dp->d_type = DT_DIR;
   2832  1.1  dholland 			dp->d_fileno = dotfileid;
   2833  1.1  dholland 			dp->d_namlen = 1;
   2834  1.1  dholland 			dp->d_name[0] = '.';
   2835  1.1  dholland 			dp->d_name[1] = '\0';
   2836  1.1  dholland 			dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
   2837  1.1  dholland 			/*
   2838  1.1  dholland 			 * Just make these offset cookie 0.
   2839  1.1  dholland 			 */
   2840  1.1  dholland 			tl = (u_int32_t *)&dp->d_name[4];
   2841  1.1  dholland 			*tl++ = 0;
   2842  1.1  dholland 			*tl = 0;
   2843  1.1  dholland 			blksiz += dp->d_reclen;
   2844  1.1  dholland 			uio_uio_resid_add(uiop, -(dp->d_reclen));
   2845  1.1  dholland 			uiop->uio_offset += dp->d_reclen;
   2846  1.1  dholland 			uio_iov_base_add(uiop, dp->d_reclen);
   2847  1.1  dholland 			uio_iov_len_add(uiop, -(dp->d_reclen));
   2848  1.1  dholland 			dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
   2849  1.1  dholland 			dp->d_type = DT_DIR;
   2850  1.1  dholland 			dp->d_fileno = dotdotfileid;
   2851  1.1  dholland 			dp->d_namlen = 2;
   2852  1.1  dholland 			dp->d_name[0] = '.';
   2853  1.1  dholland 			dp->d_name[1] = '.';
   2854  1.1  dholland 			dp->d_name[2] = '\0';
   2855  1.1  dholland 			dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
   2856  1.1  dholland 			/*
   2857  1.1  dholland 			 * Just make these offset cookie 0.
   2858  1.1  dholland 			 */
   2859  1.1  dholland 			tl = (u_int32_t *)&dp->d_name[4];
   2860  1.1  dholland 			*tl++ = 0;
   2861  1.1  dholland 			*tl = 0;
   2862  1.1  dholland 			blksiz += dp->d_reclen;
   2863  1.1  dholland 			uio_uio_resid_add(uiop, -(dp->d_reclen));
   2864  1.1  dholland 			uiop->uio_offset += dp->d_reclen;
   2865  1.1  dholland 			uio_iov_base_add(uiop, dp->d_reclen);
   2866  1.1  dholland 			uio_iov_len_add(uiop, -(dp->d_reclen));
   2867  1.1  dholland 		}
   2868  1.1  dholland 		NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR);
   2869  1.1  dholland 	} else {
   2870  1.1  dholland 		reqsize = 5 * NFSX_UNSIGNED;
   2871  1.1  dholland 	}
   2872  1.1  dholland 
   2873  1.1  dholland 
   2874  1.1  dholland 	/*
   2875  1.1  dholland 	 * Loop around doing readdir rpc's of size readsize.
   2876  1.1  dholland 	 * The stopping criteria is EOF or buffer full.
   2877  1.1  dholland 	 */
   2878  1.1  dholland 	while (more_dirs && bigenough) {
   2879  1.1  dholland 		*attrflagp = 0;
   2880  1.1  dholland 		NFSCL_REQSTART(nd, NFSPROC_READDIR, vp);
   2881  1.1  dholland 		if (nd->nd_flag & ND_NFSV2) {
   2882  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2883  1.1  dholland 			*tl++ = cookie.lval[1];
   2884  1.1  dholland 			*tl = txdr_unsigned(readsize);
   2885  1.1  dholland 		} else {
   2886  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, reqsize);
   2887  1.1  dholland 			*tl++ = cookie.lval[0];
   2888  1.1  dholland 			*tl++ = cookie.lval[1];
   2889  1.1  dholland 			if (cookie.qval == 0) {
   2890  1.1  dholland 				*tl++ = 0;
   2891  1.1  dholland 				*tl++ = 0;
   2892  1.1  dholland 			} else {
   2893  1.1  dholland 				NFSLOCKNODE(dnp);
   2894  1.1  dholland 				*tl++ = dnp->n_cookieverf.nfsuquad[0];
   2895  1.1  dholland 				*tl++ = dnp->n_cookieverf.nfsuquad[1];
   2896  1.1  dholland 				NFSUNLOCKNODE(dnp);
   2897  1.1  dholland 			}
   2898  1.1  dholland 			if (nd->nd_flag & ND_NFSV4) {
   2899  1.1  dholland 				*tl++ = txdr_unsigned(readsize);
   2900  1.1  dholland 				*tl = txdr_unsigned(readsize);
   2901  1.1  dholland 				(void) nfsrv_putattrbit(nd, &attrbits);
   2902  1.1  dholland 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2903  1.1  dholland 				*tl = txdr_unsigned(NFSV4OP_GETATTR);
   2904  1.1  dholland 				(void) nfsrv_putattrbit(nd, &dattrbits);
   2905  1.1  dholland 			} else {
   2906  1.1  dholland 				*tl = txdr_unsigned(readsize);
   2907  1.1  dholland 			}
   2908  1.1  dholland 		}
   2909  1.1  dholland 		error = nfscl_request(nd, vp, p, cred, stuff);
   2910  1.1  dholland 		if (error)
   2911  1.1  dholland 			return (error);
   2912  1.1  dholland 		if (!(nd->nd_flag & ND_NFSV2)) {
   2913  1.1  dholland 			if (nd->nd_flag & ND_NFSV3)
   2914  1.1  dholland 				error = nfscl_postop_attr(nd, nap, attrflagp,
   2915  1.1  dholland 				    stuff);
   2916  1.1  dholland 			if (!nd->nd_repstat && !error) {
   2917  1.1  dholland 				NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
   2918  1.1  dholland 				NFSLOCKNODE(dnp);
   2919  1.1  dholland 				dnp->n_cookieverf.nfsuquad[0] = *tl++;
   2920  1.1  dholland 				dnp->n_cookieverf.nfsuquad[1] = *tl;
   2921  1.1  dholland 				NFSUNLOCKNODE(dnp);
   2922  1.1  dholland 			}
   2923  1.1  dholland 		}
   2924  1.1  dholland 		if (nd->nd_repstat || error) {
   2925  1.1  dholland 			if (!error)
   2926  1.1  dholland 				error = nd->nd_repstat;
   2927  1.1  dholland 			goto nfsmout;
   2928  1.1  dholland 		}
   2929  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2930  1.1  dholland 		more_dirs = fxdr_unsigned(int, *tl);
   2931  1.1  dholland 		if (!more_dirs)
   2932  1.1  dholland 			tryformoredirs = 0;
   2933  1.1  dholland 
   2934  1.2  pgoyette 		/* loop through the dir entries, doctoring them to 4bsd form */
   2935  1.1  dholland 		while (more_dirs && bigenough) {
   2936  1.1  dholland 			if (nd->nd_flag & ND_NFSV4) {
   2937  1.1  dholland 				NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
   2938  1.1  dholland 				ncookie.lval[0] = *tl++;
   2939  1.1  dholland 				ncookie.lval[1] = *tl++;
   2940  1.1  dholland 				len = fxdr_unsigned(int, *tl);
   2941  1.1  dholland 			} else if (nd->nd_flag & ND_NFSV3) {
   2942  1.1  dholland 				NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
   2943  1.1  dholland 				nfsva.na_fileid = fxdr_hyper(tl);
   2944  1.1  dholland 				tl += 2;
   2945  1.1  dholland 				len = fxdr_unsigned(int, *tl);
   2946  1.1  dholland 			} else {
   2947  1.1  dholland 				NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
   2948  1.1  dholland 				nfsva.na_fileid =
   2949  1.1  dholland 				    fxdr_unsigned(long, *tl++);
   2950  1.1  dholland 				len = fxdr_unsigned(int, *tl);
   2951  1.1  dholland 			}
   2952  1.1  dholland 			if (len <= 0 || len > NFS_MAXNAMLEN) {
   2953  1.1  dholland 				error = EBADRPC;
   2954  1.1  dholland 				goto nfsmout;
   2955  1.1  dholland 			}
   2956  1.1  dholland 			tlen = NFSM_RNDUP(len);
   2957  1.1  dholland 			if (tlen == len)
   2958  1.1  dholland 				tlen += 4;  /* To ensure null termination */
   2959  1.1  dholland 			left = DIRBLKSIZ - blksiz;
   2960  1.1  dholland 			if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > left) {
   2961  1.1  dholland 				dp->d_reclen += left;
   2962  1.1  dholland 				uio_iov_base_add(uiop, left);
   2963  1.1  dholland 				uio_iov_len_add(uiop, -(left));
   2964  1.1  dholland 				uio_uio_resid_add(uiop, -(left));
   2965  1.1  dholland 				uiop->uio_offset += left;
   2966  1.1  dholland 				blksiz = 0;
   2967  1.1  dholland 			}
   2968  1.1  dholland 			if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop))
   2969  1.1  dholland 				bigenough = 0;
   2970  1.1  dholland 			if (bigenough) {
   2971  1.1  dholland 				dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
   2972  1.1  dholland 				dp->d_namlen = len;
   2973  1.1  dholland 				dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER;
   2974  1.1  dholland 				dp->d_type = DT_UNKNOWN;
   2975  1.1  dholland 				blksiz += dp->d_reclen;
   2976  1.1  dholland 				if (blksiz == DIRBLKSIZ)
   2977  1.1  dholland 					blksiz = 0;
   2978  1.1  dholland 				uio_uio_resid_add(uiop, -(DIRHDSIZ));
   2979  1.1  dholland 				uiop->uio_offset += DIRHDSIZ;
   2980  1.1  dholland 				uio_iov_base_add(uiop, DIRHDSIZ);
   2981  1.1  dholland 				uio_iov_len_add(uiop, -(DIRHDSIZ));
   2982  1.1  dholland 				error = nfsm_mbufuio(nd, uiop, len);
   2983  1.1  dholland 				if (error)
   2984  1.1  dholland 					goto nfsmout;
   2985  1.1  dholland 				cp = CAST_DOWN(caddr_t, uio_iov_base(uiop));
   2986  1.1  dholland 				tlen -= len;
   2987  1.1  dholland 				*cp = '\0';	/* null terminate */
   2988  1.1  dholland 				cp += tlen;	/* points to cookie storage */
   2989  1.1  dholland 				tl2 = (u_int32_t *)cp;
   2990  1.1  dholland 				uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
   2991  1.1  dholland 				uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
   2992  1.1  dholland 				uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
   2993  1.1  dholland 				uiop->uio_offset += (tlen + NFSX_HYPER);
   2994  1.1  dholland 			} else {
   2995  1.1  dholland 				error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
   2996  1.1  dholland 				if (error)
   2997  1.1  dholland 					goto nfsmout;
   2998  1.1  dholland 			}
   2999  1.1  dholland 			if (nd->nd_flag & ND_NFSV4) {
   3000  1.1  dholland 				rderr = 0;
   3001  1.1  dholland 				nfsva.na_mntonfileno = 0xffffffff;
   3002  1.1  dholland 				error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
   3003  1.1  dholland 				    NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
   3004  1.1  dholland 				    NULL, NULL, &rderr, p, cred);
   3005  1.1  dholland 				if (error)
   3006  1.1  dholland 					goto nfsmout;
   3007  1.1  dholland 				NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3008  1.1  dholland 			} else if (nd->nd_flag & ND_NFSV3) {
   3009  1.1  dholland 				NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
   3010  1.1  dholland 				ncookie.lval[0] = *tl++;
   3011  1.1  dholland 				ncookie.lval[1] = *tl++;
   3012  1.1  dholland 			} else {
   3013  1.1  dholland 				NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
   3014  1.1  dholland 				ncookie.lval[0] = 0;
   3015  1.1  dholland 				ncookie.lval[1] = *tl++;
   3016  1.1  dholland 			}
   3017  1.1  dholland 			if (bigenough) {
   3018  1.1  dholland 			    if (nd->nd_flag & ND_NFSV4) {
   3019  1.1  dholland 				if (rderr) {
   3020  1.1  dholland 				    dp->d_fileno = 0;
   3021  1.1  dholland 				} else {
   3022  1.1  dholland 				    if (gotmnton) {
   3023  1.1  dholland 					if (nfsva.na_mntonfileno != 0xffffffff)
   3024  1.1  dholland 					    dp->d_fileno = nfsva.na_mntonfileno;
   3025  1.1  dholland 					else
   3026  1.1  dholland 					    dp->d_fileno = nfsva.na_fileid;
   3027  1.1  dholland 				    } else if (nfsva.na_filesid[0] ==
   3028  1.1  dholland 					dnp->n_vattr.na_filesid[0] &&
   3029  1.1  dholland 					nfsva.na_filesid[1] ==
   3030  1.1  dholland 					dnp->n_vattr.na_filesid[1]) {
   3031  1.1  dholland 					dp->d_fileno = nfsva.na_fileid;
   3032  1.1  dholland 				    } else {
   3033  1.1  dholland 					do {
   3034  1.1  dholland 					    fakefileno--;
   3035  1.1  dholland 					} while (fakefileno ==
   3036  1.1  dholland 					    nfsva.na_fileid);
   3037  1.1  dholland 					dp->d_fileno = fakefileno;
   3038  1.1  dholland 				    }
   3039  1.1  dholland 				    dp->d_type = vtonfs_dtype(nfsva.na_type);
   3040  1.1  dholland 				}
   3041  1.1  dholland 			    } else {
   3042  1.1  dholland 				dp->d_fileno = nfsva.na_fileid;
   3043  1.1  dholland 			    }
   3044  1.1  dholland 			    *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
   3045  1.1  dholland 				ncookie.lval[0];
   3046  1.1  dholland 			    *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
   3047  1.1  dholland 				ncookie.lval[1];
   3048  1.1  dholland 			}
   3049  1.1  dholland 			more_dirs = fxdr_unsigned(int, *tl);
   3050  1.1  dholland 		}
   3051  1.1  dholland 		/*
   3052  1.1  dholland 		 * If at end of rpc data, get the eof boolean
   3053  1.1  dholland 		 */
   3054  1.1  dholland 		if (!more_dirs) {
   3055  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3056  1.1  dholland 			eof = fxdr_unsigned(int, *tl);
   3057  1.1  dholland 			if (tryformoredirs)
   3058  1.1  dholland 				more_dirs = !eof;
   3059  1.1  dholland 			if (nd->nd_flag & ND_NFSV4) {
   3060  1.1  dholland 				error = nfscl_postop_attr(nd, nap, attrflagp,
   3061  1.1  dholland 				    stuff);
   3062  1.1  dholland 				if (error)
   3063  1.1  dholland 					goto nfsmout;
   3064  1.1  dholland 			}
   3065  1.1  dholland 		}
   3066  1.1  dholland 		mbuf_freem(nd->nd_mrep);
   3067  1.1  dholland 		nd->nd_mrep = NULL;
   3068  1.1  dholland 	}
   3069  1.1  dholland 	/*
   3070  1.1  dholland 	 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
   3071  1.1  dholland 	 * by increasing d_reclen for the last record.
   3072  1.1  dholland 	 */
   3073  1.1  dholland 	if (blksiz > 0) {
   3074  1.1  dholland 		left = DIRBLKSIZ - blksiz;
   3075  1.1  dholland 		dp->d_reclen += left;
   3076  1.1  dholland 		uio_iov_base_add(uiop, left);
   3077  1.1  dholland 		uio_iov_len_add(uiop, -(left));
   3078  1.1  dholland 		uio_uio_resid_add(uiop, -(left));
   3079  1.1  dholland 		uiop->uio_offset += left;
   3080  1.1  dholland 	}
   3081  1.1  dholland 
   3082  1.1  dholland 	/*
   3083  1.1  dholland 	 * If returning no data, assume end of file.
   3084  1.1  dholland 	 * If not bigenough, return not end of file, since you aren't
   3085  1.1  dholland 	 *    returning all the data
   3086  1.1  dholland 	 * Otherwise, return the eof flag from the server.
   3087  1.1  dholland 	 */
   3088  1.1  dholland 	if (eofp) {
   3089  1.1  dholland 		if (tresid == ((size_t)(uio_uio_resid(uiop))))
   3090  1.1  dholland 			*eofp = 1;
   3091  1.1  dholland 		else if (!bigenough)
   3092  1.1  dholland 			*eofp = 0;
   3093  1.1  dholland 		else
   3094  1.1  dholland 			*eofp = eof;
   3095  1.1  dholland 	}
   3096  1.1  dholland 
   3097  1.1  dholland 	/*
   3098  1.1  dholland 	 * Add extra empty records to any remaining DIRBLKSIZ chunks.
   3099  1.1  dholland 	 */
   3100  1.1  dholland 	while (uio_uio_resid(uiop) > 0 && ((size_t)(uio_uio_resid(uiop))) != tresid) {
   3101  1.1  dholland 		dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
   3102  1.1  dholland 		dp->d_type = DT_UNKNOWN;
   3103  1.1  dholland 		dp->d_fileno = 0;
   3104  1.1  dholland 		dp->d_namlen = 0;
   3105  1.1  dholland 		dp->d_name[0] = '\0';
   3106  1.1  dholland 		tl = (u_int32_t *)&dp->d_name[4];
   3107  1.1  dholland 		*tl++ = cookie.lval[0];
   3108  1.1  dholland 		*tl = cookie.lval[1];
   3109  1.1  dholland 		dp->d_reclen = DIRBLKSIZ;
   3110  1.1  dholland 		uio_iov_base_add(uiop, DIRBLKSIZ);
   3111  1.1  dholland 		uio_iov_len_add(uiop, -(DIRBLKSIZ));
   3112  1.1  dholland 		uio_uio_resid_add(uiop, -(DIRBLKSIZ));
   3113  1.1  dholland 		uiop->uio_offset += DIRBLKSIZ;
   3114  1.1  dholland 	}
   3115  1.1  dholland 
   3116  1.1  dholland nfsmout:
   3117  1.1  dholland 	if (nd->nd_mrep != NULL)
   3118  1.1  dholland 		mbuf_freem(nd->nd_mrep);
   3119  1.1  dholland 	return (error);
   3120  1.1  dholland }
   3121  1.1  dholland 
   3122  1.1  dholland #ifndef APPLE
   3123  1.1  dholland /*
   3124  1.1  dholland  * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir().
   3125  1.1  dholland  * (Also used for NFS V4 when mount flag set.)
   3126  1.1  dholland  * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.)
   3127  1.1  dholland  */
   3128  1.1  dholland APPLESTATIC int
   3129  1.1  dholland nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
   3130  1.1  dholland     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
   3131  1.1  dholland     int *eofp, void *stuff)
   3132  1.1  dholland {
   3133  1.1  dholland 	int len, left;
   3134  1.1  dholland 	struct dirent *dp = NULL;
   3135  1.1  dholland 	u_int32_t *tl;
   3136  1.1  dholland 	vnode_t newvp = NULLVP;
   3137  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   3138  1.1  dholland 	struct nameidata nami, *ndp = &nami;
   3139  1.1  dholland 	struct componentname *cnp = &ndp->ni_cnd;
   3140  1.1  dholland 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
   3141  1.1  dholland 	struct nfsnode *dnp = VTONFS(vp), *np;
   3142  1.1  dholland 	struct nfsvattr nfsva;
   3143  1.1  dholland 	struct nfsfh *nfhp;
   3144  1.1  dholland 	nfsquad_t cookie, ncookie;
   3145  1.1  dholland 	int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
   3146  1.1  dholland 	int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0;
   3147  1.1  dholland 	int isdotdot = 0, unlocknewvp = 0;
   3148  1.1  dholland 	long dotfileid, dotdotfileid = 0, fileno = 0;
   3149  1.1  dholland 	char *cp;
   3150  1.1  dholland 	nfsattrbit_t attrbits, dattrbits;
   3151  1.1  dholland 	size_t tresid;
   3152  1.1  dholland 	u_int32_t *tl2 = NULL, fakefileno = 0xffffffff, rderr;
   3153  1.1  dholland 	struct timespec dctime;
   3154  1.1  dholland 
   3155  1.1  dholland 	KASSERT(uiop->uio_iovcnt == 1 &&
   3156  1.1  dholland 	    (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
   3157  1.1  dholland 	    ("nfs readdirplusrpc bad uio"));
   3158  1.1  dholland 	timespecclear(&dctime);
   3159  1.1  dholland 	*attrflagp = 0;
   3160  1.1  dholland 	if (eofp != NULL)
   3161  1.1  dholland 		*eofp = 0;
   3162  1.1  dholland 	ndp->ni_dvp = vp;
   3163  1.1  dholland 	nd->nd_mrep = NULL;
   3164  1.1  dholland 	cookie.lval[0] = cookiep->nfsuquad[0];
   3165  1.1  dholland 	cookie.lval[1] = cookiep->nfsuquad[1];
   3166  1.1  dholland 	tresid = uio_uio_resid(uiop);
   3167  1.1  dholland 
   3168  1.1  dholland 	/*
   3169  1.1  dholland 	 * For NFSv4, first create the "." and ".." entries.
   3170  1.1  dholland 	 */
   3171  1.1  dholland 	if (NFSHASNFSV4(nmp)) {
   3172  1.1  dholland 		NFSGETATTR_ATTRBIT(&dattrbits);
   3173  1.1  dholland 		NFSZERO_ATTRBIT(&attrbits);
   3174  1.1  dholland 		NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
   3175  1.1  dholland 		if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
   3176  1.1  dholland 		    NFSATTRBIT_MOUNTEDONFILEID)) {
   3177  1.1  dholland 			NFSSETBIT_ATTRBIT(&attrbits,
   3178  1.1  dholland 			    NFSATTRBIT_MOUNTEDONFILEID);
   3179  1.1  dholland 			gotmnton = 1;
   3180  1.1  dholland 		} else {
   3181  1.1  dholland 			/*
   3182  1.1  dholland 			 * Must fake it. Use the fileno, except when the
   3183  1.1  dholland 			 * fsid is != to that of the directory. For that
   3184  1.1  dholland 			 * case, generate a fake fileno that is not the same.
   3185  1.1  dholland 			 */
   3186  1.1  dholland 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
   3187  1.1  dholland 			gotmnton = 0;
   3188  1.1  dholland 		}
   3189  1.1  dholland 
   3190  1.1  dholland 		/*
   3191  1.1  dholland 		 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
   3192  1.1  dholland 		 */
   3193  1.1  dholland 		if (uiop->uio_offset == 0) {
   3194  1.1  dholland 			NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
   3195  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   3196  1.1  dholland 			*tl++ = txdr_unsigned(NFSV4OP_GETFH);
   3197  1.1  dholland 			*tl = txdr_unsigned(NFSV4OP_GETATTR);
   3198  1.1  dholland 			(void) nfsrv_putattrbit(nd, &attrbits);
   3199  1.1  dholland 			error = nfscl_request(nd, vp, p, cred, stuff);
   3200  1.1  dholland 			if (error)
   3201  1.1  dholland 			    return (error);
   3202  1.2  pgoyette 			dotfileid = 0;	/* Fake out the compiler. */
   3203  1.2  pgoyette 			if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
   3204  1.2  pgoyette 			    error = nfsm_loadattr(nd, &nfsva);
   3205  1.2  pgoyette 			    if (error != 0)
   3206  1.2  pgoyette 				goto nfsmout;
   3207  1.2  pgoyette 			    dctime = nfsva.na_ctime;
   3208  1.2  pgoyette 			    dotfileid = nfsva.na_fileid;
   3209  1.2  pgoyette 			}
   3210  1.1  dholland 			if (nd->nd_repstat == 0) {
   3211  1.2  pgoyette 			    NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
   3212  1.2  pgoyette 			    len = fxdr_unsigned(int, *(tl + 4));
   3213  1.1  dholland 			    if (len > 0 && len <= NFSX_V4FHMAX)
   3214  1.1  dholland 				error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
   3215  1.1  dholland 			    else
   3216  1.1  dholland 				error = EPERM;
   3217  1.1  dholland 			    if (!error) {
   3218  1.1  dholland 				NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
   3219  1.1  dholland 				nfsva.na_mntonfileno = 0xffffffff;
   3220  1.1  dholland 				error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
   3221  1.1  dholland 				    NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
   3222  1.1  dholland 				    NULL, NULL, NULL, p, cred);
   3223  1.1  dholland 				if (error) {
   3224  1.1  dholland 				    dotdotfileid = dotfileid;
   3225  1.1  dholland 				} else if (gotmnton) {
   3226  1.1  dholland 				    if (nfsva.na_mntonfileno != 0xffffffff)
   3227  1.1  dholland 					dotdotfileid = nfsva.na_mntonfileno;
   3228  1.1  dholland 				    else
   3229  1.1  dholland 					dotdotfileid = nfsva.na_fileid;
   3230  1.1  dholland 				} else if (nfsva.na_filesid[0] ==
   3231  1.1  dholland 				    dnp->n_vattr.na_filesid[0] &&
   3232  1.1  dholland 				    nfsva.na_filesid[1] ==
   3233  1.1  dholland 				    dnp->n_vattr.na_filesid[1]) {
   3234  1.1  dholland 				    dotdotfileid = nfsva.na_fileid;
   3235  1.1  dholland 				} else {
   3236  1.1  dholland 				    do {
   3237  1.1  dholland 					fakefileno--;
   3238  1.1  dholland 				    } while (fakefileno ==
   3239  1.1  dholland 					nfsva.na_fileid);
   3240  1.1  dholland 				    dotdotfileid = fakefileno;
   3241  1.1  dholland 				}
   3242  1.1  dholland 			    }
   3243  1.1  dholland 			} else if (nd->nd_repstat == NFSERR_NOENT) {
   3244  1.1  dholland 			    /*
   3245  1.1  dholland 			     * Lookupp returns NFSERR_NOENT when we are
   3246  1.1  dholland 			     * at the root, so just use the current dir.
   3247  1.1  dholland 			     */
   3248  1.1  dholland 			    nd->nd_repstat = 0;
   3249  1.1  dholland 			    dotdotfileid = dotfileid;
   3250  1.1  dholland 			} else {
   3251  1.1  dholland 			    error = nd->nd_repstat;
   3252  1.1  dholland 			}
   3253  1.1  dholland 			mbuf_freem(nd->nd_mrep);
   3254  1.1  dholland 			if (error)
   3255  1.1  dholland 			    return (error);
   3256  1.1  dholland 			nd->nd_mrep = NULL;
   3257  1.1  dholland 			dp = (struct dirent *)uio_iov_base(uiop);
   3258  1.1  dholland 			dp->d_type = DT_DIR;
   3259  1.1  dholland 			dp->d_fileno = dotfileid;
   3260  1.1  dholland 			dp->d_namlen = 1;
   3261  1.1  dholland 			dp->d_name[0] = '.';
   3262  1.1  dholland 			dp->d_name[1] = '\0';
   3263  1.1  dholland 			dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
   3264  1.1  dholland 			/*
   3265  1.1  dholland 			 * Just make these offset cookie 0.
   3266  1.1  dholland 			 */
   3267  1.1  dholland 			tl = (u_int32_t *)&dp->d_name[4];
   3268  1.1  dholland 			*tl++ = 0;
   3269  1.1  dholland 			*tl = 0;
   3270  1.1  dholland 			blksiz += dp->d_reclen;
   3271  1.1  dholland 			uio_uio_resid_add(uiop, -(dp->d_reclen));
   3272  1.1  dholland 			uiop->uio_offset += dp->d_reclen;
   3273  1.1  dholland 			uio_iov_base_add(uiop, dp->d_reclen);
   3274  1.1  dholland 			uio_iov_len_add(uiop, -(dp->d_reclen));
   3275  1.1  dholland 			dp = (struct dirent *)uio_iov_base(uiop);
   3276  1.1  dholland 			dp->d_type = DT_DIR;
   3277  1.1  dholland 			dp->d_fileno = dotdotfileid;
   3278  1.1  dholland 			dp->d_namlen = 2;
   3279  1.1  dholland 			dp->d_name[0] = '.';
   3280  1.1  dholland 			dp->d_name[1] = '.';
   3281  1.1  dholland 			dp->d_name[2] = '\0';
   3282  1.1  dholland 			dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
   3283  1.1  dholland 			/*
   3284  1.1  dholland 			 * Just make these offset cookie 0.
   3285  1.1  dholland 			 */
   3286  1.1  dholland 			tl = (u_int32_t *)&dp->d_name[4];
   3287  1.1  dholland 			*tl++ = 0;
   3288  1.1  dholland 			*tl = 0;
   3289  1.1  dholland 			blksiz += dp->d_reclen;
   3290  1.1  dholland 			uio_uio_resid_add(uiop, -(dp->d_reclen));
   3291  1.1  dholland 			uiop->uio_offset += dp->d_reclen;
   3292  1.1  dholland 			uio_iov_base_add(uiop, dp->d_reclen);
   3293  1.1  dholland 			uio_iov_len_add(uiop, -(dp->d_reclen));
   3294  1.1  dholland 		}
   3295  1.1  dholland 		NFSREADDIRPLUS_ATTRBIT(&attrbits);
   3296  1.1  dholland 		if (gotmnton)
   3297  1.1  dholland 			NFSSETBIT_ATTRBIT(&attrbits,
   3298  1.1  dholland 			    NFSATTRBIT_MOUNTEDONFILEID);
   3299  1.1  dholland 	}
   3300  1.1  dholland 
   3301  1.1  dholland 	/*
   3302  1.1  dholland 	 * Loop around doing readdir rpc's of size nm_readdirsize.
   3303  1.1  dholland 	 * The stopping criteria is EOF or buffer full.
   3304  1.1  dholland 	 */
   3305  1.1  dholland 	while (more_dirs && bigenough) {
   3306  1.1  dholland 		*attrflagp = 0;
   3307  1.1  dholland 		NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp);
   3308  1.1  dholland  		NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
   3309  1.1  dholland 		*tl++ = cookie.lval[0];
   3310  1.1  dholland 		*tl++ = cookie.lval[1];
   3311  1.1  dholland 		if (cookie.qval == 0) {
   3312  1.1  dholland 			*tl++ = 0;
   3313  1.1  dholland 			*tl++ = 0;
   3314  1.1  dholland 		} else {
   3315  1.1  dholland 			NFSLOCKNODE(dnp);
   3316  1.1  dholland 			*tl++ = dnp->n_cookieverf.nfsuquad[0];
   3317  1.1  dholland 			*tl++ = dnp->n_cookieverf.nfsuquad[1];
   3318  1.1  dholland 			NFSUNLOCKNODE(dnp);
   3319  1.1  dholland 		}
   3320  1.1  dholland 		*tl++ = txdr_unsigned(nmp->nm_readdirsize);
   3321  1.1  dholland 		*tl = txdr_unsigned(nmp->nm_readdirsize);
   3322  1.1  dholland 		if (nd->nd_flag & ND_NFSV4) {
   3323  1.1  dholland 			(void) nfsrv_putattrbit(nd, &attrbits);
   3324  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   3325  1.1  dholland 			*tl = txdr_unsigned(NFSV4OP_GETATTR);
   3326  1.1  dholland 			(void) nfsrv_putattrbit(nd, &dattrbits);
   3327  1.1  dholland 		}
   3328  1.1  dholland 		error = nfscl_request(nd, vp, p, cred, stuff);
   3329  1.1  dholland 		if (error)
   3330  1.1  dholland 			return (error);
   3331  1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
   3332  1.1  dholland 			error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
   3333  1.1  dholland 		if (nd->nd_repstat || error) {
   3334  1.1  dholland 			if (!error)
   3335  1.1  dholland 				error = nd->nd_repstat;
   3336  1.1  dholland 			goto nfsmout;
   3337  1.1  dholland 		}
   3338  1.1  dholland 		if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0)
   3339  1.1  dholland 			dctime = nap->na_ctime;
   3340  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   3341  1.1  dholland 		NFSLOCKNODE(dnp);
   3342  1.1  dholland 		dnp->n_cookieverf.nfsuquad[0] = *tl++;
   3343  1.1  dholland 		dnp->n_cookieverf.nfsuquad[1] = *tl++;
   3344  1.1  dholland 		NFSUNLOCKNODE(dnp);
   3345  1.1  dholland 		more_dirs = fxdr_unsigned(int, *tl);
   3346  1.1  dholland 		if (!more_dirs)
   3347  1.1  dholland 			tryformoredirs = 0;
   3348  1.1  dholland 
   3349  1.2  pgoyette 		/* loop through the dir entries, doctoring them to 4bsd form */
   3350  1.1  dholland 		while (more_dirs && bigenough) {
   3351  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   3352  1.1  dholland 			if (nd->nd_flag & ND_NFSV4) {
   3353  1.1  dholland 				ncookie.lval[0] = *tl++;
   3354  1.1  dholland 				ncookie.lval[1] = *tl++;
   3355  1.1  dholland 			} else {
   3356  1.1  dholland 				fileno = fxdr_unsigned(long, *++tl);
   3357  1.1  dholland 				tl++;
   3358  1.1  dholland 			}
   3359  1.1  dholland 			len = fxdr_unsigned(int, *tl);
   3360  1.1  dholland 			if (len <= 0 || len > NFS_MAXNAMLEN) {
   3361  1.1  dholland 				error = EBADRPC;
   3362  1.1  dholland 				goto nfsmout;
   3363  1.1  dholland 			}
   3364  1.1  dholland 			tlen = NFSM_RNDUP(len);
   3365  1.1  dholland 			if (tlen == len)
   3366  1.1  dholland 				tlen += 4;  /* To ensure null termination */
   3367  1.1  dholland 			left = DIRBLKSIZ - blksiz;
   3368  1.1  dholland 			if ((tlen + DIRHDSIZ + NFSX_HYPER) > left) {
   3369  1.1  dholland 				dp->d_reclen += left;
   3370  1.1  dholland 				uio_iov_base_add(uiop, left);
   3371  1.1  dholland 				uio_iov_len_add(uiop, -(left));
   3372  1.1  dholland 				uio_uio_resid_add(uiop, -(left));
   3373  1.1  dholland 				uiop->uio_offset += left;
   3374  1.1  dholland 				blksiz = 0;
   3375  1.1  dholland 			}
   3376  1.1  dholland 			if ((tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop))
   3377  1.1  dholland 				bigenough = 0;
   3378  1.1  dholland 			if (bigenough) {
   3379  1.1  dholland 				dp = (struct dirent *)uio_iov_base(uiop);
   3380  1.1  dholland 				dp->d_namlen = len;
   3381  1.1  dholland 				dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER;
   3382  1.1  dholland 				dp->d_type = DT_UNKNOWN;
   3383  1.1  dholland 				blksiz += dp->d_reclen;
   3384  1.1  dholland 				if (blksiz == DIRBLKSIZ)
   3385  1.1  dholland 					blksiz = 0;
   3386  1.1  dholland 				uio_uio_resid_add(uiop, -(DIRHDSIZ));
   3387  1.1  dholland 				uiop->uio_offset += DIRHDSIZ;
   3388  1.1  dholland 				uio_iov_base_add(uiop, DIRHDSIZ);
   3389  1.1  dholland 				uio_iov_len_add(uiop, -(DIRHDSIZ));
   3390  1.1  dholland 				cnp->cn_nameptr = uio_iov_base(uiop);
   3391  1.1  dholland 				cnp->cn_namelen = len;
   3392  1.1  dholland 				NFSCNHASHZERO(cnp);
   3393  1.1  dholland 				error = nfsm_mbufuio(nd, uiop, len);
   3394  1.1  dholland 				if (error)
   3395  1.1  dholland 					goto nfsmout;
   3396  1.1  dholland 				cp = uio_iov_base(uiop);
   3397  1.1  dholland 				tlen -= len;
   3398  1.1  dholland 				*cp = '\0';
   3399  1.1  dholland 				cp += tlen;	/* points to cookie storage */
   3400  1.1  dholland 				tl2 = (u_int32_t *)cp;
   3401  1.1  dholland 				if (len == 2 && cnp->cn_nameptr[0] == '.' &&
   3402  1.1  dholland 				    cnp->cn_nameptr[1] == '.')
   3403  1.1  dholland 					isdotdot = 1;
   3404  1.1  dholland 				else
   3405  1.1  dholland 					isdotdot = 0;
   3406  1.1  dholland 				uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
   3407  1.1  dholland 				uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
   3408  1.1  dholland 				uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
   3409  1.1  dholland 				uiop->uio_offset += (tlen + NFSX_HYPER);
   3410  1.1  dholland 			} else {
   3411  1.1  dholland 				error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
   3412  1.1  dholland 				if (error)
   3413  1.1  dholland 					goto nfsmout;
   3414  1.1  dholland 			}
   3415  1.1  dholland 			nfhp = NULL;
   3416  1.1  dholland 			if (nd->nd_flag & ND_NFSV3) {
   3417  1.1  dholland 				NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
   3418  1.1  dholland 				ncookie.lval[0] = *tl++;
   3419  1.1  dholland 				ncookie.lval[1] = *tl++;
   3420  1.1  dholland 				attrflag = fxdr_unsigned(int, *tl);
   3421  1.1  dholland 				if (attrflag) {
   3422  1.1  dholland 				  error = nfsm_loadattr(nd, &nfsva);
   3423  1.1  dholland 				  if (error)
   3424  1.1  dholland 					goto nfsmout;
   3425  1.1  dholland 				}
   3426  1.1  dholland 				NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED);
   3427  1.1  dholland 				if (*tl) {
   3428  1.1  dholland 					error = nfsm_getfh(nd, &nfhp);
   3429  1.1  dholland 					if (error)
   3430  1.1  dholland 					    goto nfsmout;
   3431  1.1  dholland 				}
   3432  1.1  dholland 				if (!attrflag && nfhp != NULL) {
   3433  1.1  dholland 					FREE((caddr_t)nfhp, M_NFSFH);
   3434  1.1  dholland 					nfhp = NULL;
   3435  1.1  dholland 				}
   3436  1.1  dholland 			} else {
   3437  1.1  dholland 				rderr = 0;
   3438  1.1  dholland 				nfsva.na_mntonfileno = 0xffffffff;
   3439  1.1  dholland 				error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp,
   3440  1.1  dholland 				    NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
   3441  1.1  dholland 				    NULL, NULL, &rderr, p, cred);
   3442  1.1  dholland 				if (error)
   3443  1.1  dholland 					goto nfsmout;
   3444  1.1  dholland 			}
   3445  1.1  dholland 
   3446  1.1  dholland 			if (bigenough) {
   3447  1.1  dholland 			    if (nd->nd_flag & ND_NFSV4) {
   3448  1.1  dholland 				if (rderr) {
   3449  1.1  dholland 				    dp->d_fileno = 0;
   3450  1.1  dholland 				} else if (gotmnton) {
   3451  1.1  dholland 				    if (nfsva.na_mntonfileno != 0xffffffff)
   3452  1.1  dholland 					dp->d_fileno = nfsva.na_mntonfileno;
   3453  1.1  dholland 				    else
   3454  1.1  dholland 					dp->d_fileno = nfsva.na_fileid;
   3455  1.1  dholland 				} else if (nfsva.na_filesid[0] ==
   3456  1.1  dholland 				    dnp->n_vattr.na_filesid[0] &&
   3457  1.1  dholland 				    nfsva.na_filesid[1] ==
   3458  1.1  dholland 				    dnp->n_vattr.na_filesid[1]) {
   3459  1.1  dholland 				    dp->d_fileno = nfsva.na_fileid;
   3460  1.1  dholland 				} else {
   3461  1.1  dholland 				    do {
   3462  1.1  dholland 					fakefileno--;
   3463  1.1  dholland 				    } while (fakefileno ==
   3464  1.1  dholland 					nfsva.na_fileid);
   3465  1.1  dholland 				    dp->d_fileno = fakefileno;
   3466  1.1  dholland 				}
   3467  1.1  dholland 			    } else {
   3468  1.1  dholland 				dp->d_fileno = fileno;
   3469  1.1  dholland 			    }
   3470  1.1  dholland 			    *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
   3471  1.1  dholland 				ncookie.lval[0];
   3472  1.1  dholland 			    *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
   3473  1.1  dholland 				ncookie.lval[1];
   3474  1.1  dholland 
   3475  1.1  dholland 			    if (nfhp != NULL) {
   3476  1.1  dholland 				if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len,
   3477  1.1  dholland 				    dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) {
   3478  1.1  dholland 				    VREF(vp);
   3479  1.1  dholland 				    newvp = vp;
   3480  1.1  dholland 				    unlocknewvp = 0;
   3481  1.1  dholland 				    FREE((caddr_t)nfhp, M_NFSFH);
   3482  1.1  dholland 				    np = dnp;
   3483  1.1  dholland 				} else if (isdotdot != 0) {
   3484  1.1  dholland 				    /*
   3485  1.1  dholland 				     * Skip doing a nfscl_nget() call for "..".
   3486  1.1  dholland 				     * There's a race between acquiring the nfs
   3487  1.1  dholland 				     * node here and lookups that look for the
   3488  1.1  dholland 				     * directory being read (in the parent).
   3489  1.1  dholland 				     * It would try to get a lock on ".." here,
   3490  1.1  dholland 				     * owning the lock on the directory being
   3491  1.1  dholland 				     * read. Lookup will hold the lock on ".."
   3492  1.1  dholland 				     * and try to acquire the lock on the
   3493  1.1  dholland 				     * directory being read.
   3494  1.1  dholland 				     * If the directory is unlocked/relocked,
   3495  1.1  dholland 				     * then there is a LOR with the buflock
   3496  1.1  dholland 				     * vp is relocked.
   3497  1.1  dholland 				     */
   3498  1.1  dholland 				    free(nfhp, M_NFSFH);
   3499  1.1  dholland 				} else {
   3500  1.1  dholland 				    error = nfscl_nget(vnode_mount(vp), vp,
   3501  1.1  dholland 				      nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE);
   3502  1.1  dholland 				    if (!error) {
   3503  1.1  dholland 					newvp = NFSTOV(np);
   3504  1.1  dholland 					unlocknewvp = 1;
   3505  1.1  dholland 				    }
   3506  1.1  dholland 				}
   3507  1.1  dholland 				nfhp = NULL;
   3508  1.1  dholland 				if (newvp != NULLVP) {
   3509  1.1  dholland 				    error = nfscl_loadattrcache(&newvp,
   3510  1.1  dholland 					&nfsva, NULL, NULL, 0, 0);
   3511  1.1  dholland 				    if (error) {
   3512  1.1  dholland 					if (unlocknewvp)
   3513  1.1  dholland 					    vput(newvp);
   3514  1.1  dholland 					else
   3515  1.1  dholland 					    vrele(newvp);
   3516  1.1  dholland 					goto nfsmout;
   3517  1.1  dholland 				    }
   3518  1.1  dholland 				    dp->d_type =
   3519  1.1  dholland 					vtonfs_dtype(np->n_vattr.na_type);
   3520  1.1  dholland 				    ndp->ni_vp = newvp;
   3521  1.1  dholland 				    NFSCNHASH(cnp, HASHINIT);
   3522  1.1  dholland 				    if (cnp->cn_namelen <= NCHNAMLEN &&
   3523  1.1  dholland 					(newvp->v_type != VDIR ||
   3524  1.1  dholland 					 dctime.tv_sec != 0)) {
   3525  1.1  dholland 					cache_enter_time(ndp->ni_dvp,
   3526  1.1  dholland 					    ndp->ni_vp, cnp,
   3527  1.1  dholland 					    &nfsva.na_ctime,
   3528  1.1  dholland 					    newvp->v_type != VDIR ? NULL :
   3529  1.1  dholland 					    &dctime);
   3530  1.1  dholland 				    }
   3531  1.1  dholland 				    if (unlocknewvp)
   3532  1.1  dholland 					vput(newvp);
   3533  1.1  dholland 				    else
   3534  1.1  dholland 					vrele(newvp);
   3535  1.1  dholland 				    newvp = NULLVP;
   3536  1.1  dholland 				}
   3537  1.1  dholland 			    }
   3538  1.1  dholland 			} else if (nfhp != NULL) {
   3539  1.1  dholland 			    FREE((caddr_t)nfhp, M_NFSFH);
   3540  1.1  dholland 			}
   3541  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3542  1.1  dholland 			more_dirs = fxdr_unsigned(int, *tl);
   3543  1.1  dholland 		}
   3544  1.1  dholland 		/*
   3545  1.1  dholland 		 * If at end of rpc data, get the eof boolean
   3546  1.1  dholland 		 */
   3547  1.1  dholland 		if (!more_dirs) {
   3548  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3549  1.1  dholland 			eof = fxdr_unsigned(int, *tl);
   3550  1.1  dholland 			if (tryformoredirs)
   3551  1.1  dholland 				more_dirs = !eof;
   3552  1.1  dholland 			if (nd->nd_flag & ND_NFSV4) {
   3553  1.1  dholland 				error = nfscl_postop_attr(nd, nap, attrflagp,
   3554  1.1  dholland 				    stuff);
   3555  1.1  dholland 				if (error)
   3556  1.1  dholland 					goto nfsmout;
   3557  1.1  dholland 			}
   3558  1.1  dholland 		}
   3559  1.1  dholland 		mbuf_freem(nd->nd_mrep);
   3560  1.1  dholland 		nd->nd_mrep = NULL;
   3561  1.1  dholland 	}
   3562  1.1  dholland 	/*
   3563  1.1  dholland 	 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
   3564  1.1  dholland 	 * by increasing d_reclen for the last record.
   3565  1.1  dholland 	 */
   3566  1.1  dholland 	if (blksiz > 0) {
   3567  1.1  dholland 		left = DIRBLKSIZ - blksiz;
   3568  1.1  dholland 		dp->d_reclen += left;
   3569  1.1  dholland 		uio_iov_base_add(uiop, left);
   3570  1.1  dholland 		uio_iov_len_add(uiop, -(left));
   3571  1.1  dholland 		uio_uio_resid_add(uiop, -(left));
   3572  1.1  dholland 		uiop->uio_offset += left;
   3573  1.1  dholland 	}
   3574  1.1  dholland 
   3575  1.1  dholland 	/*
   3576  1.1  dholland 	 * If returning no data, assume end of file.
   3577  1.1  dholland 	 * If not bigenough, return not end of file, since you aren't
   3578  1.1  dholland 	 *    returning all the data
   3579  1.1  dholland 	 * Otherwise, return the eof flag from the server.
   3580  1.1  dholland 	 */
   3581  1.1  dholland 	if (eofp != NULL) {
   3582  1.1  dholland 		if (tresid == uio_uio_resid(uiop))
   3583  1.1  dholland 			*eofp = 1;
   3584  1.1  dholland 		else if (!bigenough)
   3585  1.1  dholland 			*eofp = 0;
   3586  1.1  dholland 		else
   3587  1.1  dholland 			*eofp = eof;
   3588  1.1  dholland 	}
   3589  1.1  dholland 
   3590  1.1  dholland 	/*
   3591  1.1  dholland 	 * Add extra empty records to any remaining DIRBLKSIZ chunks.
   3592  1.1  dholland 	 */
   3593  1.1  dholland 	while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) {
   3594  1.1  dholland 		dp = (struct dirent *)uio_iov_base(uiop);
   3595  1.1  dholland 		dp->d_type = DT_UNKNOWN;
   3596  1.1  dholland 		dp->d_fileno = 0;
   3597  1.1  dholland 		dp->d_namlen = 0;
   3598  1.1  dholland 		dp->d_name[0] = '\0';
   3599  1.1  dholland 		tl = (u_int32_t *)&dp->d_name[4];
   3600  1.1  dholland 		*tl++ = cookie.lval[0];
   3601  1.1  dholland 		*tl = cookie.lval[1];
   3602  1.1  dholland 		dp->d_reclen = DIRBLKSIZ;
   3603  1.1  dholland 		uio_iov_base_add(uiop, DIRBLKSIZ);
   3604  1.1  dholland 		uio_iov_len_add(uiop, -(DIRBLKSIZ));
   3605  1.1  dholland 		uio_uio_resid_add(uiop, -(DIRBLKSIZ));
   3606  1.1  dholland 		uiop->uio_offset += DIRBLKSIZ;
   3607  1.1  dholland 	}
   3608  1.1  dholland 
   3609  1.1  dholland nfsmout:
   3610  1.1  dholland 	if (nd->nd_mrep != NULL)
   3611  1.1  dholland 		mbuf_freem(nd->nd_mrep);
   3612  1.1  dholland 	return (error);
   3613  1.1  dholland }
   3614  1.1  dholland #endif	/* !APPLE */
   3615  1.1  dholland 
   3616  1.1  dholland /*
   3617  1.1  dholland  * Nfs commit rpc
   3618  1.1  dholland  */
   3619  1.1  dholland APPLESTATIC int
   3620  1.1  dholland nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred,
   3621  1.1  dholland     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
   3622  1.1  dholland {
   3623  1.1  dholland 	u_int32_t *tl;
   3624  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   3625  1.1  dholland 	nfsattrbit_t attrbits;
   3626  1.1  dholland 	int error;
   3627  1.1  dholland 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
   3628  1.1  dholland 
   3629  1.1  dholland 	*attrflagp = 0;
   3630  1.1  dholland 	NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp);
   3631  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   3632  1.1  dholland 	txdr_hyper(offset, tl);
   3633  1.1  dholland 	tl += 2;
   3634  1.1  dholland 	*tl = txdr_unsigned(cnt);
   3635  1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
   3636  1.1  dholland 		/*
   3637  1.1  dholland 		 * And do a Getattr op.
   3638  1.1  dholland 		 */
   3639  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   3640  1.1  dholland 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
   3641  1.1  dholland 		NFSGETATTR_ATTRBIT(&attrbits);
   3642  1.1  dholland 		(void) nfsrv_putattrbit(nd, &attrbits);
   3643  1.1  dholland 	}
   3644  1.1  dholland 	error = nfscl_request(nd, vp, p, cred, stuff);
   3645  1.1  dholland 	if (error)
   3646  1.1  dholland 		return (error);
   3647  1.1  dholland 	error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff);
   3648  1.1  dholland 	if (!error && !nd->nd_repstat) {
   3649  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
   3650  1.1  dholland 		NFSLOCKMNT(nmp);
   3651  1.1  dholland 		if (NFSBCMP(nmp->nm_verf, tl, NFSX_VERF)) {
   3652  1.1  dholland 			NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
   3653  1.1  dholland 			nd->nd_repstat = NFSERR_STALEWRITEVERF;
   3654  1.1  dholland 		}
   3655  1.1  dholland 		NFSUNLOCKMNT(nmp);
   3656  1.1  dholland 		if (nd->nd_flag & ND_NFSV4)
   3657  1.1  dholland 			error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
   3658  1.1  dholland 	}
   3659  1.1  dholland nfsmout:
   3660  1.1  dholland 	if (!error && nd->nd_repstat)
   3661  1.1  dholland 		error = nd->nd_repstat;
   3662  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   3663  1.1  dholland 	return (error);
   3664  1.1  dholland }
   3665  1.1  dholland 
   3666  1.1  dholland /*
   3667  1.1  dholland  * NFS byte range lock rpc.
   3668  1.1  dholland  * (Mostly just calls one of the three lower level RPC routines.)
   3669  1.1  dholland  */
   3670  1.1  dholland APPLESTATIC int
   3671  1.1  dholland nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
   3672  1.1  dholland     int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags)
   3673  1.1  dholland {
   3674  1.1  dholland 	struct nfscllockowner *lp;
   3675  1.1  dholland 	struct nfsclclient *clp;
   3676  1.1  dholland 	struct nfsfh *nfhp;
   3677  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   3678  1.1  dholland 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
   3679  1.1  dholland 	u_int64_t off, len;
   3680  1.1  dholland 	off_t start, end;
   3681  1.1  dholland 	u_int32_t clidrev = 0;
   3682  1.1  dholland 	int error = 0, newone = 0, expireret = 0, retrycnt, donelocally;
   3683  1.1  dholland 	int callcnt, dorpc;
   3684  1.1  dholland 
   3685  1.1  dholland 	/*
   3686  1.1  dholland 	 * Convert the flock structure into a start and end and do POSIX
   3687  1.1  dholland 	 * bounds checking.
   3688  1.1  dholland 	 */
   3689  1.1  dholland 	switch (fl->l_whence) {
   3690  1.1  dholland 	case SEEK_SET:
   3691  1.1  dholland 	case SEEK_CUR:
   3692  1.1  dholland 		/*
   3693  1.1  dholland 		 * Caller is responsible for adding any necessary offset
   3694  1.1  dholland 		 * when SEEK_CUR is used.
   3695  1.1  dholland 		 */
   3696  1.1  dholland 		start = fl->l_start;
   3697  1.1  dholland 		off = fl->l_start;
   3698  1.1  dholland 		break;
   3699  1.1  dholland 	case SEEK_END:
   3700  1.1  dholland 		start = size + fl->l_start;
   3701  1.1  dholland 		off = size + fl->l_start;
   3702  1.1  dholland 		break;
   3703  1.1  dholland 	default:
   3704  1.1  dholland 		return (EINVAL);
   3705  1.2  pgoyette 	}
   3706  1.1  dholland 	if (start < 0)
   3707  1.1  dholland 		return (EINVAL);
   3708  1.1  dholland 	if (fl->l_len != 0) {
   3709  1.1  dholland 		end = start + fl->l_len - 1;
   3710  1.1  dholland 		if (end < start)
   3711  1.1  dholland 			return (EINVAL);
   3712  1.1  dholland 	}
   3713  1.1  dholland 
   3714  1.1  dholland 	len = fl->l_len;
   3715  1.1  dholland 	if (len == 0)
   3716  1.1  dholland 		len = NFS64BITSSET;
   3717  1.1  dholland 	retrycnt = 0;
   3718  1.1  dholland 	do {
   3719  1.1  dholland 	    nd->nd_repstat = 0;
   3720  1.1  dholland 	    if (op == F_GETLK) {
   3721  1.1  dholland 		error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp);
   3722  1.1  dholland 		if (error)
   3723  1.1  dholland 			return (error);
   3724  1.1  dholland 		error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags);
   3725  1.1  dholland 		if (!error) {
   3726  1.1  dholland 			clidrev = clp->nfsc_clientidrev;
   3727  1.1  dholland 			error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred,
   3728  1.1  dholland 			    p, id, flags);
   3729  1.1  dholland 		} else if (error == -1) {
   3730  1.1  dholland 			error = 0;
   3731  1.1  dholland 		}
   3732  1.1  dholland 		nfscl_clientrelease(clp);
   3733  1.1  dholland 	    } else if (op == F_UNLCK && fl->l_type == F_UNLCK) {
   3734  1.1  dholland 		/*
   3735  1.1  dholland 		 * We must loop around for all lockowner cases.
   3736  1.1  dholland 		 */
   3737  1.1  dholland 		callcnt = 0;
   3738  1.1  dholland 		error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp);
   3739  1.1  dholland 		if (error)
   3740  1.1  dholland 			return (error);
   3741  1.1  dholland 		do {
   3742  1.1  dholland 		    error = nfscl_relbytelock(vp, off, len, cred, p, callcnt,
   3743  1.1  dholland 			clp, id, flags, &lp, &dorpc);
   3744  1.1  dholland 		    /*
   3745  1.1  dholland 		     * If it returns a NULL lp, we're done.
   3746  1.1  dholland 		     */
   3747  1.1  dholland 		    if (lp == NULL) {
   3748  1.1  dholland 			if (callcnt == 0)
   3749  1.1  dholland 			    nfscl_clientrelease(clp);
   3750  1.1  dholland 			else
   3751  1.1  dholland 			    nfscl_releasealllocks(clp, vp, p, id, flags);
   3752  1.1  dholland 			return (error);
   3753  1.1  dholland 		    }
   3754  1.1  dholland 		    if (nmp->nm_clp != NULL)
   3755  1.1  dholland 			clidrev = nmp->nm_clp->nfsc_clientidrev;
   3756  1.1  dholland 		    else
   3757  1.1  dholland 			clidrev = 0;
   3758  1.1  dholland 		    /*
   3759  1.1  dholland 		     * If the server doesn't support Posix lock semantics,
   3760  1.1  dholland 		     * only allow locks on the entire file, since it won't
   3761  1.1  dholland 		     * handle overlapping byte ranges.
   3762  1.1  dholland 		     * There might still be a problem when a lock
   3763  1.1  dholland 		     * upgrade/downgrade (read<->write) occurs, since the
   3764  1.1  dholland 		     * server "might" expect an unlock first?
   3765  1.1  dholland 		     */
   3766  1.1  dholland 		    if (dorpc && (lp->nfsl_open->nfso_posixlock ||
   3767  1.1  dholland 			(off == 0 && len == NFS64BITSSET))) {
   3768  1.1  dholland 			/*
   3769  1.1  dholland 			 * Since the lock records will go away, we must
   3770  1.1  dholland 			 * wait for grace and delay here.
   3771  1.1  dholland 			 */
   3772  1.1  dholland 			do {
   3773  1.1  dholland 			    error = nfsrpc_locku(nd, nmp, lp, off, len,
   3774  1.1  dholland 				NFSV4LOCKT_READ, cred, p, 0);
   3775  1.1  dholland 			    if ((nd->nd_repstat == NFSERR_GRACE ||
   3776  1.1  dholland 				 nd->nd_repstat == NFSERR_DELAY) &&
   3777  1.1  dholland 				error == 0)
   3778  1.1  dholland 				(void) nfs_catnap(PZERO, (int)nd->nd_repstat,
   3779  1.1  dholland 				    "nfs_advlock");
   3780  1.1  dholland 			} while ((nd->nd_repstat == NFSERR_GRACE ||
   3781  1.1  dholland 			    nd->nd_repstat == NFSERR_DELAY) && error == 0);
   3782  1.1  dholland 		    }
   3783  1.1  dholland 		    callcnt++;
   3784  1.1  dholland 		} while (error == 0 && nd->nd_repstat == 0);
   3785  1.1  dholland 		nfscl_releasealllocks(clp, vp, p, id, flags);
   3786  1.1  dholland 	    } else if (op == F_SETLK) {
   3787  1.1  dholland 		error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p,
   3788  1.1  dholland 		    NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally);
   3789  1.1  dholland 		if (error || donelocally) {
   3790  1.1  dholland 			return (error);
   3791  1.1  dholland 		}
   3792  1.1  dholland 		if (nmp->nm_clp != NULL)
   3793  1.1  dholland 			clidrev = nmp->nm_clp->nfsc_clientidrev;
   3794  1.1  dholland 		else
   3795  1.1  dholland 			clidrev = 0;
   3796  1.1  dholland 		nfhp = VTONFS(vp)->n_fhp;
   3797  1.1  dholland 		if (!lp->nfsl_open->nfso_posixlock &&
   3798  1.1  dholland 		    (off != 0 || len != NFS64BITSSET)) {
   3799  1.1  dholland 			error = EINVAL;
   3800  1.1  dholland 		} else {
   3801  1.1  dholland 			error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh,
   3802  1.1  dholland 			    nfhp->nfh_len, lp, newone, reclaim, off,
   3803  1.1  dholland 			    len, fl->l_type, cred, p, 0);
   3804  1.1  dholland 		}
   3805  1.1  dholland 		if (!error)
   3806  1.1  dholland 			error = nd->nd_repstat;
   3807  1.1  dholland 		nfscl_lockrelease(lp, error, newone);
   3808  1.1  dholland 	    } else {
   3809  1.1  dholland 		error = EINVAL;
   3810  1.1  dholland 	    }
   3811  1.1  dholland 	    if (!error)
   3812  1.1  dholland 	        error = nd->nd_repstat;
   3813  1.1  dholland 	    if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
   3814  1.1  dholland 		error == NFSERR_STALEDONTRECOVER ||
   3815  1.1  dholland 		error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
   3816  1.1  dholland 		error == NFSERR_BADSESSION) {
   3817  1.1  dholland 		(void) nfs_catnap(PZERO, error, "nfs_advlock");
   3818  1.1  dholland 	    } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
   3819  1.1  dholland 		&& clidrev != 0) {
   3820  1.1  dholland 		expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
   3821  1.1  dholland 		retrycnt++;
   3822  1.1  dholland 	    }
   3823  1.1  dholland 	} while (error == NFSERR_GRACE ||
   3824  1.1  dholland 	    error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
   3825  1.1  dholland 	    error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID ||
   3826  1.1  dholland 	    error == NFSERR_BADSESSION ||
   3827  1.1  dholland 	    ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
   3828  1.1  dholland 	     expireret == 0 && clidrev != 0 && retrycnt < 4));
   3829  1.1  dholland 	if (error && retrycnt >= 4)
   3830  1.1  dholland 		error = EIO;
   3831  1.1  dholland 	return (error);
   3832  1.1  dholland }
   3833  1.1  dholland 
   3834  1.1  dholland /*
   3835  1.1  dholland  * The lower level routine for the LockT case.
   3836  1.1  dholland  */
   3837  1.1  dholland APPLESTATIC int
   3838  1.1  dholland nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
   3839  1.1  dholland     struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl,
   3840  1.1  dholland     struct ucred *cred, NFSPROC_T *p, void *id, int flags)
   3841  1.1  dholland {
   3842  1.1  dholland 	u_int32_t *tl;
   3843  1.1  dholland 	int error, type, size;
   3844  1.1  dholland 	uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
   3845  1.1  dholland 	struct nfsnode *np;
   3846  1.1  dholland 	struct nfsmount *nmp;
   3847  1.1  dholland 
   3848  1.1  dholland 	nmp = VFSTONFS(vp->v_mount);
   3849  1.1  dholland 	NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp);
   3850  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
   3851  1.1  dholland 	if (fl->l_type == F_RDLCK)
   3852  1.1  dholland 		*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
   3853  1.1  dholland 	else
   3854  1.1  dholland 		*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
   3855  1.1  dholland 	txdr_hyper(off, tl);
   3856  1.1  dholland 	tl += 2;
   3857  1.1  dholland 	txdr_hyper(len, tl);
   3858  1.1  dholland 	tl += 2;
   3859  1.1  dholland 	*tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
   3860  1.1  dholland 	*tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
   3861  1.1  dholland 	nfscl_filllockowner(id, own, flags);
   3862  1.1  dholland 	np = VTONFS(vp);
   3863  1.1  dholland 	NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN],
   3864  1.1  dholland 	    np->n_fhp->nfh_len);
   3865  1.1  dholland 	(void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len);
   3866  1.1  dholland 	error = nfscl_request(nd, vp, p, cred, NULL);
   3867  1.1  dholland 	if (error)
   3868  1.1  dholland 		return (error);
   3869  1.1  dholland 	if (nd->nd_repstat == 0) {
   3870  1.1  dholland 		fl->l_type = F_UNLCK;
   3871  1.1  dholland 	} else if (nd->nd_repstat == NFSERR_DENIED) {
   3872  1.1  dholland 		nd->nd_repstat = 0;
   3873  1.1  dholland 		fl->l_whence = SEEK_SET;
   3874  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
   3875  1.1  dholland 		fl->l_start = fxdr_hyper(tl);
   3876  1.1  dholland 		tl += 2;
   3877  1.1  dholland 		len = fxdr_hyper(tl);
   3878  1.1  dholland 		tl += 2;
   3879  1.1  dholland 		if (len == NFS64BITSSET)
   3880  1.1  dholland 			fl->l_len = 0;
   3881  1.1  dholland 		else
   3882  1.1  dholland 			fl->l_len = len;
   3883  1.1  dholland 		type = fxdr_unsigned(int, *tl++);
   3884  1.1  dholland 		if (type == NFSV4LOCKT_WRITE)
   3885  1.1  dholland 			fl->l_type = F_WRLCK;
   3886  1.1  dholland 		else
   3887  1.1  dholland 			fl->l_type = F_RDLCK;
   3888  1.1  dholland 		/*
   3889  1.1  dholland 		 * XXX For now, I have no idea what to do with the
   3890  1.1  dholland 		 * conflicting lock_owner, so I'll just set the pid == 0
   3891  1.1  dholland 		 * and skip over the lock_owner.
   3892  1.1  dholland 		 */
   3893  1.1  dholland 		fl->l_pid = (pid_t)0;
   3894  1.1  dholland 		tl += 2;
   3895  1.1  dholland 		size = fxdr_unsigned(int, *tl);
   3896  1.1  dholland 		if (size < 0 || size > NFSV4_OPAQUELIMIT)
   3897  1.1  dholland 			error = EBADRPC;
   3898  1.1  dholland 		if (!error)
   3899  1.1  dholland 			error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
   3900  1.1  dholland 	} else if (nd->nd_repstat == NFSERR_STALECLIENTID ||
   3901  1.1  dholland 	    nd->nd_repstat == NFSERR_BADSESSION)
   3902  1.1  dholland 		nfscl_initiate_recovery(clp);
   3903  1.1  dholland nfsmout:
   3904  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   3905  1.1  dholland 	return (error);
   3906  1.1  dholland }
   3907  1.1  dholland 
   3908  1.1  dholland /*
   3909  1.1  dholland  * Lower level function that performs the LockU RPC.
   3910  1.1  dholland  */
   3911  1.1  dholland static int
   3912  1.1  dholland nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp,
   3913  1.1  dholland     struct nfscllockowner *lp, u_int64_t off, u_int64_t len,
   3914  1.1  dholland     u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred)
   3915  1.1  dholland {
   3916  1.1  dholland 	u_int32_t *tl;
   3917  1.1  dholland 	int error;
   3918  1.1  dholland 
   3919  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh,
   3920  1.1  dholland 	    lp->nfsl_open->nfso_fhlen, NULL, NULL);
   3921  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
   3922  1.1  dholland 	*tl++ = txdr_unsigned(type);
   3923  1.1  dholland 	*tl = txdr_unsigned(lp->nfsl_seqid);
   3924  1.1  dholland 	if (nfstest_outofseq &&
   3925  1.1  dholland 	    (arc4random() % nfstest_outofseq) == 0)
   3926  1.1  dholland 		*tl = txdr_unsigned(lp->nfsl_seqid + 1);
   3927  1.1  dholland 	tl++;
   3928  1.1  dholland 	if (NFSHASNFSV4N(nmp))
   3929  1.1  dholland 		*tl++ = 0;
   3930  1.1  dholland 	else
   3931  1.1  dholland 		*tl++ = lp->nfsl_stateid.seqid;
   3932  1.1  dholland 	*tl++ = lp->nfsl_stateid.other[0];
   3933  1.1  dholland 	*tl++ = lp->nfsl_stateid.other[1];
   3934  1.1  dholland 	*tl++ = lp->nfsl_stateid.other[2];
   3935  1.1  dholland 	txdr_hyper(off, tl);
   3936  1.1  dholland 	tl += 2;
   3937  1.1  dholland 	txdr_hyper(len, tl);
   3938  1.1  dholland 	if (syscred)
   3939  1.1  dholland 		nd->nd_flag |= ND_USEGSSNAME;
   3940  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
   3941  1.1  dholland 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
   3942  1.1  dholland 	NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
   3943  1.1  dholland 	if (error)
   3944  1.1  dholland 		return (error);
   3945  1.1  dholland 	if (nd->nd_repstat == 0) {
   3946  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
   3947  1.1  dholland 		lp->nfsl_stateid.seqid = *tl++;
   3948  1.1  dholland 		lp->nfsl_stateid.other[0] = *tl++;
   3949  1.1  dholland 		lp->nfsl_stateid.other[1] = *tl++;
   3950  1.1  dholland 		lp->nfsl_stateid.other[2] = *tl;
   3951  1.1  dholland 	} else if (nd->nd_repstat == NFSERR_STALESTATEID ||
   3952  1.1  dholland 	    nd->nd_repstat == NFSERR_BADSESSION)
   3953  1.1  dholland 		nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
   3954  1.1  dholland nfsmout:
   3955  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   3956  1.1  dholland 	return (error);
   3957  1.1  dholland }
   3958  1.1  dholland 
   3959  1.1  dholland /*
   3960  1.1  dholland  * The actual Lock RPC.
   3961  1.1  dholland  */
   3962  1.1  dholland APPLESTATIC int
   3963  1.1  dholland nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp,
   3964  1.1  dholland     u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone,
   3965  1.1  dholland     int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred,
   3966  1.1  dholland     NFSPROC_T *p, int syscred)
   3967  1.1  dholland {
   3968  1.1  dholland 	u_int32_t *tl;
   3969  1.1  dholland 	int error, size;
   3970  1.1  dholland 	uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
   3971  1.1  dholland 
   3972  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL);
   3973  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
   3974  1.1  dholland 	if (type == F_RDLCK)
   3975  1.1  dholland 		*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
   3976  1.1  dholland 	else
   3977  1.1  dholland 		*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
   3978  1.1  dholland 	*tl++ = txdr_unsigned(reclaim);
   3979  1.1  dholland 	txdr_hyper(off, tl);
   3980  1.1  dholland 	tl += 2;
   3981  1.1  dholland 	txdr_hyper(len, tl);
   3982  1.1  dholland 	tl += 2;
   3983  1.1  dholland 	if (newone) {
   3984  1.1  dholland 	    *tl = newnfs_true;
   3985  1.1  dholland 	    NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
   3986  1.1  dholland 		2 * NFSX_UNSIGNED + NFSX_HYPER);
   3987  1.1  dholland 	    *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid);
   3988  1.1  dholland 	    if (NFSHASNFSV4N(nmp))
   3989  1.1  dholland 		*tl++ = 0;
   3990  1.1  dholland 	    else
   3991  1.1  dholland 		*tl++ = lp->nfsl_open->nfso_stateid.seqid;
   3992  1.1  dholland 	    *tl++ = lp->nfsl_open->nfso_stateid.other[0];
   3993  1.1  dholland 	    *tl++ = lp->nfsl_open->nfso_stateid.other[1];
   3994  1.1  dholland 	    *tl++ = lp->nfsl_open->nfso_stateid.other[2];
   3995  1.1  dholland 	    *tl++ = txdr_unsigned(lp->nfsl_seqid);
   3996  1.1  dholland 	    *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
   3997  1.1  dholland 	    *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
   3998  1.1  dholland 	    NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
   3999  1.1  dholland 	    NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen);
   4000  1.1  dholland 	    (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
   4001  1.1  dholland 	} else {
   4002  1.1  dholland 	    *tl = newnfs_false;
   4003  1.1  dholland 	    NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
   4004  1.1  dholland 	    if (NFSHASNFSV4N(nmp))
   4005  1.1  dholland 		*tl++ = 0;
   4006  1.1  dholland 	    else
   4007  1.1  dholland 		*tl++ = lp->nfsl_stateid.seqid;
   4008  1.1  dholland 	    *tl++ = lp->nfsl_stateid.other[0];
   4009  1.1  dholland 	    *tl++ = lp->nfsl_stateid.other[1];
   4010  1.1  dholland 	    *tl++ = lp->nfsl_stateid.other[2];
   4011  1.1  dholland 	    *tl = txdr_unsigned(lp->nfsl_seqid);
   4012  1.1  dholland 	    if (nfstest_outofseq &&
   4013  1.1  dholland 		(arc4random() % nfstest_outofseq) == 0)
   4014  1.1  dholland 		    *tl = txdr_unsigned(lp->nfsl_seqid + 1);
   4015  1.1  dholland 	}
   4016  1.1  dholland 	if (syscred)
   4017  1.1  dholland 		nd->nd_flag |= ND_USEGSSNAME;
   4018  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
   4019  1.1  dholland 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
   4020  1.1  dholland 	if (error)
   4021  1.1  dholland 		return (error);
   4022  1.1  dholland 	if (newone)
   4023  1.1  dholland 	    NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd);
   4024  1.1  dholland 	NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
   4025  1.1  dholland 	if (nd->nd_repstat == 0) {
   4026  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
   4027  1.1  dholland 		lp->nfsl_stateid.seqid = *tl++;
   4028  1.1  dholland 		lp->nfsl_stateid.other[0] = *tl++;
   4029  1.1  dholland 		lp->nfsl_stateid.other[1] = *tl++;
   4030  1.1  dholland 		lp->nfsl_stateid.other[2] = *tl;
   4031  1.1  dholland 	} else if (nd->nd_repstat == NFSERR_DENIED) {
   4032  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
   4033  1.1  dholland 		size = fxdr_unsigned(int, *(tl + 7));
   4034  1.1  dholland 		if (size < 0 || size > NFSV4_OPAQUELIMIT)
   4035  1.1  dholland 			error = EBADRPC;
   4036  1.1  dholland 		if (!error)
   4037  1.1  dholland 			error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
   4038  1.1  dholland 	} else if (nd->nd_repstat == NFSERR_STALESTATEID ||
   4039  1.1  dholland 	    nd->nd_repstat == NFSERR_BADSESSION)
   4040  1.1  dholland 		nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
   4041  1.1  dholland nfsmout:
   4042  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   4043  1.1  dholland 	return (error);
   4044  1.1  dholland }
   4045  1.1  dholland 
   4046  1.1  dholland /*
   4047  1.1  dholland  * nfs statfs rpc
   4048  1.1  dholland  * (always called with the vp for the mount point)
   4049  1.1  dholland  */
   4050  1.1  dholland APPLESTATIC int
   4051  1.1  dholland nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
   4052  1.1  dholland     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
   4053  1.1  dholland     void *stuff)
   4054  1.1  dholland {
   4055  1.1  dholland 	u_int32_t *tl = NULL;
   4056  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   4057  1.1  dholland 	struct nfsmount *nmp;
   4058  1.1  dholland 	nfsattrbit_t attrbits;
   4059  1.1  dholland 	int error;
   4060  1.1  dholland 
   4061  1.1  dholland 	*attrflagp = 0;
   4062  1.1  dholland 	nmp = VFSTONFS(vnode_mount(vp));
   4063  1.1  dholland 	if (NFSHASNFSV4(nmp)) {
   4064  1.1  dholland 		/*
   4065  1.1  dholland 		 * For V4, you actually do a getattr.
   4066  1.1  dholland 		 */
   4067  1.1  dholland 		NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
   4068  1.1  dholland 		NFSSTATFS_GETATTRBIT(&attrbits);
   4069  1.1  dholland 		(void) nfsrv_putattrbit(nd, &attrbits);
   4070  1.1  dholland 		nd->nd_flag |= ND_USEGSSNAME;
   4071  1.1  dholland 		error = nfscl_request(nd, vp, p, cred, stuff);
   4072  1.1  dholland 		if (error)
   4073  1.1  dholland 			return (error);
   4074  1.1  dholland 		if (nd->nd_repstat == 0) {
   4075  1.1  dholland 			error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
   4076  1.1  dholland 			    NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p,
   4077  1.1  dholland 			    cred);
   4078  1.1  dholland 			if (!error) {
   4079  1.1  dholland 				nmp->nm_fsid[0] = nap->na_filesid[0];
   4080  1.1  dholland 				nmp->nm_fsid[1] = nap->na_filesid[1];
   4081  1.1  dholland 				NFSSETHASSETFSID(nmp);
   4082  1.1  dholland 				*attrflagp = 1;
   4083  1.1  dholland 			}
   4084  1.1  dholland 		} else {
   4085  1.1  dholland 			error = nd->nd_repstat;
   4086  1.1  dholland 		}
   4087  1.1  dholland 		if (error)
   4088  1.1  dholland 			goto nfsmout;
   4089  1.1  dholland 	} else {
   4090  1.1  dholland 		NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp);
   4091  1.1  dholland 		error = nfscl_request(nd, vp, p, cred, stuff);
   4092  1.1  dholland 		if (error)
   4093  1.1  dholland 			return (error);
   4094  1.1  dholland 		if (nd->nd_flag & ND_NFSV3) {
   4095  1.1  dholland 			error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
   4096  1.1  dholland 			if (error)
   4097  1.1  dholland 				goto nfsmout;
   4098  1.1  dholland 		}
   4099  1.1  dholland 		if (nd->nd_repstat) {
   4100  1.1  dholland 			error = nd->nd_repstat;
   4101  1.1  dholland 			goto nfsmout;
   4102  1.1  dholland 		}
   4103  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *,
   4104  1.1  dholland 		    NFSX_STATFS(nd->nd_flag & ND_NFSV3));
   4105  1.1  dholland 	}
   4106  1.1  dholland 	if (NFSHASNFSV3(nmp)) {
   4107  1.1  dholland 		sbp->sf_tbytes = fxdr_hyper(tl); tl += 2;
   4108  1.1  dholland 		sbp->sf_fbytes = fxdr_hyper(tl); tl += 2;
   4109  1.1  dholland 		sbp->sf_abytes = fxdr_hyper(tl); tl += 2;
   4110  1.1  dholland 		sbp->sf_tfiles = fxdr_hyper(tl); tl += 2;
   4111  1.1  dholland 		sbp->sf_ffiles = fxdr_hyper(tl); tl += 2;
   4112  1.1  dholland 		sbp->sf_afiles = fxdr_hyper(tl); tl += 2;
   4113  1.1  dholland 		sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl);
   4114  1.1  dholland 	} else if (NFSHASNFSV4(nmp) == 0) {
   4115  1.1  dholland 		sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++);
   4116  1.1  dholland 		sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++);
   4117  1.1  dholland 		sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++);
   4118  1.1  dholland 		sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++);
   4119  1.1  dholland 		sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl);
   4120  1.1  dholland 	}
   4121  1.1  dholland nfsmout:
   4122  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   4123  1.1  dholland 	return (error);
   4124  1.1  dholland }
   4125  1.1  dholland 
   4126  1.1  dholland /*
   4127  1.1  dholland  * nfs pathconf rpc
   4128  1.1  dholland  */
   4129  1.1  dholland APPLESTATIC int
   4130  1.1  dholland nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc,
   4131  1.1  dholland     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
   4132  1.1  dholland     void *stuff)
   4133  1.1  dholland {
   4134  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   4135  1.1  dholland 	struct nfsmount *nmp;
   4136  1.1  dholland 	u_int32_t *tl;
   4137  1.1  dholland 	nfsattrbit_t attrbits;
   4138  1.1  dholland 	int error;
   4139  1.1  dholland 
   4140  1.1  dholland 	*attrflagp = 0;
   4141  1.1  dholland 	nmp = VFSTONFS(vnode_mount(vp));
   4142  1.1  dholland 	if (NFSHASNFSV4(nmp)) {
   4143  1.1  dholland 		/*
   4144  1.1  dholland 		 * For V4, you actually do a getattr.
   4145  1.1  dholland 		 */
   4146  1.1  dholland 		NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
   4147  1.1  dholland 		NFSPATHCONF_GETATTRBIT(&attrbits);
   4148  1.1  dholland 		(void) nfsrv_putattrbit(nd, &attrbits);
   4149  1.1  dholland 		nd->nd_flag |= ND_USEGSSNAME;
   4150  1.1  dholland 		error = nfscl_request(nd, vp, p, cred, stuff);
   4151  1.1  dholland 		if (error)
   4152  1.1  dholland 			return (error);
   4153  1.1  dholland 		if (nd->nd_repstat == 0) {
   4154  1.1  dholland 			error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
   4155  1.1  dholland 			    pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p,
   4156  1.1  dholland 			    cred);
   4157  1.1  dholland 			if (!error)
   4158  1.1  dholland 				*attrflagp = 1;
   4159  1.1  dholland 		} else {
   4160  1.1  dholland 			error = nd->nd_repstat;
   4161  1.1  dholland 		}
   4162  1.1  dholland 	} else {
   4163  1.1  dholland 		NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp);
   4164  1.1  dholland 		error = nfscl_request(nd, vp, p, cred, stuff);
   4165  1.1  dholland 		if (error)
   4166  1.1  dholland 			return (error);
   4167  1.1  dholland 		error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
   4168  1.1  dholland 		if (nd->nd_repstat && !error)
   4169  1.1  dholland 			error = nd->nd_repstat;
   4170  1.1  dholland 		if (!error) {
   4171  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF);
   4172  1.1  dholland 			pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++);
   4173  1.1  dholland 			pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++);
   4174  1.1  dholland 			pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++);
   4175  1.1  dholland 			pc->pc_chownrestricted =
   4176  1.1  dholland 			    fxdr_unsigned(u_int32_t, *tl++);
   4177  1.1  dholland 			pc->pc_caseinsensitive =
   4178  1.1  dholland 			    fxdr_unsigned(u_int32_t, *tl++);
   4179  1.1  dholland 			pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl);
   4180  1.1  dholland 		}
   4181  1.1  dholland 	}
   4182  1.1  dholland nfsmout:
   4183  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   4184  1.1  dholland 	return (error);
   4185  1.1  dholland }
   4186  1.1  dholland 
   4187  1.1  dholland /*
   4188  1.1  dholland  * nfs version 3 fsinfo rpc call
   4189  1.1  dholland  */
   4190  1.1  dholland APPLESTATIC int
   4191  1.1  dholland nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred,
   4192  1.1  dholland     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
   4193  1.1  dholland {
   4194  1.1  dholland 	u_int32_t *tl;
   4195  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   4196  1.1  dholland 	int error;
   4197  1.1  dholland 
   4198  1.1  dholland 	*attrflagp = 0;
   4199  1.1  dholland 	NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp);
   4200  1.1  dholland 	error = nfscl_request(nd, vp, p, cred, stuff);
   4201  1.1  dholland 	if (error)
   4202  1.1  dholland 		return (error);
   4203  1.1  dholland 	error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
   4204  1.1  dholland 	if (nd->nd_repstat && !error)
   4205  1.1  dholland 		error = nd->nd_repstat;
   4206  1.1  dholland 	if (!error) {
   4207  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO);
   4208  1.1  dholland 		fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++);
   4209  1.1  dholland 		fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++);
   4210  1.1  dholland 		fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++);
   4211  1.1  dholland 		fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++);
   4212  1.1  dholland 		fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++);
   4213  1.1  dholland 		fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++);
   4214  1.1  dholland 		fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++);
   4215  1.1  dholland 		fsp->fs_maxfilesize = fxdr_hyper(tl);
   4216  1.1  dholland 		tl += 2;
   4217  1.1  dholland 		fxdr_nfsv3time(tl, &fsp->fs_timedelta);
   4218  1.1  dholland 		tl += 2;
   4219  1.1  dholland 		fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl);
   4220  1.1  dholland 	}
   4221  1.1  dholland nfsmout:
   4222  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   4223  1.1  dholland 	return (error);
   4224  1.1  dholland }
   4225  1.1  dholland 
   4226  1.1  dholland /*
   4227  1.1  dholland  * This function performs the Renew RPC.
   4228  1.1  dholland  */
   4229  1.1  dholland APPLESTATIC int
   4230  1.1  dholland nfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred,
   4231  1.1  dholland     NFSPROC_T *p)
   4232  1.1  dholland {
   4233  1.1  dholland 	u_int32_t *tl;
   4234  1.1  dholland 	struct nfsrv_descript nfsd;
   4235  1.1  dholland 	struct nfsrv_descript *nd = &nfsd;
   4236  1.1  dholland 	struct nfsmount *nmp;
   4237  1.1  dholland 	int error;
   4238  1.1  dholland 	struct nfssockreq *nrp;
   4239  1.1  dholland 
   4240  1.1  dholland 	nmp = clp->nfsc_nmp;
   4241  1.1  dholland 	if (nmp == NULL)
   4242  1.1  dholland 		return (0);
   4243  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL,
   4244  1.1  dholland 	    &dsp->nfsclds_sess);
   4245  1.1  dholland 	if (!NFSHASNFSV4N(nmp)) {
   4246  1.1  dholland 		/* NFSv4.1 just uses a Sequence Op and not a Renew. */
   4247  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   4248  1.1  dholland 		*tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
   4249  1.1  dholland 		*tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
   4250  1.1  dholland 	}
   4251  1.1  dholland 	nrp = dsp->nfsclds_sockp;
   4252  1.1  dholland 	if (nrp == NULL)
   4253  1.1  dholland 		/* If NULL, use the MDS socket. */
   4254  1.1  dholland 		nrp = &nmp->nm_sockreq;
   4255  1.1  dholland 	nd->nd_flag |= ND_USEGSSNAME;
   4256  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
   4257  1.1  dholland 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
   4258  1.1  dholland 	if (error)
   4259  1.1  dholland 		return (error);
   4260  1.1  dholland 	error = nd->nd_repstat;
   4261  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   4262  1.1  dholland 	return (error);
   4263  1.1  dholland }
   4264  1.1  dholland 
   4265  1.1  dholland /*
   4266  1.1  dholland  * This function performs the Releaselockowner RPC.
   4267  1.1  dholland  */
   4268  1.1  dholland APPLESTATIC int
   4269  1.1  dholland nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp,
   4270  1.1  dholland     uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p)
   4271  1.1  dholland {
   4272  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   4273  1.1  dholland 	u_int32_t *tl;
   4274  1.1  dholland 	int error;
   4275  1.1  dholland 	uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
   4276  1.1  dholland 
   4277  1.1  dholland 	if (NFSHASNFSV4N(nmp)) {
   4278  1.1  dholland 		/* For NFSv4.1, do a FreeStateID. */
   4279  1.1  dholland 		nfscl_reqstart(nd, NFSPROC_FREESTATEID, nmp, NULL, 0, NULL,
   4280  1.1  dholland 		    NULL);
   4281  1.1  dholland 		nfsm_stateidtom(nd, &lp->nfsl_stateid, NFSSTATEID_PUTSTATEID);
   4282  1.1  dholland 	} else {
   4283  1.1  dholland 		nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL,
   4284  1.1  dholland 		    NULL);
   4285  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   4286  1.1  dholland 		*tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
   4287  1.1  dholland 		*tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
   4288  1.1  dholland 		NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
   4289  1.1  dholland 		NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen);
   4290  1.1  dholland 		(void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
   4291  1.1  dholland 	}
   4292  1.1  dholland 	nd->nd_flag |= ND_USEGSSNAME;
   4293  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
   4294  1.1  dholland 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
   4295  1.1  dholland 	if (error)
   4296  1.1  dholland 		return (error);
   4297  1.1  dholland 	error = nd->nd_repstat;
   4298  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   4299  1.1  dholland 	return (error);
   4300  1.1  dholland }
   4301  1.1  dholland 
   4302  1.1  dholland /*
   4303  1.1  dholland  * This function performs the Compound to get the mount pt FH.
   4304  1.1  dholland  */
   4305  1.1  dholland APPLESTATIC int
   4306  1.1  dholland nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
   4307  1.1  dholland     NFSPROC_T *p)
   4308  1.1  dholland {
   4309  1.1  dholland 	u_int32_t *tl;
   4310  1.1  dholland 	struct nfsrv_descript nfsd;
   4311  1.1  dholland 	struct nfsrv_descript *nd = &nfsd;
   4312  1.1  dholland 	u_char *cp, *cp2;
   4313  1.1  dholland 	int error, cnt, len, setnil;
   4314  1.1  dholland 	u_int32_t *opcntp;
   4315  1.1  dholland 
   4316  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL);
   4317  1.1  dholland 	cp = dirpath;
   4318  1.1  dholland 	cnt = 0;
   4319  1.1  dholland 	do {
   4320  1.1  dholland 		setnil = 0;
   4321  1.1  dholland 		while (*cp == '/')
   4322  1.1  dholland 			cp++;
   4323  1.1  dholland 		cp2 = cp;
   4324  1.1  dholland 		while (*cp2 != '\0' && *cp2 != '/')
   4325  1.1  dholland 			cp2++;
   4326  1.1  dholland 		if (*cp2 == '/') {
   4327  1.1  dholland 			setnil = 1;
   4328  1.1  dholland 			*cp2 = '\0';
   4329  1.1  dholland 		}
   4330  1.1  dholland 		if (cp2 != cp) {
   4331  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   4332  1.1  dholland 			*tl = txdr_unsigned(NFSV4OP_LOOKUP);
   4333  1.1  dholland 			nfsm_strtom(nd, cp, strlen(cp));
   4334  1.1  dholland 			cnt++;
   4335  1.1  dholland 		}
   4336  1.1  dholland 		if (setnil)
   4337  1.1  dholland 			*cp2++ = '/';
   4338  1.1  dholland 		cp = cp2;
   4339  1.1  dholland 	} while (*cp != '\0');
   4340  1.1  dholland 	if (NFSHASNFSV4N(nmp))
   4341  1.1  dholland 		/* Has a Sequence Op done by nfscl_reqstart(). */
   4342  1.1  dholland 		*opcntp = txdr_unsigned(3 + cnt);
   4343  1.1  dholland 	else
   4344  1.1  dholland 		*opcntp = txdr_unsigned(2 + cnt);
   4345  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   4346  1.1  dholland 	*tl = txdr_unsigned(NFSV4OP_GETFH);
   4347  1.1  dholland 	nd->nd_flag |= ND_USEGSSNAME;
   4348  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
   4349  1.1  dholland 		NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
   4350  1.1  dholland 	if (error)
   4351  1.1  dholland 		return (error);
   4352  1.1  dholland 	if (nd->nd_repstat == 0) {
   4353  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED);
   4354  1.1  dholland 		tl += (2 + 2 * cnt);
   4355  1.1  dholland 		if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
   4356  1.1  dholland 			len > NFSX_FHMAX) {
   4357  1.1  dholland 			nd->nd_repstat = NFSERR_BADXDR;
   4358  1.1  dholland 		} else {
   4359  1.1  dholland 			nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len);
   4360  1.1  dholland 			if (nd->nd_repstat == 0)
   4361  1.1  dholland 				nmp->nm_fhsize = len;
   4362  1.1  dholland 		}
   4363  1.1  dholland 	}
   4364  1.1  dholland 	error = nd->nd_repstat;
   4365  1.1  dholland nfsmout:
   4366  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   4367  1.1  dholland 	return (error);
   4368  1.1  dholland }
   4369  1.1  dholland 
   4370  1.1  dholland /*
   4371  1.1  dholland  * This function performs the Delegreturn RPC.
   4372  1.1  dholland  */
   4373  1.1  dholland APPLESTATIC int
   4374  1.1  dholland nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred,
   4375  1.1  dholland     struct nfsmount *nmp, NFSPROC_T *p, int syscred)
   4376  1.1  dholland {
   4377  1.1  dholland 	u_int32_t *tl;
   4378  1.1  dholland 	struct nfsrv_descript nfsd;
   4379  1.1  dholland 	struct nfsrv_descript *nd = &nfsd;
   4380  1.1  dholland 	int error;
   4381  1.1  dholland 
   4382  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh,
   4383  1.1  dholland 	    dp->nfsdl_fhlen, NULL, NULL);
   4384  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
   4385  1.1  dholland 	if (NFSHASNFSV4N(nmp))
   4386  1.1  dholland 		*tl++ = 0;
   4387  1.1  dholland 	else
   4388  1.1  dholland 		*tl++ = dp->nfsdl_stateid.seqid;
   4389  1.1  dholland 	*tl++ = dp->nfsdl_stateid.other[0];
   4390  1.1  dholland 	*tl++ = dp->nfsdl_stateid.other[1];
   4391  1.1  dholland 	*tl = dp->nfsdl_stateid.other[2];
   4392  1.1  dholland 	if (syscred)
   4393  1.1  dholland 		nd->nd_flag |= ND_USEGSSNAME;
   4394  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
   4395  1.1  dholland 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
   4396  1.1  dholland 	if (error)
   4397  1.1  dholland 		return (error);
   4398  1.1  dholland 	error = nd->nd_repstat;
   4399  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   4400  1.1  dholland 	return (error);
   4401  1.1  dholland }
   4402  1.1  dholland 
   4403  1.1  dholland /*
   4404  1.1  dholland  * nfs getacl call.
   4405  1.1  dholland  */
   4406  1.1  dholland APPLESTATIC int
   4407  1.1  dholland nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
   4408  1.1  dholland     struct acl *aclp, void *stuff)
   4409  1.1  dholland {
   4410  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   4411  1.1  dholland 	int error;
   4412  1.1  dholland 	nfsattrbit_t attrbits;
   4413  1.1  dholland 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
   4414  1.1  dholland 
   4415  1.1  dholland 	if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
   4416  1.1  dholland 		return (EOPNOTSUPP);
   4417  1.1  dholland 	NFSCL_REQSTART(nd, NFSPROC_GETACL, vp);
   4418  1.1  dholland 	NFSZERO_ATTRBIT(&attrbits);
   4419  1.1  dholland 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
   4420  1.1  dholland 	(void) nfsrv_putattrbit(nd, &attrbits);
   4421  1.1  dholland 	error = nfscl_request(nd, vp, p, cred, stuff);
   4422  1.1  dholland 	if (error)
   4423  1.1  dholland 		return (error);
   4424  1.1  dholland 	if (!nd->nd_repstat)
   4425  1.1  dholland 		error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL,
   4426  1.1  dholland 		    NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred);
   4427  1.1  dholland 	else
   4428  1.1  dholland 		error = nd->nd_repstat;
   4429  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   4430  1.1  dholland 	return (error);
   4431  1.1  dholland }
   4432  1.1  dholland 
   4433  1.1  dholland /*
   4434  1.1  dholland  * nfs setacl call.
   4435  1.1  dholland  */
   4436  1.1  dholland APPLESTATIC int
   4437  1.1  dholland nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
   4438  1.1  dholland     struct acl *aclp, void *stuff)
   4439  1.1  dholland {
   4440  1.1  dholland 	int error;
   4441  1.1  dholland 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
   4442  1.1  dholland 
   4443  1.1  dholland 	if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
   4444  1.1  dholland 		return (EOPNOTSUPP);
   4445  1.1  dholland 	error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff);
   4446  1.1  dholland 	return (error);
   4447  1.1  dholland }
   4448  1.1  dholland 
   4449  1.1  dholland /*
   4450  1.1  dholland  * nfs setacl call.
   4451  1.1  dholland  */
   4452  1.1  dholland static int
   4453  1.1  dholland nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
   4454  1.1  dholland     struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff)
   4455  1.1  dholland {
   4456  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   4457  1.1  dholland 	int error;
   4458  1.1  dholland 	nfsattrbit_t attrbits;
   4459  1.1  dholland 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
   4460  1.1  dholland 
   4461  1.1  dholland 	if (!NFSHASNFSV4(nmp))
   4462  1.1  dholland 		return (EOPNOTSUPP);
   4463  1.1  dholland 	NFSCL_REQSTART(nd, NFSPROC_SETACL, vp);
   4464  1.1  dholland 	nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
   4465  1.1  dholland 	NFSZERO_ATTRBIT(&attrbits);
   4466  1.1  dholland 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
   4467  1.1  dholland 	(void) nfsv4_fillattr(nd, vnode_mount(vp), vp, aclp, NULL, NULL, 0,
   4468  1.1  dholland 	    &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0);
   4469  1.1  dholland 	error = nfscl_request(nd, vp, p, cred, stuff);
   4470  1.1  dholland 	if (error)
   4471  1.1  dholland 		return (error);
   4472  1.1  dholland 	/* Don't care about the pre/postop attributes */
   4473  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   4474  1.1  dholland 	return (nd->nd_repstat);
   4475  1.1  dholland }
   4476  1.1  dholland 
   4477  1.1  dholland /*
   4478  1.1  dholland  * Do the NFSv4.1 Exchange ID.
   4479  1.1  dholland  */
   4480  1.1  dholland int
   4481  1.1  dholland nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp,
   4482  1.1  dholland     struct nfssockreq *nrp, uint32_t exchflags, struct nfsclds **dspp,
   4483  1.1  dholland     struct ucred *cred, NFSPROC_T *p)
   4484  1.1  dholland {
   4485  1.1  dholland 	uint32_t *tl, v41flags;
   4486  1.1  dholland 	struct nfsrv_descript nfsd;
   4487  1.1  dholland 	struct nfsrv_descript *nd = &nfsd;
   4488  1.1  dholland 	struct nfsclds *dsp;
   4489  1.1  dholland 	struct timespec verstime;
   4490  1.1  dholland 	int error, len;
   4491  1.1  dholland 
   4492  1.1  dholland 	*dspp = NULL;
   4493  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL);
   4494  1.1  dholland 	NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
   4495  1.1  dholland 	*tl++ = txdr_unsigned(nfsboottime.tv_sec);	/* Client owner */
   4496  1.1  dholland 	*tl = txdr_unsigned(clp->nfsc_rev);
   4497  1.1  dholland 	(void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
   4498  1.1  dholland 
   4499  1.1  dholland 	NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
   4500  1.1  dholland 	*tl++ = txdr_unsigned(exchflags);
   4501  1.1  dholland 	*tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE);
   4502  1.1  dholland 
   4503  1.1  dholland 	/* Set the implementation id4 */
   4504  1.1  dholland 	*tl = txdr_unsigned(1);
   4505  1.1  dholland 	(void) nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
   4506  1.1  dholland 	(void) nfsm_strtom(nd, version, strlen(version));
   4507  1.1  dholland 	NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
   4508  1.1  dholland 	verstime.tv_sec = 1293840000;		/* Jan 1, 2011 */
   4509  1.1  dholland 	verstime.tv_nsec = 0;
   4510  1.1  dholland 	txdr_nfsv4time(&verstime, tl);
   4511  1.1  dholland 	nd->nd_flag |= ND_USEGSSNAME;
   4512  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
   4513  1.1  dholland 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
   4514  1.1  dholland 	NFSCL_DEBUG(1, "exchangeid err=%d reps=%d\n", error,
   4515  1.1  dholland 	    (int)nd->nd_repstat);
   4516  1.1  dholland 	if (error != 0)
   4517  1.1  dholland 		return (error);
   4518  1.1  dholland 	if (nd->nd_repstat == 0) {
   4519  1.1  dholland 		NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_UNSIGNED + NFSX_HYPER);
   4520  1.1  dholland 		len = fxdr_unsigned(int, *(tl + 7));
   4521  1.1  dholland 		if (len < 0 || len > NFSV4_OPAQUELIMIT) {
   4522  1.1  dholland 			error = NFSERR_BADXDR;
   4523  1.1  dholland 			goto nfsmout;
   4524  1.1  dholland 		}
   4525  1.1  dholland 		dsp = malloc(sizeof(struct nfsclds) + len, M_NFSCLDS,
   4526  1.1  dholland 		    M_WAITOK | M_ZERO);
   4527  1.1  dholland 		dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew;
   4528  1.1  dholland 		dsp->nfsclds_servownlen = len;
   4529  1.1  dholland 		dsp->nfsclds_sess.nfsess_clientid.lval[0] = *tl++;
   4530  1.1  dholland 		dsp->nfsclds_sess.nfsess_clientid.lval[1] = *tl++;
   4531  1.1  dholland 		dsp->nfsclds_sess.nfsess_sequenceid =
   4532  1.1  dholland 		    fxdr_unsigned(uint32_t, *tl++);
   4533  1.1  dholland 		v41flags = fxdr_unsigned(uint32_t, *tl);
   4534  1.1  dholland 		if ((v41flags & NFSV4EXCH_USEPNFSMDS) != 0 &&
   4535  1.1  dholland 		    NFSHASPNFSOPT(nmp)) {
   4536  1.1  dholland 			NFSCL_DEBUG(1, "set PNFS\n");
   4537  1.1  dholland 			NFSLOCKMNT(nmp);
   4538  1.1  dholland 			nmp->nm_state |= NFSSTA_PNFS;
   4539  1.1  dholland 			NFSUNLOCKMNT(nmp);
   4540  1.1  dholland 			dsp->nfsclds_flags |= NFSCLDS_MDS;
   4541  1.1  dholland 		}
   4542  1.1  dholland 		if ((v41flags & NFSV4EXCH_USEPNFSDS) != 0)
   4543  1.1  dholland 			dsp->nfsclds_flags |= NFSCLDS_DS;
   4544  1.1  dholland 		if (len > 0)
   4545  1.1  dholland 			nd->nd_repstat = nfsrv_mtostr(nd,
   4546  1.1  dholland 			    dsp->nfsclds_serverown, len);
   4547  1.1  dholland 		if (nd->nd_repstat == 0) {
   4548  1.1  dholland 			mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
   4549  1.1  dholland 			mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession",
   4550  1.1  dholland 			    NULL, MTX_DEF);
   4551  1.1  dholland 			nfscl_initsessionslots(&dsp->nfsclds_sess);
   4552  1.1  dholland 			*dspp = dsp;
   4553  1.1  dholland 		} else
   4554  1.1  dholland 			free(dsp, M_NFSCLDS);
   4555  1.1  dholland 	}
   4556  1.1  dholland 	error = nd->nd_repstat;
   4557  1.1  dholland nfsmout:
   4558  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   4559  1.1  dholland 	return (error);
   4560  1.1  dholland }
   4561  1.1  dholland 
   4562  1.1  dholland /*
   4563  1.1  dholland  * Do the NFSv4.1 Create Session.
   4564  1.1  dholland  */
   4565  1.1  dholland int
   4566  1.1  dholland nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep,
   4567  1.1  dholland     struct nfssockreq *nrp, uint32_t sequenceid, int mds, struct ucred *cred,
   4568  1.1  dholland     NFSPROC_T *p)
   4569  1.1  dholland {
   4570  1.1  dholland 	uint32_t crflags, *tl;
   4571  1.1  dholland 	struct nfsrv_descript nfsd;
   4572  1.1  dholland 	struct nfsrv_descript *nd = &nfsd;
   4573  1.1  dholland 	int error, irdcnt;
   4574  1.1  dholland 
   4575  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL);
   4576  1.1  dholland 	NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
   4577  1.1  dholland 	*tl++ = sep->nfsess_clientid.lval[0];
   4578  1.1  dholland 	*tl++ = sep->nfsess_clientid.lval[1];
   4579  1.1  dholland 	*tl++ = txdr_unsigned(sequenceid);
   4580  1.1  dholland 	crflags = (NFSMNT_RDONLY(nmp->nm_mountp) ? 0 : NFSV4CRSESS_PERSIST);
   4581  1.1  dholland 	if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0)
   4582  1.1  dholland 		crflags |= NFSV4CRSESS_CONNBACKCHAN;
   4583  1.1  dholland 	*tl = txdr_unsigned(crflags);
   4584  1.1  dholland 
   4585  1.1  dholland 	/* Fill in fore channel attributes. */
   4586  1.1  dholland 	NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
   4587  1.1  dholland 	*tl++ = 0;				/* Header pad size */
   4588  1.1  dholland 	*tl++ = txdr_unsigned(100000);		/* Max request size */
   4589  1.1  dholland 	*tl++ = txdr_unsigned(100000);		/* Max response size */
   4590  1.1  dholland 	*tl++ = txdr_unsigned(4096);		/* Max response size cached */
   4591  1.1  dholland 	*tl++ = txdr_unsigned(20);		/* Max operations */
   4592  1.1  dholland 	*tl++ = txdr_unsigned(64);		/* Max slots */
   4593  1.1  dholland 	*tl = 0;				/* No rdma ird */
   4594  1.1  dholland 
   4595  1.1  dholland 	/* Fill in back channel attributes. */
   4596  1.1  dholland 	NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
   4597  1.1  dholland 	*tl++ = 0;				/* Header pad size */
   4598  1.1  dholland 	*tl++ = txdr_unsigned(10000);		/* Max request size */
   4599  1.1  dholland 	*tl++ = txdr_unsigned(10000);		/* Max response size */
   4600  1.1  dholland 	*tl++ = txdr_unsigned(4096);		/* Max response size cached */
   4601  1.1  dholland 	*tl++ = txdr_unsigned(4);		/* Max operations */
   4602  1.1  dholland 	*tl++ = txdr_unsigned(NFSV4_CBSLOTS);	/* Max slots */
   4603  1.1  dholland 	*tl = 0;				/* No rdma ird */
   4604  1.1  dholland 
   4605  1.1  dholland 	NFSM_BUILD(tl, uint32_t *, 8 * NFSX_UNSIGNED);
   4606  1.1  dholland 	*tl++ = txdr_unsigned(NFS_CALLBCKPROG);	/* Call back prog # */
   4607  1.1  dholland 
   4608  1.1  dholland 	/* Allow AUTH_SYS callbacks as uid, gid == 0. */
   4609  1.1  dholland 	*tl++ = txdr_unsigned(1);		/* Auth_sys only */
   4610  1.1  dholland 	*tl++ = txdr_unsigned(AUTH_SYS);	/* AUTH_SYS type */
   4611  1.1  dholland 	*tl++ = txdr_unsigned(nfsboottime.tv_sec); /* time stamp */
   4612  1.1  dholland 	*tl++ = 0;				/* Null machine name */
   4613  1.1  dholland 	*tl++ = 0;				/* Uid == 0 */
   4614  1.1  dholland 	*tl++ = 0;				/* Gid == 0 */
   4615  1.1  dholland 	*tl = 0;				/* No additional gids */
   4616  1.1  dholland 	nd->nd_flag |= ND_USEGSSNAME;
   4617  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG,
   4618  1.1  dholland 	    NFS_VER4, NULL, 1, NULL, NULL);
   4619  1.1  dholland 	if (error != 0)
   4620  1.1  dholland 		return (error);
   4621  1.1  dholland 	if (nd->nd_repstat == 0) {
   4622  1.1  dholland 		NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID +
   4623  1.1  dholland 		    2 * NFSX_UNSIGNED);
   4624  1.1  dholland 		bcopy(tl, sep->nfsess_sessionid, NFSX_V4SESSIONID);
   4625  1.1  dholland 		tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
   4626  1.1  dholland 		sep->nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++);
   4627  1.1  dholland 		crflags = fxdr_unsigned(uint32_t, *tl);
   4628  1.1  dholland 		if ((crflags & NFSV4CRSESS_PERSIST) != 0 && mds != 0) {
   4629  1.1  dholland 			NFSLOCKMNT(nmp);
   4630  1.1  dholland 			nmp->nm_state |= NFSSTA_SESSPERSIST;
   4631  1.1  dholland 			NFSUNLOCKMNT(nmp);
   4632  1.1  dholland 		}
   4633  1.1  dholland 
   4634  1.1  dholland 		/* Get the fore channel slot count. */
   4635  1.1  dholland 		NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
   4636  1.1  dholland 		tl += 3;		/* Skip the other counts. */
   4637  1.1  dholland 		sep->nfsess_maxcache = fxdr_unsigned(int, *tl++);
   4638  1.1  dholland 		tl++;
   4639  1.1  dholland 		sep->nfsess_foreslots = fxdr_unsigned(uint16_t, *tl++);
   4640  1.1  dholland 		NFSCL_DEBUG(4, "fore slots=%d\n", (int)sep->nfsess_foreslots);
   4641  1.1  dholland 		irdcnt = fxdr_unsigned(int, *tl);
   4642  1.1  dholland 		if (irdcnt > 0)
   4643  1.1  dholland 			NFSM_DISSECT(tl, uint32_t *, irdcnt * NFSX_UNSIGNED);
   4644  1.1  dholland 
   4645  1.1  dholland 		/* and the back channel slot count. */
   4646  1.1  dholland 		NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
   4647  1.1  dholland 		tl += 5;
   4648  1.1  dholland 		sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl);
   4649  1.1  dholland 		NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots);
   4650  1.1  dholland 	}
   4651  1.1  dholland 	error = nd->nd_repstat;
   4652  1.1  dholland nfsmout:
   4653  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   4654  1.1  dholland 	return (error);
   4655  1.1  dholland }
   4656  1.1  dholland 
   4657  1.1  dholland /*
   4658  1.1  dholland  * Do the NFSv4.1 Destroy Session.
   4659  1.1  dholland  */
   4660  1.1  dholland int
   4661  1.1  dholland nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclclient *clp,
   4662  1.1  dholland     struct ucred *cred, NFSPROC_T *p)
   4663  1.1  dholland {
   4664  1.1  dholland 	uint32_t *tl;
   4665  1.1  dholland 	struct nfsrv_descript nfsd;
   4666  1.1  dholland 	struct nfsrv_descript *nd = &nfsd;
   4667  1.1  dholland 	int error;
   4668  1.1  dholland 
   4669  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL);
   4670  1.1  dholland 	NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
   4671  1.1  dholland 	bcopy(NFSMNT_MDSSESSION(nmp)->nfsess_sessionid, tl, NFSX_V4SESSIONID);
   4672  1.1  dholland 	nd->nd_flag |= ND_USEGSSNAME;
   4673  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
   4674  1.1  dholland 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
   4675  1.1  dholland 	if (error != 0)
   4676  1.1  dholland 		return (error);
   4677  1.1  dholland 	error = nd->nd_repstat;
   4678  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   4679  1.1  dholland 	return (error);
   4680  1.1  dholland }
   4681  1.1  dholland 
   4682  1.1  dholland /*
   4683  1.1  dholland  * Do the NFSv4.1 Destroy Client.
   4684  1.1  dholland  */
   4685  1.1  dholland int
   4686  1.1  dholland nfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp,
   4687  1.1  dholland     struct ucred *cred, NFSPROC_T *p)
   4688  1.1  dholland {
   4689  1.1  dholland 	uint32_t *tl;
   4690  1.1  dholland 	struct nfsrv_descript nfsd;
   4691  1.1  dholland 	struct nfsrv_descript *nd = &nfsd;
   4692  1.1  dholland 	int error;
   4693  1.1  dholland 
   4694  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL);
   4695  1.1  dholland 	NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
   4696  1.1  dholland 	*tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
   4697  1.1  dholland 	*tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
   4698  1.1  dholland 	nd->nd_flag |= ND_USEGSSNAME;
   4699  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
   4700  1.1  dholland 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
   4701  1.1  dholland 	if (error != 0)
   4702  1.1  dholland 		return (error);
   4703  1.1  dholland 	error = nd->nd_repstat;
   4704  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   4705  1.1  dholland 	return (error);
   4706  1.1  dholland }
   4707  1.1  dholland 
   4708  1.1  dholland /*
   4709  1.1  dholland  * Do the NFSv4.1 LayoutGet.
   4710  1.1  dholland  */
   4711  1.1  dholland int
   4712  1.1  dholland nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode,
   4713  1.1  dholland     uint64_t offset, uint64_t len, uint64_t minlen, int layoutlen,
   4714  1.1  dholland     nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp,
   4715  1.1  dholland     struct ucred *cred, NFSPROC_T *p, void *stuff)
   4716  1.1  dholland {
   4717  1.1  dholland 	uint32_t *tl;
   4718  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   4719  1.1  dholland 	struct nfsfh *nfhp;
   4720  1.1  dholland 	struct nfsclflayout *flp, *prevflp, *tflp;
   4721  1.1  dholland 	int cnt, error, gotiomode, fhcnt, nfhlen, i, j;
   4722  1.1  dholland 	uint8_t *cp;
   4723  1.1  dholland 	uint64_t retlen;
   4724  1.1  dholland 
   4725  1.1  dholland 	flp = NULL;
   4726  1.1  dholland 	gotiomode = -1;
   4727  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL);
   4728  1.1  dholland 	NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
   4729  1.1  dholland 	    NFSX_STATEID);
   4730  1.1  dholland 	*tl++ = newnfs_false;		/* Don't signal availability. */
   4731  1.1  dholland 	*tl++ = txdr_unsigned(NFSLAYOUT_NFSV4_1_FILES);
   4732  1.1  dholland 	*tl++ = txdr_unsigned(iomode);
   4733  1.1  dholland 	txdr_hyper(offset, tl);
   4734  1.1  dholland 	tl += 2;
   4735  1.1  dholland 	txdr_hyper(len, tl);
   4736  1.1  dholland 	tl += 2;
   4737  1.1  dholland 	txdr_hyper(minlen, tl);
   4738  1.1  dholland 	tl += 2;
   4739  1.1  dholland 	*tl++ = txdr_unsigned(stateidp->seqid);
   4740  1.1  dholland 	NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid);
   4741  1.1  dholland 	*tl++ = stateidp->other[0];
   4742  1.1  dholland 	*tl++ = stateidp->other[1];
   4743  1.1  dholland 	*tl++ = stateidp->other[2];
   4744  1.1  dholland 	*tl = txdr_unsigned(layoutlen);
   4745  1.1  dholland 	nd->nd_flag |= ND_USEGSSNAME;
   4746  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
   4747  1.1  dholland 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
   4748  1.1  dholland 	if (error != 0)
   4749  1.1  dholland 		return (error);
   4750  1.1  dholland 	if (nd->nd_repstat == 0) {
   4751  1.1  dholland 		NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID);
   4752  1.1  dholland 		if (*tl++ != 0)
   4753  1.1  dholland 			*retonclosep = 1;
   4754  1.1  dholland 		else
   4755  1.1  dholland 			*retonclosep = 0;
   4756  1.1  dholland 		stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
   4757  1.1  dholland 		NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep,
   4758  1.1  dholland 		    (int)stateidp->seqid);
   4759  1.1  dholland 		stateidp->other[0] = *tl++;
   4760  1.1  dholland 		stateidp->other[1] = *tl++;
   4761  1.1  dholland 		stateidp->other[2] = *tl++;
   4762  1.1  dholland 		cnt = fxdr_unsigned(int, *tl);
   4763  1.1  dholland 		NFSCL_DEBUG(4, "layg cnt=%d\n", cnt);
   4764  1.1  dholland 		if (cnt <= 0 || cnt > 10000) {
   4765  1.1  dholland 			/* Don't accept more than 10000 layouts in reply. */
   4766  1.1  dholland 			error = NFSERR_BADXDR;
   4767  1.1  dholland 			goto nfsmout;
   4768  1.1  dholland 		}
   4769  1.1  dholland 		for (i = 0; i < cnt; i++) {
   4770  1.1  dholland 			/* Dissect all the way to the file handle cnt. */
   4771  1.1  dholland 			NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_HYPER +
   4772  1.1  dholland 			    6 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
   4773  1.1  dholland 			fhcnt = fxdr_unsigned(int, *(tl + 11 +
   4774  1.1  dholland 			    NFSX_V4DEVICEID / NFSX_UNSIGNED));
   4775  1.1  dholland 			NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt);
   4776  1.1  dholland 			if (fhcnt < 0 || fhcnt > 100) {
   4777  1.1  dholland 				/* Don't accept more than 100 file handles. */
   4778  1.1  dholland 				error = NFSERR_BADXDR;
   4779  1.1  dholland 				goto nfsmout;
   4780  1.1  dholland 			}
   4781  1.1  dholland 			if (fhcnt > 1)
   4782  1.1  dholland 				flp = malloc(sizeof(*flp) + (fhcnt - 1) *
   4783  1.1  dholland 				    sizeof(struct nfsfh *),
   4784  1.1  dholland 				    M_NFSFLAYOUT, M_WAITOK);
   4785  1.1  dholland 			else
   4786  1.1  dholland 				flp = malloc(sizeof(*flp),
   4787  1.1  dholland 				    M_NFSFLAYOUT, M_WAITOK);
   4788  1.1  dholland 			flp->nfsfl_flags = 0;
   4789  1.1  dholland 			flp->nfsfl_fhcnt = 0;
   4790  1.1  dholland 			flp->nfsfl_devp = NULL;
   4791  1.1  dholland 			flp->nfsfl_off = fxdr_hyper(tl); tl += 2;
   4792  1.1  dholland 			retlen = fxdr_hyper(tl); tl += 2;
   4793  1.1  dholland 			if (flp->nfsfl_off + retlen < flp->nfsfl_off)
   4794  1.1  dholland 				flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off;
   4795  1.1  dholland 			else
   4796  1.1  dholland 				flp->nfsfl_end = flp->nfsfl_off + retlen;
   4797  1.1  dholland 			flp->nfsfl_iomode = fxdr_unsigned(int, *tl++);
   4798  1.1  dholland 			if (gotiomode == -1)
   4799  1.1  dholland 				gotiomode = flp->nfsfl_iomode;
   4800  1.1  dholland 			NFSCL_DEBUG(4, "layg reqiom=%d retiom=%d\n", iomode,
   4801  1.1  dholland 			    (int)flp->nfsfl_iomode);
   4802  1.1  dholland 			if (fxdr_unsigned(int, *tl++) !=
   4803  1.1  dholland 			    NFSLAYOUT_NFSV4_1_FILES) {
   4804  1.1  dholland 				printf("NFSv4.1: got non-files layout\n");
   4805  1.1  dholland 				error = NFSERR_BADXDR;
   4806  1.1  dholland 				goto nfsmout;
   4807  1.1  dholland 			}
   4808  1.1  dholland 			NFSBCOPY(++tl, flp->nfsfl_dev, NFSX_V4DEVICEID);
   4809  1.1  dholland 			tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
   4810  1.1  dholland 			flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++);
   4811  1.1  dholland 			NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util);
   4812  1.1  dholland 			flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++);
   4813  1.1  dholland 			flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2;
   4814  1.1  dholland 			if (fxdr_unsigned(int, *tl) != fhcnt) {
   4815  1.1  dholland 				printf("EEK! bad fhcnt\n");
   4816  1.1  dholland 				error = NFSERR_BADXDR;
   4817  1.1  dholland 				goto nfsmout;
   4818  1.1  dholland 			}
   4819  1.1  dholland 			for (j = 0; j < fhcnt; j++) {
   4820  1.1  dholland 				NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
   4821  1.1  dholland 				nfhlen = fxdr_unsigned(int, *tl);
   4822  1.1  dholland 				if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) {
   4823  1.1  dholland 					error = NFSERR_BADXDR;
   4824  1.1  dholland 					goto nfsmout;
   4825  1.1  dholland 				}
   4826  1.1  dholland 				nfhp = malloc(sizeof(*nfhp) + nfhlen - 1,
   4827  1.1  dholland 				    M_NFSFH, M_WAITOK);
   4828  1.1  dholland 				flp->nfsfl_fh[j] = nfhp;
   4829  1.1  dholland 				flp->nfsfl_fhcnt++;
   4830  1.1  dholland 				nfhp->nfh_len = nfhlen;
   4831  1.1  dholland 				NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen));
   4832  1.1  dholland 				NFSBCOPY(cp, nfhp->nfh_fh, nfhlen);
   4833  1.1  dholland 			}
   4834  1.1  dholland 			if (flp->nfsfl_iomode == gotiomode) {
   4835  1.1  dholland 				/* Keep the list in increasing offset order. */
   4836  1.1  dholland 				tflp = LIST_FIRST(flhp);
   4837  1.1  dholland 				prevflp = NULL;
   4838  1.1  dholland 				while (tflp != NULL &&
   4839  1.1  dholland 				    tflp->nfsfl_off < flp->nfsfl_off) {
   4840  1.1  dholland 					prevflp = tflp;
   4841  1.1  dholland 					tflp = LIST_NEXT(tflp, nfsfl_list);
   4842  1.1  dholland 				}
   4843  1.1  dholland 				if (prevflp == NULL)
   4844  1.1  dholland 					LIST_INSERT_HEAD(flhp, flp, nfsfl_list);
   4845  1.1  dholland 				else
   4846  1.1  dholland 					LIST_INSERT_AFTER(prevflp, flp,
   4847  1.1  dholland 					    nfsfl_list);
   4848  1.1  dholland 			} else {
   4849  1.1  dholland 				printf("nfscl_layoutget(): got wrong iomode\n");
   4850  1.1  dholland 				nfscl_freeflayout(flp);
   4851  1.1  dholland 			}
   4852  1.1  dholland 			flp = NULL;
   4853  1.1  dholland 		}
   4854  1.1  dholland 	}
   4855  1.1  dholland 	if (nd->nd_repstat != 0 && error == 0)
   4856  1.1  dholland 		error = nd->nd_repstat;
   4857  1.1  dholland nfsmout:
   4858  1.1  dholland 	if (error != 0 && flp != NULL)
   4859  1.1  dholland 		nfscl_freeflayout(flp);
   4860  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   4861  1.1  dholland 	return (error);
   4862  1.1  dholland }
   4863  1.1  dholland 
   4864  1.1  dholland /*
   4865  1.1  dholland  * Do the NFSv4.1 Get Device Info.
   4866  1.1  dholland  */
   4867  1.1  dholland int
   4868  1.1  dholland nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype,
   4869  1.1  dholland     uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred,
   4870  1.1  dholland     NFSPROC_T *p)
   4871  1.1  dholland {
   4872  1.1  dholland 	uint32_t cnt, *tl;
   4873  1.1  dholland 	struct nfsrv_descript nfsd;
   4874  1.1  dholland 	struct nfsrv_descript *nd = &nfsd;
   4875  1.1  dholland 	struct sockaddr_storage ss;
   4876  1.1  dholland 	struct nfsclds *dsp = NULL, **dspp;
   4877  1.1  dholland 	struct nfscldevinfo *ndi;
   4878  1.1  dholland 	int addrcnt, bitcnt, error, i, isudp, j, pos, safilled, stripecnt;
   4879  1.1  dholland 	uint8_t stripeindex;
   4880  1.1  dholland 
   4881  1.1  dholland 	*ndip = NULL;
   4882  1.1  dholland 	ndi = NULL;
   4883  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL);
   4884  1.1  dholland 	NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED);
   4885  1.1  dholland 	NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID);
   4886  1.1  dholland 	tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
   4887  1.1  dholland 	*tl++ = txdr_unsigned(layouttype);
   4888  1.1  dholland 	*tl++ = txdr_unsigned(100000);
   4889  1.1  dholland 	if (notifybitsp != NULL && *notifybitsp != 0) {
   4890  1.1  dholland 		*tl = txdr_unsigned(1);		/* One word of bits. */
   4891  1.1  dholland 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
   4892  1.1  dholland 		*tl = txdr_unsigned(*notifybitsp);
   4893  1.1  dholland 	} else
   4894  1.1  dholland 		*tl = txdr_unsigned(0);
   4895  1.1  dholland 	nd->nd_flag |= ND_USEGSSNAME;
   4896  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
   4897  1.1  dholland 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
   4898  1.1  dholland 	if (error != 0)
   4899  1.1  dholland 		return (error);
   4900  1.1  dholland 	if (nd->nd_repstat == 0) {
   4901  1.1  dholland 		NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED);
   4902  1.1  dholland 		if (layouttype != fxdr_unsigned(int, *tl++))
   4903  1.1  dholland 			printf("EEK! devinfo layout type not same!\n");
   4904  1.1  dholland 		stripecnt = fxdr_unsigned(int, *++tl);
   4905  1.1  dholland 		NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt);
   4906  1.1  dholland 		if (stripecnt < 1 || stripecnt > 4096) {
   4907  1.1  dholland 			printf("NFS devinfo stripecnt %d: out of range\n",
   4908  1.1  dholland 			    stripecnt);
   4909  1.1  dholland 			error = NFSERR_BADXDR;
   4910  1.1  dholland 			goto nfsmout;
   4911  1.1  dholland 		}
   4912  1.1  dholland 		NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) * NFSX_UNSIGNED);
   4913  1.1  dholland 		addrcnt = fxdr_unsigned(int, *(tl + stripecnt));
   4914  1.1  dholland 		NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt);
   4915  1.1  dholland 		if (addrcnt < 1 || addrcnt > 128) {
   4916  1.1  dholland 			printf("NFS devinfo addrcnt %d: out of range\n",
   4917  1.1  dholland 			    addrcnt);
   4918  1.1  dholland 			error = NFSERR_BADXDR;
   4919  1.1  dholland 			goto nfsmout;
   4920  1.1  dholland 		}
   4921  1.1  dholland 
   4922  1.1  dholland 		/*
   4923  1.1  dholland 		 * Now we know how many stripe indices and addresses, so
   4924  1.1  dholland 		 * we can allocate the structure the correct size.
   4925  1.1  dholland 		 */
   4926  1.1  dholland 		i = (stripecnt * sizeof(uint8_t)) / sizeof(struct nfsclds *)
   4927  1.1  dholland 		    + 1;
   4928  1.1  dholland 		NFSCL_DEBUG(4, "stripeindices=%d\n", i);
   4929  1.1  dholland 		ndi = malloc(sizeof(*ndi) + (addrcnt + i) *
   4930  1.1  dholland 		    sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK | M_ZERO);
   4931  1.1  dholland 		NFSBCOPY(deviceid, ndi->nfsdi_deviceid, NFSX_V4DEVICEID);
   4932  1.1  dholland 		ndi->nfsdi_refcnt = 0;
   4933  1.1  dholland 		ndi->nfsdi_stripecnt = stripecnt;
   4934  1.1  dholland 		ndi->nfsdi_addrcnt = addrcnt;
   4935  1.1  dholland 		/* Fill in the stripe indices. */
   4936  1.1  dholland 		for (i = 0; i < stripecnt; i++) {
   4937  1.1  dholland 			stripeindex = fxdr_unsigned(uint8_t, *tl++);
   4938  1.1  dholland 			NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex);
   4939  1.1  dholland 			if (stripeindex >= addrcnt) {
   4940  1.1  dholland 				printf("NFS devinfo stripeindex %d: too big\n",
   4941  1.1  dholland 				    (int)stripeindex);
   4942  1.1  dholland 				error = NFSERR_BADXDR;
   4943  1.1  dholland 				goto nfsmout;
   4944  1.1  dholland 			}
   4945  1.1  dholland 			nfsfldi_setstripeindex(ndi, i, stripeindex);
   4946  1.1  dholland 		}
   4947  1.1  dholland 
   4948  1.1  dholland 		/* Now, dissect the server address(es). */
   4949  1.1  dholland 		safilled = 0;
   4950  1.1  dholland 		for (i = 0; i < addrcnt; i++) {
   4951  1.1  dholland 			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
   4952  1.1  dholland 			cnt = fxdr_unsigned(uint32_t, *tl);
   4953  1.1  dholland 			if (cnt == 0) {
   4954  1.1  dholland 				printf("NFS devinfo 0 len addrlist\n");
   4955  1.1  dholland 				error = NFSERR_BADXDR;
   4956  1.1  dholland 				goto nfsmout;
   4957  1.1  dholland 			}
   4958  1.1  dholland 			dspp = nfsfldi_addr(ndi, i);
   4959  1.1  dholland 			pos = arc4random() % cnt;	/* Choose one. */
   4960  1.1  dholland 			safilled = 0;
   4961  1.1  dholland 			for (j = 0; j < cnt; j++) {
   4962  1.1  dholland 				error = nfsv4_getipaddr(nd, &ss, &isudp);
   4963  1.1  dholland 				if (error != 0 && error != EPERM) {
   4964  1.1  dholland 					error = NFSERR_BADXDR;
   4965  1.1  dholland 					goto nfsmout;
   4966  1.1  dholland 				}
   4967  1.1  dholland 				if (error == 0 && isudp == 0) {
   4968  1.1  dholland 					/*
   4969  1.1  dholland 					 * The algorithm is:
   4970  1.1  dholland 					 * - use "pos" entry if it is of the
   4971  1.1  dholland 					 *   same af_family or none of them
   4972  1.1  dholland 					 *   is of the same af_family
   4973  1.1  dholland 					 * else
   4974  1.1  dholland 					 * - use the first one of the same
   4975  1.1  dholland 					 *   af_family.
   4976  1.1  dholland 					 */
   4977  1.1  dholland 					if ((safilled == 0 && ss.ss_family ==
   4978  1.1  dholland 					     nmp->nm_nam->sa_family) ||
   4979  1.1  dholland 					    (j == pos &&
   4980  1.1  dholland 					     (safilled == 0 || ss.ss_family ==
   4981  1.1  dholland 					      nmp->nm_nam->sa_family)) ||
   4982  1.1  dholland 					    (safilled == 1 && ss.ss_family ==
   4983  1.1  dholland 					     nmp->nm_nam->sa_family)) {
   4984  1.1  dholland 						error = nfsrpc_fillsa(nmp, &ss,
   4985  1.1  dholland 						    &dsp, p);
   4986  1.1  dholland 						if (error == 0) {
   4987  1.1  dholland 							*dspp = dsp;
   4988  1.1  dholland 							if (ss.ss_family ==
   4989  1.1  dholland 							 nmp->nm_nam->sa_family)
   4990  1.1  dholland 								safilled = 2;
   4991  1.1  dholland 							else
   4992  1.1  dholland 								safilled = 1;
   4993  1.1  dholland 						}
   4994  1.1  dholland 					}
   4995  1.1  dholland 				}
   4996  1.1  dholland 			}
   4997  1.1  dholland 			if (safilled == 0)
   4998  1.1  dholland 				break;
   4999  1.1  dholland 		}
   5000  1.1  dholland 
   5001  1.1  dholland 		/* And the notify bits. */
   5002  1.1  dholland 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
   5003  1.1  dholland 		if (safilled != 0) {
   5004  1.1  dholland 			bitcnt = fxdr_unsigned(int, *tl);
   5005  1.1  dholland 			if (bitcnt > 0) {
   5006  1.1  dholland 				NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
   5007  1.1  dholland 				if (notifybitsp != NULL)
   5008  1.1  dholland 					*notifybitsp =
   5009  1.1  dholland 					    fxdr_unsigned(uint32_t, *tl);
   5010  1.1  dholland 			}
   5011  1.1  dholland 			*ndip = ndi;
   5012  1.1  dholland 		} else
   5013  1.1  dholland 			error = EPERM;
   5014  1.1  dholland 	}
   5015  1.1  dholland 	if (nd->nd_repstat != 0)
   5016  1.1  dholland 		error = nd->nd_repstat;
   5017  1.1  dholland nfsmout:
   5018  1.1  dholland 	if (error != 0 && ndi != NULL)
   5019  1.1  dholland 		nfscl_freedevinfo(ndi);
   5020  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   5021  1.1  dholland 	return (error);
   5022  1.1  dholland }
   5023  1.1  dholland 
   5024  1.1  dholland /*
   5025  1.1  dholland  * Do the NFSv4.1 LayoutCommit.
   5026  1.1  dholland  */
   5027  1.1  dholland int
   5028  1.1  dholland nfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
   5029  1.1  dholland     uint64_t off, uint64_t len, uint64_t lastbyte, nfsv4stateid_t *stateidp,
   5030  1.1  dholland     int layouttype, int layoutupdatecnt, uint8_t *layp, struct ucred *cred,
   5031  1.1  dholland     NFSPROC_T *p, void *stuff)
   5032  1.1  dholland {
   5033  1.1  dholland 	uint32_t *tl;
   5034  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   5035  1.1  dholland 	int error, outcnt, i;
   5036  1.1  dholland 	uint8_t *cp;
   5037  1.1  dholland 
   5038  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL);
   5039  1.1  dholland 	NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
   5040  1.1  dholland 	    NFSX_STATEID);
   5041  1.1  dholland 	txdr_hyper(off, tl);
   5042  1.1  dholland 	tl += 2;
   5043  1.1  dholland 	txdr_hyper(len, tl);
   5044  1.1  dholland 	tl += 2;
   5045  1.1  dholland 	if (reclaim != 0)
   5046  1.1  dholland 		*tl++ = newnfs_true;
   5047  1.1  dholland 	else
   5048  1.1  dholland 		*tl++ = newnfs_false;
   5049  1.1  dholland 	*tl++ = txdr_unsigned(stateidp->seqid);
   5050  1.1  dholland 	*tl++ = stateidp->other[0];
   5051  1.1  dholland 	*tl++ = stateidp->other[1];
   5052  1.1  dholland 	*tl++ = stateidp->other[2];
   5053  1.1  dholland 	*tl++ = newnfs_true;
   5054  1.1  dholland 	if (lastbyte < off)
   5055  1.1  dholland 		lastbyte = off;
   5056  1.1  dholland 	else if (lastbyte >= (off + len))
   5057  1.1  dholland 		lastbyte = off + len - 1;
   5058  1.1  dholland 	txdr_hyper(lastbyte, tl);
   5059  1.1  dholland 	tl += 2;
   5060  1.1  dholland 	*tl++ = newnfs_false;
   5061  1.1  dholland 	*tl++ = txdr_unsigned(layouttype);
   5062  1.1  dholland 	*tl = txdr_unsigned(layoutupdatecnt);
   5063  1.1  dholland 	if (layoutupdatecnt > 0) {
   5064  1.1  dholland 		KASSERT(layouttype != NFSLAYOUT_NFSV4_1_FILES,
   5065  1.1  dholland 		    ("Must be nil for Files Layout"));
   5066  1.1  dholland 		outcnt = NFSM_RNDUP(layoutupdatecnt);
   5067  1.1  dholland 		NFSM_BUILD(cp, uint8_t *, outcnt);
   5068  1.1  dholland 		NFSBCOPY(layp, cp, layoutupdatecnt);
   5069  1.1  dholland 		cp += layoutupdatecnt;
   5070  1.1  dholland 		for (i = 0; i < (outcnt - layoutupdatecnt); i++)
   5071  1.1  dholland 			*cp++ = 0x0;
   5072  1.1  dholland 	}
   5073  1.1  dholland 	nd->nd_flag |= ND_USEGSSNAME;
   5074  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
   5075  1.1  dholland 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
   5076  1.1  dholland 	if (error != 0)
   5077  1.1  dholland 		return (error);
   5078  1.1  dholland 	error = nd->nd_repstat;
   5079  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   5080  1.1  dholland 	return (error);
   5081  1.1  dholland }
   5082  1.1  dholland 
   5083  1.1  dholland /*
   5084  1.1  dholland  * Do the NFSv4.1 LayoutReturn.
   5085  1.1  dholland  */
   5086  1.1  dholland int
   5087  1.1  dholland nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
   5088  1.1  dholland     int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset,
   5089  1.1  dholland     uint64_t len, nfsv4stateid_t *stateidp, int layoutcnt, uint32_t *layp,
   5090  1.1  dholland     struct ucred *cred, NFSPROC_T *p, void *stuff)
   5091  1.1  dholland {
   5092  1.1  dholland 	uint32_t *tl;
   5093  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   5094  1.1  dholland 	int error, outcnt, i;
   5095  1.1  dholland 	uint8_t *cp;
   5096  1.1  dholland 
   5097  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL);
   5098  1.1  dholland 	NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
   5099  1.1  dholland 	if (reclaim != 0)
   5100  1.1  dholland 		*tl++ = newnfs_true;
   5101  1.1  dholland 	else
   5102  1.1  dholland 		*tl++ = newnfs_false;
   5103  1.1  dholland 	*tl++ = txdr_unsigned(layouttype);
   5104  1.1  dholland 	*tl++ = txdr_unsigned(iomode);
   5105  1.1  dholland 	*tl = txdr_unsigned(layoutreturn);
   5106  1.1  dholland 	if (layoutreturn == NFSLAYOUTRETURN_FILE) {
   5107  1.1  dholland 		NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
   5108  1.1  dholland 		    NFSX_UNSIGNED);
   5109  1.1  dholland 		txdr_hyper(offset, tl);
   5110  1.1  dholland 		tl += 2;
   5111  1.1  dholland 		txdr_hyper(len, tl);
   5112  1.1  dholland 		tl += 2;
   5113  1.1  dholland 		NFSCL_DEBUG(4, "layoutret stseq=%d\n", (int)stateidp->seqid);
   5114  1.1  dholland 		*tl++ = txdr_unsigned(stateidp->seqid);
   5115  1.1  dholland 		*tl++ = stateidp->other[0];
   5116  1.1  dholland 		*tl++ = stateidp->other[1];
   5117  1.1  dholland 		*tl++ = stateidp->other[2];
   5118  1.1  dholland 		*tl = txdr_unsigned(layoutcnt);
   5119  1.1  dholland 		if (layoutcnt > 0) {
   5120  1.1  dholland 			outcnt = NFSM_RNDUP(layoutcnt);
   5121  1.1  dholland 			NFSM_BUILD(cp, uint8_t *, outcnt);
   5122  1.1  dholland 			NFSBCOPY(layp, cp, layoutcnt);
   5123  1.1  dholland 			cp += layoutcnt;
   5124  1.1  dholland 			for (i = 0; i < (outcnt - layoutcnt); i++)
   5125  1.1  dholland 				*cp++ = 0x0;
   5126  1.1  dholland 		}
   5127  1.1  dholland 	}
   5128  1.1  dholland 	nd->nd_flag |= ND_USEGSSNAME;
   5129  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
   5130  1.1  dholland 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
   5131  1.1  dholland 	if (error != 0)
   5132  1.1  dholland 		return (error);
   5133  1.1  dholland 	if (nd->nd_repstat == 0) {
   5134  1.1  dholland 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
   5135  1.1  dholland 		if (*tl != 0) {
   5136  1.1  dholland 			NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
   5137  1.1  dholland 			stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
   5138  1.1  dholland 			stateidp->other[0] = *tl++;
   5139  1.1  dholland 			stateidp->other[1] = *tl++;
   5140  1.1  dholland 			stateidp->other[2] = *tl;
   5141  1.1  dholland 		}
   5142  1.1  dholland 	} else
   5143  1.1  dholland 		error = nd->nd_repstat;
   5144  1.1  dholland nfsmout:
   5145  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   5146  1.1  dholland 	return (error);
   5147  1.1  dholland }
   5148  1.1  dholland 
   5149  1.1  dholland /*
   5150  1.1  dholland  * Acquire a layout and devinfo, if possible. The caller must have acquired
   5151  1.1  dholland  * a reference count on the nfsclclient structure before calling this.
   5152  1.1  dholland  * Return the layout in lypp with a reference count on it, if successful.
   5153  1.1  dholland  */
   5154  1.1  dholland static int
   5155  1.1  dholland nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp,
   5156  1.1  dholland     int iomode, uint32_t *notifybitsp, nfsv4stateid_t *stateidp, uint64_t off,
   5157  1.1  dholland     struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p)
   5158  1.1  dholland {
   5159  1.1  dholland 	struct nfscllayout *lyp;
   5160  1.1  dholland 	struct nfsclflayout *flp, *tflp;
   5161  1.1  dholland 	struct nfscldevinfo *dip;
   5162  1.1  dholland 	struct nfsclflayouthead flh;
   5163  1.1  dholland 	int error = 0, islocked, layoutlen, recalled, retonclose;
   5164  1.1  dholland 	nfsv4stateid_t stateid;
   5165  1.1  dholland 
   5166  1.1  dholland 	*lypp = NULL;
   5167  1.1  dholland 	/*
   5168  1.1  dholland 	 * If lyp is returned non-NULL, there will be a refcnt (shared lock)
   5169  1.1  dholland 	 * on it, iff flp != NULL or a lock (exclusive lock) on it iff
   5170  1.1  dholland 	 * flp == NULL.
   5171  1.1  dholland 	 */
   5172  1.1  dholland 	lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len,
   5173  1.1  dholland 	    off, &flp, &recalled);
   5174  1.1  dholland 	islocked = 0;
   5175  1.1  dholland 	if (lyp == NULL || flp == NULL) {
   5176  1.1  dholland 		if (recalled != 0)
   5177  1.1  dholland 			return (EIO);
   5178  1.1  dholland 		LIST_INIT(&flh);
   5179  1.1  dholland 		layoutlen = NFSMNT_MDSSESSION(nmp)->nfsess_maxcache -
   5180  1.1  dholland 		    (NFSX_STATEID + 3 * NFSX_UNSIGNED);
   5181  1.1  dholland 		if (lyp == NULL) {
   5182  1.1  dholland 			stateid.seqid = 0;
   5183  1.1  dholland 			stateid.other[0] = stateidp->other[0];
   5184  1.1  dholland 			stateid.other[1] = stateidp->other[1];
   5185  1.1  dholland 			stateid.other[2] = stateidp->other[2];
   5186  1.1  dholland 			error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
   5187  1.1  dholland 			    nfhp->nfh_len, iomode, (uint64_t)0, INT64_MAX,
   5188  1.1  dholland 			    (uint64_t)0, layoutlen, &stateid, &retonclose,
   5189  1.1  dholland 			    &flh, cred, p, NULL);
   5190  1.1  dholland 		} else {
   5191  1.1  dholland 			islocked = 1;
   5192  1.1  dholland 			stateid.seqid = lyp->nfsly_stateid.seqid;
   5193  1.1  dholland 			stateid.other[0] = lyp->nfsly_stateid.other[0];
   5194  1.1  dholland 			stateid.other[1] = lyp->nfsly_stateid.other[1];
   5195  1.1  dholland 			stateid.other[2] = lyp->nfsly_stateid.other[2];
   5196  1.1  dholland 			error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
   5197  1.1  dholland 			    nfhp->nfh_len, iomode, off, INT64_MAX,
   5198  1.1  dholland 			    (uint64_t)0, layoutlen, &stateid, &retonclose,
   5199  1.1  dholland 			    &flh, cred, p, NULL);
   5200  1.1  dholland 		}
   5201  1.1  dholland 		if (error == 0)
   5202  1.1  dholland 			LIST_FOREACH(tflp, &flh, nfsfl_list) {
   5203  1.1  dholland 				error = nfscl_adddevinfo(nmp, NULL, tflp);
   5204  1.1  dholland 				if (error != 0) {
   5205  1.1  dholland 					error = nfsrpc_getdeviceinfo(nmp,
   5206  1.1  dholland 					    tflp->nfsfl_dev,
   5207  1.1  dholland 					    NFSLAYOUT_NFSV4_1_FILES,
   5208  1.1  dholland 					    notifybitsp, &dip, cred, p);
   5209  1.1  dholland 					if (error != 0)
   5210  1.1  dholland 						break;
   5211  1.1  dholland 					error = nfscl_adddevinfo(nmp, dip,
   5212  1.1  dholland 					    tflp);
   5213  1.1  dholland 					if (error != 0)
   5214  1.1  dholland 						printf(
   5215  1.1  dholland 						    "getlayout: cannot add\n");
   5216  1.1  dholland 				}
   5217  1.1  dholland 			}
   5218  1.1  dholland 		if (error == 0) {
   5219  1.1  dholland 			/*
   5220  1.1  dholland 			 * nfscl_layout() always returns with the nfsly_lock
   5221  1.1  dholland 			 * set to a refcnt (shared lock).
   5222  1.1  dholland 			 */
   5223  1.1  dholland 			error = nfscl_layout(nmp, vp, nfhp->nfh_fh,
   5224  1.1  dholland 			    nfhp->nfh_len, &stateid, retonclose, &flh, &lyp,
   5225  1.1  dholland 			    cred, p);
   5226  1.1  dholland 			if (error == 0)
   5227  1.1  dholland 				*lypp = lyp;
   5228  1.1  dholland 		} else if (islocked != 0)
   5229  1.1  dholland 			nfsv4_unlock(&lyp->nfsly_lock, 0);
   5230  1.1  dholland 	} else
   5231  1.1  dholland 		*lypp = lyp;
   5232  1.1  dholland 	return (error);
   5233  1.1  dholland }
   5234  1.1  dholland 
   5235  1.1  dholland /*
   5236  1.1  dholland  * Do a TCP connection plus exchange id and create session.
   5237  1.1  dholland  * If successful, a "struct nfsclds" is linked into the list for the
   5238  1.1  dholland  * mount point and a pointer to it is returned.
   5239  1.1  dholland  */
   5240  1.1  dholland static int
   5241  1.1  dholland nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_storage *ssp,
   5242  1.1  dholland     struct nfsclds **dspp, NFSPROC_T *p)
   5243  1.1  dholland {
   5244  1.1  dholland 	struct sockaddr_in *msad, *sad, *ssd;
   5245  1.1  dholland 	struct sockaddr_in6 *msad6, *sad6, *ssd6;
   5246  1.1  dholland 	struct nfsclclient *clp;
   5247  1.1  dholland 	struct nfssockreq *nrp;
   5248  1.1  dholland 	struct nfsclds *dsp, *tdsp;
   5249  1.1  dholland 	int error;
   5250  1.1  dholland 	enum nfsclds_state retv;
   5251  1.1  dholland 	uint32_t sequenceid;
   5252  1.1  dholland 
   5253  1.1  dholland 	KASSERT(nmp->nm_sockreq.nr_cred != NULL,
   5254  1.1  dholland 	    ("nfsrpc_fillsa: NULL nr_cred"));
   5255  1.1  dholland 	NFSLOCKCLSTATE();
   5256  1.1  dholland 	clp = nmp->nm_clp;
   5257  1.1  dholland 	NFSUNLOCKCLSTATE();
   5258  1.1  dholland 	if (clp == NULL)
   5259  1.1  dholland 		return (EPERM);
   5260  1.1  dholland 	if (ssp->ss_family == AF_INET) {
   5261  1.1  dholland 		ssd = (struct sockaddr_in *)ssp;
   5262  1.1  dholland 		NFSLOCKMNT(nmp);
   5263  1.1  dholland 
   5264  1.1  dholland 		/*
   5265  1.1  dholland 		 * Check to see if we already have a session for this
   5266  1.1  dholland 		 * address that is usable for a DS.
   5267  1.1  dholland 		 * Note that the MDS's address is in a different place
   5268  1.1  dholland 		 * than the sessions already acquired for DS's.
   5269  1.1  dholland 		 */
   5270  1.1  dholland 		msad = (struct sockaddr_in *)nmp->nm_sockreq.nr_nam;
   5271  1.1  dholland 		tdsp = TAILQ_FIRST(&nmp->nm_sess);
   5272  1.1  dholland 		while (tdsp != NULL) {
   5273  1.1  dholland 			if (msad != NULL && msad->sin_family == AF_INET &&
   5274  1.1  dholland 			    ssd->sin_addr.s_addr == msad->sin_addr.s_addr &&
   5275  1.1  dholland 			    ssd->sin_port == msad->sin_port &&
   5276  1.1  dholland 			    (tdsp->nfsclds_flags & NFSCLDS_DS) != 0) {
   5277  1.1  dholland 				*dspp = tdsp;
   5278  1.1  dholland 				NFSUNLOCKMNT(nmp);
   5279  1.1  dholland 				NFSCL_DEBUG(4, "fnd same addr\n");
   5280  1.1  dholland 				return (0);
   5281  1.1  dholland 			}
   5282  1.1  dholland 			tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
   5283  1.1  dholland 			if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
   5284  1.1  dholland 				msad = (struct sockaddr_in *)
   5285  1.1  dholland 				    tdsp->nfsclds_sockp->nr_nam;
   5286  1.1  dholland 			else
   5287  1.1  dholland 				msad = NULL;
   5288  1.1  dholland 		}
   5289  1.1  dholland 		NFSUNLOCKMNT(nmp);
   5290  1.1  dholland 
   5291  1.1  dholland 		/* No IP address match, so look for new/trunked one. */
   5292  1.1  dholland 		sad = malloc(sizeof(*sad), M_SONAME, M_WAITOK | M_ZERO);
   5293  1.1  dholland 		sad->sin_len = sizeof(*sad);
   5294  1.1  dholland 		sad->sin_family = AF_INET;
   5295  1.1  dholland 		sad->sin_port = ssd->sin_port;
   5296  1.1  dholland 		sad->sin_addr.s_addr = ssd->sin_addr.s_addr;
   5297  1.1  dholland 		nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO);
   5298  1.1  dholland 		nrp->nr_nam = (struct sockaddr *)sad;
   5299  1.1  dholland 	} else if (ssp->ss_family == AF_INET6) {
   5300  1.1  dholland 		ssd6 = (struct sockaddr_in6 *)ssp;
   5301  1.1  dholland 		NFSLOCKMNT(nmp);
   5302  1.1  dholland 
   5303  1.1  dholland 		/*
   5304  1.1  dholland 		 * Check to see if we already have a session for this
   5305  1.1  dholland 		 * address that is usable for a DS.
   5306  1.1  dholland 		 * Note that the MDS's address is in a different place
   5307  1.1  dholland 		 * than the sessions already acquired for DS's.
   5308  1.1  dholland 		 */
   5309  1.1  dholland 		msad6 = (struct sockaddr_in6 *)nmp->nm_sockreq.nr_nam;
   5310  1.1  dholland 		tdsp = TAILQ_FIRST(&nmp->nm_sess);
   5311  1.1  dholland 		while (tdsp != NULL) {
   5312  1.1  dholland 			if (msad6 != NULL && msad6->sin6_family == AF_INET6 &&
   5313  1.1  dholland 			    IN6_ARE_ADDR_EQUAL(&ssd6->sin6_addr,
   5314  1.1  dholland 			    &msad6->sin6_addr) &&
   5315  1.1  dholland 			    ssd6->sin6_port == msad6->sin6_port &&
   5316  1.1  dholland 			    (tdsp->nfsclds_flags & NFSCLDS_DS) != 0) {
   5317  1.1  dholland 				*dspp = tdsp;
   5318  1.1  dholland 				NFSUNLOCKMNT(nmp);
   5319  1.1  dholland 				return (0);
   5320  1.1  dholland 			}
   5321  1.1  dholland 			tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
   5322  1.1  dholland 			if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
   5323  1.1  dholland 				msad6 = (struct sockaddr_in6 *)
   5324  1.1  dholland 				    tdsp->nfsclds_sockp->nr_nam;
   5325  1.1  dholland 			else
   5326  1.1  dholland 				msad6 = NULL;
   5327  1.1  dholland 		}
   5328  1.1  dholland 		NFSUNLOCKMNT(nmp);
   5329  1.1  dholland 
   5330  1.1  dholland 		/* No IP address match, so look for new/trunked one. */
   5331  1.1  dholland 		sad6 = malloc(sizeof(*sad6), M_SONAME, M_WAITOK | M_ZERO);
   5332  1.1  dholland 		sad6->sin6_len = sizeof(*sad6);
   5333  1.1  dholland 		sad6->sin6_family = AF_INET6;
   5334  1.1  dholland 		sad6->sin6_port = ssd6->sin6_port;
   5335  1.1  dholland 		NFSBCOPY(&ssd6->sin6_addr, &sad6->sin6_addr,
   5336  1.1  dholland 		    sizeof(struct in6_addr));
   5337  1.1  dholland 		nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO);
   5338  1.1  dholland 		nrp->nr_nam = (struct sockaddr *)sad6;
   5339  1.1  dholland 	} else
   5340  1.1  dholland 		return (EPERM);
   5341  1.1  dholland 
   5342  1.1  dholland 	nrp->nr_sotype = SOCK_STREAM;
   5343  1.1  dholland 	mtx_init(&nrp->nr_mtx, "nfssock", NULL, MTX_DEF);
   5344  1.1  dholland 	nrp->nr_prog = NFS_PROG;
   5345  1.1  dholland 	nrp->nr_vers = NFS_VER4;
   5346  1.1  dholland 
   5347  1.1  dholland 	/*
   5348  1.1  dholland 	 * Use the credentials that were used for the mount, which are
   5349  1.1  dholland 	 * in nmp->nm_sockreq.nr_cred for newnfs_connect() etc.
   5350  1.1  dholland 	 * Ref. counting the credentials with crhold() is probably not
   5351  1.1  dholland 	 * necessary, since nm_sockreq.nr_cred won't be crfree()'d until
   5352  1.1  dholland 	 * unmount, but I did it anyhow.
   5353  1.1  dholland 	 */
   5354  1.1  dholland 	nrp->nr_cred = crhold(nmp->nm_sockreq.nr_cred);
   5355  1.1  dholland 	error = newnfs_connect(nmp, nrp, NULL, p, 0);
   5356  1.1  dholland 	NFSCL_DEBUG(3, "DS connect=%d\n", error);
   5357  1.1  dholland 
   5358  1.1  dholland 	/* Now, do the exchangeid and create session. */
   5359  1.1  dholland 	if (error == 0)
   5360  1.1  dholland 		error = nfsrpc_exchangeid(nmp, clp, nrp, NFSV4EXCH_USEPNFSDS,
   5361  1.1  dholland 		    &dsp, nrp->nr_cred, p);
   5362  1.1  dholland 	NFSCL_DEBUG(3, "DS exchangeid=%d\n", error);
   5363  1.1  dholland 	if (error == 0) {
   5364  1.1  dholland 		dsp->nfsclds_sockp = nrp;
   5365  1.1  dholland 		NFSLOCKMNT(nmp);
   5366  1.1  dholland 		retv = nfscl_getsameserver(nmp, dsp, &tdsp);
   5367  1.1  dholland 		NFSCL_DEBUG(3, "getsame ret=%d\n", retv);
   5368  1.1  dholland 		if (retv == NFSDSP_USETHISSESSION) {
   5369  1.1  dholland 			NFSUNLOCKMNT(nmp);
   5370  1.1  dholland 			/*
   5371  1.1  dholland 			 * If there is already a session for this server,
   5372  1.1  dholland 			 * use it.
   5373  1.1  dholland 			 */
   5374  1.1  dholland 			(void)newnfs_disconnect(nrp);
   5375  1.1  dholland 			nfscl_freenfsclds(dsp);
   5376  1.1  dholland 			*dspp = tdsp;
   5377  1.1  dholland 			return (0);
   5378  1.1  dholland 		}
   5379  1.1  dholland 		if (retv == NFSDSP_SEQTHISSESSION)
   5380  1.1  dholland 			sequenceid = tdsp->nfsclds_sess.nfsess_sequenceid;
   5381  1.1  dholland 		else
   5382  1.1  dholland 			sequenceid = dsp->nfsclds_sess.nfsess_sequenceid;
   5383  1.1  dholland 		NFSUNLOCKMNT(nmp);
   5384  1.1  dholland 		error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
   5385  1.1  dholland 		    nrp, sequenceid, 0, nrp->nr_cred, p);
   5386  1.1  dholland 		NFSCL_DEBUG(3, "DS createsess=%d\n", error);
   5387  1.1  dholland 	} else {
   5388  1.1  dholland 		NFSFREECRED(nrp->nr_cred);
   5389  1.1  dholland 		NFSFREEMUTEX(&nrp->nr_mtx);
   5390  1.1  dholland 		free(nrp->nr_nam, M_SONAME);
   5391  1.1  dholland 		free(nrp, M_NFSSOCKREQ);
   5392  1.1  dholland 	}
   5393  1.1  dholland 	if (error == 0) {
   5394  1.1  dholland 		NFSCL_DEBUG(3, "add DS session\n");
   5395  1.1  dholland 		/*
   5396  1.1  dholland 		 * Put it at the end of the list. That way the list
   5397  1.1  dholland 		 * is ordered by when the entry was added. This matters
   5398  1.1  dholland 		 * since the one done first is the one that should be
   5399  1.1  dholland 		 * used for sequencid'ing any subsequent create sessions.
   5400  1.1  dholland 		 */
   5401  1.1  dholland 		NFSLOCKMNT(nmp);
   5402  1.1  dholland 		TAILQ_INSERT_TAIL(&nmp->nm_sess, dsp, nfsclds_list);
   5403  1.1  dholland 		NFSUNLOCKMNT(nmp);
   5404  1.1  dholland 		*dspp = dsp;
   5405  1.1  dholland 	} else if (dsp != NULL)
   5406  1.1  dholland 		nfscl_freenfsclds(dsp);
   5407  1.1  dholland 	return (error);
   5408  1.1  dholland }
   5409  1.1  dholland 
   5410  1.1  dholland /*
   5411  1.1  dholland  * Do the NFSv4.1 Reclaim Complete.
   5412  1.1  dholland  */
   5413  1.1  dholland int
   5414  1.1  dholland nfsrpc_reclaimcomplete(struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p)
   5415  1.1  dholland {
   5416  1.1  dholland 	uint32_t *tl;
   5417  1.1  dholland 	struct nfsrv_descript nfsd;
   5418  1.1  dholland 	struct nfsrv_descript *nd = &nfsd;
   5419  1.1  dholland 	int error;
   5420  1.1  dholland 
   5421  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_RECLAIMCOMPL, nmp, NULL, 0, NULL, NULL);
   5422  1.1  dholland 	NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
   5423  1.1  dholland 	*tl = newnfs_false;
   5424  1.1  dholland 	nd->nd_flag |= ND_USEGSSNAME;
   5425  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
   5426  1.1  dholland 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
   5427  1.1  dholland 	if (error != 0)
   5428  1.1  dholland 		return (error);
   5429  1.1  dholland 	error = nd->nd_repstat;
   5430  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   5431  1.1  dholland 	return (error);
   5432  1.1  dholland }
   5433  1.1  dholland 
   5434  1.1  dholland /*
   5435  1.1  dholland  * Initialize the slot tables for a session.
   5436  1.1  dholland  */
   5437  1.1  dholland static void
   5438  1.1  dholland nfscl_initsessionslots(struct nfsclsession *sep)
   5439  1.1  dholland {
   5440  1.1  dholland 	int i;
   5441  1.1  dholland 
   5442  1.1  dholland 	for (i = 0; i < NFSV4_CBSLOTS; i++) {
   5443  1.1  dholland 		if (sep->nfsess_cbslots[i].nfssl_reply != NULL)
   5444  1.1  dholland 			m_freem(sep->nfsess_cbslots[i].nfssl_reply);
   5445  1.1  dholland 		NFSBZERO(&sep->nfsess_cbslots[i], sizeof(struct nfsslot));
   5446  1.1  dholland 	}
   5447  1.1  dholland 	for (i = 0; i < 64; i++)
   5448  1.1  dholland 		sep->nfsess_slotseq[i] = 0;
   5449  1.1  dholland 	sep->nfsess_slots = 0;
   5450  1.1  dholland }
   5451  1.1  dholland 
   5452  1.1  dholland /*
   5453  1.1  dholland  * Called to try and do an I/O operation via an NFSv4.1 Data Server (DS).
   5454  1.1  dholland  */
   5455  1.1  dholland int
   5456  1.1  dholland nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
   5457  1.1  dholland     uint32_t rwaccess, struct ucred *cred, NFSPROC_T *p)
   5458  1.1  dholland {
   5459  1.1  dholland 	struct nfsnode *np = VTONFS(vp);
   5460  1.1  dholland 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
   5461  1.1  dholland 	struct nfscllayout *layp;
   5462  1.1  dholland 	struct nfscldevinfo *dip;
   5463  1.1  dholland 	struct nfsclflayout *rflp;
   5464  1.1  dholland 	nfsv4stateid_t stateid;
   5465  1.1  dholland 	struct ucred *newcred;
   5466  1.1  dholland 	uint64_t lastbyte, len, off, oresid, xfer;
   5467  1.1  dholland 	int eof, error, iolaymode, recalled;
   5468  1.1  dholland 	void *lckp;
   5469  1.1  dholland 
   5470  1.1  dholland 	if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 ||
   5471  1.1  dholland 	    (np->n_flag & NNOLAYOUT) != 0)
   5472  1.1  dholland 		return (EIO);
   5473  1.1  dholland 	/* Now, get a reference cnt on the clientid for this mount. */
   5474  1.1  dholland 	if (nfscl_getref(nmp) == 0)
   5475  1.1  dholland 		return (EIO);
   5476  1.1  dholland 
   5477  1.1  dholland 	/* Find an appropriate stateid. */
   5478  1.1  dholland 	newcred = NFSNEWCRED(cred);
   5479  1.1  dholland 	error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
   5480  1.1  dholland 	    rwaccess, 1, newcred, p, &stateid, &lckp);
   5481  1.1  dholland 	if (error != 0) {
   5482  1.1  dholland 		NFSFREECRED(newcred);
   5483  1.1  dholland 		nfscl_relref(nmp);
   5484  1.1  dholland 		return (error);
   5485  1.1  dholland 	}
   5486  1.1  dholland 	/* Search for a layout for this file. */
   5487  1.1  dholland 	off = uiop->uio_offset;
   5488  1.1  dholland 	layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh,
   5489  1.1  dholland 	    np->n_fhp->nfh_len, off, &rflp, &recalled);
   5490  1.1  dholland 	if (layp == NULL || rflp == NULL) {
   5491  1.1  dholland 		if (recalled != 0) {
   5492  1.1  dholland 			NFSFREECRED(newcred);
   5493  1.1  dholland 			nfscl_relref(nmp);
   5494  1.1  dholland 			return (EIO);
   5495  1.1  dholland 		}
   5496  1.1  dholland 		if (layp != NULL) {
   5497  1.1  dholland 			nfscl_rellayout(layp, (rflp == NULL) ? 1 : 0);
   5498  1.1  dholland 			layp = NULL;
   5499  1.1  dholland 		}
   5500  1.1  dholland 		/* Try and get a Layout, if it is supported. */
   5501  1.1  dholland 		if (rwaccess == NFSV4OPEN_ACCESSWRITE ||
   5502  1.1  dholland 		    (np->n_flag & NWRITEOPENED) != 0)
   5503  1.1  dholland 			iolaymode = NFSLAYOUTIOMODE_RW;
   5504  1.1  dholland 		else
   5505  1.1  dholland 			iolaymode = NFSLAYOUTIOMODE_READ;
   5506  1.1  dholland 		error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode,
   5507  1.1  dholland 		    NULL, &stateid, off, &layp, newcred, p);
   5508  1.1  dholland 		if (error != 0) {
   5509  1.1  dholland 			NFSLOCKNODE(np);
   5510  1.1  dholland 			np->n_flag |= NNOLAYOUT;
   5511  1.1  dholland 			NFSUNLOCKNODE(np);
   5512  1.1  dholland 			if (lckp != NULL)
   5513  1.1  dholland 				nfscl_lockderef(lckp);
   5514  1.1  dholland 			NFSFREECRED(newcred);
   5515  1.1  dholland 			if (layp != NULL)
   5516  1.1  dholland 				nfscl_rellayout(layp, 0);
   5517  1.1  dholland 			nfscl_relref(nmp);
   5518  1.1  dholland 			return (error);
   5519  1.1  dholland 		}
   5520  1.1  dholland 	}
   5521  1.1  dholland 
   5522  1.1  dholland 	/*
   5523  1.1  dholland 	 * Loop around finding a layout that works for the first part of
   5524  1.1  dholland 	 * this I/O operation, and then call the function that actually
   5525  1.1  dholland 	 * does the RPC.
   5526  1.1  dholland 	 */
   5527  1.1  dholland 	eof = 0;
   5528  1.1  dholland 	len = (uint64_t)uiop->uio_resid;
   5529  1.1  dholland 	while (len > 0 && error == 0 && eof == 0) {
   5530  1.1  dholland 		off = uiop->uio_offset;
   5531  1.1  dholland 		error = nfscl_findlayoutforio(layp, off, rwaccess, &rflp);
   5532  1.1  dholland 		if (error == 0) {
   5533  1.1  dholland 			oresid = xfer = (uint64_t)uiop->uio_resid;
   5534  1.1  dholland 			if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off))
   5535  1.1  dholland 				xfer = rflp->nfsfl_end - rflp->nfsfl_off;
   5536  1.1  dholland 			dip = nfscl_getdevinfo(nmp->nm_clp, rflp->nfsfl_dev,
   5537  1.1  dholland 			    rflp->nfsfl_devp);
   5538  1.1  dholland 			if (dip != NULL) {
   5539  1.1  dholland 				error = nfscl_doflayoutio(vp, uiop, iomode,
   5540  1.1  dholland 				    must_commit, &eof, &stateid, rwaccess, dip,
   5541  1.1  dholland 				    layp, rflp, off, xfer, newcred, p);
   5542  1.1  dholland 				nfscl_reldevinfo(dip);
   5543  1.1  dholland 				lastbyte = off + xfer - 1;
   5544  1.1  dholland 				if (error == 0) {
   5545  1.1  dholland 					NFSLOCKCLSTATE();
   5546  1.1  dholland 					if (lastbyte > layp->nfsly_lastbyte)
   5547  1.1  dholland 						layp->nfsly_lastbyte = lastbyte;
   5548  1.1  dholland 					NFSUNLOCKCLSTATE();
   5549  1.1  dholland 				}
   5550  1.1  dholland 			} else
   5551  1.1  dholland 				error = EIO;
   5552  1.1  dholland 			if (error == 0)
   5553  1.1  dholland 				len -= (oresid - (uint64_t)uiop->uio_resid);
   5554  1.1  dholland 		}
   5555  1.1  dholland 	}
   5556  1.1  dholland 	if (lckp != NULL)
   5557  1.1  dholland 		nfscl_lockderef(lckp);
   5558  1.1  dholland 	NFSFREECRED(newcred);
   5559  1.1  dholland 	nfscl_rellayout(layp, 0);
   5560  1.1  dholland 	nfscl_relref(nmp);
   5561  1.1  dholland 	return (error);
   5562  1.1  dholland }
   5563  1.1  dholland 
   5564  1.1  dholland /*
   5565  1.1  dholland  * Find a file layout that will handle the first bytes of the requested
   5566  1.1  dholland  * range and return the information from it needed to to the I/O operation.
   5567  1.1  dholland  */
   5568  1.1  dholland int
   5569  1.1  dholland nfscl_findlayoutforio(struct nfscllayout *lyp, uint64_t off, uint32_t rwaccess,
   5570  1.1  dholland     struct nfsclflayout **retflpp)
   5571  1.1  dholland {
   5572  1.1  dholland 	struct nfsclflayout *flp, *nflp, *rflp;
   5573  1.1  dholland 	uint32_t rw;
   5574  1.1  dholland 
   5575  1.1  dholland 	rflp = NULL;
   5576  1.1  dholland 	rw = rwaccess;
   5577  1.1  dholland 	/* For reading, do the Read list first and then the Write list. */
   5578  1.1  dholland 	do {
   5579  1.1  dholland 		if (rw == NFSV4OPEN_ACCESSREAD)
   5580  1.1  dholland 			flp = LIST_FIRST(&lyp->nfsly_flayread);
   5581  1.1  dholland 		else
   5582  1.1  dholland 			flp = LIST_FIRST(&lyp->nfsly_flayrw);
   5583  1.1  dholland 		while (flp != NULL) {
   5584  1.1  dholland 			nflp = LIST_NEXT(flp, nfsfl_list);
   5585  1.1  dholland 			if (flp->nfsfl_off > off)
   5586  1.1  dholland 				break;
   5587  1.1  dholland 			if (flp->nfsfl_end > off &&
   5588  1.1  dholland 			    (rflp == NULL || rflp->nfsfl_end < flp->nfsfl_end))
   5589  1.1  dholland 				rflp = flp;
   5590  1.1  dholland 			flp = nflp;
   5591  1.1  dholland 		}
   5592  1.1  dholland 		if (rw == NFSV4OPEN_ACCESSREAD)
   5593  1.1  dholland 			rw = NFSV4OPEN_ACCESSWRITE;
   5594  1.1  dholland 		else
   5595  1.1  dholland 			rw = 0;
   5596  1.1  dholland 	} while (rw != 0);
   5597  1.1  dholland 	if (rflp != NULL) {
   5598  1.1  dholland 		/* This one covers the most bytes starting at off. */
   5599  1.1  dholland 		*retflpp = rflp;
   5600  1.1  dholland 		return (0);
   5601  1.1  dholland 	}
   5602  1.1  dholland 	return (EIO);
   5603  1.1  dholland }
   5604  1.1  dholland 
   5605  1.1  dholland /*
   5606  1.1  dholland  * Do I/O using an NFSv4.1 file layout.
   5607  1.1  dholland  */
   5608  1.1  dholland static int
   5609  1.1  dholland nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
   5610  1.1  dholland     int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp,
   5611  1.1  dholland     struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off,
   5612  1.1  dholland     uint64_t len, struct ucred *cred, NFSPROC_T *p)
   5613  1.1  dholland {
   5614  1.1  dholland 	uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer;
   5615  1.1  dholland 	int commit_thru_mds, error = 0, stripe_index, stripe_pos;
   5616  1.1  dholland 	struct nfsnode *np;
   5617  1.1  dholland 	struct nfsfh *fhp;
   5618  1.1  dholland 	struct nfsclds **dspp;
   5619  1.1  dholland 
   5620  1.1  dholland 	np = VTONFS(vp);
   5621  1.1  dholland 	rel_off = off - flp->nfsfl_patoff;
   5622  1.1  dholland 	stripe_unit_size = (flp->nfsfl_util >> 6) & 0x3ffffff;
   5623  1.1  dholland 	stripe_pos = (rel_off / stripe_unit_size + flp->nfsfl_stripe1) %
   5624  1.1  dholland 	    dp->nfsdi_stripecnt;
   5625  1.1  dholland 	transfer = stripe_unit_size - (rel_off % stripe_unit_size);
   5626  1.1  dholland 
   5627  1.1  dholland 	/* Loop around, doing I/O for each stripe unit. */
   5628  1.1  dholland 	while (len > 0 && error == 0) {
   5629  1.1  dholland 		stripe_index = nfsfldi_stripeindex(dp, stripe_pos);
   5630  1.1  dholland 		dspp = nfsfldi_addr(dp, stripe_index);
   5631  1.1  dholland 		if (len > transfer)
   5632  1.1  dholland 			xfer = transfer;
   5633  1.1  dholland 		else
   5634  1.1  dholland 			xfer = len;
   5635  1.1  dholland 		if ((flp->nfsfl_util & NFSFLAYUTIL_DENSE) != 0) {
   5636  1.1  dholland 			/* Dense layout. */
   5637  1.1  dholland 			if (stripe_pos >= flp->nfsfl_fhcnt)
   5638  1.1  dholland 				return (EIO);
   5639  1.1  dholland 			fhp = flp->nfsfl_fh[stripe_pos];
   5640  1.1  dholland 			io_off = (rel_off / (stripe_unit_size *
   5641  1.1  dholland 			    dp->nfsdi_stripecnt)) * stripe_unit_size +
   5642  1.1  dholland 			    rel_off % stripe_unit_size;
   5643  1.1  dholland 		} else {
   5644  1.1  dholland 			/* Sparse layout. */
   5645  1.1  dholland 			if (flp->nfsfl_fhcnt > 1) {
   5646  1.1  dholland 				if (stripe_index >= flp->nfsfl_fhcnt)
   5647  1.1  dholland 					return (EIO);
   5648  1.1  dholland 				fhp = flp->nfsfl_fh[stripe_index];
   5649  1.1  dholland 			} else if (flp->nfsfl_fhcnt == 1)
   5650  1.1  dholland 				fhp = flp->nfsfl_fh[0];
   5651  1.1  dholland 			else
   5652  1.1  dholland 				fhp = np->n_fhp;
   5653  1.1  dholland 			io_off = off;
   5654  1.1  dholland 		}
   5655  1.1  dholland 		if ((flp->nfsfl_util & NFSFLAYUTIL_COMMIT_THRU_MDS) != 0)
   5656  1.1  dholland 			commit_thru_mds = 1;
   5657  1.1  dholland 		else
   5658  1.1  dholland 			commit_thru_mds = 0;
   5659  1.1  dholland 		if (rwflag == FREAD)
   5660  1.1  dholland 			error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp,
   5661  1.1  dholland 			    io_off, xfer, fhp, cred, p);
   5662  1.1  dholland 		else {
   5663  1.1  dholland 			error = nfsrpc_writeds(vp, uiop, iomode, must_commit,
   5664  1.1  dholland 			    stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds,
   5665  1.1  dholland 			    cred, p);
   5666  1.1  dholland 			if (error == 0) {
   5667  1.1  dholland 				NFSLOCKCLSTATE();
   5668  1.1  dholland 				lyp->nfsly_flags |= NFSLY_WRITTEN;
   5669  1.1  dholland 				NFSUNLOCKCLSTATE();
   5670  1.1  dholland 			}
   5671  1.1  dholland 		}
   5672  1.1  dholland 		if (error == 0) {
   5673  1.1  dholland 			transfer = stripe_unit_size;
   5674  1.1  dholland 			stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt;
   5675  1.1  dholland 			len -= xfer;
   5676  1.1  dholland 			off += xfer;
   5677  1.1  dholland 		}
   5678  1.1  dholland 	}
   5679  1.1  dholland 	return (error);
   5680  1.1  dholland }
   5681  1.1  dholland 
   5682  1.1  dholland /*
   5683  1.1  dholland  * The actual read RPC done to a DS.
   5684  1.1  dholland  */
   5685  1.1  dholland static int
   5686  1.1  dholland nfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp,
   5687  1.1  dholland     struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp,
   5688  1.1  dholland     struct ucred *cred, NFSPROC_T *p)
   5689  1.1  dholland {
   5690  1.1  dholland 	uint32_t *tl;
   5691  1.1  dholland 	int error, retlen;
   5692  1.1  dholland 	struct nfsrv_descript nfsd;
   5693  1.1  dholland 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
   5694  1.1  dholland 	struct nfsrv_descript *nd = &nfsd;
   5695  1.1  dholland 	struct nfssockreq *nrp;
   5696  1.1  dholland 
   5697  1.1  dholland 	nd->nd_mrep = NULL;
   5698  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh, fhp->nfh_len,
   5699  1.1  dholland 	    NULL, &dsp->nfsclds_sess);
   5700  1.1  dholland 	nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
   5701  1.1  dholland 	NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3);
   5702  1.1  dholland 	txdr_hyper(io_off, tl);
   5703  1.1  dholland 	*(tl + 2) = txdr_unsigned(len);
   5704  1.1  dholland 	nrp = dsp->nfsclds_sockp;
   5705  1.1  dholland 	if (nrp == NULL)
   5706  1.1  dholland 		/* If NULL, use the MDS socket. */
   5707  1.1  dholland 		nrp = &nmp->nm_sockreq;
   5708  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
   5709  1.1  dholland 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
   5710  1.1  dholland 	if (error != 0)
   5711  1.1  dholland 		return (error);
   5712  1.1  dholland 	if (nd->nd_repstat != 0) {
   5713  1.1  dholland 		error = nd->nd_repstat;
   5714  1.1  dholland 		goto nfsmout;
   5715  1.1  dholland 	}
   5716  1.1  dholland 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
   5717  1.1  dholland 	*eofp = fxdr_unsigned(int, *tl);
   5718  1.1  dholland 	NFSM_STRSIZ(retlen, len);
   5719  1.1  dholland 	error = nfsm_mbufuio(nd, uiop, retlen);
   5720  1.1  dholland nfsmout:
   5721  1.1  dholland 	if (nd->nd_mrep != NULL)
   5722  1.1  dholland 		mbuf_freem(nd->nd_mrep);
   5723  1.1  dholland 	return (error);
   5724  1.1  dholland }
   5725  1.1  dholland 
   5726  1.1  dholland /*
   5727  1.1  dholland  * The actual write RPC done to a DS.
   5728  1.1  dholland  */
   5729  1.1  dholland static int
   5730  1.1  dholland nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
   5731  1.1  dholland     nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len,
   5732  1.1  dholland     struct nfsfh *fhp, int commit_thru_mds, struct ucred *cred, NFSPROC_T *p)
   5733  1.1  dholland {
   5734  1.1  dholland 	uint32_t *tl;
   5735  1.1  dholland 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
   5736  1.1  dholland 	int error, rlen, commit, committed = NFSWRITE_FILESYNC;
   5737  1.1  dholland 	int32_t backup;
   5738  1.1  dholland 	struct nfsrv_descript nfsd;
   5739  1.1  dholland 	struct nfsrv_descript *nd = &nfsd;
   5740  1.1  dholland 	struct nfssockreq *nrp;
   5741  1.1  dholland 
   5742  1.1  dholland 	KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
   5743  1.1  dholland 	nd->nd_mrep = NULL;
   5744  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, fhp->nfh_len,
   5745  1.1  dholland 	    NULL, &dsp->nfsclds_sess);
   5746  1.1  dholland 	nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
   5747  1.1  dholland 	NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
   5748  1.1  dholland 	txdr_hyper(io_off, tl);
   5749  1.1  dholland 	tl += 2;
   5750  1.1  dholland 	*tl++ = txdr_unsigned(*iomode);
   5751  1.1  dholland 	*tl = txdr_unsigned(len);
   5752  1.1  dholland 	nfsm_uiombuf(nd, uiop, len);
   5753  1.1  dholland 	nrp = dsp->nfsclds_sockp;
   5754  1.1  dholland 	if (nrp == NULL)
   5755  1.1  dholland 		/* If NULL, use the MDS socket. */
   5756  1.1  dholland 		nrp = &nmp->nm_sockreq;
   5757  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
   5758  1.1  dholland 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
   5759  1.1  dholland 	if (error != 0)
   5760  1.1  dholland 		return (error);
   5761  1.1  dholland 	if (nd->nd_repstat != 0) {
   5762  1.1  dholland 		/*
   5763  1.1  dholland 		 * In case the rpc gets retried, roll
   5764  1.1  dholland 		 * the uio fileds changed by nfsm_uiombuf()
   5765  1.1  dholland 		 * back.
   5766  1.1  dholland 		 */
   5767  1.1  dholland 		uiop->uio_offset -= len;
   5768  1.1  dholland 		uio_uio_resid_add(uiop, len);
   5769  1.1  dholland 		uio_iov_base_add(uiop, -len);
   5770  1.1  dholland 		uio_iov_len_add(uiop, len);
   5771  1.1  dholland 		error = nd->nd_repstat;
   5772  1.1  dholland 	} else {
   5773  1.1  dholland 		NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF);
   5774  1.1  dholland 		rlen = fxdr_unsigned(int, *tl++);
   5775  1.1  dholland 		if (rlen == 0) {
   5776  1.1  dholland 			error = NFSERR_IO;
   5777  1.1  dholland 			goto nfsmout;
   5778  1.1  dholland 		} else if (rlen < len) {
   5779  1.1  dholland 			backup = len - rlen;
   5780  1.1  dholland 			uio_iov_base_add(uiop, -(backup));
   5781  1.1  dholland 			uio_iov_len_add(uiop, backup);
   5782  1.1  dholland 			uiop->uio_offset -= backup;
   5783  1.1  dholland 			uio_uio_resid_add(uiop, backup);
   5784  1.1  dholland 			len = rlen;
   5785  1.1  dholland 		}
   5786  1.1  dholland 		commit = fxdr_unsigned(int, *tl++);
   5787  1.1  dholland 
   5788  1.1  dholland 		/*
   5789  1.2  pgoyette 		 * Return the lowest commitment level
   5790  1.1  dholland 		 * obtained by any of the RPCs.
   5791  1.1  dholland 		 */
   5792  1.1  dholland 		if (committed == NFSWRITE_FILESYNC)
   5793  1.1  dholland 			committed = commit;
   5794  1.1  dholland 		else if (committed == NFSWRITE_DATASYNC &&
   5795  1.1  dholland 		    commit == NFSWRITE_UNSTABLE)
   5796  1.1  dholland 			committed = commit;
   5797  1.1  dholland 		if (commit_thru_mds != 0) {
   5798  1.1  dholland 			NFSLOCKMNT(nmp);
   5799  1.1  dholland 			if (!NFSHASWRITEVERF(nmp)) {
   5800  1.1  dholland 				NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
   5801  1.1  dholland 				NFSSETWRITEVERF(nmp);
   5802  1.1  dholland 	    		} else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) {
   5803  1.1  dholland 				*must_commit = 1;
   5804  1.1  dholland 				NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
   5805  1.1  dholland 			}
   5806  1.1  dholland 			NFSUNLOCKMNT(nmp);
   5807  1.1  dholland 		} else {
   5808  1.1  dholland 			NFSLOCKDS(dsp);
   5809  1.1  dholland 			if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) {
   5810  1.1  dholland 				NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
   5811  1.1  dholland 				dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF;
   5812  1.1  dholland 			} else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
   5813  1.1  dholland 				*must_commit = 1;
   5814  1.1  dholland 				NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
   5815  1.1  dholland 			}
   5816  1.1  dholland 			NFSUNLOCKDS(dsp);
   5817  1.1  dholland 		}
   5818  1.1  dholland 	}
   5819  1.1  dholland nfsmout:
   5820  1.1  dholland 	if (nd->nd_mrep != NULL)
   5821  1.1  dholland 		mbuf_freem(nd->nd_mrep);
   5822  1.1  dholland 	*iomode = committed;
   5823  1.1  dholland 	if (nd->nd_repstat != 0 && error == 0)
   5824  1.1  dholland 		error = nd->nd_repstat;
   5825  1.1  dholland 	return (error);
   5826  1.1  dholland }
   5827  1.1  dholland 
   5828  1.1  dholland /*
   5829  1.1  dholland  * Free up the nfsclds structure.
   5830  1.1  dholland  */
   5831  1.1  dholland void
   5832  1.1  dholland nfscl_freenfsclds(struct nfsclds *dsp)
   5833  1.1  dholland {
   5834  1.1  dholland 	int i;
   5835  1.1  dholland 
   5836  1.1  dholland 	if (dsp == NULL)
   5837  1.1  dholland 		return;
   5838  1.1  dholland 	if (dsp->nfsclds_sockp != NULL) {
   5839  1.1  dholland 		NFSFREECRED(dsp->nfsclds_sockp->nr_cred);
   5840  1.1  dholland 		NFSFREEMUTEX(&dsp->nfsclds_sockp->nr_mtx);
   5841  1.1  dholland 		free(dsp->nfsclds_sockp->nr_nam, M_SONAME);
   5842  1.1  dholland 		free(dsp->nfsclds_sockp, M_NFSSOCKREQ);
   5843  1.1  dholland 	}
   5844  1.1  dholland 	NFSFREEMUTEX(&dsp->nfsclds_mtx);
   5845  1.1  dholland 	NFSFREEMUTEX(&dsp->nfsclds_sess.nfsess_mtx);
   5846  1.1  dholland 	for (i = 0; i < NFSV4_CBSLOTS; i++) {
   5847  1.1  dholland 		if (dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply != NULL)
   5848  1.1  dholland 			m_freem(
   5849  1.1  dholland 			    dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply);
   5850  1.1  dholland 	}
   5851  1.1  dholland 	free(dsp, M_NFSCLDS);
   5852  1.1  dholland }
   5853  1.1  dholland 
   5854  1.1  dholland static enum nfsclds_state
   5855  1.1  dholland nfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp,
   5856  1.1  dholland     struct nfsclds **retdspp)
   5857  1.1  dholland {
   5858  1.1  dholland 	struct nfsclds *dsp, *cur_dsp;
   5859  1.1  dholland 
   5860  1.1  dholland 	/*
   5861  1.1  dholland 	 * Search the list of nfsclds structures for one with the same
   5862  1.1  dholland 	 * server.
   5863  1.1  dholland 	 */
   5864  1.1  dholland 	cur_dsp = NULL;
   5865  1.1  dholland 	TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) {
   5866  1.1  dholland 		if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen &&
   5867  1.1  dholland 		    dsp->nfsclds_servownlen != 0 &&
   5868  1.1  dholland 		    !NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown,
   5869  1.1  dholland 		    dsp->nfsclds_servownlen)) {
   5870  1.1  dholland 			NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n",
   5871  1.1  dholland 			    TAILQ_FIRST(&nmp->nm_sess), dsp,
   5872  1.1  dholland 			    dsp->nfsclds_flags);
   5873  1.1  dholland 			/* Server major id matches. */
   5874  1.1  dholland 			if ((dsp->nfsclds_flags & NFSCLDS_DS) != 0) {
   5875  1.1  dholland 				*retdspp = dsp;
   5876  1.1  dholland 				return (NFSDSP_USETHISSESSION);
   5877  1.1  dholland 			}
   5878  1.1  dholland 
   5879  1.1  dholland 			/*
   5880  1.1  dholland 			 * Note the first match, so it can be used for
   5881  1.1  dholland 			 * sequence'ing new sessions.
   5882  1.1  dholland 			 */
   5883  1.1  dholland 			if (cur_dsp == NULL)
   5884  1.1  dholland 				cur_dsp = dsp;
   5885  1.1  dholland 		}
   5886  1.1  dholland 	}
   5887  1.1  dholland 	if (cur_dsp != NULL) {
   5888  1.1  dholland 		*retdspp = cur_dsp;
   5889  1.1  dholland 		return (NFSDSP_SEQTHISSESSION);
   5890  1.1  dholland 	}
   5891  1.1  dholland 	return (NFSDSP_NOTFOUND);
   5892  1.1  dholland }
   5893  1.1  dholland 
   5894  1.1  dholland #ifdef notyet
   5895  1.1  dholland /*
   5896  1.1  dholland  * NFS commit rpc to a DS.
   5897  1.1  dholland  */
   5898  1.1  dholland static int
   5899  1.1  dholland nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp,
   5900  1.1  dholland     struct nfsfh *fhp, struct ucred *cred, NFSPROC_T *p, void *stuff)
   5901  1.1  dholland {
   5902  1.1  dholland 	uint32_t *tl;
   5903  1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   5904  1.1  dholland 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
   5905  1.1  dholland 	struct nfssockreq *nrp;
   5906  1.1  dholland 	int error;
   5907  1.1  dholland 
   5908  1.1  dholland 	nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh, fhp->nfh_len,
   5909  1.1  dholland 	    NULL, &dsp->nfsclds_sess);
   5910  1.1  dholland 	NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
   5911  1.1  dholland 	txdr_hyper(offset, tl);
   5912  1.1  dholland 	tl += 2;
   5913  1.1  dholland 	*tl = txdr_unsigned(cnt);
   5914  1.1  dholland 	nrp = dsp->nfsclds_sockp;
   5915  1.1  dholland 	if (nrp == NULL)
   5916  1.1  dholland 		/* If NULL, use the MDS socket. */
   5917  1.1  dholland 		nrp = &nmp->nm_sockreq;
   5918  1.1  dholland 	error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
   5919  1.1  dholland 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
   5920  1.1  dholland 	if (error)
   5921  1.1  dholland 		return (error);
   5922  1.1  dholland 	if (nd->nd_repstat == 0) {
   5923  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
   5924  1.1  dholland 		NFSLOCKDS(dsp);
   5925  1.1  dholland 		if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
   5926  1.1  dholland 			NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
   5927  1.1  dholland 			error = NFSERR_STALEWRITEVERF;
   5928  1.1  dholland 		}
   5929  1.1  dholland 		NFSUNLOCKDS(dsp);
   5930  1.1  dholland 	}
   5931  1.1  dholland nfsmout:
   5932  1.1  dholland 	if (error == 0 && nd->nd_repstat != 0)
   5933  1.1  dholland 		error = nd->nd_repstat;
   5934  1.1  dholland 	mbuf_freem(nd->nd_mrep);
   5935  1.1  dholland 	return (error);
   5936  1.1  dholland }
   5937  1.1  dholland #endif
   5938  1.1  dholland 
   5939