Home | History | Annotate | Line # | Download | only in client
nfs_clrpcops.c revision 1.1.1.1.16.1
      1  1.1.1.1.16.1  pgoyette /*	$NetBSD: nfs_clrpcops.c,v 1.1.1.1.16.1 2017/01/07 08:56:48 pgoyette 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.1.1.1.16.1  pgoyette /* __FBSDID("FreeBSD: head/sys/fs/nfsclient/nfs_clrpcops.c 298788 2016-04-29 16:07:25Z pfg "); */
     37  1.1.1.1.16.1  pgoyette __RCSID("$NetBSD: nfs_clrpcops.c,v 1.1.1.1.16.1 2017/01/07 08:56:48 pgoyette 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.1.1.1.16.1  pgoyette #ifdef _KERNEL_OPT
     49           1.1  dholland #include "opt_inet6.h"
     50  1.1.1.1.16.1  pgoyette #endif
     51  1.1.1.1.16.1  pgoyette 
     52  1.1.1.1.16.1  pgoyette #include <fs/nfs/common/nfsport.h>
     53  1.1.1.1.16.1  pgoyette #include <sys/sysctl.h>
     54  1.1.1.1.16.1  pgoyette 
     55  1.1.1.1.16.1  pgoyette SYSCTL_DECL(_vfs_nfs);
     56           1.1  dholland 
     57  1.1.1.1.16.1  pgoyette static int	nfsignore_eexist = 0;
     58  1.1.1.1.16.1  pgoyette SYSCTL_INT(_vfs_nfs, OID_AUTO, ignore_eexist, CTLFLAG_RW,
     59  1.1.1.1.16.1  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.1.1.1.16.1  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.1.1.1.16.1  pgoyette 			if (ndp != NULL) {
    552           1.1  dholland 				FREE((caddr_t)ndp, M_NFSCLDELEG);
    553  1.1.1.1.16.1  pgoyette 				ndp = NULL;
    554  1.1.1.1.16.1  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.1.1.1.16.1  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.1.1.1.16.1  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.1  dholland  * nfs getattr call with non-vnode arguemnts.
   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.1.1.1.16.1  pgoyette 		else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
   1256  1.1.1.1.16.1  pgoyette 		    ND_NFSV4) {
   1257  1.1.1.1.16.1  pgoyette 			/* Load the directory attributes. */
   1258  1.1.1.1.16.1  pgoyette 			error = nfsm_loadattr(nd, dnap);
   1259  1.1.1.1.16.1  pgoyette 			if (error == 0)
   1260  1.1.1.1.16.1  pgoyette 				*dattrflagp = 1;
   1261  1.1.1.1.16.1  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.1.1.1.16.1  pgoyette 		/* Load the directory attributes. */
   1266  1.1.1.1.16.1  pgoyette 		error = nfsm_loadattr(nd, dnap);
   1267  1.1.1.1.16.1  pgoyette 		if (error != 0)
   1268           1.1  dholland 			goto nfsmout;
   1269  1.1.1.1.16.1  pgoyette 		*dattrflagp = 1;
   1270  1.1.1.1.16.1  pgoyette 		/* Skip over the Lookup and GetFH operation status values. */
   1271  1.1.1.1.16.1  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.1.1.1.16.1  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.1.1.1.16.1  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.1.1.1.16.1  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.1.1.1.16.1  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.1.1.1.16.1  pgoyette 	/* Get the directory's post-op attributes. */
   2030  1.1.1.1.16.1  pgoyette 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2031  1.1.1.1.16.1  pgoyette 	*tl = txdr_unsigned(NFSV4OP_PUTFH);
   2032  1.1.1.1.16.1  pgoyette 	(void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
   2033  1.1.1.1.16.1  pgoyette 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2034  1.1.1.1.16.1  pgoyette 	*tl = txdr_unsigned(NFSV4OP_GETATTR);
   2035  1.1.1.1.16.1  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.1.1.1.16.1  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.1.1.1.16.1  pgoyette 		/* Get rid of the PutFH and Getattr status values. */
   2111  1.1.1.1.16.1  pgoyette 		NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
   2112  1.1.1.1.16.1  pgoyette 		/* Load the directory attributes. */
   2113  1.1.1.1.16.1  pgoyette 		error = nfsm_loadattr(nd, dnap);
   2114  1.1.1.1.16.1  pgoyette 		if (error)
   2115  1.1.1.1.16.1  pgoyette 			goto nfsmout;
   2116  1.1.1.1.16.1  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.1.1.1.16.1  pgoyette 			if (dp != NULL) {
   2171           1.1  dholland 				FREE((caddr_t)dp, M_NFSCLDELEG);
   2172  1.1.1.1.16.1  pgoyette 				dp = NULL;
   2173  1.1.1.1.16.1  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.1.1.1.16.1  pgoyette 	 * Only do this if vfs.nfs.ignore_eexist is set.
   2546  1.1.1.1.16.1  pgoyette 	 * Never do this for NFSv4.1 or later minor versions, since sessions
   2547  1.1.1.1.16.1  pgoyette 	 * should guarantee "exactly once" RPC semantics.
   2548           1.1  dholland 	 */
   2549  1.1.1.1.16.1  pgoyette 	if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
   2550  1.1.1.1.16.1  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.1.1.1.16.1  pgoyette 	struct nfsfh *fhp;
   2569  1.1.1.1.16.1  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.1.1.1.16.1  pgoyette 	nmp = VFSTONFS(vnode_mount(dvp));
   2575  1.1.1.1.16.1  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.1.1.1.16.1  pgoyette 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2592  1.1.1.1.16.1  pgoyette 		*tl = txdr_unsigned(NFSV4OP_PUTFH);
   2593  1.1.1.1.16.1  pgoyette 		(void) nfsm_fhtom(nd, fhp->nfh_fh, fhp->nfh_len, 0);
   2594  1.1.1.1.16.1  pgoyette 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2595  1.1.1.1.16.1  pgoyette 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
   2596  1.1.1.1.16.1  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.1.1.1.16.1  pgoyette 		if (error == 0 && (nd->nd_flag & ND_NFSV4) != 0) {
   2611  1.1.1.1.16.1  pgoyette 			/* Get rid of the PutFH and Getattr status values. */
   2612  1.1.1.1.16.1  pgoyette 			NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
   2613  1.1.1.1.16.1  pgoyette 			/* Load the directory attributes. */
   2614  1.1.1.1.16.1  pgoyette 			error = nfsm_loadattr(nd, dnap);
   2615  1.1.1.1.16.1  pgoyette 			if (error == 0)
   2616  1.1.1.1.16.1  pgoyette 				*dattrflagp = 1;
   2617  1.1.1.1.16.1  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.1.1.1.16.1  pgoyette 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
   2627  1.1.1.1.16.1  pgoyette 	 * Only do this if vfs.nfs.ignore_eexist is set.
   2628  1.1.1.1.16.1  pgoyette 	 * Never do this for NFSv4.1 or later minor versions, since sessions
   2629  1.1.1.1.16.1  pgoyette 	 * should guarantee "exactly once" RPC semantics.
   2630           1.1  dholland 	 */
   2631  1.1.1.1.16.1  pgoyette 	if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
   2632  1.1.1.1.16.1  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.1.1.1.16.1  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.1.1.1.16.1  pgoyette 			dotfileid = 0;	/* Fake out the compiler. */
   2777  1.1.1.1.16.1  pgoyette 			if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
   2778  1.1.1.1.16.1  pgoyette 			    error = nfsm_loadattr(nd, &nfsva);
   2779  1.1.1.1.16.1  pgoyette 			    if (error != 0)
   2780  1.1.1.1.16.1  pgoyette 				goto nfsmout;
   2781  1.1.1.1.16.1  pgoyette 			    dotfileid = nfsva.na_fileid;
   2782  1.1.1.1.16.1  pgoyette 			}
   2783           1.1  dholland 			if (nd->nd_repstat == 0) {
   2784  1.1.1.1.16.1  pgoyette 			    NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
   2785  1.1.1.1.16.1  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.1.1.1.16.1  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.1.1.1.16.1  pgoyette 			dotfileid = 0;	/* Fake out the compiler. */
   3203  1.1.1.1.16.1  pgoyette 			if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
   3204  1.1.1.1.16.1  pgoyette 			    error = nfsm_loadattr(nd, &nfsva);
   3205  1.1.1.1.16.1  pgoyette 			    if (error != 0)
   3206  1.1.1.1.16.1  pgoyette 				goto nfsmout;
   3207  1.1.1.1.16.1  pgoyette 			    dctime = nfsva.na_ctime;
   3208  1.1.1.1.16.1  pgoyette 			    dotfileid = nfsva.na_fileid;
   3209  1.1.1.1.16.1  pgoyette 			}
   3210           1.1  dholland 			if (nd->nd_repstat == 0) {
   3211  1.1.1.1.16.1  pgoyette 			    NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
   3212  1.1.1.1.16.1  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.1.1.1.16.1  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.1.1.1.16.1  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.1.1.1.16.1  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