Home | History | Annotate | Line # | Download | only in client
nfs_clstate.c revision 1.1.1.2
      1      1.1  dholland /*	$NetBSD: nfs_clstate.c,v 1.1.1.2 2016/11/18 07:49:10 pgoyette Exp $	*/
      2      1.1  dholland /*-
      3      1.1  dholland  * Copyright (c) 2009 Rick Macklem, University of Guelph
      4      1.1  dholland  * All rights reserved.
      5      1.1  dholland  *
      6      1.1  dholland  * Redistribution and use in source and binary forms, with or without
      7      1.1  dholland  * modification, are permitted provided that the following conditions
      8      1.1  dholland  * are met:
      9      1.1  dholland  * 1. Redistributions of source code must retain the above copyright
     10      1.1  dholland  *    notice, this list of conditions and the following disclaimer.
     11      1.1  dholland  * 2. Redistributions in binary form must reproduce the above copyright
     12      1.1  dholland  *    notice, this list of conditions and the following disclaimer in the
     13      1.1  dholland  *    documentation and/or other materials provided with the distribution.
     14      1.1  dholland  *
     15      1.1  dholland  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     16      1.1  dholland  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17      1.1  dholland  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18      1.1  dholland  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19      1.1  dholland  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20      1.1  dholland  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     21      1.1  dholland  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22      1.1  dholland  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23      1.1  dholland  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24      1.1  dholland  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25      1.1  dholland  * SUCH DAMAGE.
     26      1.1  dholland  *
     27      1.1  dholland  */
     28      1.1  dholland 
     29      1.1  dholland #include <sys/cdefs.h>
     30  1.1.1.2  pgoyette /* __FBSDID("FreeBSD: head/sys/fs/nfsclient/nfs_clstate.c 304026 2016-08-12 22:44:59Z rmacklem "); */
     31      1.1  dholland __RCSID("$NetBSD: nfs_clstate.c,v 1.1.1.2 2016/11/18 07:49:10 pgoyette Exp $");
     32      1.1  dholland 
     33      1.1  dholland /*
     34      1.1  dholland  * These functions implement the client side state handling for NFSv4.
     35      1.1  dholland  * NFSv4 state handling:
     36      1.1  dholland  * - A lockowner is used to determine lock contention, so it
     37      1.1  dholland  *   corresponds directly to a Posix pid. (1 to 1 mapping)
     38      1.1  dholland  * - The correct granularity of an OpenOwner is not nearly so
     39      1.1  dholland  *   obvious. An OpenOwner does the following:
     40      1.1  dholland  *   - provides a serial sequencing of Open/Close/Lock-with-new-lockowner
     41      1.1  dholland  *   - is used to check for Open/Share contention (not applicable to
     42      1.1  dholland  *     this client, since all Opens are Deny_None)
     43      1.1  dholland  *   As such, I considered both extreme.
     44      1.1  dholland  *   1 OpenOwner per ClientID - Simple to manage, but fully serializes
     45      1.1  dholland  *   all Open, Close and Lock (with a new lockowner) Ops.
     46      1.1  dholland  *   1 OpenOwner for each Open - This one results in an OpenConfirm for
     47      1.1  dholland  *   every Open, for most servers.
     48      1.1  dholland  *   So, I chose to use the same mapping as I did for LockOwnwers.
     49      1.1  dholland  *   The main concern here is that you can end up with multiple Opens
     50      1.1  dholland  *   for the same File Handle, but on different OpenOwners (opens
     51      1.1  dholland  *   inherited from parents, grandparents...) and you do not know
     52      1.1  dholland  *   which of these the vnodeop close applies to. This is handled by
     53      1.1  dholland  *   delaying the Close Op(s) until all of the Opens have been closed.
     54      1.1  dholland  *   (It is not yet obvious if this is the correct granularity.)
     55      1.1  dholland  * - How the code handles serialization:
     56      1.1  dholland  *   - For the ClientId, it uses an exclusive lock while getting its
     57      1.1  dholland  *     SetClientId and during recovery. Otherwise, it uses a shared
     58      1.1  dholland  *     lock via a reference count.
     59      1.1  dholland  *   - For the rest of the data structures, it uses an SMP mutex
     60      1.1  dholland  *     (once the nfs client is SMP safe) and doesn't sleep while
     61      1.1  dholland  *     manipulating the linked lists.
     62      1.1  dholland  *   - The serialization of Open/Close/Lock/LockU falls out in the
     63      1.1  dholland  *     "wash", since OpenOwners and LockOwners are both mapped from
     64      1.1  dholland  *     Posix pid. In other words, there is only one Posix pid using
     65      1.1  dholland  *     any given owner, so that owner is serialized. (If you change
     66      1.1  dholland  *     the granularity of the OpenOwner, then code must be added to
     67      1.1  dholland  *     serialize Ops on the OpenOwner.)
     68      1.1  dholland  * - When to get rid of OpenOwners and LockOwners.
     69      1.1  dholland  *   - The function nfscl_cleanup_common() is executed after a process exits.
     70      1.1  dholland  *     It goes through the client list looking for all Open and Lock Owners.
     71      1.1  dholland  *     When one is found, it is marked "defunct" or in the case of
     72      1.1  dholland  *     an OpenOwner without any Opens, freed.
     73      1.1  dholland  *     The renew thread scans for defunct Owners and gets rid of them,
     74      1.1  dholland  *     if it can. The LockOwners will also be deleted when the
     75      1.1  dholland  *     associated Open is closed.
     76      1.1  dholland  *   - If the LockU or Close Op(s) fail during close in a way
     77      1.1  dholland  *     that could be recovered upon retry, they are relinked to the
     78      1.1  dholland  *     ClientId's defunct open list and retried by the renew thread
     79      1.1  dholland  *     until they succeed or an unmount/recovery occurs.
     80      1.1  dholland  *     (Since we are done with them, they do not need to be recovered.)
     81      1.1  dholland  */
     82      1.1  dholland 
     83      1.1  dholland #ifndef APPLEKEXT
     84      1.1  dholland #include <fs/nfs/nfsport.h>
     85      1.1  dholland 
     86      1.1  dholland /*
     87      1.1  dholland  * Global variables
     88      1.1  dholland  */
     89  1.1.1.2  pgoyette extern struct nfsstatsv1 nfsstatsv1;
     90      1.1  dholland extern struct nfsreqhead nfsd_reqq;
     91      1.1  dholland extern u_int32_t newnfs_false, newnfs_true;
     92      1.1  dholland extern int nfscl_debuglevel;
     93      1.1  dholland NFSREQSPINLOCK;
     94      1.1  dholland NFSCLSTATEMUTEX;
     95      1.1  dholland int nfscl_inited = 0;
     96      1.1  dholland struct nfsclhead nfsclhead;	/* Head of clientid list */
     97      1.1  dholland int nfscl_deleghighwater = NFSCLDELEGHIGHWATER;
     98      1.1  dholland int nfscl_layouthighwater = NFSCLLAYOUTHIGHWATER;
     99      1.1  dholland #endif	/* !APPLEKEXT */
    100      1.1  dholland 
    101      1.1  dholland static int nfscl_delegcnt = 0;
    102      1.1  dholland static int nfscl_layoutcnt = 0;
    103      1.1  dholland static int nfscl_getopen(struct nfsclownerhead *, u_int8_t *, int, u_int8_t *,
    104      1.1  dholland     u_int8_t *, u_int32_t, struct nfscllockowner **, struct nfsclopen **);
    105      1.1  dholland static void nfscl_clrelease(struct nfsclclient *);
    106      1.1  dholland static void nfscl_cleanclient(struct nfsclclient *);
    107      1.1  dholland static void nfscl_expireclient(struct nfsclclient *, struct nfsmount *,
    108      1.1  dholland     struct ucred *, NFSPROC_T *);
    109      1.1  dholland static int nfscl_expireopen(struct nfsclclient *, struct nfsclopen *,
    110      1.1  dholland     struct nfsmount *, struct ucred *, NFSPROC_T *);
    111      1.1  dholland static void nfscl_recover(struct nfsclclient *, struct ucred *, NFSPROC_T *);
    112      1.1  dholland static void nfscl_insertlock(struct nfscllockowner *, struct nfscllock *,
    113      1.1  dholland     struct nfscllock *, int);
    114      1.1  dholland static int nfscl_updatelock(struct nfscllockowner *, struct nfscllock **,
    115      1.1  dholland     struct nfscllock **, int);
    116      1.1  dholland static void nfscl_delegreturnall(struct nfsclclient *, NFSPROC_T *);
    117      1.1  dholland static u_int32_t nfscl_nextcbident(void);
    118      1.1  dholland static mount_t nfscl_getmnt(int, uint8_t *, u_int32_t, struct nfsclclient **);
    119      1.1  dholland static struct nfsclclient *nfscl_getclnt(u_int32_t);
    120      1.1  dholland static struct nfsclclient *nfscl_getclntsess(uint8_t *);
    121      1.1  dholland static struct nfscldeleg *nfscl_finddeleg(struct nfsclclient *, u_int8_t *,
    122      1.1  dholland     int);
    123      1.1  dholland static void nfscl_retoncloselayout(struct nfsclclient *, uint8_t *, int);
    124      1.1  dholland static void nfscl_reldevinfo_locked(struct nfscldevinfo *);
    125      1.1  dholland static struct nfscllayout *nfscl_findlayout(struct nfsclclient *, u_int8_t *,
    126      1.1  dholland     int);
    127      1.1  dholland static struct nfscldevinfo *nfscl_finddevinfo(struct nfsclclient *, uint8_t *);
    128      1.1  dholland static int nfscl_checkconflict(struct nfscllockownerhead *, struct nfscllock *,
    129      1.1  dholland     u_int8_t *, struct nfscllock **);
    130      1.1  dholland static void nfscl_freealllocks(struct nfscllockownerhead *, int);
    131      1.1  dholland static int nfscl_localconflict(struct nfsclclient *, u_int8_t *, int,
    132      1.1  dholland     struct nfscllock *, u_int8_t *, struct nfscldeleg *, struct nfscllock **);
    133      1.1  dholland static void nfscl_newopen(struct nfsclclient *, struct nfscldeleg *,
    134      1.1  dholland     struct nfsclowner **, struct nfsclowner **, struct nfsclopen **,
    135      1.1  dholland     struct nfsclopen **, u_int8_t *, u_int8_t *, int, int *);
    136      1.1  dholland static int nfscl_moveopen(vnode_t , struct nfsclclient *,
    137      1.1  dholland     struct nfsmount *, struct nfsclopen *, struct nfsclowner *,
    138      1.1  dholland     struct nfscldeleg *, struct ucred *, NFSPROC_T *);
    139      1.1  dholland static void nfscl_totalrecall(struct nfsclclient *);
    140      1.1  dholland static int nfscl_relock(vnode_t , struct nfsclclient *, struct nfsmount *,
    141      1.1  dholland     struct nfscllockowner *, struct nfscllock *, struct ucred *, NFSPROC_T *);
    142      1.1  dholland static int nfscl_tryopen(struct nfsmount *, vnode_t , u_int8_t *, int,
    143      1.1  dholland     u_int8_t *, int, u_int32_t, struct nfsclopen *, u_int8_t *, int,
    144      1.1  dholland     struct nfscldeleg **, int, u_int32_t, struct ucred *, NFSPROC_T *);
    145      1.1  dholland static int nfscl_trylock(struct nfsmount *, vnode_t , u_int8_t *,
    146      1.1  dholland     int, struct nfscllockowner *, int, int, u_int64_t, u_int64_t, short,
    147      1.1  dholland     struct ucred *, NFSPROC_T *);
    148      1.1  dholland static int nfsrpc_reopen(struct nfsmount *, u_int8_t *, int, u_int32_t,
    149      1.1  dholland     struct nfsclopen *, struct nfscldeleg **, struct ucred *, NFSPROC_T *);
    150      1.1  dholland static void nfscl_freedeleg(struct nfscldeleghead *, struct nfscldeleg *);
    151  1.1.1.2  pgoyette static int nfscl_errmap(struct nfsrv_descript *, u_int32_t);
    152      1.1  dholland static void nfscl_cleanup_common(struct nfsclclient *, u_int8_t *);
    153      1.1  dholland static int nfscl_recalldeleg(struct nfsclclient *, struct nfsmount *,
    154      1.1  dholland     struct nfscldeleg *, vnode_t, struct ucred *, NFSPROC_T *, int);
    155      1.1  dholland static void nfscl_freeopenowner(struct nfsclowner *, int);
    156      1.1  dholland static void nfscl_cleandeleg(struct nfscldeleg *);
    157      1.1  dholland static int nfscl_trydelegreturn(struct nfscldeleg *, struct ucred *,
    158      1.1  dholland     struct nfsmount *, NFSPROC_T *);
    159      1.1  dholland static void nfscl_emptylockowner(struct nfscllockowner *,
    160      1.1  dholland     struct nfscllockownerfhhead *);
    161      1.1  dholland static void nfscl_mergeflayouts(struct nfsclflayouthead *,
    162      1.1  dholland     struct nfsclflayouthead *);
    163      1.1  dholland static int nfscl_layoutrecall(int, struct nfscllayout *, uint32_t, uint64_t,
    164      1.1  dholland     uint64_t, uint32_t, struct nfsclrecalllayout *);
    165      1.1  dholland static int nfscl_seq(uint32_t, uint32_t);
    166      1.1  dholland static void nfscl_layoutreturn(struct nfsmount *, struct nfscllayout *,
    167      1.1  dholland     struct ucred *, NFSPROC_T *);
    168      1.1  dholland static void nfscl_dolayoutcommit(struct nfsmount *, struct nfscllayout *,
    169      1.1  dholland     struct ucred *, NFSPROC_T *);
    170      1.1  dholland 
    171      1.1  dholland static short nfscberr_null[] = {
    172      1.1  dholland 	0,
    173      1.1  dholland 	0,
    174      1.1  dholland };
    175      1.1  dholland 
    176      1.1  dholland static short nfscberr_getattr[] = {
    177      1.1  dholland 	NFSERR_RESOURCE,
    178      1.1  dholland 	NFSERR_BADHANDLE,
    179      1.1  dholland 	NFSERR_BADXDR,
    180      1.1  dholland 	NFSERR_RESOURCE,
    181      1.1  dholland 	NFSERR_SERVERFAULT,
    182      1.1  dholland 	0,
    183      1.1  dholland };
    184      1.1  dholland 
    185      1.1  dholland static short nfscberr_recall[] = {
    186      1.1  dholland 	NFSERR_RESOURCE,
    187      1.1  dholland 	NFSERR_BADHANDLE,
    188      1.1  dholland 	NFSERR_BADSTATEID,
    189      1.1  dholland 	NFSERR_BADXDR,
    190      1.1  dholland 	NFSERR_RESOURCE,
    191      1.1  dholland 	NFSERR_SERVERFAULT,
    192      1.1  dholland 	0,
    193      1.1  dholland };
    194      1.1  dholland 
    195      1.1  dholland static short *nfscl_cberrmap[] = {
    196      1.1  dholland 	nfscberr_null,
    197      1.1  dholland 	nfscberr_null,
    198      1.1  dholland 	nfscberr_null,
    199      1.1  dholland 	nfscberr_getattr,
    200      1.1  dholland 	nfscberr_recall
    201      1.1  dholland };
    202      1.1  dholland 
    203      1.1  dholland #define	NETFAMILY(clp) \
    204      1.1  dholland 		(((clp)->nfsc_flags & NFSCLFLAGS_AFINET6) ? AF_INET6 : AF_INET)
    205      1.1  dholland 
    206      1.1  dholland /*
    207      1.1  dholland  * Called for an open operation.
    208      1.1  dholland  * If the nfhp argument is NULL, just get an openowner.
    209      1.1  dholland  */
    210      1.1  dholland APPLESTATIC int
    211      1.1  dholland nfscl_open(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t amode, int usedeleg,
    212      1.1  dholland     struct ucred *cred, NFSPROC_T *p, struct nfsclowner **owpp,
    213      1.1  dholland     struct nfsclopen **opp, int *newonep, int *retp, int lockit)
    214      1.1  dholland {
    215      1.1  dholland 	struct nfsclclient *clp;
    216      1.1  dholland 	struct nfsclowner *owp, *nowp;
    217      1.1  dholland 	struct nfsclopen *op = NULL, *nop = NULL;
    218      1.1  dholland 	struct nfscldeleg *dp;
    219      1.1  dholland 	struct nfsclownerhead *ohp;
    220      1.1  dholland 	u_int8_t own[NFSV4CL_LOCKNAMELEN];
    221      1.1  dholland 	int ret;
    222      1.1  dholland 
    223      1.1  dholland 	if (newonep != NULL)
    224      1.1  dholland 		*newonep = 0;
    225      1.1  dholland 	if (opp != NULL)
    226      1.1  dholland 		*opp = NULL;
    227      1.1  dholland 	if (owpp != NULL)
    228      1.1  dholland 		*owpp = NULL;
    229      1.1  dholland 
    230      1.1  dholland 	/*
    231      1.1  dholland 	 * Might need one or both of these, so MALLOC them now, to
    232      1.1  dholland 	 * avoid a tsleep() in MALLOC later.
    233      1.1  dholland 	 */
    234      1.1  dholland 	MALLOC(nowp, struct nfsclowner *, sizeof (struct nfsclowner),
    235      1.1  dholland 	    M_NFSCLOWNER, M_WAITOK);
    236      1.1  dholland 	if (nfhp != NULL)
    237      1.1  dholland 	    MALLOC(nop, struct nfsclopen *, sizeof (struct nfsclopen) +
    238      1.1  dholland 		fhlen - 1, M_NFSCLOPEN, M_WAITOK);
    239      1.1  dholland 	ret = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp);
    240      1.1  dholland 	if (ret != 0) {
    241      1.1  dholland 		FREE((caddr_t)nowp, M_NFSCLOWNER);
    242      1.1  dholland 		if (nop != NULL)
    243      1.1  dholland 			FREE((caddr_t)nop, M_NFSCLOPEN);
    244      1.1  dholland 		return (ret);
    245      1.1  dholland 	}
    246      1.1  dholland 
    247      1.1  dholland 	/*
    248      1.1  dholland 	 * Get the Open iff it already exists.
    249      1.1  dholland 	 * If none found, add the new one or return error, depending upon
    250      1.1  dholland 	 * "create".
    251      1.1  dholland 	 */
    252      1.1  dholland 	nfscl_filllockowner(p->td_proc, own, F_POSIX);
    253      1.1  dholland 	NFSLOCKCLSTATE();
    254      1.1  dholland 	dp = NULL;
    255      1.1  dholland 	/* First check the delegation list */
    256      1.1  dholland 	if (nfhp != NULL && usedeleg) {
    257      1.1  dholland 		LIST_FOREACH(dp, NFSCLDELEGHASH(clp, nfhp, fhlen), nfsdl_hash) {
    258      1.1  dholland 			if (dp->nfsdl_fhlen == fhlen &&
    259      1.1  dholland 			    !NFSBCMP(nfhp, dp->nfsdl_fh, fhlen)) {
    260      1.1  dholland 				if (!(amode & NFSV4OPEN_ACCESSWRITE) ||
    261      1.1  dholland 				    (dp->nfsdl_flags & NFSCLDL_WRITE))
    262      1.1  dholland 					break;
    263      1.1  dholland 				dp = NULL;
    264      1.1  dholland 				break;
    265      1.1  dholland 			}
    266      1.1  dholland 		}
    267      1.1  dholland 	}
    268      1.1  dholland 
    269      1.1  dholland 	if (dp != NULL)
    270      1.1  dholland 		ohp = &dp->nfsdl_owner;
    271      1.1  dholland 	else
    272      1.1  dholland 		ohp = &clp->nfsc_owner;
    273      1.1  dholland 	/* Now, search for an openowner */
    274      1.1  dholland 	LIST_FOREACH(owp, ohp, nfsow_list) {
    275      1.1  dholland 		if (!NFSBCMP(owp->nfsow_owner, own, NFSV4CL_LOCKNAMELEN))
    276      1.1  dholland 			break;
    277      1.1  dholland 	}
    278      1.1  dholland 
    279      1.1  dholland 	/*
    280      1.1  dholland 	 * Create a new open, as required.
    281      1.1  dholland 	 */
    282      1.1  dholland 	nfscl_newopen(clp, dp, &owp, &nowp, &op, &nop, own, nfhp, fhlen,
    283      1.1  dholland 	    newonep);
    284      1.1  dholland 
    285      1.1  dholland 	/*
    286  1.1.1.2  pgoyette 	 * Now, check the mode on the open and return the appropriate
    287  1.1.1.2  pgoyette 	 * value.
    288  1.1.1.2  pgoyette 	 */
    289  1.1.1.2  pgoyette 	if (retp != NULL) {
    290  1.1.1.2  pgoyette 		if (nfhp != NULL && dp != NULL && nop == NULL)
    291  1.1.1.2  pgoyette 			/* new local open on delegation */
    292  1.1.1.2  pgoyette 			*retp = NFSCLOPEN_SETCRED;
    293  1.1.1.2  pgoyette 		else
    294  1.1.1.2  pgoyette 			*retp = NFSCLOPEN_OK;
    295  1.1.1.2  pgoyette 	}
    296  1.1.1.2  pgoyette 	if (op != NULL && (amode & ~(op->nfso_mode))) {
    297  1.1.1.2  pgoyette 		op->nfso_mode |= amode;
    298  1.1.1.2  pgoyette 		if (retp != NULL && dp == NULL)
    299  1.1.1.2  pgoyette 			*retp = NFSCLOPEN_DOOPEN;
    300  1.1.1.2  pgoyette 	}
    301  1.1.1.2  pgoyette 
    302  1.1.1.2  pgoyette 	/*
    303      1.1  dholland 	 * Serialize modifications to the open owner for multiple threads
    304      1.1  dholland 	 * within the same process using a read/write sleep lock.
    305      1.1  dholland 	 */
    306      1.1  dholland 	if (lockit)
    307      1.1  dholland 		nfscl_lockexcl(&owp->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
    308      1.1  dholland 	NFSUNLOCKCLSTATE();
    309      1.1  dholland 	if (nowp != NULL)
    310      1.1  dholland 		FREE((caddr_t)nowp, M_NFSCLOWNER);
    311      1.1  dholland 	if (nop != NULL)
    312      1.1  dholland 		FREE((caddr_t)nop, M_NFSCLOPEN);
    313      1.1  dholland 	if (owpp != NULL)
    314      1.1  dholland 		*owpp = owp;
    315      1.1  dholland 	if (opp != NULL)
    316      1.1  dholland 		*opp = op;
    317      1.1  dholland 	return (0);
    318      1.1  dholland }
    319      1.1  dholland 
    320      1.1  dholland /*
    321      1.1  dholland  * Create a new open, as required.
    322      1.1  dholland  */
    323      1.1  dholland static void
    324      1.1  dholland nfscl_newopen(struct nfsclclient *clp, struct nfscldeleg *dp,
    325      1.1  dholland     struct nfsclowner **owpp, struct nfsclowner **nowpp, struct nfsclopen **opp,
    326      1.1  dholland     struct nfsclopen **nopp, u_int8_t *own, u_int8_t *fhp, int fhlen,
    327      1.1  dholland     int *newonep)
    328      1.1  dholland {
    329      1.1  dholland 	struct nfsclowner *owp = *owpp, *nowp;
    330      1.1  dholland 	struct nfsclopen *op, *nop;
    331      1.1  dholland 
    332      1.1  dholland 	if (nowpp != NULL)
    333      1.1  dholland 		nowp = *nowpp;
    334      1.1  dholland 	else
    335      1.1  dholland 		nowp = NULL;
    336      1.1  dholland 	if (nopp != NULL)
    337      1.1  dholland 		nop = *nopp;
    338      1.1  dholland 	else
    339      1.1  dholland 		nop = NULL;
    340      1.1  dholland 	if (owp == NULL && nowp != NULL) {
    341      1.1  dholland 		NFSBCOPY(own, nowp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
    342      1.1  dholland 		LIST_INIT(&nowp->nfsow_open);
    343      1.1  dholland 		nowp->nfsow_clp = clp;
    344      1.1  dholland 		nowp->nfsow_seqid = 0;
    345      1.1  dholland 		nowp->nfsow_defunct = 0;
    346      1.1  dholland 		nfscl_lockinit(&nowp->nfsow_rwlock);
    347      1.1  dholland 		if (dp != NULL) {
    348  1.1.1.2  pgoyette 			nfsstatsv1.cllocalopenowners++;
    349      1.1  dholland 			LIST_INSERT_HEAD(&dp->nfsdl_owner, nowp, nfsow_list);
    350      1.1  dholland 		} else {
    351  1.1.1.2  pgoyette 			nfsstatsv1.clopenowners++;
    352      1.1  dholland 			LIST_INSERT_HEAD(&clp->nfsc_owner, nowp, nfsow_list);
    353      1.1  dholland 		}
    354      1.1  dholland 		owp = *owpp = nowp;
    355      1.1  dholland 		*nowpp = NULL;
    356      1.1  dholland 		if (newonep != NULL)
    357      1.1  dholland 			*newonep = 1;
    358      1.1  dholland 	}
    359      1.1  dholland 
    360      1.1  dholland 	 /* If an fhp has been specified, create an Open as well. */
    361      1.1  dholland 	if (fhp != NULL) {
    362      1.1  dholland 		/* and look for the correct open, based upon FH */
    363      1.1  dholland 		LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
    364      1.1  dholland 			if (op->nfso_fhlen == fhlen &&
    365      1.1  dholland 			    !NFSBCMP(op->nfso_fh, fhp, fhlen))
    366      1.1  dholland 				break;
    367      1.1  dholland 		}
    368      1.1  dholland 		if (op == NULL && nop != NULL) {
    369      1.1  dholland 			nop->nfso_own = owp;
    370      1.1  dholland 			nop->nfso_mode = 0;
    371      1.1  dholland 			nop->nfso_opencnt = 0;
    372      1.1  dholland 			nop->nfso_posixlock = 1;
    373      1.1  dholland 			nop->nfso_fhlen = fhlen;
    374      1.1  dholland 			NFSBCOPY(fhp, nop->nfso_fh, fhlen);
    375      1.1  dholland 			LIST_INIT(&nop->nfso_lock);
    376      1.1  dholland 			nop->nfso_stateid.seqid = 0;
    377      1.1  dholland 			nop->nfso_stateid.other[0] = 0;
    378      1.1  dholland 			nop->nfso_stateid.other[1] = 0;
    379      1.1  dholland 			nop->nfso_stateid.other[2] = 0;
    380      1.1  dholland 			if (dp != NULL) {
    381      1.1  dholland 				TAILQ_REMOVE(&clp->nfsc_deleg, dp, nfsdl_list);
    382      1.1  dholland 				TAILQ_INSERT_HEAD(&clp->nfsc_deleg, dp,
    383      1.1  dholland 				    nfsdl_list);
    384      1.1  dholland 				dp->nfsdl_timestamp = NFSD_MONOSEC + 120;
    385  1.1.1.2  pgoyette 				nfsstatsv1.cllocalopens++;
    386      1.1  dholland 			} else {
    387  1.1.1.2  pgoyette 				nfsstatsv1.clopens++;
    388      1.1  dholland 			}
    389      1.1  dholland 			LIST_INSERT_HEAD(&owp->nfsow_open, nop, nfso_list);
    390      1.1  dholland 			*opp = nop;
    391      1.1  dholland 			*nopp = NULL;
    392      1.1  dholland 			if (newonep != NULL)
    393      1.1  dholland 				*newonep = 1;
    394      1.1  dholland 		} else {
    395      1.1  dholland 			*opp = op;
    396      1.1  dholland 		}
    397      1.1  dholland 	}
    398      1.1  dholland }
    399      1.1  dholland 
    400      1.1  dholland /*
    401      1.1  dholland  * Called to find/add a delegation to a client.
    402      1.1  dholland  */
    403      1.1  dholland APPLESTATIC int
    404      1.1  dholland nfscl_deleg(mount_t mp, struct nfsclclient *clp, u_int8_t *nfhp,
    405      1.1  dholland     int fhlen, struct ucred *cred, NFSPROC_T *p, struct nfscldeleg **dpp)
    406      1.1  dholland {
    407      1.1  dholland 	struct nfscldeleg *dp = *dpp, *tdp;
    408      1.1  dholland 
    409      1.1  dholland 	/*
    410      1.1  dholland 	 * First, if we have received a Read delegation for a file on a
    411      1.1  dholland 	 * read/write file system, just return it, because they aren't
    412      1.1  dholland 	 * useful, imho.
    413      1.1  dholland 	 */
    414      1.1  dholland 	if (mp != NULL && dp != NULL && !NFSMNT_RDONLY(mp) &&
    415      1.1  dholland 	    (dp->nfsdl_flags & NFSCLDL_READ)) {
    416      1.1  dholland 		(void) nfscl_trydelegreturn(dp, cred, VFSTONFS(mp), p);
    417      1.1  dholland 		FREE((caddr_t)dp, M_NFSCLDELEG);
    418      1.1  dholland 		*dpp = NULL;
    419      1.1  dholland 		return (0);
    420      1.1  dholland 	}
    421      1.1  dholland 
    422      1.1  dholland 	/* Look for the correct deleg, based upon FH */
    423      1.1  dholland 	NFSLOCKCLSTATE();
    424      1.1  dholland 	tdp = nfscl_finddeleg(clp, nfhp, fhlen);
    425      1.1  dholland 	if (tdp == NULL) {
    426      1.1  dholland 		if (dp == NULL) {
    427      1.1  dholland 			NFSUNLOCKCLSTATE();
    428      1.1  dholland 			return (NFSERR_BADSTATEID);
    429      1.1  dholland 		}
    430      1.1  dholland 		*dpp = NULL;
    431      1.1  dholland 		TAILQ_INSERT_HEAD(&clp->nfsc_deleg, dp, nfsdl_list);
    432      1.1  dholland 		LIST_INSERT_HEAD(NFSCLDELEGHASH(clp, nfhp, fhlen), dp,
    433      1.1  dholland 		    nfsdl_hash);
    434      1.1  dholland 		dp->nfsdl_timestamp = NFSD_MONOSEC + 120;
    435  1.1.1.2  pgoyette 		nfsstatsv1.cldelegates++;
    436      1.1  dholland 		nfscl_delegcnt++;
    437      1.1  dholland 	} else {
    438      1.1  dholland 		/*
    439      1.1  dholland 		 * Delegation already exists, what do we do if a new one??
    440      1.1  dholland 		 */
    441      1.1  dholland 		if (dp != NULL) {
    442      1.1  dholland 			printf("Deleg already exists!\n");
    443      1.1  dholland 			FREE((caddr_t)dp, M_NFSCLDELEG);
    444      1.1  dholland 			*dpp = NULL;
    445      1.1  dholland 		} else {
    446      1.1  dholland 			*dpp = tdp;
    447      1.1  dholland 		}
    448      1.1  dholland 	}
    449      1.1  dholland 	NFSUNLOCKCLSTATE();
    450      1.1  dholland 	return (0);
    451      1.1  dholland }
    452      1.1  dholland 
    453      1.1  dholland /*
    454      1.1  dholland  * Find a delegation for this file handle. Return NULL upon failure.
    455      1.1  dholland  */
    456      1.1  dholland static struct nfscldeleg *
    457      1.1  dholland nfscl_finddeleg(struct nfsclclient *clp, u_int8_t *fhp, int fhlen)
    458      1.1  dholland {
    459      1.1  dholland 	struct nfscldeleg *dp;
    460      1.1  dholland 
    461      1.1  dholland 	LIST_FOREACH(dp, NFSCLDELEGHASH(clp, fhp, fhlen), nfsdl_hash) {
    462      1.1  dholland 	    if (dp->nfsdl_fhlen == fhlen &&
    463      1.1  dholland 		!NFSBCMP(dp->nfsdl_fh, fhp, fhlen))
    464      1.1  dholland 		break;
    465      1.1  dholland 	}
    466      1.1  dholland 	return (dp);
    467      1.1  dholland }
    468      1.1  dholland 
    469      1.1  dholland /*
    470      1.1  dholland  * Get a stateid for an I/O operation. First, look for an open and iff
    471      1.1  dholland  * found, return either a lockowner stateid or the open stateid.
    472      1.1  dholland  * If no Open is found, just return error and the special stateid of all zeros.
    473      1.1  dholland  */
    474      1.1  dholland APPLESTATIC int
    475      1.1  dholland nfscl_getstateid(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t mode,
    476      1.1  dholland     int fords, struct ucred *cred, NFSPROC_T *p, nfsv4stateid_t *stateidp,
    477      1.1  dholland     void **lckpp)
    478      1.1  dholland {
    479      1.1  dholland 	struct nfsclclient *clp;
    480      1.1  dholland 	struct nfsclowner *owp;
    481      1.1  dholland 	struct nfsclopen *op = NULL;
    482      1.1  dholland 	struct nfscllockowner *lp;
    483      1.1  dholland 	struct nfscldeleg *dp;
    484      1.1  dholland 	struct nfsnode *np;
    485      1.1  dholland 	u_int8_t own[NFSV4CL_LOCKNAMELEN];
    486      1.1  dholland 	int error, done;
    487      1.1  dholland 
    488      1.1  dholland 	*lckpp = NULL;
    489      1.1  dholland 	/*
    490      1.1  dholland 	 * Initially, just set the special stateid of all zeros.
    491      1.1  dholland 	 * (Don't do this for a DS, since the special stateid can't be used.)
    492      1.1  dholland 	 */
    493      1.1  dholland 	if (fords == 0) {
    494      1.1  dholland 		stateidp->seqid = 0;
    495      1.1  dholland 		stateidp->other[0] = 0;
    496      1.1  dholland 		stateidp->other[1] = 0;
    497      1.1  dholland 		stateidp->other[2] = 0;
    498      1.1  dholland 	}
    499      1.1  dholland 	if (vnode_vtype(vp) != VREG)
    500      1.1  dholland 		return (EISDIR);
    501      1.1  dholland 	np = VTONFS(vp);
    502      1.1  dholland 	NFSLOCKCLSTATE();
    503      1.1  dholland 	clp = nfscl_findcl(VFSTONFS(vnode_mount(vp)));
    504      1.1  dholland 	if (clp == NULL) {
    505      1.1  dholland 		NFSUNLOCKCLSTATE();
    506      1.1  dholland 		return (EACCES);
    507      1.1  dholland 	}
    508      1.1  dholland 
    509      1.1  dholland 	/*
    510      1.1  dholland 	 * Wait for recovery to complete.
    511      1.1  dholland 	 */
    512      1.1  dholland 	while ((clp->nfsc_flags & NFSCLFLAGS_RECVRINPROG))
    513      1.1  dholland 		(void) nfsmsleep(&clp->nfsc_flags, NFSCLSTATEMUTEXPTR,
    514      1.1  dholland 		    PZERO, "nfsrecvr", NULL);
    515      1.1  dholland 
    516      1.1  dholland 	/*
    517      1.1  dholland 	 * First, look for a delegation.
    518      1.1  dholland 	 */
    519      1.1  dholland 	LIST_FOREACH(dp, NFSCLDELEGHASH(clp, nfhp, fhlen), nfsdl_hash) {
    520      1.1  dholland 		if (dp->nfsdl_fhlen == fhlen &&
    521      1.1  dholland 		    !NFSBCMP(nfhp, dp->nfsdl_fh, fhlen)) {
    522      1.1  dholland 			if (!(mode & NFSV4OPEN_ACCESSWRITE) ||
    523      1.1  dholland 			    (dp->nfsdl_flags & NFSCLDL_WRITE)) {
    524      1.1  dholland 				stateidp->seqid = dp->nfsdl_stateid.seqid;
    525      1.1  dholland 				stateidp->other[0] = dp->nfsdl_stateid.other[0];
    526      1.1  dholland 				stateidp->other[1] = dp->nfsdl_stateid.other[1];
    527      1.1  dholland 				stateidp->other[2] = dp->nfsdl_stateid.other[2];
    528      1.1  dholland 				if (!(np->n_flag & NDELEGRECALL)) {
    529      1.1  dholland 					TAILQ_REMOVE(&clp->nfsc_deleg, dp,
    530      1.1  dholland 					    nfsdl_list);
    531      1.1  dholland 					TAILQ_INSERT_HEAD(&clp->nfsc_deleg, dp,
    532      1.1  dholland 					    nfsdl_list);
    533      1.1  dholland 					dp->nfsdl_timestamp = NFSD_MONOSEC +
    534      1.1  dholland 					    120;
    535      1.1  dholland 					dp->nfsdl_rwlock.nfslock_usecnt++;
    536      1.1  dholland 					*lckpp = (void *)&dp->nfsdl_rwlock;
    537      1.1  dholland 				}
    538      1.1  dholland 				NFSUNLOCKCLSTATE();
    539      1.1  dholland 				return (0);
    540      1.1  dholland 			}
    541      1.1  dholland 			break;
    542      1.1  dholland 		}
    543      1.1  dholland 	}
    544      1.1  dholland 
    545      1.1  dholland 	if (p != NULL) {
    546      1.1  dholland 		/*
    547      1.1  dholland 		 * If p != NULL, we want to search the parentage tree
    548      1.1  dholland 		 * for a matching OpenOwner and use that.
    549      1.1  dholland 		 */
    550      1.1  dholland 		nfscl_filllockowner(p->td_proc, own, F_POSIX);
    551      1.1  dholland 		lp = NULL;
    552      1.1  dholland 		error = nfscl_getopen(&clp->nfsc_owner, nfhp, fhlen, own, own,
    553      1.1  dholland 		    mode, &lp, &op);
    554      1.1  dholland 		if (error == 0 && lp != NULL && fords == 0) {
    555      1.1  dholland 			/* Don't return a lock stateid for a DS. */
    556      1.1  dholland 			stateidp->seqid =
    557      1.1  dholland 			    lp->nfsl_stateid.seqid;
    558      1.1  dholland 			stateidp->other[0] =
    559      1.1  dholland 			    lp->nfsl_stateid.other[0];
    560      1.1  dholland 			stateidp->other[1] =
    561      1.1  dholland 			    lp->nfsl_stateid.other[1];
    562      1.1  dholland 			stateidp->other[2] =
    563      1.1  dholland 			    lp->nfsl_stateid.other[2];
    564      1.1  dholland 			NFSUNLOCKCLSTATE();
    565      1.1  dholland 			return (0);
    566      1.1  dholland 		}
    567      1.1  dholland 	}
    568      1.1  dholland 	if (op == NULL) {
    569      1.1  dholland 		/* If not found, just look for any OpenOwner that will work. */
    570      1.1  dholland 		done = 0;
    571      1.1  dholland 		owp = LIST_FIRST(&clp->nfsc_owner);
    572      1.1  dholland 		while (!done && owp != NULL) {
    573      1.1  dholland 			LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
    574      1.1  dholland 				if (op->nfso_fhlen == fhlen &&
    575      1.1  dholland 				    !NFSBCMP(op->nfso_fh, nfhp, fhlen) &&
    576      1.1  dholland 				    (mode & op->nfso_mode) == mode) {
    577      1.1  dholland 					done = 1;
    578      1.1  dholland 					break;
    579      1.1  dholland 				}
    580      1.1  dholland 			}
    581      1.1  dholland 			if (!done)
    582      1.1  dholland 				owp = LIST_NEXT(owp, nfsow_list);
    583      1.1  dholland 		}
    584      1.1  dholland 		if (!done) {
    585      1.1  dholland 			NFSUNLOCKCLSTATE();
    586      1.1  dholland 			return (ENOENT);
    587      1.1  dholland 		}
    588      1.1  dholland 		/*
    589      1.1  dholland 		 * For read aheads or write behinds, use the open cred.
    590      1.1  dholland 		 * A read ahead or write behind is indicated by p == NULL.
    591      1.1  dholland 		 */
    592      1.1  dholland 		if (p == NULL)
    593      1.1  dholland 			newnfs_copycred(&op->nfso_cred, cred);
    594      1.1  dholland 	}
    595      1.1  dholland 
    596      1.1  dholland 	/*
    597      1.1  dholland 	 * No lock stateid, so return the open stateid.
    598      1.1  dholland 	 */
    599      1.1  dholland 	stateidp->seqid = op->nfso_stateid.seqid;
    600      1.1  dholland 	stateidp->other[0] = op->nfso_stateid.other[0];
    601      1.1  dholland 	stateidp->other[1] = op->nfso_stateid.other[1];
    602      1.1  dholland 	stateidp->other[2] = op->nfso_stateid.other[2];
    603      1.1  dholland 	NFSUNLOCKCLSTATE();
    604      1.1  dholland 	return (0);
    605      1.1  dholland }
    606      1.1  dholland 
    607      1.1  dholland /*
    608      1.1  dholland  * Search for a matching file, mode and, optionally, lockowner.
    609      1.1  dholland  */
    610      1.1  dholland static int
    611      1.1  dholland nfscl_getopen(struct nfsclownerhead *ohp, u_int8_t *nfhp, int fhlen,
    612      1.1  dholland     u_int8_t *openown, u_int8_t *lockown, u_int32_t mode,
    613      1.1  dholland     struct nfscllockowner **lpp, struct nfsclopen **opp)
    614      1.1  dholland {
    615      1.1  dholland 	struct nfsclowner *owp;
    616      1.1  dholland 	struct nfsclopen *op, *rop, *rop2;
    617      1.1  dholland 	struct nfscllockowner *lp;
    618      1.1  dholland 	int keep_looping;
    619      1.1  dholland 
    620      1.1  dholland 	if (lpp != NULL)
    621      1.1  dholland 		*lpp = NULL;
    622      1.1  dholland 	/*
    623      1.1  dholland 	 * rop will be set to the open to be returned. There are three
    624      1.1  dholland 	 * variants of this, all for an open of the correct file:
    625      1.1  dholland 	 * 1 - A match of lockown.
    626      1.1  dholland 	 * 2 - A match of the openown, when no lockown match exists.
    627      1.1  dholland 	 * 3 - A match for any open, if no openown or lockown match exists.
    628      1.1  dholland 	 * Looking for #2 over #3 probably isn't necessary, but since
    629      1.1  dholland 	 * RFC3530 is vague w.r.t. the relationship between openowners and
    630      1.1  dholland 	 * lockowners, I think this is the safer way to go.
    631      1.1  dholland 	 */
    632      1.1  dholland 	rop = NULL;
    633      1.1  dholland 	rop2 = NULL;
    634      1.1  dholland 	keep_looping = 1;
    635      1.1  dholland 	/* Search the client list */
    636      1.1  dholland 	owp = LIST_FIRST(ohp);
    637      1.1  dholland 	while (owp != NULL && keep_looping != 0) {
    638      1.1  dholland 		/* and look for the correct open */
    639      1.1  dholland 		op = LIST_FIRST(&owp->nfsow_open);
    640      1.1  dholland 		while (op != NULL && keep_looping != 0) {
    641      1.1  dholland 			if (op->nfso_fhlen == fhlen &&
    642      1.1  dholland 			    !NFSBCMP(op->nfso_fh, nfhp, fhlen)
    643      1.1  dholland 			    && (op->nfso_mode & mode) == mode) {
    644      1.1  dholland 				if (lpp != NULL) {
    645      1.1  dholland 					/* Now look for a matching lockowner. */
    646      1.1  dholland 					LIST_FOREACH(lp, &op->nfso_lock,
    647      1.1  dholland 					    nfsl_list) {
    648      1.1  dholland 						if (!NFSBCMP(lp->nfsl_owner,
    649      1.1  dholland 						    lockown,
    650      1.1  dholland 						    NFSV4CL_LOCKNAMELEN)) {
    651      1.1  dholland 							*lpp = lp;
    652      1.1  dholland 							rop = op;
    653      1.1  dholland 							keep_looping = 0;
    654      1.1  dholland 							break;
    655      1.1  dholland 						}
    656      1.1  dholland 					}
    657      1.1  dholland 				}
    658      1.1  dholland 				if (rop == NULL && !NFSBCMP(owp->nfsow_owner,
    659      1.1  dholland 				    openown, NFSV4CL_LOCKNAMELEN)) {
    660      1.1  dholland 					rop = op;
    661      1.1  dholland 					if (lpp == NULL)
    662      1.1  dholland 						keep_looping = 0;
    663      1.1  dholland 				}
    664      1.1  dholland 				if (rop2 == NULL)
    665      1.1  dholland 					rop2 = op;
    666      1.1  dholland 			}
    667      1.1  dholland 			op = LIST_NEXT(op, nfso_list);
    668      1.1  dholland 		}
    669      1.1  dholland 		owp = LIST_NEXT(owp, nfsow_list);
    670      1.1  dholland 	}
    671      1.1  dholland 	if (rop == NULL)
    672      1.1  dholland 		rop = rop2;
    673      1.1  dholland 	if (rop == NULL)
    674      1.1  dholland 		return (EBADF);
    675      1.1  dholland 	*opp = rop;
    676      1.1  dholland 	return (0);
    677      1.1  dholland }
    678      1.1  dholland 
    679      1.1  dholland /*
    680      1.1  dholland  * Release use of an open owner. Called when open operations are done
    681      1.1  dholland  * with the open owner.
    682      1.1  dholland  */
    683      1.1  dholland APPLESTATIC void
    684      1.1  dholland nfscl_ownerrelease(struct nfsclowner *owp, __unused int error,
    685      1.1  dholland     __unused int candelete, int unlocked)
    686      1.1  dholland {
    687      1.1  dholland 
    688      1.1  dholland 	if (owp == NULL)
    689      1.1  dholland 		return;
    690      1.1  dholland 	NFSLOCKCLSTATE();
    691      1.1  dholland 	if (!unlocked)
    692      1.1  dholland 		nfscl_lockunlock(&owp->nfsow_rwlock);
    693      1.1  dholland 	nfscl_clrelease(owp->nfsow_clp);
    694      1.1  dholland 	NFSUNLOCKCLSTATE();
    695      1.1  dholland }
    696      1.1  dholland 
    697      1.1  dholland /*
    698      1.1  dholland  * Release use of an open structure under an open owner.
    699      1.1  dholland  */
    700      1.1  dholland APPLESTATIC void
    701      1.1  dholland nfscl_openrelease(struct nfsclopen *op, int error, int candelete)
    702      1.1  dholland {
    703      1.1  dholland 	struct nfsclclient *clp;
    704      1.1  dholland 	struct nfsclowner *owp;
    705      1.1  dholland 
    706      1.1  dholland 	if (op == NULL)
    707      1.1  dholland 		return;
    708      1.1  dholland 	NFSLOCKCLSTATE();
    709      1.1  dholland 	owp = op->nfso_own;
    710      1.1  dholland 	nfscl_lockunlock(&owp->nfsow_rwlock);
    711      1.1  dholland 	clp = owp->nfsow_clp;
    712      1.1  dholland 	if (error && candelete && op->nfso_opencnt == 0)
    713      1.1  dholland 		nfscl_freeopen(op, 0);
    714      1.1  dholland 	nfscl_clrelease(clp);
    715      1.1  dholland 	NFSUNLOCKCLSTATE();
    716      1.1  dholland }
    717      1.1  dholland 
    718      1.1  dholland /*
    719      1.1  dholland  * Called to get a clientid structure. It will optionally lock the
    720      1.1  dholland  * client data structures to do the SetClientId/SetClientId_confirm,
    721  1.1.1.2  pgoyette  * but will release that lock and return the clientid with a reference
    722      1.1  dholland  * count on it.
    723      1.1  dholland  * If the "cred" argument is NULL, a new clientid should not be created.
    724      1.1  dholland  * If the "p" argument is NULL, a SetClientID/SetClientIDConfirm cannot
    725      1.1  dholland  * be done.
    726      1.1  dholland  * The start_renewthread argument tells nfscl_getcl() to start a renew
    727      1.1  dholland  * thread if this creates a new clp.
    728      1.1  dholland  * It always clpp with a reference count on it, unless returning an error.
    729      1.1  dholland  */
    730      1.1  dholland APPLESTATIC int
    731      1.1  dholland nfscl_getcl(struct mount *mp, struct ucred *cred, NFSPROC_T *p,
    732      1.1  dholland     int start_renewthread, struct nfsclclient **clpp)
    733      1.1  dholland {
    734      1.1  dholland 	struct nfsclclient *clp;
    735      1.1  dholland 	struct nfsclclient *newclp = NULL;
    736      1.1  dholland 	struct nfsmount *nmp;
    737      1.1  dholland 	char uuid[HOSTUUIDLEN];
    738      1.1  dholland 	int igotlock = 0, error, trystalecnt, clidinusedelay, i;
    739      1.1  dholland 	u_int16_t idlen = 0;
    740      1.1  dholland 
    741      1.1  dholland 	nmp = VFSTONFS(mp);
    742      1.1  dholland 	if (cred != NULL) {
    743      1.1  dholland 		getcredhostuuid(cred, uuid, sizeof uuid);
    744      1.1  dholland 		idlen = strlen(uuid);
    745      1.1  dholland 		if (idlen > 0)
    746      1.1  dholland 			idlen += sizeof (u_int64_t);
    747      1.1  dholland 		else
    748      1.1  dholland 			idlen += sizeof (u_int64_t) + 16; /* 16 random bytes */
    749      1.1  dholland 		MALLOC(newclp, struct nfsclclient *,
    750      1.1  dholland 		    sizeof (struct nfsclclient) + idlen - 1, M_NFSCLCLIENT,
    751      1.1  dholland 		    M_WAITOK | M_ZERO);
    752      1.1  dholland 	}
    753      1.1  dholland 	NFSLOCKCLSTATE();
    754      1.1  dholland 	/*
    755      1.1  dholland 	 * If a forced dismount is already in progress, don't
    756      1.1  dholland 	 * allocate a new clientid and get out now. For the case where
    757      1.1  dholland 	 * clp != NULL, this is a harmless optimization.
    758      1.1  dholland 	 */
    759      1.1  dholland 	if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
    760      1.1  dholland 		NFSUNLOCKCLSTATE();
    761      1.1  dholland 		if (newclp != NULL)
    762      1.1  dholland 			free(newclp, M_NFSCLCLIENT);
    763      1.1  dholland 		return (EBADF);
    764      1.1  dholland 	}
    765      1.1  dholland 	clp = nmp->nm_clp;
    766      1.1  dholland 	if (clp == NULL) {
    767      1.1  dholland 		if (newclp == NULL) {
    768      1.1  dholland 			NFSUNLOCKCLSTATE();
    769      1.1  dholland 			return (EACCES);
    770      1.1  dholland 		}
    771      1.1  dholland 		clp = newclp;
    772      1.1  dholland 		clp->nfsc_idlen = idlen;
    773      1.1  dholland 		LIST_INIT(&clp->nfsc_owner);
    774      1.1  dholland 		TAILQ_INIT(&clp->nfsc_deleg);
    775      1.1  dholland 		TAILQ_INIT(&clp->nfsc_layout);
    776      1.1  dholland 		LIST_INIT(&clp->nfsc_devinfo);
    777      1.1  dholland 		for (i = 0; i < NFSCLDELEGHASHSIZE; i++)
    778      1.1  dholland 			LIST_INIT(&clp->nfsc_deleghash[i]);
    779      1.1  dholland 		for (i = 0; i < NFSCLLAYOUTHASHSIZE; i++)
    780      1.1  dholland 			LIST_INIT(&clp->nfsc_layouthash[i]);
    781      1.1  dholland 		clp->nfsc_flags = NFSCLFLAGS_INITED;
    782      1.1  dholland 		clp->nfsc_clientidrev = 1;
    783      1.1  dholland 		clp->nfsc_cbident = nfscl_nextcbident();
    784      1.1  dholland 		nfscl_fillclid(nmp->nm_clval, uuid, clp->nfsc_id,
    785      1.1  dholland 		    clp->nfsc_idlen);
    786      1.1  dholland 		LIST_INSERT_HEAD(&nfsclhead, clp, nfsc_list);
    787      1.1  dholland 		nmp->nm_clp = clp;
    788      1.1  dholland 		clp->nfsc_nmp = nmp;
    789      1.1  dholland 		NFSUNLOCKCLSTATE();
    790      1.1  dholland 		if (start_renewthread != 0)
    791      1.1  dholland 			nfscl_start_renewthread(clp);
    792      1.1  dholland 	} else {
    793      1.1  dholland 		NFSUNLOCKCLSTATE();
    794      1.1  dholland 		if (newclp != NULL)
    795      1.1  dholland 			free(newclp, M_NFSCLCLIENT);
    796      1.1  dholland 	}
    797      1.1  dholland 	NFSLOCKCLSTATE();
    798      1.1  dholland 	while ((clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID) == 0 && !igotlock &&
    799      1.1  dholland 	    (mp->mnt_kern_flag & MNTK_UNMOUNTF) == 0)
    800      1.1  dholland 		igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL,
    801      1.1  dholland 		    NFSCLSTATEMUTEXPTR, mp);
    802      1.1  dholland 	if (!igotlock)
    803      1.1  dholland 		nfsv4_getref(&clp->nfsc_lock, NULL, NFSCLSTATEMUTEXPTR, mp);
    804      1.1  dholland 	if (igotlock == 0 && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
    805      1.1  dholland 		/*
    806      1.1  dholland 		 * Both nfsv4_lock() and nfsv4_getref() know to check
    807      1.1  dholland 		 * for MNTK_UNMOUNTF and return without sleeping to
    808      1.1  dholland 		 * wait for the exclusive lock to be released, since it
    809      1.1  dholland 		 * might be held by nfscl_umount() and we need to get out
    810      1.1  dholland 		 * now for that case and not wait until nfscl_umount()
    811      1.1  dholland 		 * releases it.
    812      1.1  dholland 		 */
    813      1.1  dholland 		NFSUNLOCKCLSTATE();
    814      1.1  dholland 		return (EBADF);
    815      1.1  dholland 	}
    816      1.1  dholland 	NFSUNLOCKCLSTATE();
    817      1.1  dholland 
    818      1.1  dholland 	/*
    819      1.1  dholland 	 * If it needs a clientid, do the setclientid now.
    820      1.1  dholland 	 */
    821      1.1  dholland 	if ((clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID) == 0) {
    822      1.1  dholland 		if (!igotlock)
    823      1.1  dholland 			panic("nfscl_clget");
    824      1.1  dholland 		if (p == NULL || cred == NULL) {
    825      1.1  dholland 			NFSLOCKCLSTATE();
    826      1.1  dholland 			nfsv4_unlock(&clp->nfsc_lock, 0);
    827      1.1  dholland 			NFSUNLOCKCLSTATE();
    828      1.1  dholland 			return (EACCES);
    829      1.1  dholland 		}
    830      1.1  dholland 		/*
    831      1.1  dholland 		 * If RFC3530 Sec. 14.2.33 is taken literally,
    832      1.1  dholland 		 * NFSERR_CLIDINUSE will be returned persistently for the
    833      1.1  dholland 		 * case where a new mount of the same file system is using
    834      1.1  dholland 		 * a different principal. In practice, NFSERR_CLIDINUSE is
    835      1.1  dholland 		 * only returned when there is outstanding unexpired state
    836      1.1  dholland 		 * on the clientid. As such, try for twice the lease
    837      1.1  dholland 		 * interval, if we know what that is. Otherwise, make a
    838      1.1  dholland 		 * wild ass guess.
    839      1.1  dholland 		 * The case of returning NFSERR_STALECLIENTID is far less
    840      1.1  dholland 		 * likely, but might occur if there is a significant delay
    841      1.1  dholland 		 * between doing the SetClientID and SetClientIDConfirm Ops,
    842      1.1  dholland 		 * such that the server throws away the clientid before
    843      1.1  dholland 		 * receiving the SetClientIDConfirm.
    844      1.1  dholland 		 */
    845      1.1  dholland 		if (clp->nfsc_renew > 0)
    846      1.1  dholland 			clidinusedelay = NFSCL_LEASE(clp->nfsc_renew) * 2;
    847      1.1  dholland 		else
    848      1.1  dholland 			clidinusedelay = 120;
    849      1.1  dholland 		trystalecnt = 3;
    850      1.1  dholland 		do {
    851      1.1  dholland 			error = nfsrpc_setclient(nmp, clp, 0, cred, p);
    852      1.1  dholland 			if (error == NFSERR_STALECLIENTID ||
    853      1.1  dholland 			    error == NFSERR_STALEDONTRECOVER ||
    854      1.1  dholland 			    error == NFSERR_BADSESSION ||
    855      1.1  dholland 			    error == NFSERR_CLIDINUSE) {
    856      1.1  dholland 				(void) nfs_catnap(PZERO, error, "nfs_setcl");
    857      1.1  dholland 			}
    858      1.1  dholland 		} while (((error == NFSERR_STALECLIENTID ||
    859      1.1  dholland 		     error == NFSERR_BADSESSION ||
    860      1.1  dholland 		     error == NFSERR_STALEDONTRECOVER) && --trystalecnt > 0) ||
    861      1.1  dholland 		    (error == NFSERR_CLIDINUSE && --clidinusedelay > 0));
    862      1.1  dholland 		if (error) {
    863      1.1  dholland 			NFSLOCKCLSTATE();
    864      1.1  dholland 			nfsv4_unlock(&clp->nfsc_lock, 0);
    865      1.1  dholland 			NFSUNLOCKCLSTATE();
    866      1.1  dholland 			return (error);
    867      1.1  dholland 		}
    868      1.1  dholland 		clp->nfsc_flags |= NFSCLFLAGS_HASCLIENTID;
    869      1.1  dholland 	}
    870      1.1  dholland 	if (igotlock) {
    871      1.1  dholland 		NFSLOCKCLSTATE();
    872      1.1  dholland 		nfsv4_unlock(&clp->nfsc_lock, 1);
    873      1.1  dholland 		NFSUNLOCKCLSTATE();
    874      1.1  dholland 	}
    875      1.1  dholland 
    876      1.1  dholland 	*clpp = clp;
    877      1.1  dholland 	return (0);
    878      1.1  dholland }
    879      1.1  dholland 
    880      1.1  dholland /*
    881      1.1  dholland  * Get a reference to a clientid and return it, if valid.
    882      1.1  dholland  */
    883      1.1  dholland APPLESTATIC struct nfsclclient *
    884      1.1  dholland nfscl_findcl(struct nfsmount *nmp)
    885      1.1  dholland {
    886      1.1  dholland 	struct nfsclclient *clp;
    887      1.1  dholland 
    888      1.1  dholland 	clp = nmp->nm_clp;
    889      1.1  dholland 	if (clp == NULL || !(clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID))
    890      1.1  dholland 		return (NULL);
    891      1.1  dholland 	return (clp);
    892      1.1  dholland }
    893      1.1  dholland 
    894      1.1  dholland /*
    895      1.1  dholland  * Release the clientid structure. It may be locked or reference counted.
    896      1.1  dholland  */
    897      1.1  dholland static void
    898      1.1  dholland nfscl_clrelease(struct nfsclclient *clp)
    899      1.1  dholland {
    900      1.1  dholland 
    901      1.1  dholland 	if (clp->nfsc_lock.nfslock_lock & NFSV4LOCK_LOCK)
    902      1.1  dholland 		nfsv4_unlock(&clp->nfsc_lock, 0);
    903      1.1  dholland 	else
    904      1.1  dholland 		nfsv4_relref(&clp->nfsc_lock);
    905      1.1  dholland }
    906      1.1  dholland 
    907      1.1  dholland /*
    908      1.1  dholland  * External call for nfscl_clrelease.
    909      1.1  dholland  */
    910      1.1  dholland APPLESTATIC void
    911      1.1  dholland nfscl_clientrelease(struct nfsclclient *clp)
    912      1.1  dholland {
    913      1.1  dholland 
    914      1.1  dholland 	NFSLOCKCLSTATE();
    915      1.1  dholland 	if (clp->nfsc_lock.nfslock_lock & NFSV4LOCK_LOCK)
    916      1.1  dholland 		nfsv4_unlock(&clp->nfsc_lock, 0);
    917      1.1  dholland 	else
    918      1.1  dholland 		nfsv4_relref(&clp->nfsc_lock);
    919      1.1  dholland 	NFSUNLOCKCLSTATE();
    920      1.1  dholland }
    921      1.1  dholland 
    922      1.1  dholland /*
    923      1.1  dholland  * Called when wanting to lock a byte region.
    924      1.1  dholland  */
    925      1.1  dholland APPLESTATIC int
    926      1.1  dholland nfscl_getbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
    927      1.1  dholland     short type, struct ucred *cred, NFSPROC_T *p, struct nfsclclient *rclp,
    928      1.1  dholland     int recovery, void *id, int flags, u_int8_t *rownp, u_int8_t *ropenownp,
    929      1.1  dholland     struct nfscllockowner **lpp, int *newonep, int *donelocallyp)
    930      1.1  dholland {
    931      1.1  dholland 	struct nfscllockowner *lp;
    932      1.1  dholland 	struct nfsclopen *op;
    933      1.1  dholland 	struct nfsclclient *clp;
    934      1.1  dholland 	struct nfscllockowner *nlp;
    935      1.1  dholland 	struct nfscllock *nlop, *otherlop;
    936      1.1  dholland 	struct nfscldeleg *dp = NULL, *ldp = NULL;
    937      1.1  dholland 	struct nfscllockownerhead *lhp = NULL;
    938      1.1  dholland 	struct nfsnode *np;
    939      1.1  dholland 	u_int8_t own[NFSV4CL_LOCKNAMELEN], *ownp, openown[NFSV4CL_LOCKNAMELEN];
    940      1.1  dholland 	u_int8_t *openownp;
    941      1.1  dholland 	int error = 0, ret, donelocally = 0;
    942      1.1  dholland 	u_int32_t mode;
    943      1.1  dholland 
    944      1.1  dholland 	/* For Lock Ops, the open mode doesn't matter, so use 0 to match any. */
    945      1.1  dholland 	mode = 0;
    946      1.1  dholland 	np = VTONFS(vp);
    947      1.1  dholland 	*lpp = NULL;
    948      1.1  dholland 	lp = NULL;
    949      1.1  dholland 	*newonep = 0;
    950      1.1  dholland 	*donelocallyp = 0;
    951      1.1  dholland 
    952      1.1  dholland 	/*
    953      1.1  dholland 	 * Might need these, so MALLOC them now, to
    954      1.1  dholland 	 * avoid a tsleep() in MALLOC later.
    955      1.1  dholland 	 */
    956      1.1  dholland 	MALLOC(nlp, struct nfscllockowner *,
    957      1.1  dholland 	    sizeof (struct nfscllockowner), M_NFSCLLOCKOWNER, M_WAITOK);
    958      1.1  dholland 	MALLOC(otherlop, struct nfscllock *,
    959      1.1  dholland 	    sizeof (struct nfscllock), M_NFSCLLOCK, M_WAITOK);
    960      1.1  dholland 	MALLOC(nlop, struct nfscllock *,
    961      1.1  dholland 	    sizeof (struct nfscllock), M_NFSCLLOCK, M_WAITOK);
    962      1.1  dholland 	nlop->nfslo_type = type;
    963      1.1  dholland 	nlop->nfslo_first = off;
    964      1.1  dholland 	if (len == NFS64BITSSET) {
    965      1.1  dholland 		nlop->nfslo_end = NFS64BITSSET;
    966      1.1  dholland 	} else {
    967      1.1  dholland 		nlop->nfslo_end = off + len;
    968      1.1  dholland 		if (nlop->nfslo_end <= nlop->nfslo_first)
    969      1.1  dholland 			error = NFSERR_INVAL;
    970      1.1  dholland 	}
    971      1.1  dholland 
    972      1.1  dholland 	if (!error) {
    973      1.1  dholland 		if (recovery)
    974      1.1  dholland 			clp = rclp;
    975      1.1  dholland 		else
    976      1.1  dholland 			error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp);
    977      1.1  dholland 	}
    978      1.1  dholland 	if (error) {
    979      1.1  dholland 		FREE((caddr_t)nlp, M_NFSCLLOCKOWNER);
    980      1.1  dholland 		FREE((caddr_t)otherlop, M_NFSCLLOCK);
    981      1.1  dholland 		FREE((caddr_t)nlop, M_NFSCLLOCK);
    982      1.1  dholland 		return (error);
    983      1.1  dholland 	}
    984      1.1  dholland 
    985      1.1  dholland 	op = NULL;
    986      1.1  dholland 	if (recovery) {
    987      1.1  dholland 		ownp = rownp;
    988      1.1  dholland 		openownp = ropenownp;
    989      1.1  dholland 	} else {
    990      1.1  dholland 		nfscl_filllockowner(id, own, flags);
    991      1.1  dholland 		ownp = own;
    992      1.1  dholland 		nfscl_filllockowner(p->td_proc, openown, F_POSIX);
    993      1.1  dholland 		openownp = openown;
    994      1.1  dholland 	}
    995      1.1  dholland 	if (!recovery) {
    996      1.1  dholland 		NFSLOCKCLSTATE();
    997      1.1  dholland 		/*
    998      1.1  dholland 		 * First, search for a delegation. If one exists for this file,
    999      1.1  dholland 		 * the lock can be done locally against it, so long as there
   1000      1.1  dholland 		 * isn't a local lock conflict.
   1001      1.1  dholland 		 */
   1002      1.1  dholland 		ldp = dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh,
   1003      1.1  dholland 		    np->n_fhp->nfh_len);
   1004      1.1  dholland 		/* Just sanity check for correct type of delegation */
   1005      1.1  dholland 		if (dp != NULL && ((dp->nfsdl_flags &
   1006      1.1  dholland 		    (NFSCLDL_RECALL | NFSCLDL_DELEGRET)) != 0 ||
   1007      1.1  dholland 		     (type == F_WRLCK &&
   1008      1.1  dholland 		      (dp->nfsdl_flags & NFSCLDL_WRITE) == 0)))
   1009      1.1  dholland 			dp = NULL;
   1010      1.1  dholland 	}
   1011      1.1  dholland 	if (dp != NULL) {
   1012      1.1  dholland 		/* Now, find an open and maybe a lockowner. */
   1013      1.1  dholland 		ret = nfscl_getopen(&dp->nfsdl_owner, np->n_fhp->nfh_fh,
   1014      1.1  dholland 		    np->n_fhp->nfh_len, openownp, ownp, mode, NULL, &op);
   1015      1.1  dholland 		if (ret)
   1016      1.1  dholland 			ret = nfscl_getopen(&clp->nfsc_owner,
   1017      1.1  dholland 			    np->n_fhp->nfh_fh, np->n_fhp->nfh_len, openownp,
   1018      1.1  dholland 			    ownp, mode, NULL, &op);
   1019      1.1  dholland 		if (!ret) {
   1020      1.1  dholland 			lhp = &dp->nfsdl_lock;
   1021      1.1  dholland 			TAILQ_REMOVE(&clp->nfsc_deleg, dp, nfsdl_list);
   1022      1.1  dholland 			TAILQ_INSERT_HEAD(&clp->nfsc_deleg, dp, nfsdl_list);
   1023      1.1  dholland 			dp->nfsdl_timestamp = NFSD_MONOSEC + 120;
   1024      1.1  dholland 			donelocally = 1;
   1025      1.1  dholland 		} else {
   1026      1.1  dholland 			dp = NULL;
   1027      1.1  dholland 		}
   1028      1.1  dholland 	}
   1029      1.1  dholland 	if (!donelocally) {
   1030      1.1  dholland 		/*
   1031      1.1  dholland 		 * Get the related Open and maybe lockowner.
   1032      1.1  dholland 		 */
   1033      1.1  dholland 		error = nfscl_getopen(&clp->nfsc_owner,
   1034      1.1  dholland 		    np->n_fhp->nfh_fh, np->n_fhp->nfh_len, openownp,
   1035      1.1  dholland 		    ownp, mode, &lp, &op);
   1036      1.1  dholland 		if (!error)
   1037      1.1  dholland 			lhp = &op->nfso_lock;
   1038      1.1  dholland 	}
   1039      1.1  dholland 	if (!error && !recovery)
   1040      1.1  dholland 		error = nfscl_localconflict(clp, np->n_fhp->nfh_fh,
   1041      1.1  dholland 		    np->n_fhp->nfh_len, nlop, ownp, ldp, NULL);
   1042      1.1  dholland 	if (error) {
   1043      1.1  dholland 		if (!recovery) {
   1044      1.1  dholland 			nfscl_clrelease(clp);
   1045      1.1  dholland 			NFSUNLOCKCLSTATE();
   1046      1.1  dholland 		}
   1047      1.1  dholland 		FREE((caddr_t)nlp, M_NFSCLLOCKOWNER);
   1048      1.1  dholland 		FREE((caddr_t)otherlop, M_NFSCLLOCK);
   1049      1.1  dholland 		FREE((caddr_t)nlop, M_NFSCLLOCK);
   1050      1.1  dholland 		return (error);
   1051      1.1  dholland 	}
   1052      1.1  dholland 
   1053      1.1  dholland 	/*
   1054      1.1  dholland 	 * Ok, see if a lockowner exists and create one, as required.
   1055      1.1  dholland 	 */
   1056      1.1  dholland 	if (lp == NULL)
   1057      1.1  dholland 		LIST_FOREACH(lp, lhp, nfsl_list) {
   1058      1.1  dholland 			if (!NFSBCMP(lp->nfsl_owner, ownp, NFSV4CL_LOCKNAMELEN))
   1059      1.1  dholland 				break;
   1060      1.1  dholland 		}
   1061      1.1  dholland 	if (lp == NULL) {
   1062      1.1  dholland 		NFSBCOPY(ownp, nlp->nfsl_owner, NFSV4CL_LOCKNAMELEN);
   1063      1.1  dholland 		if (recovery)
   1064      1.1  dholland 			NFSBCOPY(ropenownp, nlp->nfsl_openowner,
   1065      1.1  dholland 			    NFSV4CL_LOCKNAMELEN);
   1066      1.1  dholland 		else
   1067      1.1  dholland 			NFSBCOPY(op->nfso_own->nfsow_owner, nlp->nfsl_openowner,
   1068      1.1  dholland 			    NFSV4CL_LOCKNAMELEN);
   1069      1.1  dholland 		nlp->nfsl_seqid = 0;
   1070      1.1  dholland 		nlp->nfsl_lockflags = flags;
   1071      1.1  dholland 		nlp->nfsl_inprog = NULL;
   1072      1.1  dholland 		nfscl_lockinit(&nlp->nfsl_rwlock);
   1073      1.1  dholland 		LIST_INIT(&nlp->nfsl_lock);
   1074      1.1  dholland 		if (donelocally) {
   1075      1.1  dholland 			nlp->nfsl_open = NULL;
   1076  1.1.1.2  pgoyette 			nfsstatsv1.cllocallockowners++;
   1077      1.1  dholland 		} else {
   1078      1.1  dholland 			nlp->nfsl_open = op;
   1079  1.1.1.2  pgoyette 			nfsstatsv1.cllockowners++;
   1080      1.1  dholland 		}
   1081      1.1  dholland 		LIST_INSERT_HEAD(lhp, nlp, nfsl_list);
   1082      1.1  dholland 		lp = nlp;
   1083      1.1  dholland 		nlp = NULL;
   1084      1.1  dholland 		*newonep = 1;
   1085      1.1  dholland 	}
   1086      1.1  dholland 
   1087      1.1  dholland 	/*
   1088      1.1  dholland 	 * Now, update the byte ranges for locks.
   1089      1.1  dholland 	 */
   1090      1.1  dholland 	ret = nfscl_updatelock(lp, &nlop, &otherlop, donelocally);
   1091      1.1  dholland 	if (!ret)
   1092      1.1  dholland 		donelocally = 1;
   1093      1.1  dholland 	if (donelocally) {
   1094      1.1  dholland 		*donelocallyp = 1;
   1095      1.1  dholland 		if (!recovery)
   1096      1.1  dholland 			nfscl_clrelease(clp);
   1097      1.1  dholland 	} else {
   1098      1.1  dholland 		/*
   1099      1.1  dholland 		 * Serial modifications on the lock owner for multiple threads
   1100      1.1  dholland 		 * for the same process using a read/write lock.
   1101      1.1  dholland 		 */
   1102      1.1  dholland 		if (!recovery)
   1103      1.1  dholland 			nfscl_lockexcl(&lp->nfsl_rwlock, NFSCLSTATEMUTEXPTR);
   1104      1.1  dholland 	}
   1105      1.1  dholland 	if (!recovery)
   1106      1.1  dholland 		NFSUNLOCKCLSTATE();
   1107      1.1  dholland 
   1108      1.1  dholland 	if (nlp)
   1109      1.1  dholland 		FREE((caddr_t)nlp, M_NFSCLLOCKOWNER);
   1110      1.1  dholland 	if (nlop)
   1111      1.1  dholland 		FREE((caddr_t)nlop, M_NFSCLLOCK);
   1112      1.1  dholland 	if (otherlop)
   1113      1.1  dholland 		FREE((caddr_t)otherlop, M_NFSCLLOCK);
   1114      1.1  dholland 
   1115      1.1  dholland 	*lpp = lp;
   1116      1.1  dholland 	return (0);
   1117      1.1  dholland }
   1118      1.1  dholland 
   1119      1.1  dholland /*
   1120      1.1  dholland  * Called to unlock a byte range, for LockU.
   1121      1.1  dholland  */
   1122      1.1  dholland APPLESTATIC int
   1123      1.1  dholland nfscl_relbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
   1124      1.1  dholland     __unused struct ucred *cred, NFSPROC_T *p, int callcnt,
   1125      1.1  dholland     struct nfsclclient *clp, void *id, int flags,
   1126      1.1  dholland     struct nfscllockowner **lpp, int *dorpcp)
   1127      1.1  dholland {
   1128      1.1  dholland 	struct nfscllockowner *lp;
   1129      1.1  dholland 	struct nfsclowner *owp;
   1130      1.1  dholland 	struct nfsclopen *op;
   1131      1.1  dholland 	struct nfscllock *nlop, *other_lop = NULL;
   1132      1.1  dholland 	struct nfscldeleg *dp;
   1133      1.1  dholland 	struct nfsnode *np;
   1134      1.1  dholland 	u_int8_t own[NFSV4CL_LOCKNAMELEN];
   1135      1.1  dholland 	int ret = 0, fnd;
   1136      1.1  dholland 
   1137      1.1  dholland 	np = VTONFS(vp);
   1138      1.1  dholland 	*lpp = NULL;
   1139      1.1  dholland 	*dorpcp = 0;
   1140      1.1  dholland 
   1141      1.1  dholland 	/*
   1142      1.1  dholland 	 * Might need these, so MALLOC them now, to
   1143      1.1  dholland 	 * avoid a tsleep() in MALLOC later.
   1144      1.1  dholland 	 */
   1145      1.1  dholland 	MALLOC(nlop, struct nfscllock *,
   1146      1.1  dholland 	    sizeof (struct nfscllock), M_NFSCLLOCK, M_WAITOK);
   1147      1.1  dholland 	nlop->nfslo_type = F_UNLCK;
   1148      1.1  dholland 	nlop->nfslo_first = off;
   1149      1.1  dholland 	if (len == NFS64BITSSET) {
   1150      1.1  dholland 		nlop->nfslo_end = NFS64BITSSET;
   1151      1.1  dholland 	} else {
   1152      1.1  dholland 		nlop->nfslo_end = off + len;
   1153      1.1  dholland 		if (nlop->nfslo_end <= nlop->nfslo_first) {
   1154      1.1  dholland 			FREE((caddr_t)nlop, M_NFSCLLOCK);
   1155      1.1  dholland 			return (NFSERR_INVAL);
   1156      1.1  dholland 		}
   1157      1.1  dholland 	}
   1158      1.1  dholland 	if (callcnt == 0) {
   1159      1.1  dholland 		MALLOC(other_lop, struct nfscllock *,
   1160      1.1  dholland 		    sizeof (struct nfscllock), M_NFSCLLOCK, M_WAITOK);
   1161      1.1  dholland 		*other_lop = *nlop;
   1162      1.1  dholland 	}
   1163      1.1  dholland 	nfscl_filllockowner(id, own, flags);
   1164      1.1  dholland 	dp = NULL;
   1165      1.1  dholland 	NFSLOCKCLSTATE();
   1166      1.1  dholland 	if (callcnt == 0)
   1167      1.1  dholland 		dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh,
   1168      1.1  dholland 		    np->n_fhp->nfh_len);
   1169      1.1  dholland 
   1170      1.1  dholland 	/*
   1171      1.1  dholland 	 * First, unlock any local regions on a delegation.
   1172      1.1  dholland 	 */
   1173      1.1  dholland 	if (dp != NULL) {
   1174      1.1  dholland 		/* Look for this lockowner. */
   1175      1.1  dholland 		LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) {
   1176      1.1  dholland 			if (!NFSBCMP(lp->nfsl_owner, own,
   1177      1.1  dholland 			    NFSV4CL_LOCKNAMELEN))
   1178      1.1  dholland 				break;
   1179      1.1  dholland 		}
   1180      1.1  dholland 		if (lp != NULL)
   1181      1.1  dholland 			/* Use other_lop, so nlop is still available */
   1182      1.1  dholland 			(void)nfscl_updatelock(lp, &other_lop, NULL, 1);
   1183      1.1  dholland 	}
   1184      1.1  dholland 
   1185      1.1  dholland 	/*
   1186      1.1  dholland 	 * Now, find a matching open/lockowner that hasn't already been done,
   1187      1.1  dholland 	 * as marked by nfsl_inprog.
   1188      1.1  dholland 	 */
   1189      1.1  dholland 	lp = NULL;
   1190      1.1  dholland 	fnd = 0;
   1191      1.1  dholland 	LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
   1192      1.1  dholland 	    LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
   1193      1.1  dholland 		if (op->nfso_fhlen == np->n_fhp->nfh_len &&
   1194      1.1  dholland 		    !NFSBCMP(op->nfso_fh, np->n_fhp->nfh_fh, op->nfso_fhlen)) {
   1195      1.1  dholland 		    LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
   1196      1.1  dholland 			if (lp->nfsl_inprog == NULL &&
   1197      1.1  dholland 			    !NFSBCMP(lp->nfsl_owner, own,
   1198      1.1  dholland 			     NFSV4CL_LOCKNAMELEN)) {
   1199      1.1  dholland 				fnd = 1;
   1200      1.1  dholland 				break;
   1201      1.1  dholland 			}
   1202      1.1  dholland 		    }
   1203      1.1  dholland 		    if (fnd)
   1204      1.1  dholland 			break;
   1205      1.1  dholland 		}
   1206      1.1  dholland 	    }
   1207      1.1  dholland 	    if (fnd)
   1208      1.1  dholland 		break;
   1209      1.1  dholland 	}
   1210      1.1  dholland 
   1211      1.1  dholland 	if (lp != NULL) {
   1212      1.1  dholland 		ret = nfscl_updatelock(lp, &nlop, NULL, 0);
   1213      1.1  dholland 		if (ret)
   1214      1.1  dholland 			*dorpcp = 1;
   1215      1.1  dholland 		/*
   1216      1.1  dholland 		 * Serial modifications on the lock owner for multiple
   1217      1.1  dholland 		 * threads for the same process using a read/write lock.
   1218      1.1  dholland 		 */
   1219      1.1  dholland 		lp->nfsl_inprog = p;
   1220      1.1  dholland 		nfscl_lockexcl(&lp->nfsl_rwlock, NFSCLSTATEMUTEXPTR);
   1221      1.1  dholland 		*lpp = lp;
   1222      1.1  dholland 	}
   1223      1.1  dholland 	NFSUNLOCKCLSTATE();
   1224      1.1  dholland 	if (nlop)
   1225      1.1  dholland 		FREE((caddr_t)nlop, M_NFSCLLOCK);
   1226      1.1  dholland 	if (other_lop)
   1227      1.1  dholland 		FREE((caddr_t)other_lop, M_NFSCLLOCK);
   1228      1.1  dholland 	return (0);
   1229      1.1  dholland }
   1230      1.1  dholland 
   1231      1.1  dholland /*
   1232      1.1  dholland  * Release all lockowners marked in progess for this process and file.
   1233      1.1  dholland  */
   1234      1.1  dholland APPLESTATIC void
   1235      1.1  dholland nfscl_releasealllocks(struct nfsclclient *clp, vnode_t vp, NFSPROC_T *p,
   1236      1.1  dholland     void *id, int flags)
   1237      1.1  dholland {
   1238      1.1  dholland 	struct nfsclowner *owp;
   1239      1.1  dholland 	struct nfsclopen *op;
   1240      1.1  dholland 	struct nfscllockowner *lp;
   1241      1.1  dholland 	struct nfsnode *np;
   1242      1.1  dholland 	u_int8_t own[NFSV4CL_LOCKNAMELEN];
   1243      1.1  dholland 
   1244      1.1  dholland 	np = VTONFS(vp);
   1245      1.1  dholland 	nfscl_filllockowner(id, own, flags);
   1246      1.1  dholland 	NFSLOCKCLSTATE();
   1247      1.1  dholland 	LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
   1248      1.1  dholland 	    LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
   1249      1.1  dholland 		if (op->nfso_fhlen == np->n_fhp->nfh_len &&
   1250      1.1  dholland 		    !NFSBCMP(op->nfso_fh, np->n_fhp->nfh_fh, op->nfso_fhlen)) {
   1251      1.1  dholland 		    LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
   1252      1.1  dholland 			if (lp->nfsl_inprog == p &&
   1253      1.1  dholland 			    !NFSBCMP(lp->nfsl_owner, own,
   1254      1.1  dholland 			    NFSV4CL_LOCKNAMELEN)) {
   1255      1.1  dholland 			    lp->nfsl_inprog = NULL;
   1256      1.1  dholland 			    nfscl_lockunlock(&lp->nfsl_rwlock);
   1257      1.1  dholland 			}
   1258      1.1  dholland 		    }
   1259      1.1  dholland 		}
   1260      1.1  dholland 	    }
   1261      1.1  dholland 	}
   1262      1.1  dholland 	nfscl_clrelease(clp);
   1263      1.1  dholland 	NFSUNLOCKCLSTATE();
   1264      1.1  dholland }
   1265      1.1  dholland 
   1266      1.1  dholland /*
   1267      1.1  dholland  * Called to find out if any bytes within the byte range specified are
   1268      1.1  dholland  * write locked by the calling process. Used to determine if flushing
   1269      1.1  dholland  * is required before a LockU.
   1270      1.1  dholland  * If in doubt, return 1, so the flush will occur.
   1271      1.1  dholland  */
   1272      1.1  dholland APPLESTATIC int
   1273      1.1  dholland nfscl_checkwritelocked(vnode_t vp, struct flock *fl,
   1274      1.1  dholland     struct ucred *cred, NFSPROC_T *p, void *id, int flags)
   1275      1.1  dholland {
   1276      1.1  dholland 	struct nfsclowner *owp;
   1277      1.1  dholland 	struct nfscllockowner *lp;
   1278      1.1  dholland 	struct nfsclopen *op;
   1279      1.1  dholland 	struct nfsclclient *clp;
   1280      1.1  dholland 	struct nfscllock *lop;
   1281      1.1  dholland 	struct nfscldeleg *dp;
   1282      1.1  dholland 	struct nfsnode *np;
   1283      1.1  dholland 	u_int64_t off, end;
   1284      1.1  dholland 	u_int8_t own[NFSV4CL_LOCKNAMELEN];
   1285      1.1  dholland 	int error = 0;
   1286      1.1  dholland 
   1287      1.1  dholland 	np = VTONFS(vp);
   1288      1.1  dholland 	switch (fl->l_whence) {
   1289      1.1  dholland 	case SEEK_SET:
   1290      1.1  dholland 	case SEEK_CUR:
   1291      1.1  dholland 		/*
   1292      1.1  dholland 		 * Caller is responsible for adding any necessary offset
   1293      1.1  dholland 		 * when SEEK_CUR is used.
   1294      1.1  dholland 		 */
   1295      1.1  dholland 		off = fl->l_start;
   1296      1.1  dholland 		break;
   1297      1.1  dholland 	case SEEK_END:
   1298      1.1  dholland 		off = np->n_size + fl->l_start;
   1299      1.1  dholland 		break;
   1300      1.1  dholland 	default:
   1301      1.1  dholland 		return (1);
   1302  1.1.1.2  pgoyette 	}
   1303      1.1  dholland 	if (fl->l_len != 0) {
   1304      1.1  dholland 		end = off + fl->l_len;
   1305      1.1  dholland 		if (end < off)
   1306      1.1  dholland 			return (1);
   1307      1.1  dholland 	} else {
   1308      1.1  dholland 		end = NFS64BITSSET;
   1309      1.1  dholland 	}
   1310      1.1  dholland 
   1311      1.1  dholland 	error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp);
   1312      1.1  dholland 	if (error)
   1313      1.1  dholland 		return (1);
   1314      1.1  dholland 	nfscl_filllockowner(id, own, flags);
   1315      1.1  dholland 	NFSLOCKCLSTATE();
   1316      1.1  dholland 
   1317      1.1  dholland 	/*
   1318      1.1  dholland 	 * First check the delegation locks.
   1319      1.1  dholland 	 */
   1320      1.1  dholland 	dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
   1321      1.1  dholland 	if (dp != NULL) {
   1322      1.1  dholland 		LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) {
   1323      1.1  dholland 			if (!NFSBCMP(lp->nfsl_owner, own,
   1324      1.1  dholland 			    NFSV4CL_LOCKNAMELEN))
   1325      1.1  dholland 				break;
   1326      1.1  dholland 		}
   1327      1.1  dholland 		if (lp != NULL) {
   1328      1.1  dholland 			LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) {
   1329      1.1  dholland 				if (lop->nfslo_first >= end)
   1330      1.1  dholland 					break;
   1331      1.1  dholland 				if (lop->nfslo_end <= off)
   1332      1.1  dholland 					continue;
   1333      1.1  dholland 				if (lop->nfslo_type == F_WRLCK) {
   1334      1.1  dholland 					nfscl_clrelease(clp);
   1335      1.1  dholland 					NFSUNLOCKCLSTATE();
   1336      1.1  dholland 					return (1);
   1337      1.1  dholland 				}
   1338      1.1  dholland 			}
   1339      1.1  dholland 		}
   1340      1.1  dholland 	}
   1341      1.1  dholland 
   1342      1.1  dholland 	/*
   1343      1.1  dholland 	 * Now, check state against the server.
   1344      1.1  dholland 	 */
   1345      1.1  dholland 	LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
   1346      1.1  dholland 	    LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
   1347      1.1  dholland 		if (op->nfso_fhlen == np->n_fhp->nfh_len &&
   1348      1.1  dholland 		    !NFSBCMP(op->nfso_fh, np->n_fhp->nfh_fh, op->nfso_fhlen)) {
   1349      1.1  dholland 		    LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
   1350      1.1  dholland 			if (!NFSBCMP(lp->nfsl_owner, own,
   1351      1.1  dholland 			    NFSV4CL_LOCKNAMELEN))
   1352      1.1  dholland 			    break;
   1353      1.1  dholland 		    }
   1354      1.1  dholland 		    if (lp != NULL) {
   1355      1.1  dholland 			LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) {
   1356      1.1  dholland 			    if (lop->nfslo_first >= end)
   1357      1.1  dholland 				break;
   1358      1.1  dholland 			    if (lop->nfslo_end <= off)
   1359      1.1  dholland 				continue;
   1360      1.1  dholland 			    if (lop->nfslo_type == F_WRLCK) {
   1361      1.1  dholland 				nfscl_clrelease(clp);
   1362      1.1  dholland 				NFSUNLOCKCLSTATE();
   1363      1.1  dholland 				return (1);
   1364      1.1  dholland 			    }
   1365      1.1  dholland 			}
   1366      1.1  dholland 		    }
   1367      1.1  dholland 		}
   1368      1.1  dholland 	    }
   1369      1.1  dholland 	}
   1370      1.1  dholland 	nfscl_clrelease(clp);
   1371      1.1  dholland 	NFSUNLOCKCLSTATE();
   1372      1.1  dholland 	return (0);
   1373      1.1  dholland }
   1374      1.1  dholland 
   1375      1.1  dholland /*
   1376      1.1  dholland  * Release a byte range lock owner structure.
   1377      1.1  dholland  */
   1378      1.1  dholland APPLESTATIC void
   1379      1.1  dholland nfscl_lockrelease(struct nfscllockowner *lp, int error, int candelete)
   1380      1.1  dholland {
   1381      1.1  dholland 	struct nfsclclient *clp;
   1382      1.1  dholland 
   1383      1.1  dholland 	if (lp == NULL)
   1384      1.1  dholland 		return;
   1385      1.1  dholland 	NFSLOCKCLSTATE();
   1386      1.1  dholland 	clp = lp->nfsl_open->nfso_own->nfsow_clp;
   1387      1.1  dholland 	if (error != 0 && candelete &&
   1388      1.1  dholland 	    (lp->nfsl_rwlock.nfslock_lock & NFSV4LOCK_WANTED) == 0)
   1389      1.1  dholland 		nfscl_freelockowner(lp, 0);
   1390      1.1  dholland 	else
   1391      1.1  dholland 		nfscl_lockunlock(&lp->nfsl_rwlock);
   1392      1.1  dholland 	nfscl_clrelease(clp);
   1393      1.1  dholland 	NFSUNLOCKCLSTATE();
   1394      1.1  dholland }
   1395      1.1  dholland 
   1396      1.1  dholland /*
   1397      1.1  dholland  * Free up an open structure and any associated byte range lock structures.
   1398      1.1  dholland  */
   1399      1.1  dholland APPLESTATIC void
   1400      1.1  dholland nfscl_freeopen(struct nfsclopen *op, int local)
   1401      1.1  dholland {
   1402      1.1  dholland 
   1403      1.1  dholland 	LIST_REMOVE(op, nfso_list);
   1404      1.1  dholland 	nfscl_freealllocks(&op->nfso_lock, local);
   1405      1.1  dholland 	FREE((caddr_t)op, M_NFSCLOPEN);
   1406      1.1  dholland 	if (local)
   1407  1.1.1.2  pgoyette 		nfsstatsv1.cllocalopens--;
   1408      1.1  dholland 	else
   1409  1.1.1.2  pgoyette 		nfsstatsv1.clopens--;
   1410      1.1  dholland }
   1411      1.1  dholland 
   1412      1.1  dholland /*
   1413      1.1  dholland  * Free up all lock owners and associated locks.
   1414      1.1  dholland  */
   1415      1.1  dholland static void
   1416      1.1  dholland nfscl_freealllocks(struct nfscllockownerhead *lhp, int local)
   1417      1.1  dholland {
   1418      1.1  dholland 	struct nfscllockowner *lp, *nlp;
   1419      1.1  dholland 
   1420      1.1  dholland 	LIST_FOREACH_SAFE(lp, lhp, nfsl_list, nlp) {
   1421      1.1  dholland 		if ((lp->nfsl_rwlock.nfslock_lock & NFSV4LOCK_WANTED))
   1422      1.1  dholland 			panic("nfscllckw");
   1423      1.1  dholland 		nfscl_freelockowner(lp, local);
   1424      1.1  dholland 	}
   1425      1.1  dholland }
   1426      1.1  dholland 
   1427      1.1  dholland /*
   1428      1.1  dholland  * Called for an Open when NFSERR_EXPIRED is received from the server.
   1429      1.1  dholland  * If there are no byte range locks nor a Share Deny lost, try to do a
   1430      1.1  dholland  * fresh Open. Otherwise, free the open.
   1431      1.1  dholland  */
   1432      1.1  dholland static int
   1433      1.1  dholland nfscl_expireopen(struct nfsclclient *clp, struct nfsclopen *op,
   1434      1.1  dholland     struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p)
   1435      1.1  dholland {
   1436      1.1  dholland 	struct nfscllockowner *lp;
   1437      1.1  dholland 	struct nfscldeleg *dp;
   1438      1.1  dholland 	int mustdelete = 0, error;
   1439      1.1  dholland 
   1440      1.1  dholland 	/*
   1441      1.1  dholland 	 * Look for any byte range lock(s).
   1442      1.1  dholland 	 */
   1443      1.1  dholland 	LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
   1444      1.1  dholland 		if (!LIST_EMPTY(&lp->nfsl_lock)) {
   1445      1.1  dholland 			mustdelete = 1;
   1446      1.1  dholland 			break;
   1447      1.1  dholland 		}
   1448      1.1  dholland 	}
   1449      1.1  dholland 
   1450      1.1  dholland 	/*
   1451      1.1  dholland 	 * If no byte range lock(s) nor a Share deny, try to re-open.
   1452      1.1  dholland 	 */
   1453      1.1  dholland 	if (!mustdelete && (op->nfso_mode & NFSLCK_DENYBITS) == 0) {
   1454      1.1  dholland 		newnfs_copycred(&op->nfso_cred, cred);
   1455      1.1  dholland 		dp = NULL;
   1456      1.1  dholland 		error = nfsrpc_reopen(nmp, op->nfso_fh,
   1457      1.1  dholland 		    op->nfso_fhlen, op->nfso_mode, op, &dp, cred, p);
   1458      1.1  dholland 		if (error) {
   1459      1.1  dholland 			mustdelete = 1;
   1460      1.1  dholland 			if (dp != NULL) {
   1461      1.1  dholland 				FREE((caddr_t)dp, M_NFSCLDELEG);
   1462      1.1  dholland 				dp = NULL;
   1463      1.1  dholland 			}
   1464      1.1  dholland 		}
   1465      1.1  dholland 		if (dp != NULL)
   1466      1.1  dholland 			nfscl_deleg(nmp->nm_mountp, clp, op->nfso_fh,
   1467      1.1  dholland 			    op->nfso_fhlen, cred, p, &dp);
   1468      1.1  dholland 	}
   1469      1.1  dholland 
   1470      1.1  dholland 	/*
   1471      1.1  dholland 	 * If a byte range lock or Share deny or couldn't re-open, free it.
   1472      1.1  dholland 	 */
   1473      1.1  dholland 	if (mustdelete)
   1474      1.1  dholland 		nfscl_freeopen(op, 0);
   1475      1.1  dholland 	return (mustdelete);
   1476      1.1  dholland }
   1477      1.1  dholland 
   1478      1.1  dholland /*
   1479      1.1  dholland  * Free up an open owner structure.
   1480      1.1  dholland  */
   1481      1.1  dholland static void
   1482      1.1  dholland nfscl_freeopenowner(struct nfsclowner *owp, int local)
   1483      1.1  dholland {
   1484      1.1  dholland 
   1485      1.1  dholland 	LIST_REMOVE(owp, nfsow_list);
   1486      1.1  dholland 	FREE((caddr_t)owp, M_NFSCLOWNER);
   1487      1.1  dholland 	if (local)
   1488  1.1.1.2  pgoyette 		nfsstatsv1.cllocalopenowners--;
   1489      1.1  dholland 	else
   1490  1.1.1.2  pgoyette 		nfsstatsv1.clopenowners--;
   1491      1.1  dholland }
   1492      1.1  dholland 
   1493      1.1  dholland /*
   1494      1.1  dholland  * Free up a byte range lock owner structure.
   1495      1.1  dholland  */
   1496      1.1  dholland APPLESTATIC void
   1497      1.1  dholland nfscl_freelockowner(struct nfscllockowner *lp, int local)
   1498      1.1  dholland {
   1499      1.1  dholland 	struct nfscllock *lop, *nlop;
   1500      1.1  dholland 
   1501      1.1  dholland 	LIST_REMOVE(lp, nfsl_list);
   1502      1.1  dholland 	LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) {
   1503      1.1  dholland 		nfscl_freelock(lop, local);
   1504      1.1  dholland 	}
   1505      1.1  dholland 	FREE((caddr_t)lp, M_NFSCLLOCKOWNER);
   1506      1.1  dholland 	if (local)
   1507  1.1.1.2  pgoyette 		nfsstatsv1.cllocallockowners--;
   1508      1.1  dholland 	else
   1509  1.1.1.2  pgoyette 		nfsstatsv1.cllockowners--;
   1510      1.1  dholland }
   1511      1.1  dholland 
   1512      1.1  dholland /*
   1513      1.1  dholland  * Free up a byte range lock structure.
   1514      1.1  dholland  */
   1515      1.1  dholland APPLESTATIC void
   1516      1.1  dholland nfscl_freelock(struct nfscllock *lop, int local)
   1517      1.1  dholland {
   1518      1.1  dholland 
   1519      1.1  dholland 	LIST_REMOVE(lop, nfslo_list);
   1520      1.1  dholland 	FREE((caddr_t)lop, M_NFSCLLOCK);
   1521      1.1  dholland 	if (local)
   1522  1.1.1.2  pgoyette 		nfsstatsv1.cllocallocks--;
   1523      1.1  dholland 	else
   1524  1.1.1.2  pgoyette 		nfsstatsv1.cllocks--;
   1525      1.1  dholland }
   1526      1.1  dholland 
   1527      1.1  dholland /*
   1528      1.1  dholland  * Clean out the state related to a delegation.
   1529      1.1  dholland  */
   1530      1.1  dholland static void
   1531      1.1  dholland nfscl_cleandeleg(struct nfscldeleg *dp)
   1532      1.1  dholland {
   1533      1.1  dholland 	struct nfsclowner *owp, *nowp;
   1534      1.1  dholland 	struct nfsclopen *op;
   1535      1.1  dholland 
   1536      1.1  dholland 	LIST_FOREACH_SAFE(owp, &dp->nfsdl_owner, nfsow_list, nowp) {
   1537      1.1  dholland 		op = LIST_FIRST(&owp->nfsow_open);
   1538      1.1  dholland 		if (op != NULL) {
   1539      1.1  dholland 			if (LIST_NEXT(op, nfso_list) != NULL)
   1540      1.1  dholland 				panic("nfscleandel");
   1541      1.1  dholland 			nfscl_freeopen(op, 1);
   1542      1.1  dholland 		}
   1543      1.1  dholland 		nfscl_freeopenowner(owp, 1);
   1544      1.1  dholland 	}
   1545      1.1  dholland 	nfscl_freealllocks(&dp->nfsdl_lock, 1);
   1546      1.1  dholland }
   1547      1.1  dholland 
   1548      1.1  dholland /*
   1549      1.1  dholland  * Free a delegation.
   1550      1.1  dholland  */
   1551      1.1  dholland static void
   1552      1.1  dholland nfscl_freedeleg(struct nfscldeleghead *hdp, struct nfscldeleg *dp)
   1553      1.1  dholland {
   1554      1.1  dholland 
   1555      1.1  dholland 	TAILQ_REMOVE(hdp, dp, nfsdl_list);
   1556      1.1  dholland 	LIST_REMOVE(dp, nfsdl_hash);
   1557      1.1  dholland 	FREE((caddr_t)dp, M_NFSCLDELEG);
   1558  1.1.1.2  pgoyette 	nfsstatsv1.cldelegates--;
   1559      1.1  dholland 	nfscl_delegcnt--;
   1560      1.1  dholland }
   1561      1.1  dholland 
   1562      1.1  dholland /*
   1563      1.1  dholland  * Free up all state related to this client structure.
   1564      1.1  dholland  */
   1565      1.1  dholland static void
   1566      1.1  dholland nfscl_cleanclient(struct nfsclclient *clp)
   1567      1.1  dholland {
   1568      1.1  dholland 	struct nfsclowner *owp, *nowp;
   1569      1.1  dholland 	struct nfsclopen *op, *nop;
   1570      1.1  dholland 
   1571      1.1  dholland 	/* Now, all the OpenOwners, etc. */
   1572      1.1  dholland 	LIST_FOREACH_SAFE(owp, &clp->nfsc_owner, nfsow_list, nowp) {
   1573      1.1  dholland 		LIST_FOREACH_SAFE(op, &owp->nfsow_open, nfso_list, nop) {
   1574      1.1  dholland 			nfscl_freeopen(op, 0);
   1575      1.1  dholland 		}
   1576      1.1  dholland 		nfscl_freeopenowner(owp, 0);
   1577      1.1  dholland 	}
   1578      1.1  dholland }
   1579      1.1  dholland 
   1580      1.1  dholland /*
   1581      1.1  dholland  * Called when an NFSERR_EXPIRED is received from the server.
   1582      1.1  dholland  */
   1583      1.1  dholland static void
   1584      1.1  dholland nfscl_expireclient(struct nfsclclient *clp, struct nfsmount *nmp,
   1585      1.1  dholland     struct ucred *cred, NFSPROC_T *p)
   1586      1.1  dholland {
   1587      1.1  dholland 	struct nfsclowner *owp, *nowp, *towp;
   1588      1.1  dholland 	struct nfsclopen *op, *nop, *top;
   1589      1.1  dholland 	struct nfscldeleg *dp, *ndp;
   1590      1.1  dholland 	int ret, printed = 0;
   1591      1.1  dholland 
   1592      1.1  dholland 	/*
   1593      1.1  dholland 	 * First, merge locally issued Opens into the list for the server.
   1594      1.1  dholland 	 */
   1595      1.1  dholland 	dp = TAILQ_FIRST(&clp->nfsc_deleg);
   1596      1.1  dholland 	while (dp != NULL) {
   1597      1.1  dholland 	    ndp = TAILQ_NEXT(dp, nfsdl_list);
   1598      1.1  dholland 	    owp = LIST_FIRST(&dp->nfsdl_owner);
   1599      1.1  dholland 	    while (owp != NULL) {
   1600      1.1  dholland 		nowp = LIST_NEXT(owp, nfsow_list);
   1601      1.1  dholland 		op = LIST_FIRST(&owp->nfsow_open);
   1602      1.1  dholland 		if (op != NULL) {
   1603      1.1  dholland 		    if (LIST_NEXT(op, nfso_list) != NULL)
   1604      1.1  dholland 			panic("nfsclexp");
   1605      1.1  dholland 		    LIST_FOREACH(towp, &clp->nfsc_owner, nfsow_list) {
   1606      1.1  dholland 			if (!NFSBCMP(towp->nfsow_owner, owp->nfsow_owner,
   1607      1.1  dholland 			    NFSV4CL_LOCKNAMELEN))
   1608      1.1  dholland 			    break;
   1609      1.1  dholland 		    }
   1610      1.1  dholland 		    if (towp != NULL) {
   1611      1.1  dholland 			/* Merge opens in */
   1612      1.1  dholland 			LIST_FOREACH(top, &towp->nfsow_open, nfso_list) {
   1613      1.1  dholland 			    if (top->nfso_fhlen == op->nfso_fhlen &&
   1614      1.1  dholland 				!NFSBCMP(top->nfso_fh, op->nfso_fh,
   1615      1.1  dholland 				 op->nfso_fhlen)) {
   1616      1.1  dholland 				top->nfso_mode |= op->nfso_mode;
   1617      1.1  dholland 				top->nfso_opencnt += op->nfso_opencnt;
   1618      1.1  dholland 				break;
   1619      1.1  dholland 			    }
   1620      1.1  dholland 			}
   1621      1.1  dholland 			if (top == NULL) {
   1622      1.1  dholland 			    /* Just add the open to the owner list */
   1623      1.1  dholland 			    LIST_REMOVE(op, nfso_list);
   1624      1.1  dholland 			    op->nfso_own = towp;
   1625      1.1  dholland 			    LIST_INSERT_HEAD(&towp->nfsow_open, op, nfso_list);
   1626  1.1.1.2  pgoyette 			    nfsstatsv1.cllocalopens--;
   1627  1.1.1.2  pgoyette 			    nfsstatsv1.clopens++;
   1628      1.1  dholland 			}
   1629      1.1  dholland 		    } else {
   1630      1.1  dholland 			/* Just add the openowner to the client list */
   1631      1.1  dholland 			LIST_REMOVE(owp, nfsow_list);
   1632      1.1  dholland 			owp->nfsow_clp = clp;
   1633      1.1  dholland 			LIST_INSERT_HEAD(&clp->nfsc_owner, owp, nfsow_list);
   1634  1.1.1.2  pgoyette 			nfsstatsv1.cllocalopenowners--;
   1635  1.1.1.2  pgoyette 			nfsstatsv1.clopenowners++;
   1636  1.1.1.2  pgoyette 			nfsstatsv1.cllocalopens--;
   1637  1.1.1.2  pgoyette 			nfsstatsv1.clopens++;
   1638      1.1  dholland 		    }
   1639      1.1  dholland 		}
   1640      1.1  dholland 		owp = nowp;
   1641      1.1  dholland 	    }
   1642      1.1  dholland 	    if (!printed && !LIST_EMPTY(&dp->nfsdl_lock)) {
   1643      1.1  dholland 		printed = 1;
   1644      1.1  dholland 		printf("nfsv4 expired locks lost\n");
   1645      1.1  dholland 	    }
   1646      1.1  dholland 	    nfscl_cleandeleg(dp);
   1647      1.1  dholland 	    nfscl_freedeleg(&clp->nfsc_deleg, dp);
   1648      1.1  dholland 	    dp = ndp;
   1649      1.1  dholland 	}
   1650      1.1  dholland 	if (!TAILQ_EMPTY(&clp->nfsc_deleg))
   1651      1.1  dholland 	    panic("nfsclexp");
   1652      1.1  dholland 
   1653      1.1  dholland 	/*
   1654      1.1  dholland 	 * Now, try and reopen against the server.
   1655      1.1  dholland 	 */
   1656      1.1  dholland 	LIST_FOREACH_SAFE(owp, &clp->nfsc_owner, nfsow_list, nowp) {
   1657      1.1  dholland 		owp->nfsow_seqid = 0;
   1658      1.1  dholland 		LIST_FOREACH_SAFE(op, &owp->nfsow_open, nfso_list, nop) {
   1659      1.1  dholland 			ret = nfscl_expireopen(clp, op, nmp, cred, p);
   1660      1.1  dholland 			if (ret && !printed) {
   1661      1.1  dholland 				printed = 1;
   1662      1.1  dholland 				printf("nfsv4 expired locks lost\n");
   1663      1.1  dholland 			}
   1664      1.1  dholland 		}
   1665      1.1  dholland 		if (LIST_EMPTY(&owp->nfsow_open))
   1666      1.1  dholland 			nfscl_freeopenowner(owp, 0);
   1667      1.1  dholland 	}
   1668      1.1  dholland }
   1669      1.1  dholland 
   1670      1.1  dholland /*
   1671      1.1  dholland  * This function must be called after the process represented by "own" has
   1672      1.1  dholland  * exited. Must be called with CLSTATE lock held.
   1673      1.1  dholland  */
   1674      1.1  dholland static void
   1675      1.1  dholland nfscl_cleanup_common(struct nfsclclient *clp, u_int8_t *own)
   1676      1.1  dholland {
   1677      1.1  dholland 	struct nfsclowner *owp, *nowp;
   1678      1.1  dholland 	struct nfscllockowner *lp, *nlp;
   1679      1.1  dholland 	struct nfscldeleg *dp;
   1680      1.1  dholland 
   1681      1.1  dholland 	/* First, get rid of local locks on delegations. */
   1682      1.1  dholland 	TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) {
   1683      1.1  dholland 		LIST_FOREACH_SAFE(lp, &dp->nfsdl_lock, nfsl_list, nlp) {
   1684      1.1  dholland 		    if (!NFSBCMP(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN)) {
   1685      1.1  dholland 			if ((lp->nfsl_rwlock.nfslock_lock & NFSV4LOCK_WANTED))
   1686      1.1  dholland 			    panic("nfscllckw");
   1687      1.1  dholland 			nfscl_freelockowner(lp, 1);
   1688      1.1  dholland 		    }
   1689      1.1  dholland 		}
   1690      1.1  dholland 	}
   1691      1.1  dholland 	owp = LIST_FIRST(&clp->nfsc_owner);
   1692      1.1  dholland 	while (owp != NULL) {
   1693      1.1  dholland 		nowp = LIST_NEXT(owp, nfsow_list);
   1694      1.1  dholland 		if (!NFSBCMP(owp->nfsow_owner, own,
   1695      1.1  dholland 		    NFSV4CL_LOCKNAMELEN)) {
   1696      1.1  dholland 			/*
   1697      1.1  dholland 			 * If there are children that haven't closed the
   1698      1.1  dholland 			 * file descriptors yet, the opens will still be
   1699      1.1  dholland 			 * here. For that case, let the renew thread clear
   1700      1.1  dholland 			 * out the OpenOwner later.
   1701      1.1  dholland 			 */
   1702      1.1  dholland 			if (LIST_EMPTY(&owp->nfsow_open))
   1703      1.1  dholland 				nfscl_freeopenowner(owp, 0);
   1704      1.1  dholland 			else
   1705      1.1  dholland 				owp->nfsow_defunct = 1;
   1706      1.1  dholland 		}
   1707      1.1  dholland 		owp = nowp;
   1708      1.1  dholland 	}
   1709      1.1  dholland }
   1710      1.1  dholland 
   1711      1.1  dholland /*
   1712      1.1  dholland  * Find open/lock owners for processes that have exited.
   1713      1.1  dholland  */
   1714      1.1  dholland static void
   1715      1.1  dholland nfscl_cleanupkext(struct nfsclclient *clp, struct nfscllockownerfhhead *lhp)
   1716      1.1  dholland {
   1717      1.1  dholland 	struct nfsclowner *owp, *nowp;
   1718      1.1  dholland 	struct nfsclopen *op;
   1719      1.1  dholland 	struct nfscllockowner *lp, *nlp;
   1720      1.1  dholland 
   1721      1.1  dholland 	NFSPROCLISTLOCK();
   1722      1.1  dholland 	NFSLOCKCLSTATE();
   1723      1.1  dholland 	LIST_FOREACH_SAFE(owp, &clp->nfsc_owner, nfsow_list, nowp) {
   1724      1.1  dholland 		LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
   1725      1.1  dholland 			LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp) {
   1726      1.1  dholland 				if (LIST_EMPTY(&lp->nfsl_lock))
   1727      1.1  dholland 					nfscl_emptylockowner(lp, lhp);
   1728      1.1  dholland 			}
   1729      1.1  dholland 		}
   1730      1.1  dholland 		if (nfscl_procdoesntexist(owp->nfsow_owner))
   1731      1.1  dholland 			nfscl_cleanup_common(clp, owp->nfsow_owner);
   1732      1.1  dholland 	}
   1733      1.1  dholland 	NFSUNLOCKCLSTATE();
   1734      1.1  dholland 	NFSPROCLISTUNLOCK();
   1735      1.1  dholland }
   1736      1.1  dholland 
   1737      1.1  dholland /*
   1738      1.1  dholland  * Take the empty lock owner and move it to the local lhp list if the
   1739      1.1  dholland  * associated process no longer exists.
   1740      1.1  dholland  */
   1741      1.1  dholland static void
   1742      1.1  dholland nfscl_emptylockowner(struct nfscllockowner *lp,
   1743      1.1  dholland     struct nfscllockownerfhhead *lhp)
   1744      1.1  dholland {
   1745      1.1  dholland 	struct nfscllockownerfh *lfhp, *mylfhp;
   1746      1.1  dholland 	struct nfscllockowner *nlp;
   1747      1.1  dholland 	int fnd_it;
   1748      1.1  dholland 
   1749      1.1  dholland 	/* If not a Posix lock owner, just return. */
   1750      1.1  dholland 	if ((lp->nfsl_lockflags & F_POSIX) == 0)
   1751      1.1  dholland 		return;
   1752      1.1  dholland 
   1753      1.1  dholland 	fnd_it = 0;
   1754      1.1  dholland 	mylfhp = NULL;
   1755      1.1  dholland 	/*
   1756      1.1  dholland 	 * First, search to see if this lock owner is already in the list.
   1757      1.1  dholland 	 * If it is, then the associated process no longer exists.
   1758      1.1  dholland 	 */
   1759      1.1  dholland 	SLIST_FOREACH(lfhp, lhp, nfslfh_list) {
   1760      1.1  dholland 		if (lfhp->nfslfh_len == lp->nfsl_open->nfso_fhlen &&
   1761      1.1  dholland 		    !NFSBCMP(lfhp->nfslfh_fh, lp->nfsl_open->nfso_fh,
   1762      1.1  dholland 		    lfhp->nfslfh_len))
   1763      1.1  dholland 			mylfhp = lfhp;
   1764      1.1  dholland 		LIST_FOREACH(nlp, &lfhp->nfslfh_lock, nfsl_list)
   1765      1.1  dholland 			if (!NFSBCMP(nlp->nfsl_owner, lp->nfsl_owner,
   1766      1.1  dholland 			    NFSV4CL_LOCKNAMELEN))
   1767      1.1  dholland 				fnd_it = 1;
   1768      1.1  dholland 	}
   1769      1.1  dholland 	/* If not found, check if process still exists. */
   1770      1.1  dholland 	if (fnd_it == 0 && nfscl_procdoesntexist(lp->nfsl_owner) == 0)
   1771      1.1  dholland 		return;
   1772      1.1  dholland 
   1773      1.1  dholland 	/* Move the lock owner over to the local list. */
   1774      1.1  dholland 	if (mylfhp == NULL) {
   1775      1.1  dholland 		mylfhp = malloc(sizeof(struct nfscllockownerfh), M_TEMP,
   1776      1.1  dholland 		    M_NOWAIT);
   1777      1.1  dholland 		if (mylfhp == NULL)
   1778      1.1  dholland 			return;
   1779      1.1  dholland 		mylfhp->nfslfh_len = lp->nfsl_open->nfso_fhlen;
   1780      1.1  dholland 		NFSBCOPY(lp->nfsl_open->nfso_fh, mylfhp->nfslfh_fh,
   1781      1.1  dholland 		    mylfhp->nfslfh_len);
   1782      1.1  dholland 		LIST_INIT(&mylfhp->nfslfh_lock);
   1783      1.1  dholland 		SLIST_INSERT_HEAD(lhp, mylfhp, nfslfh_list);
   1784      1.1  dholland 	}
   1785      1.1  dholland 	LIST_REMOVE(lp, nfsl_list);
   1786      1.1  dholland 	LIST_INSERT_HEAD(&mylfhp->nfslfh_lock, lp, nfsl_list);
   1787      1.1  dholland }
   1788      1.1  dholland 
   1789      1.1  dholland static int	fake_global;	/* Used to force visibility of MNTK_UNMOUNTF */
   1790      1.1  dholland /*
   1791      1.1  dholland  * Called from nfs umount to free up the clientid.
   1792      1.1  dholland  */
   1793      1.1  dholland APPLESTATIC void
   1794      1.1  dholland nfscl_umount(struct nfsmount *nmp, NFSPROC_T *p)
   1795      1.1  dholland {
   1796      1.1  dholland 	struct nfsclclient *clp;
   1797      1.1  dholland 	struct ucred *cred;
   1798      1.1  dholland 	int igotlock;
   1799      1.1  dholland 
   1800      1.1  dholland 	/*
   1801      1.1  dholland 	 * For the case that matters, this is the thread that set
   1802      1.1  dholland 	 * MNTK_UNMOUNTF, so it will see it set. The code that follows is
   1803      1.1  dholland 	 * done to ensure that any thread executing nfscl_getcl() after
   1804      1.1  dholland 	 * this time, will see MNTK_UNMOUNTF set. nfscl_getcl() uses the
   1805      1.1  dholland 	 * mutex for NFSLOCKCLSTATE(), so it is "m" for the following
   1806      1.1  dholland 	 * explanation, courtesy of Alan Cox.
   1807      1.1  dholland 	 * What follows is a snippet from Alan Cox's email at:
   1808      1.1  dholland 	 * http://docs.FreeBSD.org/cgi/
   1809      1.1  dholland 	 *     mid.cgi?BANLkTikR3d65zPHo9==08ZfJ2vmqZucEvw
   1810      1.1  dholland 	 *
   1811      1.1  dholland 	 * 1. Set MNTK_UNMOUNTF
   1812      1.1  dholland 	 * 2. Acquire a standard FreeBSD mutex "m".
   1813      1.1  dholland 	 * 3. Update some data structures.
   1814      1.1  dholland 	 * 4. Release mutex "m".
   1815      1.1  dholland 	 *
   1816      1.1  dholland 	 * Then, other threads that acquire "m" after step 4 has occurred will
   1817      1.1  dholland 	 * see MNTK_UNMOUNTF as set.  But, other threads that beat thread X to
   1818      1.1  dholland 	 * step 2 may or may not see MNTK_UNMOUNTF as set.
   1819      1.1  dholland 	 */
   1820      1.1  dholland 	NFSLOCKCLSTATE();
   1821      1.1  dholland 	if ((nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
   1822      1.1  dholland 		fake_global++;
   1823      1.1  dholland 		NFSUNLOCKCLSTATE();
   1824      1.1  dholland 		NFSLOCKCLSTATE();
   1825      1.1  dholland 	}
   1826      1.1  dholland 
   1827      1.1  dholland 	clp = nmp->nm_clp;
   1828      1.1  dholland 	if (clp != NULL) {
   1829      1.1  dholland 		if ((clp->nfsc_flags & NFSCLFLAGS_INITED) == 0)
   1830      1.1  dholland 			panic("nfscl umount");
   1831      1.1  dholland 
   1832      1.1  dholland 		/*
   1833      1.1  dholland 		 * First, handshake with the nfscl renew thread, to terminate
   1834      1.1  dholland 		 * it.
   1835      1.1  dholland 		 */
   1836      1.1  dholland 		clp->nfsc_flags |= NFSCLFLAGS_UMOUNT;
   1837      1.1  dholland 		while (clp->nfsc_flags & NFSCLFLAGS_HASTHREAD)
   1838      1.1  dholland 			(void)mtx_sleep(clp, NFSCLSTATEMUTEXPTR, PWAIT,
   1839      1.1  dholland 			    "nfsclumnt", hz);
   1840      1.1  dholland 
   1841      1.1  dholland 		/*
   1842      1.1  dholland 		 * Now, get the exclusive lock on the client state, so
   1843      1.1  dholland 		 * that no uses of the state are still in progress.
   1844      1.1  dholland 		 */
   1845      1.1  dholland 		do {
   1846      1.1  dholland 			igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL,
   1847      1.1  dholland 			    NFSCLSTATEMUTEXPTR, NULL);
   1848      1.1  dholland 		} while (!igotlock);
   1849      1.1  dholland 		NFSUNLOCKCLSTATE();
   1850      1.1  dholland 
   1851      1.1  dholland 		/*
   1852      1.1  dholland 		 * Free up all the state. It will expire on the server, but
   1853      1.1  dholland 		 * maybe we should do a SetClientId/SetClientIdConfirm so
   1854      1.1  dholland 		 * the server throws it away?
   1855      1.1  dholland 		 */
   1856      1.1  dholland 		LIST_REMOVE(clp, nfsc_list);
   1857      1.1  dholland 		nfscl_delegreturnall(clp, p);
   1858      1.1  dholland 		cred = newnfs_getcred();
   1859      1.1  dholland 		if (NFSHASNFSV4N(nmp)) {
   1860      1.1  dholland 			(void)nfsrpc_destroysession(nmp, clp, cred, p);
   1861      1.1  dholland 			(void)nfsrpc_destroyclient(nmp, clp, cred, p);
   1862      1.1  dholland 		} else
   1863      1.1  dholland 			(void)nfsrpc_setclient(nmp, clp, 0, cred, p);
   1864      1.1  dholland 		nfscl_cleanclient(clp);
   1865      1.1  dholland 		nmp->nm_clp = NULL;
   1866      1.1  dholland 		NFSFREECRED(cred);
   1867      1.1  dholland 		free(clp, M_NFSCLCLIENT);
   1868      1.1  dholland 	} else
   1869      1.1  dholland 		NFSUNLOCKCLSTATE();
   1870      1.1  dholland }
   1871      1.1  dholland 
   1872      1.1  dholland /*
   1873      1.1  dholland  * This function is called when a server replies with NFSERR_STALECLIENTID
   1874      1.1  dholland  * NFSERR_STALESTATEID or NFSERR_BADSESSION. It traverses the clientid lists,
   1875      1.1  dholland  * doing Opens and Locks with reclaim. If these fail, it deletes the
   1876      1.1  dholland  * corresponding state.
   1877      1.1  dholland  */
   1878      1.1  dholland static void
   1879      1.1  dholland nfscl_recover(struct nfsclclient *clp, struct ucred *cred, NFSPROC_T *p)
   1880      1.1  dholland {
   1881      1.1  dholland 	struct nfsclowner *owp, *nowp;
   1882      1.1  dholland 	struct nfsclopen *op, *nop;
   1883      1.1  dholland 	struct nfscllockowner *lp, *nlp;
   1884      1.1  dholland 	struct nfscllock *lop, *nlop;
   1885      1.1  dholland 	struct nfscldeleg *dp, *ndp, *tdp;
   1886      1.1  dholland 	struct nfsmount *nmp;
   1887      1.1  dholland 	struct ucred *tcred;
   1888      1.1  dholland 	struct nfsclopenhead extra_open;
   1889      1.1  dholland 	struct nfscldeleghead extra_deleg;
   1890      1.1  dholland 	struct nfsreq *rep;
   1891      1.1  dholland 	u_int64_t len;
   1892      1.1  dholland 	u_int32_t delegtype = NFSV4OPEN_DELEGATEWRITE, mode;
   1893      1.1  dholland 	int i, igotlock = 0, error, trycnt, firstlock;
   1894      1.1  dholland 	struct nfscllayout *lyp, *nlyp;
   1895      1.1  dholland 
   1896      1.1  dholland 	/*
   1897      1.1  dholland 	 * First, lock the client structure, so everyone else will
   1898      1.1  dholland 	 * block when trying to use state.
   1899      1.1  dholland 	 */
   1900      1.1  dholland 	NFSLOCKCLSTATE();
   1901      1.1  dholland 	clp->nfsc_flags |= NFSCLFLAGS_RECVRINPROG;
   1902      1.1  dholland 	do {
   1903      1.1  dholland 		igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL,
   1904      1.1  dholland 		    NFSCLSTATEMUTEXPTR, NULL);
   1905      1.1  dholland 	} while (!igotlock);
   1906      1.1  dholland 	NFSUNLOCKCLSTATE();
   1907      1.1  dholland 
   1908      1.1  dholland 	nmp = clp->nfsc_nmp;
   1909      1.1  dholland 	if (nmp == NULL)
   1910      1.1  dholland 		panic("nfscl recover");
   1911      1.1  dholland 
   1912      1.1  dholland 	/*
   1913      1.1  dholland 	 * For now, just get rid of all layouts. There may be a need
   1914      1.1  dholland 	 * to do LayoutCommit Ops with reclaim == true later.
   1915      1.1  dholland 	 */
   1916      1.1  dholland 	TAILQ_FOREACH_SAFE(lyp, &clp->nfsc_layout, nfsly_list, nlyp)
   1917      1.1  dholland 		nfscl_freelayout(lyp);
   1918      1.1  dholland 	TAILQ_INIT(&clp->nfsc_layout);
   1919      1.1  dholland 	for (i = 0; i < NFSCLLAYOUTHASHSIZE; i++)
   1920      1.1  dholland 		LIST_INIT(&clp->nfsc_layouthash[i]);
   1921      1.1  dholland 
   1922      1.1  dholland 	trycnt = 5;
   1923      1.1  dholland 	do {
   1924      1.1  dholland 		error = nfsrpc_setclient(nmp, clp, 1, cred, p);
   1925      1.1  dholland 	} while ((error == NFSERR_STALECLIENTID ||
   1926      1.1  dholland 	     error == NFSERR_BADSESSION ||
   1927      1.1  dholland 	     error == NFSERR_STALEDONTRECOVER) && --trycnt > 0);
   1928      1.1  dholland 	if (error) {
   1929      1.1  dholland 		nfscl_cleanclient(clp);
   1930      1.1  dholland 		NFSLOCKCLSTATE();
   1931      1.1  dholland 		clp->nfsc_flags &= ~(NFSCLFLAGS_HASCLIENTID |
   1932      1.1  dholland 		    NFSCLFLAGS_RECOVER | NFSCLFLAGS_RECVRINPROG);
   1933      1.1  dholland 		wakeup(&clp->nfsc_flags);
   1934      1.1  dholland 		nfsv4_unlock(&clp->nfsc_lock, 0);
   1935      1.1  dholland 		NFSUNLOCKCLSTATE();
   1936      1.1  dholland 		return;
   1937      1.1  dholland 	}
   1938      1.1  dholland 	clp->nfsc_flags |= NFSCLFLAGS_HASCLIENTID;
   1939      1.1  dholland 	clp->nfsc_flags &= ~NFSCLFLAGS_RECOVER;
   1940      1.1  dholland 
   1941      1.1  dholland 	/*
   1942      1.1  dholland 	 * Mark requests already queued on the server, so that they don't
   1943      1.1  dholland 	 * initiate another recovery cycle. Any requests already in the
   1944      1.1  dholland 	 * queue that handle state information will have the old stale
   1945      1.1  dholland 	 * clientid/stateid and will get a NFSERR_STALESTATEID,
   1946      1.1  dholland 	 * NFSERR_STALECLIENTID or NFSERR_BADSESSION reply from the server.
   1947      1.1  dholland 	 * This will be translated to NFSERR_STALEDONTRECOVER when
   1948      1.1  dholland 	 * R_DONTRECOVER is set.
   1949      1.1  dholland 	 */
   1950      1.1  dholland 	NFSLOCKREQ();
   1951      1.1  dholland 	TAILQ_FOREACH(rep, &nfsd_reqq, r_chain) {
   1952      1.1  dholland 		if (rep->r_nmp == nmp)
   1953      1.1  dholland 			rep->r_flags |= R_DONTRECOVER;
   1954      1.1  dholland 	}
   1955      1.1  dholland 	NFSUNLOCKREQ();
   1956      1.1  dholland 
   1957      1.1  dholland 	/*
   1958      1.1  dholland 	 * Now, mark all delegations "need reclaim".
   1959      1.1  dholland 	 */
   1960      1.1  dholland 	TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list)
   1961      1.1  dholland 		dp->nfsdl_flags |= NFSCLDL_NEEDRECLAIM;
   1962      1.1  dholland 
   1963      1.1  dholland 	TAILQ_INIT(&extra_deleg);
   1964      1.1  dholland 	LIST_INIT(&extra_open);
   1965      1.1  dholland 	/*
   1966      1.1  dholland 	 * Now traverse the state lists, doing Open and Lock Reclaims.
   1967      1.1  dholland 	 */
   1968      1.1  dholland 	tcred = newnfs_getcred();
   1969      1.1  dholland 	owp = LIST_FIRST(&clp->nfsc_owner);
   1970      1.1  dholland 	while (owp != NULL) {
   1971      1.1  dholland 	    nowp = LIST_NEXT(owp, nfsow_list);
   1972      1.1  dholland 	    owp->nfsow_seqid = 0;
   1973      1.1  dholland 	    op = LIST_FIRST(&owp->nfsow_open);
   1974      1.1  dholland 	    while (op != NULL) {
   1975      1.1  dholland 		nop = LIST_NEXT(op, nfso_list);
   1976      1.1  dholland 		if (error != NFSERR_NOGRACE) {
   1977      1.1  dholland 		    /* Search for a delegation to reclaim with the open */
   1978      1.1  dholland 		    TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) {
   1979      1.1  dholland 			if (!(dp->nfsdl_flags & NFSCLDL_NEEDRECLAIM))
   1980      1.1  dholland 			    continue;
   1981      1.1  dholland 			if ((dp->nfsdl_flags & NFSCLDL_WRITE)) {
   1982      1.1  dholland 			    mode = NFSV4OPEN_ACCESSWRITE;
   1983      1.1  dholland 			    delegtype = NFSV4OPEN_DELEGATEWRITE;
   1984      1.1  dholland 			} else {
   1985      1.1  dholland 			    mode = NFSV4OPEN_ACCESSREAD;
   1986      1.1  dholland 			    delegtype = NFSV4OPEN_DELEGATEREAD;
   1987      1.1  dholland 			}
   1988      1.1  dholland 			if ((op->nfso_mode & mode) == mode &&
   1989      1.1  dholland 			    op->nfso_fhlen == dp->nfsdl_fhlen &&
   1990      1.1  dholland 			    !NFSBCMP(op->nfso_fh, dp->nfsdl_fh, op->nfso_fhlen))
   1991      1.1  dholland 			    break;
   1992      1.1  dholland 		    }
   1993      1.1  dholland 		    ndp = dp;
   1994      1.1  dholland 		    if (dp == NULL)
   1995      1.1  dholland 			delegtype = NFSV4OPEN_DELEGATENONE;
   1996      1.1  dholland 		    newnfs_copycred(&op->nfso_cred, tcred);
   1997      1.1  dholland 		    error = nfscl_tryopen(nmp, NULL, op->nfso_fh,
   1998      1.1  dholland 			op->nfso_fhlen, op->nfso_fh, op->nfso_fhlen,
   1999      1.1  dholland 			op->nfso_mode, op, NULL, 0, &ndp, 1, delegtype,
   2000      1.1  dholland 			tcred, p);
   2001      1.1  dholland 		    if (!error) {
   2002      1.1  dholland 			/* Handle any replied delegation */
   2003      1.1  dholland 			if (ndp != NULL && ((ndp->nfsdl_flags & NFSCLDL_WRITE)
   2004      1.1  dholland 			    || NFSMNT_RDONLY(nmp->nm_mountp))) {
   2005      1.1  dholland 			    if ((ndp->nfsdl_flags & NFSCLDL_WRITE))
   2006      1.1  dholland 				mode = NFSV4OPEN_ACCESSWRITE;
   2007      1.1  dholland 			    else
   2008      1.1  dholland 				mode = NFSV4OPEN_ACCESSREAD;
   2009      1.1  dholland 			    TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) {
   2010      1.1  dholland 				if (!(dp->nfsdl_flags & NFSCLDL_NEEDRECLAIM))
   2011      1.1  dholland 				    continue;
   2012      1.1  dholland 				if ((op->nfso_mode & mode) == mode &&
   2013      1.1  dholland 				    op->nfso_fhlen == dp->nfsdl_fhlen &&
   2014      1.1  dholland 				    !NFSBCMP(op->nfso_fh, dp->nfsdl_fh,
   2015      1.1  dholland 				    op->nfso_fhlen)) {
   2016      1.1  dholland 				    dp->nfsdl_stateid = ndp->nfsdl_stateid;
   2017      1.1  dholland 				    dp->nfsdl_sizelimit = ndp->nfsdl_sizelimit;
   2018      1.1  dholland 				    dp->nfsdl_ace = ndp->nfsdl_ace;
   2019      1.1  dholland 				    dp->nfsdl_change = ndp->nfsdl_change;
   2020      1.1  dholland 				    dp->nfsdl_flags &= ~NFSCLDL_NEEDRECLAIM;
   2021      1.1  dholland 				    if ((ndp->nfsdl_flags & NFSCLDL_RECALL))
   2022      1.1  dholland 					dp->nfsdl_flags |= NFSCLDL_RECALL;
   2023      1.1  dholland 				    FREE((caddr_t)ndp, M_NFSCLDELEG);
   2024      1.1  dholland 				    ndp = NULL;
   2025      1.1  dholland 				    break;
   2026      1.1  dholland 				}
   2027      1.1  dholland 			    }
   2028      1.1  dholland 			}
   2029      1.1  dholland 			if (ndp != NULL)
   2030      1.1  dholland 			    TAILQ_INSERT_HEAD(&extra_deleg, ndp, nfsdl_list);
   2031      1.1  dholland 
   2032      1.1  dholland 			/* and reclaim all byte range locks */
   2033      1.1  dholland 			lp = LIST_FIRST(&op->nfso_lock);
   2034      1.1  dholland 			while (lp != NULL) {
   2035      1.1  dholland 			    nlp = LIST_NEXT(lp, nfsl_list);
   2036      1.1  dholland 			    lp->nfsl_seqid = 0;
   2037      1.1  dholland 			    firstlock = 1;
   2038      1.1  dholland 			    lop = LIST_FIRST(&lp->nfsl_lock);
   2039      1.1  dholland 			    while (lop != NULL) {
   2040      1.1  dholland 				nlop = LIST_NEXT(lop, nfslo_list);
   2041      1.1  dholland 				if (lop->nfslo_end == NFS64BITSSET)
   2042      1.1  dholland 				    len = NFS64BITSSET;
   2043      1.1  dholland 				else
   2044      1.1  dholland 				    len = lop->nfslo_end - lop->nfslo_first;
   2045      1.1  dholland 				if (error != NFSERR_NOGRACE)
   2046      1.1  dholland 				    error = nfscl_trylock(nmp, NULL,
   2047      1.1  dholland 					op->nfso_fh, op->nfso_fhlen, lp,
   2048      1.1  dholland 					firstlock, 1, lop->nfslo_first, len,
   2049      1.1  dholland 					lop->nfslo_type, tcred, p);
   2050      1.1  dholland 				if (error != 0)
   2051      1.1  dholland 				    nfscl_freelock(lop, 0);
   2052      1.1  dholland 				else
   2053      1.1  dholland 				    firstlock = 0;
   2054      1.1  dholland 				lop = nlop;
   2055      1.1  dholland 			    }
   2056      1.1  dholland 			    /* If no locks, but a lockowner, just delete it. */
   2057      1.1  dholland 			    if (LIST_EMPTY(&lp->nfsl_lock))
   2058      1.1  dholland 				nfscl_freelockowner(lp, 0);
   2059      1.1  dholland 			    lp = nlp;
   2060      1.1  dholland 			}
   2061      1.1  dholland 		    } else {
   2062      1.1  dholland 			nfscl_freeopen(op, 0);
   2063      1.1  dholland 		    }
   2064      1.1  dholland 		}
   2065      1.1  dholland 		op = nop;
   2066      1.1  dholland 	    }
   2067      1.1  dholland 	    owp = nowp;
   2068      1.1  dholland 	}
   2069      1.1  dholland 
   2070      1.1  dholland 	/*
   2071      1.1  dholland 	 * Now, try and get any delegations not yet reclaimed by cobbling
   2072      1.1  dholland 	 * to-gether an appropriate open.
   2073      1.1  dholland 	 */
   2074      1.1  dholland 	nowp = NULL;
   2075      1.1  dholland 	dp = TAILQ_FIRST(&clp->nfsc_deleg);
   2076      1.1  dholland 	while (dp != NULL) {
   2077      1.1  dholland 	    ndp = TAILQ_NEXT(dp, nfsdl_list);
   2078      1.1  dholland 	    if ((dp->nfsdl_flags & NFSCLDL_NEEDRECLAIM)) {
   2079      1.1  dholland 		if (nowp == NULL) {
   2080      1.1  dholland 		    MALLOC(nowp, struct nfsclowner *,
   2081      1.1  dholland 			sizeof (struct nfsclowner), M_NFSCLOWNER, M_WAITOK);
   2082      1.1  dholland 		    /*
   2083      1.1  dholland 		     * Name must be as long an largest possible
   2084      1.1  dholland 		     * NFSV4CL_LOCKNAMELEN. 12 for now.
   2085      1.1  dholland 		     */
   2086      1.1  dholland 		    NFSBCOPY("RECLAIMDELEG", nowp->nfsow_owner,
   2087      1.1  dholland 			NFSV4CL_LOCKNAMELEN);
   2088      1.1  dholland 		    LIST_INIT(&nowp->nfsow_open);
   2089      1.1  dholland 		    nowp->nfsow_clp = clp;
   2090      1.1  dholland 		    nowp->nfsow_seqid = 0;
   2091      1.1  dholland 		    nowp->nfsow_defunct = 0;
   2092      1.1  dholland 		    nfscl_lockinit(&nowp->nfsow_rwlock);
   2093      1.1  dholland 		}
   2094      1.1  dholland 		nop = NULL;
   2095      1.1  dholland 		if (error != NFSERR_NOGRACE) {
   2096      1.1  dholland 		    MALLOC(nop, struct nfsclopen *, sizeof (struct nfsclopen) +
   2097      1.1  dholland 			dp->nfsdl_fhlen - 1, M_NFSCLOPEN, M_WAITOK);
   2098      1.1  dholland 		    nop->nfso_own = nowp;
   2099      1.1  dholland 		    if ((dp->nfsdl_flags & NFSCLDL_WRITE)) {
   2100      1.1  dholland 			nop->nfso_mode = NFSV4OPEN_ACCESSWRITE;
   2101      1.1  dholland 			delegtype = NFSV4OPEN_DELEGATEWRITE;
   2102      1.1  dholland 		    } else {
   2103      1.1  dholland 			nop->nfso_mode = NFSV4OPEN_ACCESSREAD;
   2104      1.1  dholland 			delegtype = NFSV4OPEN_DELEGATEREAD;
   2105      1.1  dholland 		    }
   2106      1.1  dholland 		    nop->nfso_opencnt = 0;
   2107      1.1  dholland 		    nop->nfso_posixlock = 1;
   2108      1.1  dholland 		    nop->nfso_fhlen = dp->nfsdl_fhlen;
   2109      1.1  dholland 		    NFSBCOPY(dp->nfsdl_fh, nop->nfso_fh, dp->nfsdl_fhlen);
   2110      1.1  dholland 		    LIST_INIT(&nop->nfso_lock);
   2111      1.1  dholland 		    nop->nfso_stateid.seqid = 0;
   2112      1.1  dholland 		    nop->nfso_stateid.other[0] = 0;
   2113      1.1  dholland 		    nop->nfso_stateid.other[1] = 0;
   2114      1.1  dholland 		    nop->nfso_stateid.other[2] = 0;
   2115      1.1  dholland 		    newnfs_copycred(&dp->nfsdl_cred, tcred);
   2116      1.1  dholland 		    newnfs_copyincred(tcred, &nop->nfso_cred);
   2117      1.1  dholland 		    tdp = NULL;
   2118      1.1  dholland 		    error = nfscl_tryopen(nmp, NULL, nop->nfso_fh,
   2119      1.1  dholland 			nop->nfso_fhlen, nop->nfso_fh, nop->nfso_fhlen,
   2120      1.1  dholland 			nop->nfso_mode, nop, NULL, 0, &tdp, 1,
   2121      1.1  dholland 			delegtype, tcred, p);
   2122      1.1  dholland 		    if (tdp != NULL) {
   2123      1.1  dholland 			if ((tdp->nfsdl_flags & NFSCLDL_WRITE))
   2124      1.1  dholland 			    mode = NFSV4OPEN_ACCESSWRITE;
   2125      1.1  dholland 			else
   2126      1.1  dholland 			    mode = NFSV4OPEN_ACCESSREAD;
   2127      1.1  dholland 			if ((nop->nfso_mode & mode) == mode &&
   2128      1.1  dholland 			    nop->nfso_fhlen == tdp->nfsdl_fhlen &&
   2129      1.1  dholland 			    !NFSBCMP(nop->nfso_fh, tdp->nfsdl_fh,
   2130      1.1  dholland 			    nop->nfso_fhlen)) {
   2131      1.1  dholland 			    dp->nfsdl_stateid = tdp->nfsdl_stateid;
   2132      1.1  dholland 			    dp->nfsdl_sizelimit = tdp->nfsdl_sizelimit;
   2133      1.1  dholland 			    dp->nfsdl_ace = tdp->nfsdl_ace;
   2134      1.1  dholland 			    dp->nfsdl_change = tdp->nfsdl_change;
   2135      1.1  dholland 			    dp->nfsdl_flags &= ~NFSCLDL_NEEDRECLAIM;
   2136      1.1  dholland 			    if ((tdp->nfsdl_flags & NFSCLDL_RECALL))
   2137      1.1  dholland 				dp->nfsdl_flags |= NFSCLDL_RECALL;
   2138      1.1  dholland 			    FREE((caddr_t)tdp, M_NFSCLDELEG);
   2139      1.1  dholland 			} else {
   2140      1.1  dholland 			    TAILQ_INSERT_HEAD(&extra_deleg, tdp, nfsdl_list);
   2141      1.1  dholland 			}
   2142      1.1  dholland 		    }
   2143      1.1  dholland 		}
   2144      1.1  dholland 		if (error) {
   2145      1.1  dholland 		    if (nop != NULL)
   2146      1.1  dholland 			FREE((caddr_t)nop, M_NFSCLOPEN);
   2147      1.1  dholland 		    /*
   2148      1.1  dholland 		     * Couldn't reclaim it, so throw the state
   2149      1.1  dholland 		     * away. Ouch!!
   2150      1.1  dholland 		     */
   2151      1.1  dholland 		    nfscl_cleandeleg(dp);
   2152      1.1  dholland 		    nfscl_freedeleg(&clp->nfsc_deleg, dp);
   2153      1.1  dholland 		} else {
   2154      1.1  dholland 		    LIST_INSERT_HEAD(&extra_open, nop, nfso_list);
   2155      1.1  dholland 		}
   2156      1.1  dholland 	    }
   2157      1.1  dholland 	    dp = ndp;
   2158      1.1  dholland 	}
   2159      1.1  dholland 
   2160      1.1  dholland 	/*
   2161      1.1  dholland 	 * Now, get rid of extra Opens and Delegations.
   2162      1.1  dholland 	 */
   2163      1.1  dholland 	LIST_FOREACH_SAFE(op, &extra_open, nfso_list, nop) {
   2164      1.1  dholland 		do {
   2165      1.1  dholland 			newnfs_copycred(&op->nfso_cred, tcred);
   2166      1.1  dholland 			error = nfscl_tryclose(op, tcred, nmp, p);
   2167      1.1  dholland 			if (error == NFSERR_GRACE)
   2168      1.1  dholland 				(void) nfs_catnap(PZERO, error, "nfsexcls");
   2169      1.1  dholland 		} while (error == NFSERR_GRACE);
   2170      1.1  dholland 		LIST_REMOVE(op, nfso_list);
   2171      1.1  dholland 		FREE((caddr_t)op, M_NFSCLOPEN);
   2172      1.1  dholland 	}
   2173      1.1  dholland 	if (nowp != NULL)
   2174      1.1  dholland 		FREE((caddr_t)nowp, M_NFSCLOWNER);
   2175      1.1  dholland 
   2176      1.1  dholland 	TAILQ_FOREACH_SAFE(dp, &extra_deleg, nfsdl_list, ndp) {
   2177      1.1  dholland 		do {
   2178      1.1  dholland 			newnfs_copycred(&dp->nfsdl_cred, tcred);
   2179      1.1  dholland 			error = nfscl_trydelegreturn(dp, tcred, nmp, p);
   2180      1.1  dholland 			if (error == NFSERR_GRACE)
   2181      1.1  dholland 				(void) nfs_catnap(PZERO, error, "nfsexdlg");
   2182      1.1  dholland 		} while (error == NFSERR_GRACE);
   2183      1.1  dholland 		TAILQ_REMOVE(&extra_deleg, dp, nfsdl_list);
   2184      1.1  dholland 		FREE((caddr_t)dp, M_NFSCLDELEG);
   2185      1.1  dholland 	}
   2186      1.1  dholland 
   2187      1.1  dholland 	/* For NFSv4.1 or later, do a RECLAIM_COMPLETE. */
   2188      1.1  dholland 	if (NFSHASNFSV4N(nmp))
   2189      1.1  dholland 		(void)nfsrpc_reclaimcomplete(nmp, cred, p);
   2190      1.1  dholland 
   2191      1.1  dholland 	NFSLOCKCLSTATE();
   2192      1.1  dholland 	clp->nfsc_flags &= ~NFSCLFLAGS_RECVRINPROG;
   2193      1.1  dholland 	wakeup(&clp->nfsc_flags);
   2194      1.1  dholland 	nfsv4_unlock(&clp->nfsc_lock, 0);
   2195      1.1  dholland 	NFSUNLOCKCLSTATE();
   2196      1.1  dholland 	NFSFREECRED(tcred);
   2197      1.1  dholland }
   2198      1.1  dholland 
   2199      1.1  dholland /*
   2200      1.1  dholland  * This function is called when a server replies with NFSERR_EXPIRED.
   2201      1.1  dholland  * It deletes all state for the client and does a fresh SetClientId/confirm.
   2202      1.1  dholland  * XXX Someday it should post a signal to the process(es) that hold the
   2203      1.1  dholland  * state, so they know that lock state has been lost.
   2204      1.1  dholland  */
   2205      1.1  dholland APPLESTATIC int
   2206      1.1  dholland nfscl_hasexpired(struct nfsclclient *clp, u_int32_t clidrev, NFSPROC_T *p)
   2207      1.1  dholland {
   2208      1.1  dholland 	struct nfsmount *nmp;
   2209      1.1  dholland 	struct ucred *cred;
   2210      1.1  dholland 	int igotlock = 0, error, trycnt;
   2211      1.1  dholland 
   2212      1.1  dholland 	/*
   2213      1.1  dholland 	 * If the clientid has gone away or a new SetClientid has already
   2214      1.1  dholland 	 * been done, just return ok.
   2215      1.1  dholland 	 */
   2216      1.1  dholland 	if (clp == NULL || clidrev != clp->nfsc_clientidrev)
   2217      1.1  dholland 		return (0);
   2218      1.1  dholland 
   2219      1.1  dholland 	/*
   2220      1.1  dholland 	 * First, lock the client structure, so everyone else will
   2221      1.1  dholland 	 * block when trying to use state. Also, use NFSCLFLAGS_EXPIREIT so
   2222      1.1  dholland 	 * that only one thread does the work.
   2223      1.1  dholland 	 */
   2224      1.1  dholland 	NFSLOCKCLSTATE();
   2225      1.1  dholland 	clp->nfsc_flags |= NFSCLFLAGS_EXPIREIT;
   2226      1.1  dholland 	do {
   2227      1.1  dholland 		igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL,
   2228      1.1  dholland 		    NFSCLSTATEMUTEXPTR, NULL);
   2229      1.1  dholland 	} while (!igotlock && (clp->nfsc_flags & NFSCLFLAGS_EXPIREIT));
   2230      1.1  dholland 	if ((clp->nfsc_flags & NFSCLFLAGS_EXPIREIT) == 0) {
   2231      1.1  dholland 		if (igotlock)
   2232      1.1  dholland 			nfsv4_unlock(&clp->nfsc_lock, 0);
   2233      1.1  dholland 		NFSUNLOCKCLSTATE();
   2234      1.1  dholland 		return (0);
   2235      1.1  dholland 	}
   2236      1.1  dholland 	clp->nfsc_flags |= NFSCLFLAGS_RECVRINPROG;
   2237      1.1  dholland 	NFSUNLOCKCLSTATE();
   2238      1.1  dholland 
   2239      1.1  dholland 	nmp = clp->nfsc_nmp;
   2240      1.1  dholland 	if (nmp == NULL)
   2241      1.1  dholland 		panic("nfscl expired");
   2242      1.1  dholland 	cred = newnfs_getcred();
   2243      1.1  dholland 	trycnt = 5;
   2244      1.1  dholland 	do {
   2245      1.1  dholland 		error = nfsrpc_setclient(nmp, clp, 0, cred, p);
   2246      1.1  dholland 	} while ((error == NFSERR_STALECLIENTID ||
   2247      1.1  dholland 	     error == NFSERR_BADSESSION ||
   2248      1.1  dholland 	     error == NFSERR_STALEDONTRECOVER) && --trycnt > 0);
   2249      1.1  dholland 	if (error) {
   2250      1.1  dholland 		/*
   2251      1.1  dholland 		 * Clear out any state.
   2252      1.1  dholland 		 */
   2253      1.1  dholland 		nfscl_cleanclient(clp);
   2254      1.1  dholland 		NFSLOCKCLSTATE();
   2255      1.1  dholland 		clp->nfsc_flags &= ~(NFSCLFLAGS_HASCLIENTID |
   2256      1.1  dholland 		    NFSCLFLAGS_RECOVER);
   2257      1.1  dholland 	} else {
   2258      1.1  dholland 		/*
   2259      1.1  dholland 		 * Expire the state for the client.
   2260      1.1  dholland 		 */
   2261      1.1  dholland 		nfscl_expireclient(clp, nmp, cred, p);
   2262      1.1  dholland 		NFSLOCKCLSTATE();
   2263      1.1  dholland 		clp->nfsc_flags |= NFSCLFLAGS_HASCLIENTID;
   2264      1.1  dholland 		clp->nfsc_flags &= ~NFSCLFLAGS_RECOVER;
   2265      1.1  dholland 	}
   2266      1.1  dholland 	clp->nfsc_flags &= ~(NFSCLFLAGS_EXPIREIT | NFSCLFLAGS_RECVRINPROG);
   2267      1.1  dholland 	wakeup(&clp->nfsc_flags);
   2268      1.1  dholland 	nfsv4_unlock(&clp->nfsc_lock, 0);
   2269      1.1  dholland 	NFSUNLOCKCLSTATE();
   2270      1.1  dholland 	NFSFREECRED(cred);
   2271      1.1  dholland 	return (error);
   2272      1.1  dholland }
   2273      1.1  dholland 
   2274      1.1  dholland /*
   2275      1.1  dholland  * This function inserts a lock in the list after insert_lop.
   2276      1.1  dholland  */
   2277      1.1  dholland static void
   2278      1.1  dholland nfscl_insertlock(struct nfscllockowner *lp, struct nfscllock *new_lop,
   2279      1.1  dholland     struct nfscllock *insert_lop, int local)
   2280      1.1  dholland {
   2281      1.1  dholland 
   2282      1.1  dholland 	if ((struct nfscllockowner *)insert_lop == lp)
   2283      1.1  dholland 		LIST_INSERT_HEAD(&lp->nfsl_lock, new_lop, nfslo_list);
   2284      1.1  dholland 	else
   2285      1.1  dholland 		LIST_INSERT_AFTER(insert_lop, new_lop, nfslo_list);
   2286      1.1  dholland 	if (local)
   2287  1.1.1.2  pgoyette 		nfsstatsv1.cllocallocks++;
   2288      1.1  dholland 	else
   2289  1.1.1.2  pgoyette 		nfsstatsv1.cllocks++;
   2290      1.1  dholland }
   2291      1.1  dholland 
   2292      1.1  dholland /*
   2293      1.1  dholland  * This function updates the locking for a lock owner and given file. It
   2294      1.1  dholland  * maintains a list of lock ranges ordered on increasing file offset that
   2295      1.1  dholland  * are NFSCLLOCK_READ or NFSCLLOCK_WRITE and non-overlapping (aka POSIX style).
   2296      1.1  dholland  * It always adds new_lop to the list and sometimes uses the one pointed
   2297      1.1  dholland  * at by other_lopp.
   2298      1.1  dholland  * Returns 1 if the locks were modified, 0 otherwise.
   2299      1.1  dholland  */
   2300      1.1  dholland static int
   2301      1.1  dholland nfscl_updatelock(struct nfscllockowner *lp, struct nfscllock **new_lopp,
   2302      1.1  dholland     struct nfscllock **other_lopp, int local)
   2303      1.1  dholland {
   2304      1.1  dholland 	struct nfscllock *new_lop = *new_lopp;
   2305      1.1  dholland 	struct nfscllock *lop, *tlop, *ilop;
   2306      1.1  dholland 	struct nfscllock *other_lop;
   2307      1.1  dholland 	int unlock = 0, modified = 0;
   2308      1.1  dholland 	u_int64_t tmp;
   2309      1.1  dholland 
   2310      1.1  dholland 	/*
   2311      1.1  dholland 	 * Work down the list until the lock is merged.
   2312      1.1  dholland 	 */
   2313      1.1  dholland 	if (new_lop->nfslo_type == F_UNLCK)
   2314      1.1  dholland 		unlock = 1;
   2315      1.1  dholland 	ilop = (struct nfscllock *)lp;
   2316      1.1  dholland 	lop = LIST_FIRST(&lp->nfsl_lock);
   2317      1.1  dholland 	while (lop != NULL) {
   2318      1.1  dholland 	    /*
   2319      1.1  dholland 	     * Only check locks for this file that aren't before the start of
   2320      1.1  dholland 	     * new lock's range.
   2321      1.1  dholland 	     */
   2322      1.1  dholland 	    if (lop->nfslo_end >= new_lop->nfslo_first) {
   2323      1.1  dholland 		if (new_lop->nfslo_end < lop->nfslo_first) {
   2324      1.1  dholland 		    /*
   2325      1.1  dholland 		     * If the new lock ends before the start of the
   2326      1.1  dholland 		     * current lock's range, no merge, just insert
   2327      1.1  dholland 		     * the new lock.
   2328      1.1  dholland 		     */
   2329      1.1  dholland 		    break;
   2330      1.1  dholland 		}
   2331      1.1  dholland 		if (new_lop->nfslo_type == lop->nfslo_type ||
   2332      1.1  dholland 		    (new_lop->nfslo_first <= lop->nfslo_first &&
   2333      1.1  dholland 		     new_lop->nfslo_end >= lop->nfslo_end)) {
   2334      1.1  dholland 		    /*
   2335      1.1  dholland 		     * This lock can be absorbed by the new lock/unlock.
   2336      1.1  dholland 		     * This happens when it covers the entire range
   2337      1.1  dholland 		     * of the old lock or is contiguous
   2338      1.1  dholland 		     * with the old lock and is of the same type or an
   2339      1.1  dholland 		     * unlock.
   2340      1.1  dholland 		     */
   2341      1.1  dholland 		    if (new_lop->nfslo_type != lop->nfslo_type ||
   2342      1.1  dholland 			new_lop->nfslo_first != lop->nfslo_first ||
   2343      1.1  dholland 			new_lop->nfslo_end != lop->nfslo_end)
   2344      1.1  dholland 			modified = 1;
   2345      1.1  dholland 		    if (lop->nfslo_first < new_lop->nfslo_first)
   2346      1.1  dholland 			new_lop->nfslo_first = lop->nfslo_first;
   2347      1.1  dholland 		    if (lop->nfslo_end > new_lop->nfslo_end)
   2348      1.1  dholland 			new_lop->nfslo_end = lop->nfslo_end;
   2349      1.1  dholland 		    tlop = lop;
   2350      1.1  dholland 		    lop = LIST_NEXT(lop, nfslo_list);
   2351      1.1  dholland 		    nfscl_freelock(tlop, local);
   2352      1.1  dholland 		    continue;
   2353      1.1  dholland 		}
   2354      1.1  dholland 
   2355      1.1  dholland 		/*
   2356      1.1  dholland 		 * All these cases are for contiguous locks that are not the
   2357      1.1  dholland 		 * same type, so they can't be merged.
   2358      1.1  dholland 		 */
   2359      1.1  dholland 		if (new_lop->nfslo_first <= lop->nfslo_first) {
   2360      1.1  dholland 		    /*
   2361      1.1  dholland 		     * This case is where the new lock overlaps with the
   2362      1.1  dholland 		     * first part of the old lock. Move the start of the
   2363      1.1  dholland 		     * old lock to just past the end of the new lock. The
   2364      1.1  dholland 		     * new lock will be inserted in front of the old, since
   2365      1.1  dholland 		     * ilop hasn't been updated. (We are done now.)
   2366      1.1  dholland 		     */
   2367      1.1  dholland 		    if (lop->nfslo_first != new_lop->nfslo_end) {
   2368      1.1  dholland 			lop->nfslo_first = new_lop->nfslo_end;
   2369      1.1  dholland 			modified = 1;
   2370      1.1  dholland 		    }
   2371      1.1  dholland 		    break;
   2372      1.1  dholland 		}
   2373      1.1  dholland 		if (new_lop->nfslo_end >= lop->nfslo_end) {
   2374      1.1  dholland 		    /*
   2375      1.1  dholland 		     * This case is where the new lock overlaps with the
   2376      1.1  dholland 		     * end of the old lock's range. Move the old lock's
   2377      1.1  dholland 		     * end to just before the new lock's first and insert
   2378      1.1  dholland 		     * the new lock after the old lock.
   2379      1.1  dholland 		     * Might not be done yet, since the new lock could
   2380      1.1  dholland 		     * overlap further locks with higher ranges.
   2381      1.1  dholland 		     */
   2382      1.1  dholland 		    if (lop->nfslo_end != new_lop->nfslo_first) {
   2383      1.1  dholland 			lop->nfslo_end = new_lop->nfslo_first;
   2384      1.1  dholland 			modified = 1;
   2385      1.1  dholland 		    }
   2386      1.1  dholland 		    ilop = lop;
   2387      1.1  dholland 		    lop = LIST_NEXT(lop, nfslo_list);
   2388      1.1  dholland 		    continue;
   2389      1.1  dholland 		}
   2390      1.1  dholland 		/*
   2391      1.1  dholland 		 * The final case is where the new lock's range is in the
   2392      1.1  dholland 		 * middle of the current lock's and splits the current lock
   2393      1.1  dholland 		 * up. Use *other_lopp to handle the second part of the
   2394      1.1  dholland 		 * split old lock range. (We are done now.)
   2395      1.1  dholland 		 * For unlock, we use new_lop as other_lop and tmp, since
   2396      1.1  dholland 		 * other_lop and new_lop are the same for this case.
   2397      1.1  dholland 		 * We noted the unlock case above, so we don't need
   2398      1.1  dholland 		 * new_lop->nfslo_type any longer.
   2399      1.1  dholland 		 */
   2400      1.1  dholland 		tmp = new_lop->nfslo_first;
   2401      1.1  dholland 		if (unlock) {
   2402      1.1  dholland 		    other_lop = new_lop;
   2403      1.1  dholland 		    *new_lopp = NULL;
   2404      1.1  dholland 		} else {
   2405      1.1  dholland 		    other_lop = *other_lopp;
   2406      1.1  dholland 		    *other_lopp = NULL;
   2407      1.1  dholland 		}
   2408      1.1  dholland 		other_lop->nfslo_first = new_lop->nfslo_end;
   2409      1.1  dholland 		other_lop->nfslo_end = lop->nfslo_end;
   2410      1.1  dholland 		other_lop->nfslo_type = lop->nfslo_type;
   2411      1.1  dholland 		lop->nfslo_end = tmp;
   2412      1.1  dholland 		nfscl_insertlock(lp, other_lop, lop, local);
   2413      1.1  dholland 		ilop = lop;
   2414      1.1  dholland 		modified = 1;
   2415      1.1  dholland 		break;
   2416      1.1  dholland 	    }
   2417      1.1  dholland 	    ilop = lop;
   2418      1.1  dholland 	    lop = LIST_NEXT(lop, nfslo_list);
   2419      1.1  dholland 	    if (lop == NULL)
   2420      1.1  dholland 		break;
   2421      1.1  dholland 	}
   2422      1.1  dholland 
   2423      1.1  dholland 	/*
   2424      1.1  dholland 	 * Insert the new lock in the list at the appropriate place.
   2425      1.1  dholland 	 */
   2426      1.1  dholland 	if (!unlock) {
   2427      1.1  dholland 		nfscl_insertlock(lp, new_lop, ilop, local);
   2428      1.1  dholland 		*new_lopp = NULL;
   2429      1.1  dholland 		modified = 1;
   2430      1.1  dholland 	}
   2431      1.1  dholland 	return (modified);
   2432      1.1  dholland }
   2433      1.1  dholland 
   2434      1.1  dholland /*
   2435      1.1  dholland  * This function must be run as a kernel thread.
   2436      1.1  dholland  * It does Renew Ops and recovery, when required.
   2437      1.1  dholland  */
   2438      1.1  dholland APPLESTATIC void
   2439      1.1  dholland nfscl_renewthread(struct nfsclclient *clp, NFSPROC_T *p)
   2440      1.1  dholland {
   2441      1.1  dholland 	struct nfsclowner *owp, *nowp;
   2442      1.1  dholland 	struct nfsclopen *op;
   2443      1.1  dholland 	struct nfscllockowner *lp, *nlp;
   2444      1.1  dholland 	struct nfscldeleghead dh;
   2445      1.1  dholland 	struct nfscldeleg *dp, *ndp;
   2446      1.1  dholland 	struct ucred *cred;
   2447      1.1  dholland 	u_int32_t clidrev;
   2448      1.1  dholland 	int error, cbpathdown, islept, igotlock, ret, clearok;
   2449      1.1  dholland 	uint32_t recover_done_time = 0;
   2450      1.1  dholland 	time_t mytime;
   2451      1.1  dholland 	static time_t prevsec = 0;
   2452      1.1  dholland 	struct nfscllockownerfh *lfhp, *nlfhp;
   2453      1.1  dholland 	struct nfscllockownerfhhead lfh;
   2454      1.1  dholland 	struct nfscllayout *lyp, *nlyp;
   2455      1.1  dholland 	struct nfscldevinfo *dip, *ndip;
   2456      1.1  dholland 	struct nfscllayouthead rlh;
   2457      1.1  dholland 	struct nfsclrecalllayout *recallp;
   2458      1.1  dholland 	struct nfsclds *dsp;
   2459      1.1  dholland 
   2460      1.1  dholland 	cred = newnfs_getcred();
   2461      1.1  dholland 	NFSLOCKCLSTATE();
   2462      1.1  dholland 	clp->nfsc_flags |= NFSCLFLAGS_HASTHREAD;
   2463      1.1  dholland 	NFSUNLOCKCLSTATE();
   2464      1.1  dholland 	for(;;) {
   2465      1.1  dholland 		newnfs_setroot(cred);
   2466      1.1  dholland 		cbpathdown = 0;
   2467      1.1  dholland 		if (clp->nfsc_flags & NFSCLFLAGS_RECOVER) {
   2468      1.1  dholland 			/*
   2469      1.1  dholland 			 * Only allow one recover within 1/2 of the lease
   2470      1.1  dholland 			 * duration (nfsc_renew).
   2471      1.1  dholland 			 */
   2472      1.1  dholland 			if (recover_done_time < NFSD_MONOSEC) {
   2473      1.1  dholland 				recover_done_time = NFSD_MONOSEC +
   2474      1.1  dholland 				    clp->nfsc_renew;
   2475      1.1  dholland 				nfscl_recover(clp, cred, p);
   2476      1.1  dholland 			} else {
   2477      1.1  dholland 				NFSLOCKCLSTATE();
   2478      1.1  dholland 				clp->nfsc_flags &= ~NFSCLFLAGS_RECOVER;
   2479      1.1  dholland 				NFSUNLOCKCLSTATE();
   2480      1.1  dholland 			}
   2481      1.1  dholland 		}
   2482      1.1  dholland 		if (clp->nfsc_expire <= NFSD_MONOSEC &&
   2483      1.1  dholland 		    (clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID)) {
   2484      1.1  dholland 			clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
   2485      1.1  dholland 			clidrev = clp->nfsc_clientidrev;
   2486      1.1  dholland 			error = nfsrpc_renew(clp,
   2487      1.1  dholland 			    TAILQ_FIRST(&clp->nfsc_nmp->nm_sess), cred, p);
   2488      1.1  dholland 			if (error == NFSERR_CBPATHDOWN)
   2489      1.1  dholland 			    cbpathdown = 1;
   2490      1.1  dholland 			else if (error == NFSERR_STALECLIENTID ||
   2491      1.1  dholland 			    error == NFSERR_BADSESSION) {
   2492      1.1  dholland 			    NFSLOCKCLSTATE();
   2493      1.1  dholland 			    clp->nfsc_flags |= NFSCLFLAGS_RECOVER;
   2494      1.1  dholland 			    NFSUNLOCKCLSTATE();
   2495      1.1  dholland 			} else if (error == NFSERR_EXPIRED)
   2496      1.1  dholland 			    (void) nfscl_hasexpired(clp, clidrev, p);
   2497      1.1  dholland 		}
   2498      1.1  dholland 
   2499      1.1  dholland 		/* Do renews for any DS sessions. */
   2500      1.1  dholland checkdsrenew:
   2501      1.1  dholland 		NFSLOCKMNT(clp->nfsc_nmp);
   2502      1.1  dholland 		/* Skip first entry, since the MDS is handled above. */
   2503      1.1  dholland 		dsp = TAILQ_FIRST(&clp->nfsc_nmp->nm_sess);
   2504      1.1  dholland 		if (dsp != NULL)
   2505      1.1  dholland 			dsp = TAILQ_NEXT(dsp, nfsclds_list);
   2506      1.1  dholland 		while (dsp != NULL) {
   2507      1.1  dholland 			if (dsp->nfsclds_expire <= NFSD_MONOSEC) {
   2508      1.1  dholland 				dsp->nfsclds_expire = NFSD_MONOSEC +
   2509      1.1  dholland 				    clp->nfsc_renew;
   2510      1.1  dholland 				NFSUNLOCKMNT(clp->nfsc_nmp);
   2511      1.1  dholland 				(void)nfsrpc_renew(clp, dsp, cred, p);
   2512      1.1  dholland 				goto checkdsrenew;
   2513      1.1  dholland 			}
   2514      1.1  dholland 			dsp = TAILQ_NEXT(dsp, nfsclds_list);
   2515      1.1  dholland 		}
   2516      1.1  dholland 		NFSUNLOCKMNT(clp->nfsc_nmp);
   2517      1.1  dholland 
   2518      1.1  dholland 		TAILQ_INIT(&dh);
   2519      1.1  dholland 		NFSLOCKCLSTATE();
   2520      1.1  dholland 		if (cbpathdown)
   2521      1.1  dholland 			/* It's a Total Recall! */
   2522      1.1  dholland 			nfscl_totalrecall(clp);
   2523      1.1  dholland 
   2524      1.1  dholland 		/*
   2525      1.1  dholland 		 * Now, handle defunct owners.
   2526      1.1  dholland 		 */
   2527      1.1  dholland 		LIST_FOREACH_SAFE(owp, &clp->nfsc_owner, nfsow_list, nowp) {
   2528      1.1  dholland 			if (LIST_EMPTY(&owp->nfsow_open)) {
   2529      1.1  dholland 				if (owp->nfsow_defunct != 0)
   2530      1.1  dholland 					nfscl_freeopenowner(owp, 0);
   2531      1.1  dholland 			}
   2532      1.1  dholland 		}
   2533      1.1  dholland 
   2534      1.1  dholland 		/*
   2535      1.1  dholland 		 * Do the recall on any delegations. To avoid trouble, always
   2536      1.1  dholland 		 * come back up here after having slept.
   2537      1.1  dholland 		 */
   2538      1.1  dholland 		igotlock = 0;
   2539      1.1  dholland tryagain:
   2540      1.1  dholland 		dp = TAILQ_FIRST(&clp->nfsc_deleg);
   2541      1.1  dholland 		while (dp != NULL) {
   2542      1.1  dholland 			ndp = TAILQ_NEXT(dp, nfsdl_list);
   2543      1.1  dholland 			if ((dp->nfsdl_flags & NFSCLDL_RECALL)) {
   2544      1.1  dholland 				/*
   2545      1.1  dholland 				 * Wait for outstanding I/O ops to be done.
   2546      1.1  dholland 				 */
   2547      1.1  dholland 				if (dp->nfsdl_rwlock.nfslock_usecnt > 0) {
   2548      1.1  dholland 				    if (igotlock) {
   2549      1.1  dholland 					nfsv4_unlock(&clp->nfsc_lock, 0);
   2550      1.1  dholland 					igotlock = 0;
   2551      1.1  dholland 				    }
   2552      1.1  dholland 				    dp->nfsdl_rwlock.nfslock_lock |=
   2553      1.1  dholland 					NFSV4LOCK_WANTED;
   2554      1.1  dholland 				    (void) nfsmsleep(&dp->nfsdl_rwlock,
   2555      1.1  dholland 					NFSCLSTATEMUTEXPTR, PZERO, "nfscld",
   2556      1.1  dholland 					NULL);
   2557      1.1  dholland 				    goto tryagain;
   2558      1.1  dholland 				}
   2559      1.1  dholland 				while (!igotlock) {
   2560      1.1  dholland 				    igotlock = nfsv4_lock(&clp->nfsc_lock, 1,
   2561      1.1  dholland 					&islept, NFSCLSTATEMUTEXPTR, NULL);
   2562      1.1  dholland 				    if (islept)
   2563      1.1  dholland 					goto tryagain;
   2564      1.1  dholland 				}
   2565      1.1  dholland 				NFSUNLOCKCLSTATE();
   2566      1.1  dholland 				newnfs_copycred(&dp->nfsdl_cred, cred);
   2567      1.1  dholland 				ret = nfscl_recalldeleg(clp, clp->nfsc_nmp, dp,
   2568      1.1  dholland 				    NULL, cred, p, 1);
   2569      1.1  dholland 				if (!ret) {
   2570      1.1  dholland 				    nfscl_cleandeleg(dp);
   2571      1.1  dholland 				    TAILQ_REMOVE(&clp->nfsc_deleg, dp,
   2572      1.1  dholland 					nfsdl_list);
   2573      1.1  dholland 				    LIST_REMOVE(dp, nfsdl_hash);
   2574      1.1  dholland 				    TAILQ_INSERT_HEAD(&dh, dp, nfsdl_list);
   2575      1.1  dholland 				    nfscl_delegcnt--;
   2576  1.1.1.2  pgoyette 				    nfsstatsv1.cldelegates--;
   2577      1.1  dholland 				}
   2578      1.1  dholland 				NFSLOCKCLSTATE();
   2579      1.1  dholland 			}
   2580      1.1  dholland 			dp = ndp;
   2581      1.1  dholland 		}
   2582      1.1  dholland 
   2583      1.1  dholland 		/*
   2584      1.1  dholland 		 * Clear out old delegations, if we are above the high water
   2585      1.1  dholland 		 * mark. Only clear out ones with no state related to them.
   2586      1.1  dholland 		 * The tailq list is in LRU order.
   2587      1.1  dholland 		 */
   2588      1.1  dholland 		dp = TAILQ_LAST(&clp->nfsc_deleg, nfscldeleghead);
   2589      1.1  dholland 		while (nfscl_delegcnt > nfscl_deleghighwater && dp != NULL) {
   2590      1.1  dholland 		    ndp = TAILQ_PREV(dp, nfscldeleghead, nfsdl_list);
   2591      1.1  dholland 		    if (dp->nfsdl_rwlock.nfslock_usecnt == 0 &&
   2592      1.1  dholland 			dp->nfsdl_rwlock.nfslock_lock == 0 &&
   2593      1.1  dholland 			dp->nfsdl_timestamp < NFSD_MONOSEC &&
   2594      1.1  dholland 			(dp->nfsdl_flags & (NFSCLDL_RECALL | NFSCLDL_ZAPPED |
   2595      1.1  dholland 			  NFSCLDL_NEEDRECLAIM | NFSCLDL_DELEGRET)) == 0) {
   2596      1.1  dholland 			clearok = 1;
   2597      1.1  dholland 			LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) {
   2598      1.1  dholland 			    op = LIST_FIRST(&owp->nfsow_open);
   2599      1.1  dholland 			    if (op != NULL) {
   2600      1.1  dholland 				clearok = 0;
   2601      1.1  dholland 				break;
   2602      1.1  dholland 			    }
   2603      1.1  dholland 			}
   2604      1.1  dholland 			if (clearok) {
   2605      1.1  dholland 			    LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) {
   2606      1.1  dholland 				if (!LIST_EMPTY(&lp->nfsl_lock)) {
   2607      1.1  dholland 				    clearok = 0;
   2608      1.1  dholland 				    break;
   2609      1.1  dholland 				}
   2610      1.1  dholland 			    }
   2611      1.1  dholland 			}
   2612      1.1  dholland 			if (clearok) {
   2613      1.1  dholland 			    TAILQ_REMOVE(&clp->nfsc_deleg, dp, nfsdl_list);
   2614      1.1  dholland 			    LIST_REMOVE(dp, nfsdl_hash);
   2615      1.1  dholland 			    TAILQ_INSERT_HEAD(&dh, dp, nfsdl_list);
   2616      1.1  dholland 			    nfscl_delegcnt--;
   2617  1.1.1.2  pgoyette 			    nfsstatsv1.cldelegates--;
   2618      1.1  dholland 			}
   2619      1.1  dholland 		    }
   2620      1.1  dholland 		    dp = ndp;
   2621      1.1  dholland 		}
   2622      1.1  dholland 		if (igotlock)
   2623      1.1  dholland 			nfsv4_unlock(&clp->nfsc_lock, 0);
   2624      1.1  dholland 
   2625      1.1  dholland 		/*
   2626      1.1  dholland 		 * Do the recall on any layouts. To avoid trouble, always
   2627      1.1  dholland 		 * come back up here after having slept.
   2628      1.1  dholland 		 */
   2629      1.1  dholland 		TAILQ_INIT(&rlh);
   2630      1.1  dholland tryagain2:
   2631      1.1  dholland 		TAILQ_FOREACH_SAFE(lyp, &clp->nfsc_layout, nfsly_list, nlyp) {
   2632      1.1  dholland 			if ((lyp->nfsly_flags & NFSLY_RECALL) != 0) {
   2633      1.1  dholland 				/*
   2634      1.1  dholland 				 * Wait for outstanding I/O ops to be done.
   2635      1.1  dholland 				 */
   2636      1.1  dholland 				if (lyp->nfsly_lock.nfslock_usecnt > 0 ||
   2637      1.1  dholland 				    (lyp->nfsly_lock.nfslock_lock &
   2638      1.1  dholland 				     NFSV4LOCK_LOCK) != 0) {
   2639      1.1  dholland 					lyp->nfsly_lock.nfslock_lock |=
   2640      1.1  dholland 					    NFSV4LOCK_WANTED;
   2641      1.1  dholland 					(void)nfsmsleep(&lyp->nfsly_lock,
   2642      1.1  dholland 					    NFSCLSTATEMUTEXPTR, PZERO, "nfslyp",
   2643      1.1  dholland 					    NULL);
   2644      1.1  dholland 					goto tryagain2;
   2645      1.1  dholland 				}
   2646      1.1  dholland 				/* Move the layout to the recall list. */
   2647      1.1  dholland 				TAILQ_REMOVE(&clp->nfsc_layout, lyp,
   2648      1.1  dholland 				    nfsly_list);
   2649      1.1  dholland 				LIST_REMOVE(lyp, nfsly_hash);
   2650      1.1  dholland 				TAILQ_INSERT_HEAD(&rlh, lyp, nfsly_list);
   2651      1.1  dholland 
   2652      1.1  dholland 				/* Handle any layout commits. */
   2653      1.1  dholland 				if (!NFSHASNOLAYOUTCOMMIT(clp->nfsc_nmp) &&
   2654      1.1  dholland 				    (lyp->nfsly_flags & NFSLY_WRITTEN) != 0) {
   2655      1.1  dholland 					lyp->nfsly_flags &= ~NFSLY_WRITTEN;
   2656      1.1  dholland 					NFSUNLOCKCLSTATE();
   2657      1.1  dholland 					NFSCL_DEBUG(3, "do layoutcommit\n");
   2658      1.1  dholland 					nfscl_dolayoutcommit(clp->nfsc_nmp, lyp,
   2659      1.1  dholland 					    cred, p);
   2660      1.1  dholland 					NFSLOCKCLSTATE();
   2661      1.1  dholland 					goto tryagain2;
   2662      1.1  dholland 				}
   2663      1.1  dholland 			}
   2664      1.1  dholland 		}
   2665      1.1  dholland 
   2666      1.1  dholland 		/* Now, look for stale layouts. */
   2667      1.1  dholland 		lyp = TAILQ_LAST(&clp->nfsc_layout, nfscllayouthead);
   2668      1.1  dholland 		while (lyp != NULL) {
   2669      1.1  dholland 			nlyp = TAILQ_PREV(lyp, nfscllayouthead, nfsly_list);
   2670      1.1  dholland 			if (lyp->nfsly_timestamp < NFSD_MONOSEC &&
   2671      1.1  dholland 			    (lyp->nfsly_flags & NFSLY_RECALL) == 0 &&
   2672      1.1  dholland 			    lyp->nfsly_lock.nfslock_usecnt == 0 &&
   2673      1.1  dholland 			    lyp->nfsly_lock.nfslock_lock == 0) {
   2674      1.1  dholland 				NFSCL_DEBUG(4, "ret stale lay=%d\n",
   2675      1.1  dholland 				    nfscl_layoutcnt);
   2676      1.1  dholland 				recallp = malloc(sizeof(*recallp),
   2677      1.1  dholland 				    M_NFSLAYRECALL, M_NOWAIT);
   2678      1.1  dholland 				if (recallp == NULL)
   2679      1.1  dholland 					break;
   2680      1.1  dholland 				(void)nfscl_layoutrecall(NFSLAYOUTRETURN_FILE,
   2681      1.1  dholland 				    lyp, NFSLAYOUTIOMODE_ANY, 0, UINT64_MAX,
   2682      1.1  dholland 				    lyp->nfsly_stateid.seqid, recallp);
   2683      1.1  dholland 			}
   2684      1.1  dholland 			lyp = nlyp;
   2685      1.1  dholland 		}
   2686      1.1  dholland 
   2687      1.1  dholland 		/*
   2688      1.1  dholland 		 * Free up any unreferenced device info structures.
   2689      1.1  dholland 		 */
   2690      1.1  dholland 		LIST_FOREACH_SAFE(dip, &clp->nfsc_devinfo, nfsdi_list, ndip) {
   2691      1.1  dholland 			if (dip->nfsdi_layoutrefs == 0 &&
   2692      1.1  dholland 			    dip->nfsdi_refcnt == 0) {
   2693      1.1  dholland 				NFSCL_DEBUG(4, "freeing devinfo\n");
   2694      1.1  dholland 				LIST_REMOVE(dip, nfsdi_list);
   2695      1.1  dholland 				nfscl_freedevinfo(dip);
   2696      1.1  dholland 			}
   2697      1.1  dholland 		}
   2698      1.1  dholland 		NFSUNLOCKCLSTATE();
   2699      1.1  dholland 
   2700      1.1  dholland 		/* Do layout return(s), as required. */
   2701      1.1  dholland 		TAILQ_FOREACH_SAFE(lyp, &rlh, nfsly_list, nlyp) {
   2702      1.1  dholland 			TAILQ_REMOVE(&rlh, lyp, nfsly_list);
   2703      1.1  dholland 			NFSCL_DEBUG(4, "ret layout\n");
   2704      1.1  dholland 			nfscl_layoutreturn(clp->nfsc_nmp, lyp, cred, p);
   2705      1.1  dholland 			nfscl_freelayout(lyp);
   2706      1.1  dholland 		}
   2707      1.1  dholland 
   2708      1.1  dholland 		/*
   2709      1.1  dholland 		 * Delegreturn any delegations cleaned out or recalled.
   2710      1.1  dholland 		 */
   2711      1.1  dholland 		TAILQ_FOREACH_SAFE(dp, &dh, nfsdl_list, ndp) {
   2712      1.1  dholland 			newnfs_copycred(&dp->nfsdl_cred, cred);
   2713      1.1  dholland 			(void) nfscl_trydelegreturn(dp, cred, clp->nfsc_nmp, p);
   2714      1.1  dholland 			TAILQ_REMOVE(&dh, dp, nfsdl_list);
   2715      1.1  dholland 			FREE((caddr_t)dp, M_NFSCLDELEG);
   2716      1.1  dholland 		}
   2717      1.1  dholland 
   2718      1.1  dholland 		SLIST_INIT(&lfh);
   2719      1.1  dholland 		/*
   2720      1.1  dholland 		 * Call nfscl_cleanupkext() once per second to check for
   2721      1.1  dholland 		 * open/lock owners where the process has exited.
   2722      1.1  dholland 		 */
   2723      1.1  dholland 		mytime = NFSD_MONOSEC;
   2724      1.1  dholland 		if (prevsec != mytime) {
   2725      1.1  dholland 			prevsec = mytime;
   2726      1.1  dholland 			nfscl_cleanupkext(clp, &lfh);
   2727      1.1  dholland 		}
   2728      1.1  dholland 
   2729      1.1  dholland 		/*
   2730      1.1  dholland 		 * Do a ReleaseLockOwner for all lock owners where the
   2731      1.1  dholland 		 * associated process no longer exists, as found by
   2732      1.1  dholland 		 * nfscl_cleanupkext().
   2733      1.1  dholland 		 */
   2734      1.1  dholland 		newnfs_setroot(cred);
   2735      1.1  dholland 		SLIST_FOREACH_SAFE(lfhp, &lfh, nfslfh_list, nlfhp) {
   2736      1.1  dholland 			LIST_FOREACH_SAFE(lp, &lfhp->nfslfh_lock, nfsl_list,
   2737      1.1  dholland 			    nlp) {
   2738      1.1  dholland 				(void)nfsrpc_rellockown(clp->nfsc_nmp, lp,
   2739      1.1  dholland 				    lfhp->nfslfh_fh, lfhp->nfslfh_len, cred,
   2740      1.1  dholland 				    p);
   2741      1.1  dholland 				nfscl_freelockowner(lp, 0);
   2742      1.1  dholland 			}
   2743      1.1  dholland 			free(lfhp, M_TEMP);
   2744      1.1  dholland 		}
   2745      1.1  dholland 		SLIST_INIT(&lfh);
   2746      1.1  dholland 
   2747      1.1  dholland 		NFSLOCKCLSTATE();
   2748      1.1  dholland 		if ((clp->nfsc_flags & NFSCLFLAGS_RECOVER) == 0)
   2749      1.1  dholland 			(void)mtx_sleep(clp, NFSCLSTATEMUTEXPTR, PWAIT, "nfscl",
   2750      1.1  dholland 			    hz);
   2751      1.1  dholland 		if (clp->nfsc_flags & NFSCLFLAGS_UMOUNT) {
   2752      1.1  dholland 			clp->nfsc_flags &= ~NFSCLFLAGS_HASTHREAD;
   2753      1.1  dholland 			NFSUNLOCKCLSTATE();
   2754      1.1  dholland 			NFSFREECRED(cred);
   2755      1.1  dholland 			wakeup((caddr_t)clp);
   2756      1.1  dholland 			return;
   2757      1.1  dholland 		}
   2758      1.1  dholland 		NFSUNLOCKCLSTATE();
   2759      1.1  dholland 	}
   2760      1.1  dholland }
   2761      1.1  dholland 
   2762      1.1  dholland /*
   2763      1.1  dholland  * Initiate state recovery. Called when NFSERR_STALECLIENTID,
   2764      1.1  dholland  * NFSERR_STALESTATEID or NFSERR_BADSESSION is received.
   2765      1.1  dholland  */
   2766      1.1  dholland APPLESTATIC void
   2767      1.1  dholland nfscl_initiate_recovery(struct nfsclclient *clp)
   2768      1.1  dholland {
   2769      1.1  dholland 
   2770      1.1  dholland 	if (clp == NULL)
   2771      1.1  dholland 		return;
   2772      1.1  dholland 	NFSLOCKCLSTATE();
   2773      1.1  dholland 	clp->nfsc_flags |= NFSCLFLAGS_RECOVER;
   2774      1.1  dholland 	NFSUNLOCKCLSTATE();
   2775      1.1  dholland 	wakeup((caddr_t)clp);
   2776      1.1  dholland }
   2777      1.1  dholland 
   2778      1.1  dholland /*
   2779      1.1  dholland  * Dump out the state stuff for debugging.
   2780      1.1  dholland  */
   2781      1.1  dholland APPLESTATIC void
   2782      1.1  dholland nfscl_dumpstate(struct nfsmount *nmp, int openowner, int opens,
   2783      1.1  dholland     int lockowner, int locks)
   2784      1.1  dholland {
   2785      1.1  dholland 	struct nfsclclient *clp;
   2786      1.1  dholland 	struct nfsclowner *owp;
   2787      1.1  dholland 	struct nfsclopen *op;
   2788      1.1  dholland 	struct nfscllockowner *lp;
   2789      1.1  dholland 	struct nfscllock *lop;
   2790      1.1  dholland 	struct nfscldeleg *dp;
   2791      1.1  dholland 
   2792      1.1  dholland 	clp = nmp->nm_clp;
   2793      1.1  dholland 	if (clp == NULL) {
   2794      1.1  dholland 		printf("nfscl dumpstate NULL clp\n");
   2795      1.1  dholland 		return;
   2796      1.1  dholland 	}
   2797      1.1  dholland 	NFSLOCKCLSTATE();
   2798      1.1  dholland 	TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) {
   2799      1.1  dholland 	  LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) {
   2800      1.1  dholland 	    if (openowner && !LIST_EMPTY(&owp->nfsow_open))
   2801      1.1  dholland 		printf("owner=0x%x 0x%x 0x%x 0x%x seqid=%d\n",
   2802      1.1  dholland 		    owp->nfsow_owner[0], owp->nfsow_owner[1],
   2803      1.1  dholland 		    owp->nfsow_owner[2], owp->nfsow_owner[3],
   2804      1.1  dholland 		    owp->nfsow_seqid);
   2805      1.1  dholland 	    LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
   2806      1.1  dholland 		if (opens)
   2807      1.1  dholland 		    printf("open st=0x%x 0x%x 0x%x cnt=%d fh12=0x%x\n",
   2808      1.1  dholland 			op->nfso_stateid.other[0], op->nfso_stateid.other[1],
   2809      1.1  dholland 			op->nfso_stateid.other[2], op->nfso_opencnt,
   2810      1.1  dholland 			op->nfso_fh[12]);
   2811      1.1  dholland 		LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
   2812      1.1  dholland 		    if (lockowner)
   2813      1.1  dholland 			printf("lckown=0x%x 0x%x 0x%x 0x%x seqid=%d st=0x%x 0x%x 0x%x\n",
   2814      1.1  dholland 			    lp->nfsl_owner[0], lp->nfsl_owner[1],
   2815      1.1  dholland 			    lp->nfsl_owner[2], lp->nfsl_owner[3],
   2816      1.1  dholland 			    lp->nfsl_seqid,
   2817      1.1  dholland 			    lp->nfsl_stateid.other[0], lp->nfsl_stateid.other[1],
   2818      1.1  dholland 			    lp->nfsl_stateid.other[2]);
   2819      1.1  dholland 		    LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) {
   2820      1.1  dholland 			if (locks)
   2821      1.1  dholland #ifdef __FreeBSD__
   2822      1.1  dholland 			    printf("lck typ=%d fst=%ju end=%ju\n",
   2823      1.1  dholland 				lop->nfslo_type, (intmax_t)lop->nfslo_first,
   2824      1.1  dholland 				(intmax_t)lop->nfslo_end);
   2825      1.1  dholland #else
   2826      1.1  dholland 			    printf("lck typ=%d fst=%qd end=%qd\n",
   2827      1.1  dholland 				lop->nfslo_type, lop->nfslo_first,
   2828      1.1  dholland 				lop->nfslo_end);
   2829      1.1  dholland #endif
   2830      1.1  dholland 		    }
   2831      1.1  dholland 		}
   2832      1.1  dholland 	    }
   2833      1.1  dholland 	  }
   2834      1.1  dholland 	}
   2835      1.1  dholland 	LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
   2836      1.1  dholland 	    if (openowner && !LIST_EMPTY(&owp->nfsow_open))
   2837      1.1  dholland 		printf("owner=0x%x 0x%x 0x%x 0x%x seqid=%d\n",
   2838      1.1  dholland 		    owp->nfsow_owner[0], owp->nfsow_owner[1],
   2839      1.1  dholland 		    owp->nfsow_owner[2], owp->nfsow_owner[3],
   2840      1.1  dholland 		    owp->nfsow_seqid);
   2841      1.1  dholland 	    LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
   2842      1.1  dholland 		if (opens)
   2843      1.1  dholland 		    printf("open st=0x%x 0x%x 0x%x cnt=%d fh12=0x%x\n",
   2844      1.1  dholland 			op->nfso_stateid.other[0], op->nfso_stateid.other[1],
   2845      1.1  dholland 			op->nfso_stateid.other[2], op->nfso_opencnt,
   2846      1.1  dholland 			op->nfso_fh[12]);
   2847      1.1  dholland 		LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
   2848      1.1  dholland 		    if (lockowner)
   2849      1.1  dholland 			printf("lckown=0x%x 0x%x 0x%x 0x%x seqid=%d st=0x%x 0x%x 0x%x\n",
   2850      1.1  dholland 			    lp->nfsl_owner[0], lp->nfsl_owner[1],
   2851      1.1  dholland 			    lp->nfsl_owner[2], lp->nfsl_owner[3],
   2852      1.1  dholland 			    lp->nfsl_seqid,
   2853      1.1  dholland 			    lp->nfsl_stateid.other[0], lp->nfsl_stateid.other[1],
   2854      1.1  dholland 			    lp->nfsl_stateid.other[2]);
   2855      1.1  dholland 		    LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) {
   2856      1.1  dholland 			if (locks)
   2857      1.1  dholland #ifdef __FreeBSD__
   2858      1.1  dholland 			    printf("lck typ=%d fst=%ju end=%ju\n",
   2859      1.1  dholland 				lop->nfslo_type, (intmax_t)lop->nfslo_first,
   2860      1.1  dholland 				(intmax_t)lop->nfslo_end);
   2861      1.1  dholland #else
   2862      1.1  dholland 			    printf("lck typ=%d fst=%qd end=%qd\n",
   2863      1.1  dholland 				lop->nfslo_type, lop->nfslo_first,
   2864      1.1  dholland 				lop->nfslo_end);
   2865      1.1  dholland #endif
   2866      1.1  dholland 		    }
   2867      1.1  dholland 		}
   2868      1.1  dholland 	    }
   2869      1.1  dholland 	}
   2870      1.1  dholland 	NFSUNLOCKCLSTATE();
   2871      1.1  dholland }
   2872      1.1  dholland 
   2873      1.1  dholland /*
   2874      1.1  dholland  * Check for duplicate open owners and opens.
   2875      1.1  dholland  * (Only used as a diagnostic aid.)
   2876      1.1  dholland  */
   2877      1.1  dholland APPLESTATIC void
   2878      1.1  dholland nfscl_dupopen(vnode_t vp, int dupopens)
   2879      1.1  dholland {
   2880      1.1  dholland 	struct nfsclclient *clp;
   2881      1.1  dholland 	struct nfsclowner *owp, *owp2;
   2882      1.1  dholland 	struct nfsclopen *op, *op2;
   2883      1.1  dholland 	struct nfsfh *nfhp;
   2884      1.1  dholland 
   2885      1.1  dholland 	clp = VFSTONFS(vnode_mount(vp))->nm_clp;
   2886      1.1  dholland 	if (clp == NULL) {
   2887      1.1  dholland 		printf("nfscl dupopen NULL clp\n");
   2888      1.1  dholland 		return;
   2889      1.1  dholland 	}
   2890      1.1  dholland 	nfhp = VTONFS(vp)->n_fhp;
   2891      1.1  dholland 	NFSLOCKCLSTATE();
   2892      1.1  dholland 
   2893      1.1  dholland 	/*
   2894      1.1  dholland 	 * First, search for duplicate owners.
   2895      1.1  dholland 	 * These should never happen!
   2896      1.1  dholland 	 */
   2897      1.1  dholland 	LIST_FOREACH(owp2, &clp->nfsc_owner, nfsow_list) {
   2898      1.1  dholland 	    LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
   2899      1.1  dholland 		if (owp != owp2 &&
   2900      1.1  dholland 		    !NFSBCMP(owp->nfsow_owner, owp2->nfsow_owner,
   2901      1.1  dholland 		    NFSV4CL_LOCKNAMELEN)) {
   2902      1.1  dholland 			NFSUNLOCKCLSTATE();
   2903      1.1  dholland 			printf("DUP OWNER\n");
   2904      1.1  dholland 			nfscl_dumpstate(VFSTONFS(vnode_mount(vp)), 1, 1, 0, 0);
   2905      1.1  dholland 			return;
   2906      1.1  dholland 		}
   2907      1.1  dholland 	    }
   2908      1.1  dholland 	}
   2909      1.1  dholland 
   2910      1.1  dholland 	/*
   2911      1.1  dholland 	 * Now, search for duplicate stateids.
   2912      1.1  dholland 	 * These shouldn't happen, either.
   2913      1.1  dholland 	 */
   2914      1.1  dholland 	LIST_FOREACH(owp2, &clp->nfsc_owner, nfsow_list) {
   2915      1.1  dholland 	    LIST_FOREACH(op2, &owp2->nfsow_open, nfso_list) {
   2916      1.1  dholland 		LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
   2917      1.1  dholland 		    LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
   2918      1.1  dholland 			if (op != op2 &&
   2919      1.1  dholland 			    (op->nfso_stateid.other[0] != 0 ||
   2920      1.1  dholland 			     op->nfso_stateid.other[1] != 0 ||
   2921      1.1  dholland 			     op->nfso_stateid.other[2] != 0) &&
   2922      1.1  dholland 			    op->nfso_stateid.other[0] == op2->nfso_stateid.other[0] &&
   2923      1.1  dholland 			    op->nfso_stateid.other[1] == op2->nfso_stateid.other[1] &&
   2924      1.1  dholland 			    op->nfso_stateid.other[2] == op2->nfso_stateid.other[2]) {
   2925      1.1  dholland 			    NFSUNLOCKCLSTATE();
   2926      1.1  dholland 			    printf("DUP STATEID\n");
   2927      1.1  dholland 			    nfscl_dumpstate(VFSTONFS(vnode_mount(vp)), 1, 1, 0,
   2928      1.1  dholland 				0);
   2929      1.1  dholland 			    return;
   2930      1.1  dholland 			}
   2931      1.1  dholland 		    }
   2932      1.1  dholland 		}
   2933      1.1  dholland 	    }
   2934      1.1  dholland 	}
   2935      1.1  dholland 
   2936      1.1  dholland 	/*
   2937      1.1  dholland 	 * Now search for duplicate opens.
   2938      1.1  dholland 	 * Duplicate opens for the same owner
   2939      1.1  dholland 	 * should never occur. Other duplicates are
   2940      1.1  dholland 	 * possible and are checked for if "dupopens"
   2941      1.1  dholland 	 * is true.
   2942      1.1  dholland 	 */
   2943      1.1  dholland 	LIST_FOREACH(owp2, &clp->nfsc_owner, nfsow_list) {
   2944      1.1  dholland 	    LIST_FOREACH(op2, &owp2->nfsow_open, nfso_list) {
   2945      1.1  dholland 		if (nfhp->nfh_len == op2->nfso_fhlen &&
   2946      1.1  dholland 		    !NFSBCMP(nfhp->nfh_fh, op2->nfso_fh, nfhp->nfh_len)) {
   2947      1.1  dholland 		    LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
   2948      1.1  dholland 			LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
   2949      1.1  dholland 			    if (op != op2 && nfhp->nfh_len == op->nfso_fhlen &&
   2950      1.1  dholland 				!NFSBCMP(nfhp->nfh_fh, op->nfso_fh, nfhp->nfh_len) &&
   2951      1.1  dholland 				(!NFSBCMP(op->nfso_own->nfsow_owner,
   2952      1.1  dholland 				 op2->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN) ||
   2953      1.1  dholland 				 dupopens)) {
   2954      1.1  dholland 				if (!NFSBCMP(op->nfso_own->nfsow_owner,
   2955      1.1  dholland 				    op2->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN)) {
   2956      1.1  dholland 				    NFSUNLOCKCLSTATE();
   2957      1.1  dholland 				    printf("BADDUP OPEN\n");
   2958      1.1  dholland 				} else {
   2959      1.1  dholland 				    NFSUNLOCKCLSTATE();
   2960      1.1  dholland 				    printf("DUP OPEN\n");
   2961      1.1  dholland 				}
   2962      1.1  dholland 				nfscl_dumpstate(VFSTONFS(vnode_mount(vp)), 1, 1,
   2963      1.1  dholland 				    0, 0);
   2964      1.1  dholland 				return;
   2965      1.1  dholland 			    }
   2966      1.1  dholland 			}
   2967      1.1  dholland 		    }
   2968      1.1  dholland 		}
   2969      1.1  dholland 	    }
   2970      1.1  dholland 	}
   2971      1.1  dholland 	NFSUNLOCKCLSTATE();
   2972      1.1  dholland }
   2973      1.1  dholland 
   2974      1.1  dholland /*
   2975      1.1  dholland  * During close, find an open that needs to be dereferenced and
   2976      1.1  dholland  * dereference it. If there are no more opens for this file,
   2977      1.1  dholland  * log a message to that effect.
   2978      1.1  dholland  * Opens aren't actually Close'd until VOP_INACTIVE() is performed
   2979      1.1  dholland  * on the file's vnode.
   2980      1.1  dholland  * This is the safe way, since it is difficult to identify
   2981      1.1  dholland  * which open the close is for and I/O can be performed after the
   2982      1.1  dholland  * close(2) system call when a file is mmap'd.
   2983      1.1  dholland  * If it returns 0 for success, there will be a referenced
   2984      1.1  dholland  * clp returned via clpp.
   2985      1.1  dholland  */
   2986      1.1  dholland APPLESTATIC int
   2987      1.1  dholland nfscl_getclose(vnode_t vp, struct nfsclclient **clpp)
   2988      1.1  dholland {
   2989      1.1  dholland 	struct nfsclclient *clp;
   2990      1.1  dholland 	struct nfsclowner *owp;
   2991      1.1  dholland 	struct nfsclopen *op;
   2992      1.1  dholland 	struct nfscldeleg *dp;
   2993      1.1  dholland 	struct nfsfh *nfhp;
   2994      1.1  dholland 	int error, notdecr;
   2995      1.1  dholland 
   2996      1.1  dholland 	error = nfscl_getcl(vnode_mount(vp), NULL, NULL, 1, &clp);
   2997      1.1  dholland 	if (error)
   2998      1.1  dholland 		return (error);
   2999      1.1  dholland 	*clpp = clp;
   3000      1.1  dholland 
   3001      1.1  dholland 	nfhp = VTONFS(vp)->n_fhp;
   3002      1.1  dholland 	notdecr = 1;
   3003      1.1  dholland 	NFSLOCKCLSTATE();
   3004      1.1  dholland 	/*
   3005      1.1  dholland 	 * First, look for one under a delegation that was locally issued
   3006      1.1  dholland 	 * and just decrement the opencnt for it. Since all my Opens against
   3007      1.1  dholland 	 * the server are DENY_NONE, I don't see a problem with hanging
   3008      1.1  dholland 	 * onto them. (It is much easier to use one of the extant Opens
   3009      1.1  dholland 	 * that I already have on the server when a Delegation is recalled
   3010      1.1  dholland 	 * than to do fresh Opens.) Someday, I might need to rethink this, but.
   3011      1.1  dholland 	 */
   3012      1.1  dholland 	dp = nfscl_finddeleg(clp, nfhp->nfh_fh, nfhp->nfh_len);
   3013      1.1  dholland 	if (dp != NULL) {
   3014      1.1  dholland 		LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) {
   3015      1.1  dholland 			op = LIST_FIRST(&owp->nfsow_open);
   3016      1.1  dholland 			if (op != NULL) {
   3017      1.1  dholland 				/*
   3018      1.1  dholland 				 * Since a delegation is for a file, there
   3019      1.1  dholland 				 * should never be more than one open for
   3020      1.1  dholland 				 * each openowner.
   3021      1.1  dholland 				 */
   3022      1.1  dholland 				if (LIST_NEXT(op, nfso_list) != NULL)
   3023      1.1  dholland 					panic("nfscdeleg opens");
   3024      1.1  dholland 				if (notdecr && op->nfso_opencnt > 0) {
   3025      1.1  dholland 					notdecr = 0;
   3026      1.1  dholland 					op->nfso_opencnt--;
   3027      1.1  dholland 					break;
   3028      1.1  dholland 				}
   3029      1.1  dholland 			}
   3030      1.1  dholland 		}
   3031      1.1  dholland 	}
   3032      1.1  dholland 
   3033      1.1  dholland 	/* Now process the opens against the server. */
   3034      1.1  dholland 	LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
   3035      1.1  dholland 		LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
   3036      1.1  dholland 			if (op->nfso_fhlen == nfhp->nfh_len &&
   3037      1.1  dholland 			    !NFSBCMP(op->nfso_fh, nfhp->nfh_fh,
   3038      1.1  dholland 			    nfhp->nfh_len)) {
   3039      1.1  dholland 				/* Found an open, decrement cnt if possible */
   3040      1.1  dholland 				if (notdecr && op->nfso_opencnt > 0) {
   3041      1.1  dholland 					notdecr = 0;
   3042      1.1  dholland 					op->nfso_opencnt--;
   3043      1.1  dholland 				}
   3044      1.1  dholland 				/*
   3045      1.1  dholland 				 * There are more opens, so just return.
   3046      1.1  dholland 				 */
   3047      1.1  dholland 				if (op->nfso_opencnt > 0) {
   3048      1.1  dholland 					NFSUNLOCKCLSTATE();
   3049      1.1  dholland 					return (0);
   3050      1.1  dholland 				}
   3051      1.1  dholland 			}
   3052      1.1  dholland 		}
   3053      1.1  dholland 	}
   3054      1.1  dholland 	NFSUNLOCKCLSTATE();
   3055      1.1  dholland 	if (notdecr)
   3056      1.1  dholland 		printf("nfscl: never fnd open\n");
   3057      1.1  dholland 	return (0);
   3058      1.1  dholland }
   3059      1.1  dholland 
   3060      1.1  dholland APPLESTATIC int
   3061      1.1  dholland nfscl_doclose(vnode_t vp, struct nfsclclient **clpp, NFSPROC_T *p)
   3062      1.1  dholland {
   3063      1.1  dholland 	struct nfsclclient *clp;
   3064      1.1  dholland 	struct nfsclowner *owp, *nowp;
   3065      1.1  dholland 	struct nfsclopen *op;
   3066      1.1  dholland 	struct nfscldeleg *dp;
   3067      1.1  dholland 	struct nfsfh *nfhp;
   3068      1.1  dholland 	int error;
   3069      1.1  dholland 
   3070      1.1  dholland 	error = nfscl_getcl(vnode_mount(vp), NULL, NULL, 1, &clp);
   3071      1.1  dholland 	if (error)
   3072      1.1  dholland 		return (error);
   3073      1.1  dholland 	*clpp = clp;
   3074      1.1  dholland 
   3075      1.1  dholland 	nfhp = VTONFS(vp)->n_fhp;
   3076      1.1  dholland 	NFSLOCKCLSTATE();
   3077      1.1  dholland 	/*
   3078      1.1  dholland 	 * First get rid of the local Open structures, which should be no
   3079      1.1  dholland 	 * longer in use.
   3080      1.1  dholland 	 */
   3081      1.1  dholland 	dp = nfscl_finddeleg(clp, nfhp->nfh_fh, nfhp->nfh_len);
   3082      1.1  dholland 	if (dp != NULL) {
   3083      1.1  dholland 		LIST_FOREACH_SAFE(owp, &dp->nfsdl_owner, nfsow_list, nowp) {
   3084      1.1  dholland 			op = LIST_FIRST(&owp->nfsow_open);
   3085      1.1  dholland 			if (op != NULL) {
   3086      1.1  dholland 				KASSERT((op->nfso_opencnt == 0),
   3087      1.1  dholland 				    ("nfscl: bad open cnt on deleg"));
   3088      1.1  dholland 				nfscl_freeopen(op, 1);
   3089      1.1  dholland 			}
   3090      1.1  dholland 			nfscl_freeopenowner(owp, 1);
   3091      1.1  dholland 		}
   3092      1.1  dholland 	}
   3093      1.1  dholland 
   3094      1.1  dholland 	/* Return any layouts marked return on close. */
   3095      1.1  dholland 	nfscl_retoncloselayout(clp, nfhp->nfh_fh, nfhp->nfh_len);
   3096      1.1  dholland 
   3097      1.1  dholland 	/* Now process the opens against the server. */
   3098      1.1  dholland lookformore:
   3099      1.1  dholland 	LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
   3100      1.1  dholland 		op = LIST_FIRST(&owp->nfsow_open);
   3101      1.1  dholland 		while (op != NULL) {
   3102      1.1  dholland 			if (op->nfso_fhlen == nfhp->nfh_len &&
   3103      1.1  dholland 			    !NFSBCMP(op->nfso_fh, nfhp->nfh_fh,
   3104      1.1  dholland 			    nfhp->nfh_len)) {
   3105      1.1  dholland 				/* Found an open, close it. */
   3106      1.1  dholland 				KASSERT((op->nfso_opencnt == 0),
   3107      1.1  dholland 				    ("nfscl: bad open cnt on server"));
   3108      1.1  dholland 				NFSUNLOCKCLSTATE();
   3109      1.1  dholland 				nfsrpc_doclose(VFSTONFS(vnode_mount(vp)), op,
   3110      1.1  dholland 				    p);
   3111      1.1  dholland 				NFSLOCKCLSTATE();
   3112      1.1  dholland 				goto lookformore;
   3113      1.1  dholland 			}
   3114      1.1  dholland 			op = LIST_NEXT(op, nfso_list);
   3115      1.1  dholland 		}
   3116      1.1  dholland 	}
   3117      1.1  dholland 	NFSUNLOCKCLSTATE();
   3118      1.1  dholland 	return (0);
   3119      1.1  dholland }
   3120      1.1  dholland 
   3121      1.1  dholland /*
   3122      1.1  dholland  * Return all delegations on this client.
   3123      1.1  dholland  * (Must be called with client sleep lock.)
   3124      1.1  dholland  */
   3125      1.1  dholland static void
   3126      1.1  dholland nfscl_delegreturnall(struct nfsclclient *clp, NFSPROC_T *p)
   3127      1.1  dholland {
   3128      1.1  dholland 	struct nfscldeleg *dp, *ndp;
   3129      1.1  dholland 	struct ucred *cred;
   3130      1.1  dholland 
   3131      1.1  dholland 	cred = newnfs_getcred();
   3132      1.1  dholland 	TAILQ_FOREACH_SAFE(dp, &clp->nfsc_deleg, nfsdl_list, ndp) {
   3133      1.1  dholland 		nfscl_cleandeleg(dp);
   3134      1.1  dholland 		(void) nfscl_trydelegreturn(dp, cred, clp->nfsc_nmp, p);
   3135      1.1  dholland 		nfscl_freedeleg(&clp->nfsc_deleg, dp);
   3136      1.1  dholland 	}
   3137      1.1  dholland 	NFSFREECRED(cred);
   3138      1.1  dholland }
   3139      1.1  dholland 
   3140      1.1  dholland /*
   3141      1.1  dholland  * Do a callback RPC.
   3142      1.1  dholland  */
   3143      1.1  dholland APPLESTATIC void
   3144      1.1  dholland nfscl_docb(struct nfsrv_descript *nd, NFSPROC_T *p)
   3145      1.1  dholland {
   3146      1.1  dholland 	int clist, gotseq_ok, i, j, k, op, rcalls;
   3147      1.1  dholland 	u_int32_t *tl;
   3148      1.1  dholland 	struct nfsclclient *clp;
   3149      1.1  dholland 	struct nfscldeleg *dp = NULL;
   3150      1.1  dholland 	int numops, taglen = -1, error = 0, trunc;
   3151  1.1.1.2  pgoyette 	u_int32_t minorvers = 0, retops = 0, *retopsp = NULL, *repp, cbident;
   3152      1.1  dholland 	u_char tag[NFSV4_SMALLSTR + 1], *tagstr;
   3153      1.1  dholland 	vnode_t vp = NULL;
   3154      1.1  dholland 	struct nfsnode *np;
   3155      1.1  dholland 	struct vattr va;
   3156      1.1  dholland 	struct nfsfh *nfhp;
   3157      1.1  dholland 	mount_t mp;
   3158      1.1  dholland 	nfsattrbit_t attrbits, rattrbits;
   3159      1.1  dholland 	nfsv4stateid_t stateid;
   3160      1.1  dholland 	uint32_t seqid, slotid = 0, highslot, cachethis;
   3161      1.1  dholland 	uint8_t sessionid[NFSX_V4SESSIONID];
   3162      1.1  dholland 	struct mbuf *rep;
   3163      1.1  dholland 	struct nfscllayout *lyp;
   3164      1.1  dholland 	uint64_t filesid[2], len, off;
   3165      1.1  dholland 	int changed, gotone, laytype, recalltype;
   3166      1.1  dholland 	uint32_t iomode;
   3167      1.1  dholland 	struct nfsclrecalllayout *recallp = NULL;
   3168      1.1  dholland 
   3169      1.1  dholland 	gotseq_ok = 0;
   3170      1.1  dholland 	nfsrvd_rephead(nd);
   3171      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3172      1.1  dholland 	taglen = fxdr_unsigned(int, *tl);
   3173      1.1  dholland 	if (taglen < 0) {
   3174      1.1  dholland 		error = EBADRPC;
   3175      1.1  dholland 		goto nfsmout;
   3176      1.1  dholland 	}
   3177      1.1  dholland 	if (taglen <= NFSV4_SMALLSTR)
   3178      1.1  dholland 		tagstr = tag;
   3179      1.1  dholland 	else
   3180      1.1  dholland 		tagstr = malloc(taglen + 1, M_TEMP, M_WAITOK);
   3181      1.1  dholland 	error = nfsrv_mtostr(nd, tagstr, taglen);
   3182      1.1  dholland 	if (error) {
   3183      1.1  dholland 		if (taglen > NFSV4_SMALLSTR)
   3184      1.1  dholland 			free(tagstr, M_TEMP);
   3185      1.1  dholland 		taglen = -1;
   3186      1.1  dholland 		goto nfsmout;
   3187      1.1  dholland 	}
   3188      1.1  dholland 	(void) nfsm_strtom(nd, tag, taglen);
   3189      1.1  dholland 	if (taglen > NFSV4_SMALLSTR) {
   3190      1.1  dholland 		free(tagstr, M_TEMP);
   3191      1.1  dholland 	}
   3192      1.1  dholland 	NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
   3193      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   3194      1.1  dholland 	minorvers = fxdr_unsigned(u_int32_t, *tl++);
   3195      1.1  dholland 	if (minorvers != NFSV4_MINORVERSION && minorvers != NFSV41_MINORVERSION)
   3196      1.1  dholland 		nd->nd_repstat = NFSERR_MINORVERMISMATCH;
   3197      1.1  dholland 	cbident = fxdr_unsigned(u_int32_t, *tl++);
   3198      1.1  dholland 	if (nd->nd_repstat)
   3199      1.1  dholland 		numops = 0;
   3200      1.1  dholland 	else
   3201      1.1  dholland 		numops = fxdr_unsigned(int, *tl);
   3202      1.1  dholland 	/*
   3203      1.1  dholland 	 * Loop around doing the sub ops.
   3204      1.1  dholland 	 */
   3205      1.1  dholland 	for (i = 0; i < numops; i++) {
   3206      1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3207      1.1  dholland 		NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
   3208      1.1  dholland 		*repp++ = *tl;
   3209      1.1  dholland 		op = fxdr_unsigned(int, *tl);
   3210      1.1  dholland 		if (op < NFSV4OP_CBGETATTR ||
   3211      1.1  dholland 		   (op > NFSV4OP_CBRECALL && minorvers == NFSV4_MINORVERSION) ||
   3212      1.1  dholland 		   (op > NFSV4OP_CBNOTIFYDEVID &&
   3213      1.1  dholland 		    minorvers == NFSV41_MINORVERSION)) {
   3214      1.1  dholland 		    nd->nd_repstat = NFSERR_OPILLEGAL;
   3215  1.1.1.2  pgoyette 		    *repp = nfscl_errmap(nd, minorvers);
   3216      1.1  dholland 		    retops++;
   3217      1.1  dholland 		    break;
   3218      1.1  dholland 		}
   3219      1.1  dholland 		nd->nd_procnum = op;
   3220  1.1.1.2  pgoyette 		if (op < NFSV41_CBNOPS)
   3221  1.1.1.2  pgoyette 			nfsstatsv1.cbrpccnt[nd->nd_procnum]++;
   3222      1.1  dholland 		switch (op) {
   3223      1.1  dholland 		case NFSV4OP_CBGETATTR:
   3224      1.1  dholland 			NFSCL_DEBUG(4, "cbgetattr\n");
   3225      1.1  dholland 			mp = NULL;
   3226      1.1  dholland 			vp = NULL;
   3227      1.1  dholland 			error = nfsm_getfh(nd, &nfhp);
   3228      1.1  dholland 			if (!error)
   3229      1.1  dholland 				error = nfsrv_getattrbits(nd, &attrbits,
   3230      1.1  dholland 				    NULL, NULL);
   3231      1.1  dholland 			if (error == 0 && i == 0 &&
   3232      1.1  dholland 			    minorvers != NFSV4_MINORVERSION)
   3233      1.1  dholland 				error = NFSERR_OPNOTINSESS;
   3234      1.1  dholland 			if (!error) {
   3235      1.1  dholland 				mp = nfscl_getmnt(minorvers, sessionid, cbident,
   3236      1.1  dholland 				    &clp);
   3237      1.1  dholland 				if (mp == NULL)
   3238      1.1  dholland 					error = NFSERR_SERVERFAULT;
   3239      1.1  dholland 			}
   3240      1.1  dholland 			if (!error) {
   3241      1.1  dholland 				error = nfscl_ngetreopen(mp, nfhp->nfh_fh,
   3242      1.1  dholland 				    nfhp->nfh_len, p, &np);
   3243      1.1  dholland 				if (!error)
   3244      1.1  dholland 					vp = NFSTOV(np);
   3245      1.1  dholland 			}
   3246      1.1  dholland 			if (!error) {
   3247      1.1  dholland 				NFSZERO_ATTRBIT(&rattrbits);
   3248      1.1  dholland 				NFSLOCKCLSTATE();
   3249      1.1  dholland 				dp = nfscl_finddeleg(clp, nfhp->nfh_fh,
   3250      1.1  dholland 				    nfhp->nfh_len);
   3251      1.1  dholland 				if (dp != NULL) {
   3252      1.1  dholland 					if (NFSISSET_ATTRBIT(&attrbits,
   3253      1.1  dholland 					    NFSATTRBIT_SIZE)) {
   3254      1.1  dholland 						if (vp != NULL)
   3255      1.1  dholland 							va.va_size = np->n_size;
   3256      1.1  dholland 						else
   3257      1.1  dholland 							va.va_size =
   3258      1.1  dholland 							    dp->nfsdl_size;
   3259      1.1  dholland 						NFSSETBIT_ATTRBIT(&rattrbits,
   3260      1.1  dholland 						    NFSATTRBIT_SIZE);
   3261      1.1  dholland 					}
   3262      1.1  dholland 					if (NFSISSET_ATTRBIT(&attrbits,
   3263      1.1  dholland 					    NFSATTRBIT_CHANGE)) {
   3264      1.1  dholland 						va.va_filerev =
   3265      1.1  dholland 						    dp->nfsdl_change;
   3266      1.1  dholland 						if (vp == NULL ||
   3267      1.1  dholland 						    (np->n_flag & NDELEGMOD))
   3268      1.1  dholland 							va.va_filerev++;
   3269      1.1  dholland 						NFSSETBIT_ATTRBIT(&rattrbits,
   3270      1.1  dholland 						    NFSATTRBIT_CHANGE);
   3271      1.1  dholland 					}
   3272      1.1  dholland 				} else
   3273      1.1  dholland 					error = NFSERR_SERVERFAULT;
   3274      1.1  dholland 				NFSUNLOCKCLSTATE();
   3275      1.1  dholland 			}
   3276      1.1  dholland 			if (vp != NULL)
   3277      1.1  dholland 				vrele(vp);
   3278      1.1  dholland 			if (mp != NULL)
   3279      1.1  dholland 				vfs_unbusy(mp);
   3280      1.1  dholland 			if (nfhp != NULL)
   3281      1.1  dholland 				FREE((caddr_t)nfhp, M_NFSFH);
   3282      1.1  dholland 			if (!error)
   3283      1.1  dholland 				(void) nfsv4_fillattr(nd, NULL, NULL, NULL, &va,
   3284  1.1.1.2  pgoyette 				    NULL, 0, &rattrbits, NULL, p, 0, 0, 0, 0,
   3285      1.1  dholland 				    (uint64_t)0);
   3286      1.1  dholland 			break;
   3287      1.1  dholland 		case NFSV4OP_CBRECALL:
   3288      1.1  dholland 			NFSCL_DEBUG(4, "cbrecall\n");
   3289      1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
   3290      1.1  dholland 			    NFSX_UNSIGNED);
   3291      1.1  dholland 			stateid.seqid = *tl++;
   3292      1.1  dholland 			NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other,
   3293      1.1  dholland 			    NFSX_STATEIDOTHER);
   3294      1.1  dholland 			tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
   3295      1.1  dholland 			trunc = fxdr_unsigned(int, *tl);
   3296      1.1  dholland 			error = nfsm_getfh(nd, &nfhp);
   3297      1.1  dholland 			if (error == 0 && i == 0 &&
   3298      1.1  dholland 			    minorvers != NFSV4_MINORVERSION)
   3299      1.1  dholland 				error = NFSERR_OPNOTINSESS;
   3300      1.1  dholland 			if (!error) {
   3301      1.1  dholland 				NFSLOCKCLSTATE();
   3302      1.1  dholland 				if (minorvers == NFSV4_MINORVERSION)
   3303      1.1  dholland 					clp = nfscl_getclnt(cbident);
   3304      1.1  dholland 				else
   3305      1.1  dholland 					clp = nfscl_getclntsess(sessionid);
   3306      1.1  dholland 				if (clp != NULL) {
   3307      1.1  dholland 					dp = nfscl_finddeleg(clp, nfhp->nfh_fh,
   3308      1.1  dholland 					    nfhp->nfh_len);
   3309      1.1  dholland 					if (dp != NULL && (dp->nfsdl_flags &
   3310      1.1  dholland 					    NFSCLDL_DELEGRET) == 0) {
   3311      1.1  dholland 						dp->nfsdl_flags |=
   3312      1.1  dholland 						    NFSCLDL_RECALL;
   3313      1.1  dholland 						wakeup((caddr_t)clp);
   3314      1.1  dholland 					}
   3315      1.1  dholland 				} else {
   3316      1.1  dholland 					error = NFSERR_SERVERFAULT;
   3317      1.1  dholland 				}
   3318      1.1  dholland 				NFSUNLOCKCLSTATE();
   3319      1.1  dholland 			}
   3320      1.1  dholland 			if (nfhp != NULL)
   3321      1.1  dholland 				FREE((caddr_t)nfhp, M_NFSFH);
   3322      1.1  dholland 			break;
   3323      1.1  dholland 		case NFSV4OP_CBLAYOUTRECALL:
   3324      1.1  dholland 			NFSCL_DEBUG(4, "cblayrec\n");
   3325      1.1  dholland 			nfhp = NULL;
   3326      1.1  dholland 			NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
   3327      1.1  dholland 			laytype = fxdr_unsigned(int, *tl++);
   3328      1.1  dholland 			iomode = fxdr_unsigned(uint32_t, *tl++);
   3329      1.1  dholland 			if (newnfs_true == *tl++)
   3330      1.1  dholland 				changed = 1;
   3331      1.1  dholland 			else
   3332      1.1  dholland 				changed = 0;
   3333      1.1  dholland 			recalltype = fxdr_unsigned(int, *tl);
   3334      1.1  dholland 			recallp = malloc(sizeof(*recallp), M_NFSLAYRECALL,
   3335      1.1  dholland 			    M_WAITOK);
   3336      1.1  dholland 			if (laytype != NFSLAYOUT_NFSV4_1_FILES)
   3337      1.1  dholland 				error = NFSERR_NOMATCHLAYOUT;
   3338      1.1  dholland 			else if (recalltype == NFSLAYOUTRETURN_FILE) {
   3339      1.1  dholland 				error = nfsm_getfh(nd, &nfhp);
   3340      1.1  dholland 				NFSCL_DEBUG(4, "retfile getfh=%d\n", error);
   3341      1.1  dholland 				if (error != 0)
   3342      1.1  dholland 					goto nfsmout;
   3343      1.1  dholland 				NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER +
   3344      1.1  dholland 				    NFSX_STATEID);
   3345      1.1  dholland 				off = fxdr_hyper(tl); tl += 2;
   3346      1.1  dholland 				len = fxdr_hyper(tl); tl += 2;
   3347      1.1  dholland 				stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
   3348      1.1  dholland 				NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
   3349      1.1  dholland 				if (minorvers == NFSV4_MINORVERSION)
   3350      1.1  dholland 					error = NFSERR_NOTSUPP;
   3351      1.1  dholland 				else if (i == 0)
   3352      1.1  dholland 					error = NFSERR_OPNOTINSESS;
   3353      1.1  dholland 				if (error == 0) {
   3354      1.1  dholland 					NFSLOCKCLSTATE();
   3355      1.1  dholland 					clp = nfscl_getclntsess(sessionid);
   3356      1.1  dholland 					NFSCL_DEBUG(4, "cbly clp=%p\n", clp);
   3357      1.1  dholland 					if (clp != NULL) {
   3358      1.1  dholland 						lyp = nfscl_findlayout(clp,
   3359      1.1  dholland 						    nfhp->nfh_fh,
   3360      1.1  dholland 						    nfhp->nfh_len);
   3361      1.1  dholland 						NFSCL_DEBUG(4, "cblyp=%p\n",
   3362      1.1  dholland 						    lyp);
   3363      1.1  dholland 						if (lyp != NULL &&
   3364      1.1  dholland 						    (lyp->nfsly_flags &
   3365      1.1  dholland 						     NFSLY_FILES) != 0 &&
   3366      1.1  dholland 						    !NFSBCMP(stateid.other,
   3367      1.1  dholland 						    lyp->nfsly_stateid.other,
   3368      1.1  dholland 						    NFSX_STATEIDOTHER)) {
   3369      1.1  dholland 							error =
   3370      1.1  dholland 							    nfscl_layoutrecall(
   3371      1.1  dholland 							    recalltype,
   3372      1.1  dholland 							    lyp, iomode, off,
   3373      1.1  dholland 							    len, stateid.seqid,
   3374      1.1  dholland 							    recallp);
   3375      1.1  dholland 							recallp = NULL;
   3376      1.1  dholland 							wakeup(clp);
   3377      1.1  dholland 							NFSCL_DEBUG(4,
   3378      1.1  dholland 							    "aft layrcal=%d\n",
   3379      1.1  dholland 							    error);
   3380      1.1  dholland 						} else
   3381      1.1  dholland 							error =
   3382      1.1  dholland 							  NFSERR_NOMATCHLAYOUT;
   3383      1.1  dholland 					} else
   3384      1.1  dholland 						error = NFSERR_NOMATCHLAYOUT;
   3385      1.1  dholland 					NFSUNLOCKCLSTATE();
   3386      1.1  dholland 				}
   3387      1.1  dholland 				free(nfhp, M_NFSFH);
   3388      1.1  dholland 			} else if (recalltype == NFSLAYOUTRETURN_FSID) {
   3389      1.1  dholland 				NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER);
   3390      1.1  dholland 				filesid[0] = fxdr_hyper(tl); tl += 2;
   3391      1.1  dholland 				filesid[1] = fxdr_hyper(tl); tl += 2;
   3392      1.1  dholland 				gotone = 0;
   3393      1.1  dholland 				NFSLOCKCLSTATE();
   3394      1.1  dholland 				clp = nfscl_getclntsess(sessionid);
   3395      1.1  dholland 				if (clp != NULL) {
   3396      1.1  dholland 					TAILQ_FOREACH(lyp, &clp->nfsc_layout,
   3397      1.1  dholland 					    nfsly_list) {
   3398      1.1  dholland 						if (lyp->nfsly_filesid[0] ==
   3399      1.1  dholland 						    filesid[0] &&
   3400      1.1  dholland 						    lyp->nfsly_filesid[1] ==
   3401      1.1  dholland 						    filesid[1]) {
   3402      1.1  dholland 							error =
   3403      1.1  dholland 							    nfscl_layoutrecall(
   3404      1.1  dholland 							    recalltype,
   3405      1.1  dholland 							    lyp, iomode, 0,
   3406      1.1  dholland 							    UINT64_MAX,
   3407      1.1  dholland 							    lyp->nfsly_stateid.seqid,
   3408      1.1  dholland 							    recallp);
   3409      1.1  dholland 							recallp = NULL;
   3410      1.1  dholland 							gotone = 1;
   3411      1.1  dholland 						}
   3412      1.1  dholland 					}
   3413      1.1  dholland 					if (gotone != 0)
   3414      1.1  dholland 						wakeup(clp);
   3415      1.1  dholland 					else
   3416      1.1  dholland 						error = NFSERR_NOMATCHLAYOUT;
   3417      1.1  dholland 				} else
   3418      1.1  dholland 					error = NFSERR_NOMATCHLAYOUT;
   3419      1.1  dholland 				NFSUNLOCKCLSTATE();
   3420      1.1  dholland 			} else if (recalltype == NFSLAYOUTRETURN_ALL) {
   3421      1.1  dholland 				gotone = 0;
   3422      1.1  dholland 				NFSLOCKCLSTATE();
   3423      1.1  dholland 				clp = nfscl_getclntsess(sessionid);
   3424      1.1  dholland 				if (clp != NULL) {
   3425      1.1  dholland 					TAILQ_FOREACH(lyp, &clp->nfsc_layout,
   3426      1.1  dholland 					    nfsly_list) {
   3427      1.1  dholland 						error = nfscl_layoutrecall(
   3428      1.1  dholland 						    recalltype, lyp, iomode, 0,
   3429      1.1  dholland 						    UINT64_MAX,
   3430      1.1  dholland 						    lyp->nfsly_stateid.seqid,
   3431      1.1  dholland 						    recallp);
   3432      1.1  dholland 						recallp = NULL;
   3433      1.1  dholland 						gotone = 1;
   3434      1.1  dholland 					}
   3435      1.1  dholland 					if (gotone != 0)
   3436      1.1  dholland 						wakeup(clp);
   3437      1.1  dholland 					else
   3438      1.1  dholland 						error = NFSERR_NOMATCHLAYOUT;
   3439      1.1  dholland 				} else
   3440      1.1  dholland 					error = NFSERR_NOMATCHLAYOUT;
   3441      1.1  dholland 				NFSUNLOCKCLSTATE();
   3442      1.1  dholland 			} else
   3443      1.1  dholland 				error = NFSERR_NOMATCHLAYOUT;
   3444      1.1  dholland 			if (recallp != NULL) {
   3445      1.1  dholland 				free(recallp, M_NFSLAYRECALL);
   3446      1.1  dholland 				recallp = NULL;
   3447      1.1  dholland 			}
   3448      1.1  dholland 			break;
   3449      1.1  dholland 		case NFSV4OP_CBSEQUENCE:
   3450      1.1  dholland 			NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID +
   3451      1.1  dholland 			    5 * NFSX_UNSIGNED);
   3452      1.1  dholland 			bcopy(tl, sessionid, NFSX_V4SESSIONID);
   3453      1.1  dholland 			tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
   3454      1.1  dholland 			seqid = fxdr_unsigned(uint32_t, *tl++);
   3455      1.1  dholland 			slotid = fxdr_unsigned(uint32_t, *tl++);
   3456      1.1  dholland 			highslot = fxdr_unsigned(uint32_t, *tl++);
   3457      1.1  dholland 			cachethis = *tl++;
   3458      1.1  dholland 			/* Throw away the referring call stuff. */
   3459      1.1  dholland 			clist = fxdr_unsigned(int, *tl);
   3460      1.1  dholland 			for (j = 0; j < clist; j++) {
   3461      1.1  dholland 				NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID +
   3462      1.1  dholland 				    NFSX_UNSIGNED);
   3463      1.1  dholland 				tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
   3464      1.1  dholland 				rcalls = fxdr_unsigned(int, *tl);
   3465      1.1  dholland 				for (k = 0; k < rcalls; k++) {
   3466      1.1  dholland 					NFSM_DISSECT(tl, uint32_t *,
   3467      1.1  dholland 					    2 * NFSX_UNSIGNED);
   3468      1.1  dholland 				}
   3469      1.1  dholland 			}
   3470      1.1  dholland 			NFSLOCKCLSTATE();
   3471      1.1  dholland 			if (i == 0) {
   3472      1.1  dholland 				clp = nfscl_getclntsess(sessionid);
   3473      1.1  dholland 				if (clp == NULL)
   3474      1.1  dholland 					error = NFSERR_SERVERFAULT;
   3475      1.1  dholland 			} else
   3476      1.1  dholland 				error = NFSERR_SEQUENCEPOS;
   3477      1.1  dholland 			if (error == 0)
   3478      1.1  dholland 				error = nfsv4_seqsession(seqid, slotid,
   3479      1.1  dholland 				    highslot,
   3480      1.1  dholland 				    NFSMNT_MDSSESSION(clp->nfsc_nmp)->
   3481      1.1  dholland 				    nfsess_cbslots, &rep,
   3482      1.1  dholland 				    NFSMNT_MDSSESSION(clp->nfsc_nmp)->
   3483      1.1  dholland 				    nfsess_backslots);
   3484      1.1  dholland 			NFSUNLOCKCLSTATE();
   3485      1.1  dholland 			if (error == 0) {
   3486      1.1  dholland 				gotseq_ok = 1;
   3487      1.1  dholland 				if (rep != NULL) {
   3488      1.1  dholland 					NFSCL_DEBUG(4, "Got cbretry\n");
   3489      1.1  dholland 					m_freem(nd->nd_mreq);
   3490      1.1  dholland 					nd->nd_mreq = rep;
   3491      1.1  dholland 					rep = NULL;
   3492      1.1  dholland 					goto out;
   3493      1.1  dholland 				}
   3494      1.1  dholland 				NFSM_BUILD(tl, uint32_t *,
   3495      1.1  dholland 				    NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
   3496      1.1  dholland 				bcopy(sessionid, tl, NFSX_V4SESSIONID);
   3497      1.1  dholland 				tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
   3498      1.1  dholland 				*tl++ = txdr_unsigned(seqid);
   3499      1.1  dholland 				*tl++ = txdr_unsigned(slotid);
   3500      1.1  dholland 				*tl++ = txdr_unsigned(NFSV4_CBSLOTS - 1);
   3501      1.1  dholland 				*tl = txdr_unsigned(NFSV4_CBSLOTS - 1);
   3502      1.1  dholland 			}
   3503      1.1  dholland 			break;
   3504      1.1  dholland 		default:
   3505      1.1  dholland 			if (i == 0 && minorvers == NFSV41_MINORVERSION)
   3506      1.1  dholland 				error = NFSERR_OPNOTINSESS;
   3507      1.1  dholland 			else {
   3508      1.1  dholland 				NFSCL_DEBUG(1, "unsupp callback %d\n", op);
   3509      1.1  dholland 				error = NFSERR_NOTSUPP;
   3510      1.1  dholland 			}
   3511      1.1  dholland 			break;
   3512  1.1.1.2  pgoyette 		}
   3513      1.1  dholland 		if (error) {
   3514      1.1  dholland 			if (error == EBADRPC || error == NFSERR_BADXDR) {
   3515      1.1  dholland 				nd->nd_repstat = NFSERR_BADXDR;
   3516      1.1  dholland 			} else {
   3517      1.1  dholland 				nd->nd_repstat = error;
   3518      1.1  dholland 			}
   3519      1.1  dholland 			error = 0;
   3520      1.1  dholland 		}
   3521      1.1  dholland 		retops++;
   3522      1.1  dholland 		if (nd->nd_repstat) {
   3523  1.1.1.2  pgoyette 			*repp = nfscl_errmap(nd, minorvers);
   3524      1.1  dholland 			break;
   3525      1.1  dholland 		} else
   3526      1.1  dholland 			*repp = 0;	/* NFS4_OK */
   3527      1.1  dholland 	}
   3528      1.1  dholland nfsmout:
   3529      1.1  dholland 	if (recallp != NULL)
   3530      1.1  dholland 		free(recallp, M_NFSLAYRECALL);
   3531      1.1  dholland 	if (error) {
   3532      1.1  dholland 		if (error == EBADRPC || error == NFSERR_BADXDR)
   3533      1.1  dholland 			nd->nd_repstat = NFSERR_BADXDR;
   3534      1.1  dholland 		else
   3535      1.1  dholland 			printf("nfsv4 comperr1=%d\n", error);
   3536      1.1  dholland 	}
   3537      1.1  dholland 	if (taglen == -1) {
   3538      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   3539      1.1  dholland 		*tl++ = 0;
   3540      1.1  dholland 		*tl = 0;
   3541      1.1  dholland 	} else {
   3542      1.1  dholland 		*retopsp = txdr_unsigned(retops);
   3543      1.1  dholland 	}
   3544  1.1.1.2  pgoyette 	*nd->nd_errp = nfscl_errmap(nd, minorvers);
   3545      1.1  dholland out:
   3546      1.1  dholland 	if (gotseq_ok != 0) {
   3547      1.1  dholland 		rep = m_copym(nd->nd_mreq, 0, M_COPYALL, M_WAITOK);
   3548      1.1  dholland 		NFSLOCKCLSTATE();
   3549      1.1  dholland 		clp = nfscl_getclntsess(sessionid);
   3550      1.1  dholland 		if (clp != NULL) {
   3551      1.1  dholland 			nfsv4_seqsess_cacherep(slotid,
   3552      1.1  dholland 			    NFSMNT_MDSSESSION(clp->nfsc_nmp)->nfsess_cbslots,
   3553  1.1.1.2  pgoyette 			    NFSERR_OK, &rep);
   3554      1.1  dholland 			NFSUNLOCKCLSTATE();
   3555      1.1  dholland 		} else {
   3556      1.1  dholland 			NFSUNLOCKCLSTATE();
   3557      1.1  dholland 			m_freem(rep);
   3558      1.1  dholland 		}
   3559      1.1  dholland 	}
   3560      1.1  dholland }
   3561      1.1  dholland 
   3562      1.1  dholland /*
   3563      1.1  dholland  * Generate the next cbident value. Basically just increment a static value
   3564      1.1  dholland  * and then check that it isn't already in the list, if it has wrapped around.
   3565      1.1  dholland  */
   3566      1.1  dholland static u_int32_t
   3567      1.1  dholland nfscl_nextcbident(void)
   3568      1.1  dholland {
   3569      1.1  dholland 	struct nfsclclient *clp;
   3570      1.1  dholland 	int matched;
   3571      1.1  dholland 	static u_int32_t nextcbident = 0;
   3572      1.1  dholland 	static int haswrapped = 0;
   3573      1.1  dholland 
   3574      1.1  dholland 	nextcbident++;
   3575      1.1  dholland 	if (nextcbident == 0)
   3576      1.1  dholland 		haswrapped = 1;
   3577      1.1  dholland 	if (haswrapped) {
   3578      1.1  dholland 		/*
   3579      1.1  dholland 		 * Search the clientid list for one already using this cbident.
   3580      1.1  dholland 		 */
   3581      1.1  dholland 		do {
   3582      1.1  dholland 			matched = 0;
   3583      1.1  dholland 			NFSLOCKCLSTATE();
   3584      1.1  dholland 			LIST_FOREACH(clp, &nfsclhead, nfsc_list) {
   3585      1.1  dholland 				if (clp->nfsc_cbident == nextcbident) {
   3586      1.1  dholland 					matched = 1;
   3587      1.1  dholland 					break;
   3588      1.1  dholland 				}
   3589      1.1  dholland 			}
   3590      1.1  dholland 			NFSUNLOCKCLSTATE();
   3591      1.1  dholland 			if (matched == 1)
   3592      1.1  dholland 				nextcbident++;
   3593      1.1  dholland 		} while (matched);
   3594      1.1  dholland 	}
   3595      1.1  dholland 	return (nextcbident);
   3596      1.1  dholland }
   3597      1.1  dholland 
   3598      1.1  dholland /*
   3599      1.1  dholland  * Get the mount point related to a given cbident or session and busy it.
   3600      1.1  dholland  */
   3601      1.1  dholland static mount_t
   3602      1.1  dholland nfscl_getmnt(int minorvers, uint8_t *sessionid, u_int32_t cbident,
   3603      1.1  dholland     struct nfsclclient **clpp)
   3604      1.1  dholland {
   3605      1.1  dholland 	struct nfsclclient *clp;
   3606      1.1  dholland 	mount_t mp;
   3607      1.1  dholland 	int error;
   3608      1.1  dholland 
   3609      1.1  dholland 	*clpp = NULL;
   3610      1.1  dholland 	NFSLOCKCLSTATE();
   3611      1.1  dholland 	LIST_FOREACH(clp, &nfsclhead, nfsc_list) {
   3612      1.1  dholland 		if (minorvers == NFSV4_MINORVERSION) {
   3613      1.1  dholland 			if (clp->nfsc_cbident == cbident)
   3614      1.1  dholland 				break;
   3615      1.1  dholland 		} else if (!NFSBCMP(NFSMNT_MDSSESSION(clp->nfsc_nmp)->
   3616      1.1  dholland 		    nfsess_sessionid, sessionid, NFSX_V4SESSIONID))
   3617      1.1  dholland 			break;
   3618      1.1  dholland 	}
   3619      1.1  dholland 	if (clp == NULL) {
   3620      1.1  dholland 		NFSUNLOCKCLSTATE();
   3621      1.1  dholland 		return (NULL);
   3622      1.1  dholland 	}
   3623      1.1  dholland 	mp = clp->nfsc_nmp->nm_mountp;
   3624      1.1  dholland 	vfs_ref(mp);
   3625      1.1  dholland 	NFSUNLOCKCLSTATE();
   3626      1.1  dholland 	error = vfs_busy(mp, 0);
   3627      1.1  dholland 	vfs_rel(mp);
   3628      1.1  dholland 	if (error != 0)
   3629      1.1  dholland 		return (NULL);
   3630      1.1  dholland 	*clpp = clp;
   3631      1.1  dholland 	return (mp);
   3632      1.1  dholland }
   3633      1.1  dholland 
   3634      1.1  dholland /*
   3635      1.1  dholland  * Get the clientid pointer related to a given cbident.
   3636      1.1  dholland  */
   3637      1.1  dholland static struct nfsclclient *
   3638      1.1  dholland nfscl_getclnt(u_int32_t cbident)
   3639      1.1  dholland {
   3640      1.1  dholland 	struct nfsclclient *clp;
   3641      1.1  dholland 
   3642      1.1  dholland 	LIST_FOREACH(clp, &nfsclhead, nfsc_list)
   3643      1.1  dholland 		if (clp->nfsc_cbident == cbident)
   3644      1.1  dholland 			break;
   3645      1.1  dholland 	return (clp);
   3646      1.1  dholland }
   3647      1.1  dholland 
   3648      1.1  dholland /*
   3649      1.1  dholland  * Get the clientid pointer related to a given sessionid.
   3650      1.1  dholland  */
   3651      1.1  dholland static struct nfsclclient *
   3652      1.1  dholland nfscl_getclntsess(uint8_t *sessionid)
   3653      1.1  dholland {
   3654      1.1  dholland 	struct nfsclclient *clp;
   3655      1.1  dholland 
   3656      1.1  dholland 	LIST_FOREACH(clp, &nfsclhead, nfsc_list)
   3657      1.1  dholland 		if (!NFSBCMP(NFSMNT_MDSSESSION(clp->nfsc_nmp)->nfsess_sessionid,
   3658      1.1  dholland 		    sessionid, NFSX_V4SESSIONID))
   3659      1.1  dholland 			break;
   3660      1.1  dholland 	return (clp);
   3661      1.1  dholland }
   3662      1.1  dholland 
   3663      1.1  dholland /*
   3664      1.1  dholland  * Search for a lock conflict locally on the client. A conflict occurs if
   3665      1.1  dholland  * - not same owner and overlapping byte range and at least one of them is
   3666      1.1  dholland  *   a write lock or this is an unlock.
   3667      1.1  dholland  */
   3668      1.1  dholland static int
   3669      1.1  dholland nfscl_localconflict(struct nfsclclient *clp, u_int8_t *fhp, int fhlen,
   3670      1.1  dholland     struct nfscllock *nlop, u_int8_t *own, struct nfscldeleg *dp,
   3671      1.1  dholland     struct nfscllock **lopp)
   3672      1.1  dholland {
   3673      1.1  dholland 	struct nfsclowner *owp;
   3674      1.1  dholland 	struct nfsclopen *op;
   3675      1.1  dholland 	int ret;
   3676      1.1  dholland 
   3677      1.1  dholland 	if (dp != NULL) {
   3678      1.1  dholland 		ret = nfscl_checkconflict(&dp->nfsdl_lock, nlop, own, lopp);
   3679      1.1  dholland 		if (ret)
   3680      1.1  dholland 			return (ret);
   3681      1.1  dholland 	}
   3682      1.1  dholland 	LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
   3683      1.1  dholland 		LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
   3684      1.1  dholland 			if (op->nfso_fhlen == fhlen &&
   3685      1.1  dholland 			    !NFSBCMP(op->nfso_fh, fhp, fhlen)) {
   3686      1.1  dholland 				ret = nfscl_checkconflict(&op->nfso_lock, nlop,
   3687      1.1  dholland 				    own, lopp);
   3688      1.1  dholland 				if (ret)
   3689      1.1  dholland 					return (ret);
   3690      1.1  dholland 			}
   3691      1.1  dholland 		}
   3692      1.1  dholland 	}
   3693      1.1  dholland 	return (0);
   3694      1.1  dholland }
   3695      1.1  dholland 
   3696      1.1  dholland static int
   3697      1.1  dholland nfscl_checkconflict(struct nfscllockownerhead *lhp, struct nfscllock *nlop,
   3698      1.1  dholland     u_int8_t *own, struct nfscllock **lopp)
   3699      1.1  dholland {
   3700      1.1  dholland 	struct nfscllockowner *lp;
   3701      1.1  dholland 	struct nfscllock *lop;
   3702      1.1  dholland 
   3703      1.1  dholland 	LIST_FOREACH(lp, lhp, nfsl_list) {
   3704      1.1  dholland 		if (NFSBCMP(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN)) {
   3705      1.1  dholland 			LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) {
   3706      1.1  dholland 				if (lop->nfslo_first >= nlop->nfslo_end)
   3707      1.1  dholland 					break;
   3708      1.1  dholland 				if (lop->nfslo_end <= nlop->nfslo_first)
   3709      1.1  dholland 					continue;
   3710      1.1  dholland 				if (lop->nfslo_type == F_WRLCK ||
   3711      1.1  dholland 				    nlop->nfslo_type == F_WRLCK ||
   3712      1.1  dholland 				    nlop->nfslo_type == F_UNLCK) {
   3713      1.1  dholland 					if (lopp != NULL)
   3714      1.1  dholland 						*lopp = lop;
   3715      1.1  dholland 					return (NFSERR_DENIED);
   3716      1.1  dholland 				}
   3717      1.1  dholland 			}
   3718      1.1  dholland 		}
   3719      1.1  dholland 	}
   3720      1.1  dholland 	return (0);
   3721      1.1  dholland }
   3722      1.1  dholland 
   3723      1.1  dholland /*
   3724      1.1  dholland  * Check for a local conflicting lock.
   3725      1.1  dholland  */
   3726      1.1  dholland APPLESTATIC int
   3727      1.1  dholland nfscl_lockt(vnode_t vp, struct nfsclclient *clp, u_int64_t off,
   3728      1.1  dholland     u_int64_t len, struct flock *fl, NFSPROC_T *p, void *id, int flags)
   3729      1.1  dholland {
   3730      1.1  dholland 	struct nfscllock *lop, nlck;
   3731      1.1  dholland 	struct nfscldeleg *dp;
   3732      1.1  dholland 	struct nfsnode *np;
   3733      1.1  dholland 	u_int8_t own[NFSV4CL_LOCKNAMELEN];
   3734      1.1  dholland 	int error;
   3735      1.1  dholland 
   3736      1.1  dholland 	nlck.nfslo_type = fl->l_type;
   3737      1.1  dholland 	nlck.nfslo_first = off;
   3738      1.1  dholland 	if (len == NFS64BITSSET) {
   3739      1.1  dholland 		nlck.nfslo_end = NFS64BITSSET;
   3740      1.1  dholland 	} else {
   3741      1.1  dholland 		nlck.nfslo_end = off + len;
   3742      1.1  dholland 		if (nlck.nfslo_end <= nlck.nfslo_first)
   3743      1.1  dholland 			return (NFSERR_INVAL);
   3744      1.1  dholland 	}
   3745      1.1  dholland 	np = VTONFS(vp);
   3746      1.1  dholland 	nfscl_filllockowner(id, own, flags);
   3747      1.1  dholland 	NFSLOCKCLSTATE();
   3748      1.1  dholland 	dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
   3749      1.1  dholland 	error = nfscl_localconflict(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
   3750      1.1  dholland 	    &nlck, own, dp, &lop);
   3751      1.1  dholland 	if (error != 0) {
   3752      1.1  dholland 		fl->l_whence = SEEK_SET;
   3753      1.1  dholland 		fl->l_start = lop->nfslo_first;
   3754      1.1  dholland 		if (lop->nfslo_end == NFS64BITSSET)
   3755      1.1  dholland 			fl->l_len = 0;
   3756      1.1  dholland 		else
   3757      1.1  dholland 			fl->l_len = lop->nfslo_end - lop->nfslo_first;
   3758      1.1  dholland 		fl->l_pid = (pid_t)0;
   3759      1.1  dholland 		fl->l_type = lop->nfslo_type;
   3760      1.1  dholland 		error = -1;			/* no RPC required */
   3761      1.1  dholland 	} else if (dp != NULL && ((dp->nfsdl_flags & NFSCLDL_WRITE) ||
   3762      1.1  dholland 	    fl->l_type == F_RDLCK)) {
   3763      1.1  dholland 		/*
   3764      1.1  dholland 		 * The delegation ensures that there isn't a conflicting
   3765      1.1  dholland 		 * lock on the server, so return -1 to indicate an RPC
   3766      1.1  dholland 		 * isn't required.
   3767      1.1  dholland 		 */
   3768      1.1  dholland 		fl->l_type = F_UNLCK;
   3769      1.1  dholland 		error = -1;
   3770      1.1  dholland 	}
   3771      1.1  dholland 	NFSUNLOCKCLSTATE();
   3772      1.1  dholland 	return (error);
   3773      1.1  dholland }
   3774      1.1  dholland 
   3775      1.1  dholland /*
   3776      1.1  dholland  * Handle Recall of a delegation.
   3777      1.1  dholland  * The clp must be exclusive locked when this is called.
   3778      1.1  dholland  */
   3779      1.1  dholland static int
   3780      1.1  dholland nfscl_recalldeleg(struct nfsclclient *clp, struct nfsmount *nmp,
   3781      1.1  dholland     struct nfscldeleg *dp, vnode_t vp, struct ucred *cred, NFSPROC_T *p,
   3782      1.1  dholland     int called_from_renewthread)
   3783      1.1  dholland {
   3784      1.1  dholland 	struct nfsclowner *owp, *lowp, *nowp;
   3785      1.1  dholland 	struct nfsclopen *op, *lop;
   3786      1.1  dholland 	struct nfscllockowner *lp;
   3787      1.1  dholland 	struct nfscllock *lckp;
   3788      1.1  dholland 	struct nfsnode *np;
   3789      1.1  dholland 	int error = 0, ret, gotvp = 0;
   3790      1.1  dholland 
   3791      1.1  dholland 	if (vp == NULL) {
   3792      1.1  dholland 		/*
   3793      1.1  dholland 		 * First, get a vnode for the file. This is needed to do RPCs.
   3794      1.1  dholland 		 */
   3795      1.1  dholland 		ret = nfscl_ngetreopen(nmp->nm_mountp, dp->nfsdl_fh,
   3796      1.1  dholland 		    dp->nfsdl_fhlen, p, &np);
   3797      1.1  dholland 		if (ret) {
   3798      1.1  dholland 			/*
   3799      1.1  dholland 			 * File isn't open, so nothing to move over to the
   3800      1.1  dholland 			 * server.
   3801      1.1  dholland 			 */
   3802      1.1  dholland 			return (0);
   3803      1.1  dholland 		}
   3804      1.1  dholland 		vp = NFSTOV(np);
   3805      1.1  dholland 		gotvp = 1;
   3806      1.1  dholland 	} else {
   3807      1.1  dholland 		np = VTONFS(vp);
   3808      1.1  dholland 	}
   3809      1.1  dholland 	dp->nfsdl_flags &= ~NFSCLDL_MODTIMESET;
   3810      1.1  dholland 
   3811      1.1  dholland 	/*
   3812      1.1  dholland 	 * Ok, if it's a write delegation, flush data to the server, so
   3813      1.1  dholland 	 * that close/open consistency is retained.
   3814      1.1  dholland 	 */
   3815      1.1  dholland 	ret = 0;
   3816      1.1  dholland 	NFSLOCKNODE(np);
   3817      1.1  dholland 	if ((dp->nfsdl_flags & NFSCLDL_WRITE) && (np->n_flag & NMODIFIED)) {
   3818      1.1  dholland 		np->n_flag |= NDELEGRECALL;
   3819      1.1  dholland 		NFSUNLOCKNODE(np);
   3820      1.1  dholland 		ret = ncl_flush(vp, MNT_WAIT, cred, p, 1,
   3821      1.1  dholland 		    called_from_renewthread);
   3822      1.1  dholland 		NFSLOCKNODE(np);
   3823      1.1  dholland 		np->n_flag &= ~NDELEGRECALL;
   3824      1.1  dholland 	}
   3825      1.1  dholland 	NFSINVALATTRCACHE(np);
   3826      1.1  dholland 	NFSUNLOCKNODE(np);
   3827      1.1  dholland 	if (ret == EIO && called_from_renewthread != 0) {
   3828      1.1  dholland 		/*
   3829      1.1  dholland 		 * If the flush failed with EIO for the renew thread,
   3830      1.1  dholland 		 * return now, so that the dirty buffer will be flushed
   3831      1.1  dholland 		 * later.
   3832      1.1  dholland 		 */
   3833      1.1  dholland 		if (gotvp != 0)
   3834      1.1  dholland 			vrele(vp);
   3835      1.1  dholland 		return (ret);
   3836      1.1  dholland 	}
   3837      1.1  dholland 
   3838      1.1  dholland 	/*
   3839      1.1  dholland 	 * Now, for each openowner with opens issued locally, move them
   3840      1.1  dholland 	 * over to state against the server.
   3841      1.1  dholland 	 */
   3842      1.1  dholland 	LIST_FOREACH(lowp, &dp->nfsdl_owner, nfsow_list) {
   3843      1.1  dholland 		lop = LIST_FIRST(&lowp->nfsow_open);
   3844      1.1  dholland 		if (lop != NULL) {
   3845      1.1  dholland 			if (LIST_NEXT(lop, nfso_list) != NULL)
   3846      1.1  dholland 				panic("nfsdlg mult opens");
   3847      1.1  dholland 			/*
   3848      1.1  dholland 			 * Look for the same openowner against the server.
   3849      1.1  dholland 			 */
   3850      1.1  dholland 			LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
   3851      1.1  dholland 				if (!NFSBCMP(lowp->nfsow_owner,
   3852      1.1  dholland 				    owp->nfsow_owner, NFSV4CL_LOCKNAMELEN)) {
   3853      1.1  dholland 					newnfs_copycred(&dp->nfsdl_cred, cred);
   3854      1.1  dholland 					ret = nfscl_moveopen(vp, clp, nmp, lop,
   3855      1.1  dholland 					    owp, dp, cred, p);
   3856      1.1  dholland 					if (ret == NFSERR_STALECLIENTID ||
   3857      1.1  dholland 					    ret == NFSERR_STALEDONTRECOVER ||
   3858      1.1  dholland 					    ret == NFSERR_BADSESSION) {
   3859      1.1  dholland 						if (gotvp)
   3860      1.1  dholland 							vrele(vp);
   3861      1.1  dholland 						return (ret);
   3862      1.1  dholland 					}
   3863      1.1  dholland 					if (ret) {
   3864      1.1  dholland 						nfscl_freeopen(lop, 1);
   3865      1.1  dholland 						if (!error)
   3866      1.1  dholland 							error = ret;
   3867      1.1  dholland 					}
   3868      1.1  dholland 					break;
   3869      1.1  dholland 				}
   3870      1.1  dholland 			}
   3871      1.1  dholland 
   3872      1.1  dholland 			/*
   3873      1.1  dholland 			 * If no openowner found, create one and get an open
   3874      1.1  dholland 			 * for it.
   3875      1.1  dholland 			 */
   3876      1.1  dholland 			if (owp == NULL) {
   3877      1.1  dholland 				MALLOC(nowp, struct nfsclowner *,
   3878      1.1  dholland 				    sizeof (struct nfsclowner), M_NFSCLOWNER,
   3879      1.1  dholland 				    M_WAITOK);
   3880      1.1  dholland 				nfscl_newopen(clp, NULL, &owp, &nowp, &op,
   3881      1.1  dholland 				    NULL, lowp->nfsow_owner, dp->nfsdl_fh,
   3882      1.1  dholland 				    dp->nfsdl_fhlen, NULL);
   3883      1.1  dholland 				newnfs_copycred(&dp->nfsdl_cred, cred);
   3884      1.1  dholland 				ret = nfscl_moveopen(vp, clp, nmp, lop,
   3885      1.1  dholland 				    owp, dp, cred, p);
   3886      1.1  dholland 				if (ret) {
   3887      1.1  dholland 					nfscl_freeopenowner(owp, 0);
   3888      1.1  dholland 					if (ret == NFSERR_STALECLIENTID ||
   3889      1.1  dholland 					    ret == NFSERR_STALEDONTRECOVER ||
   3890      1.1  dholland 					    ret == NFSERR_BADSESSION) {
   3891      1.1  dholland 						if (gotvp)
   3892      1.1  dholland 							vrele(vp);
   3893      1.1  dholland 						return (ret);
   3894      1.1  dholland 					}
   3895      1.1  dholland 					if (ret) {
   3896      1.1  dholland 						nfscl_freeopen(lop, 1);
   3897      1.1  dholland 						if (!error)
   3898      1.1  dholland 							error = ret;
   3899      1.1  dholland 					}
   3900      1.1  dholland 				}
   3901      1.1  dholland 			}
   3902      1.1  dholland 		}
   3903      1.1  dholland 	}
   3904      1.1  dholland 
   3905      1.1  dholland 	/*
   3906      1.1  dholland 	 * Now, get byte range locks for any locks done locally.
   3907      1.1  dholland 	 */
   3908      1.1  dholland 	LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) {
   3909      1.1  dholland 		LIST_FOREACH(lckp, &lp->nfsl_lock, nfslo_list) {
   3910      1.1  dholland 			newnfs_copycred(&dp->nfsdl_cred, cred);
   3911      1.1  dholland 			ret = nfscl_relock(vp, clp, nmp, lp, lckp, cred, p);
   3912      1.1  dholland 			if (ret == NFSERR_STALESTATEID ||
   3913      1.1  dholland 			    ret == NFSERR_STALEDONTRECOVER ||
   3914      1.1  dholland 			    ret == NFSERR_STALECLIENTID ||
   3915      1.1  dholland 			    ret == NFSERR_BADSESSION) {
   3916      1.1  dholland 				if (gotvp)
   3917      1.1  dholland 					vrele(vp);
   3918      1.1  dholland 				return (ret);
   3919      1.1  dholland 			}
   3920      1.1  dholland 			if (ret && !error)
   3921      1.1  dholland 				error = ret;
   3922      1.1  dholland 		}
   3923      1.1  dholland 	}
   3924      1.1  dholland 	if (gotvp)
   3925      1.1  dholland 		vrele(vp);
   3926      1.1  dholland 	return (error);
   3927      1.1  dholland }
   3928      1.1  dholland 
   3929      1.1  dholland /*
   3930      1.1  dholland  * Move a locally issued open over to an owner on the state list.
   3931      1.1  dholland  * SIDE EFFECT: If it needs to sleep (do an rpc), it unlocks clstate and
   3932      1.1  dholland  * returns with it unlocked.
   3933      1.1  dholland  */
   3934      1.1  dholland static int
   3935      1.1  dholland nfscl_moveopen(vnode_t vp, struct nfsclclient *clp, struct nfsmount *nmp,
   3936      1.1  dholland     struct nfsclopen *lop, struct nfsclowner *owp, struct nfscldeleg *dp,
   3937      1.1  dholland     struct ucred *cred, NFSPROC_T *p)
   3938      1.1  dholland {
   3939      1.1  dholland 	struct nfsclopen *op, *nop;
   3940      1.1  dholland 	struct nfscldeleg *ndp;
   3941      1.1  dholland 	struct nfsnode *np;
   3942      1.1  dholland 	int error = 0, newone;
   3943      1.1  dholland 
   3944      1.1  dholland 	/*
   3945      1.1  dholland 	 * First, look for an appropriate open, If found, just increment the
   3946      1.1  dholland 	 * opencnt in it.
   3947      1.1  dholland 	 */
   3948      1.1  dholland 	LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
   3949      1.1  dholland 		if ((op->nfso_mode & lop->nfso_mode) == lop->nfso_mode &&
   3950      1.1  dholland 		    op->nfso_fhlen == lop->nfso_fhlen &&
   3951      1.1  dholland 		    !NFSBCMP(op->nfso_fh, lop->nfso_fh, op->nfso_fhlen)) {
   3952      1.1  dholland 			op->nfso_opencnt += lop->nfso_opencnt;
   3953      1.1  dholland 			nfscl_freeopen(lop, 1);
   3954      1.1  dholland 			return (0);
   3955      1.1  dholland 		}
   3956      1.1  dholland 	}
   3957      1.1  dholland 
   3958      1.1  dholland 	/* No appropriate open, so we have to do one against the server. */
   3959      1.1  dholland 	np = VTONFS(vp);
   3960      1.1  dholland 	MALLOC(nop, struct nfsclopen *, sizeof (struct nfsclopen) +
   3961      1.1  dholland 	    lop->nfso_fhlen - 1, M_NFSCLOPEN, M_WAITOK);
   3962      1.1  dholland 	newone = 0;
   3963      1.1  dholland 	nfscl_newopen(clp, NULL, &owp, NULL, &op, &nop, owp->nfsow_owner,
   3964      1.1  dholland 	    lop->nfso_fh, lop->nfso_fhlen, &newone);
   3965      1.1  dholland 	ndp = dp;
   3966      1.1  dholland 	error = nfscl_tryopen(nmp, vp, np->n_v4->n4_data, np->n_v4->n4_fhlen,
   3967      1.1  dholland 	    lop->nfso_fh, lop->nfso_fhlen, lop->nfso_mode, op,
   3968      1.1  dholland 	    NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, &ndp, 0, 0, cred, p);
   3969      1.1  dholland 	if (error) {
   3970      1.1  dholland 		if (newone)
   3971      1.1  dholland 			nfscl_freeopen(op, 0);
   3972      1.1  dholland 	} else {
   3973      1.1  dholland 		if (newone)
   3974      1.1  dholland 			newnfs_copyincred(cred, &op->nfso_cred);
   3975      1.1  dholland 		op->nfso_mode |= lop->nfso_mode;
   3976      1.1  dholland 		op->nfso_opencnt += lop->nfso_opencnt;
   3977      1.1  dholland 		nfscl_freeopen(lop, 1);
   3978      1.1  dholland 	}
   3979      1.1  dholland 	if (nop != NULL)
   3980      1.1  dholland 		FREE((caddr_t)nop, M_NFSCLOPEN);
   3981      1.1  dholland 	if (ndp != NULL) {
   3982      1.1  dholland 		/*
   3983      1.1  dholland 		 * What should I do with the returned delegation, since the
   3984      1.1  dholland 		 * delegation is being recalled? For now, just printf and
   3985      1.1  dholland 		 * through it away.
   3986      1.1  dholland 		 */
   3987      1.1  dholland 		printf("Moveopen returned deleg\n");
   3988      1.1  dholland 		FREE((caddr_t)ndp, M_NFSCLDELEG);
   3989      1.1  dholland 	}
   3990      1.1  dholland 	return (error);
   3991      1.1  dholland }
   3992      1.1  dholland 
   3993      1.1  dholland /*
   3994      1.1  dholland  * Recall all delegations on this client.
   3995      1.1  dholland  */
   3996      1.1  dholland static void
   3997      1.1  dholland nfscl_totalrecall(struct nfsclclient *clp)
   3998      1.1  dholland {
   3999      1.1  dholland 	struct nfscldeleg *dp;
   4000      1.1  dholland 
   4001      1.1  dholland 	TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) {
   4002      1.1  dholland 		if ((dp->nfsdl_flags & NFSCLDL_DELEGRET) == 0)
   4003      1.1  dholland 			dp->nfsdl_flags |= NFSCLDL_RECALL;
   4004      1.1  dholland 	}
   4005      1.1  dholland }
   4006      1.1  dholland 
   4007      1.1  dholland /*
   4008      1.1  dholland  * Relock byte ranges. Called for delegation recall and state expiry.
   4009      1.1  dholland  */
   4010      1.1  dholland static int
   4011      1.1  dholland nfscl_relock(vnode_t vp, struct nfsclclient *clp, struct nfsmount *nmp,
   4012      1.1  dholland     struct nfscllockowner *lp, struct nfscllock *lop, struct ucred *cred,
   4013      1.1  dholland     NFSPROC_T *p)
   4014      1.1  dholland {
   4015      1.1  dholland 	struct nfscllockowner *nlp;
   4016      1.1  dholland 	struct nfsfh *nfhp;
   4017      1.1  dholland 	u_int64_t off, len;
   4018      1.1  dholland 	u_int32_t clidrev = 0;
   4019      1.1  dholland 	int error, newone, donelocally;
   4020      1.1  dholland 
   4021      1.1  dholland 	off = lop->nfslo_first;
   4022      1.1  dholland 	len = lop->nfslo_end - lop->nfslo_first;
   4023      1.1  dholland 	error = nfscl_getbytelock(vp, off, len, lop->nfslo_type, cred, p,
   4024      1.1  dholland 	    clp, 1, NULL, lp->nfsl_lockflags, lp->nfsl_owner,
   4025      1.1  dholland 	    lp->nfsl_openowner, &nlp, &newone, &donelocally);
   4026      1.1  dholland 	if (error || donelocally)
   4027      1.1  dholland 		return (error);
   4028      1.1  dholland 	if (nmp->nm_clp != NULL)
   4029      1.1  dholland 		clidrev = nmp->nm_clp->nfsc_clientidrev;
   4030      1.1  dholland 	else
   4031      1.1  dholland 		clidrev = 0;
   4032      1.1  dholland 	nfhp = VTONFS(vp)->n_fhp;
   4033      1.1  dholland 	error = nfscl_trylock(nmp, vp, nfhp->nfh_fh,
   4034      1.1  dholland 	    nfhp->nfh_len, nlp, newone, 0, off,
   4035      1.1  dholland 	    len, lop->nfslo_type, cred, p);
   4036      1.1  dholland 	if (error)
   4037      1.1  dholland 		nfscl_freelockowner(nlp, 0);
   4038      1.1  dholland 	return (error);
   4039      1.1  dholland }
   4040      1.1  dholland 
   4041      1.1  dholland /*
   4042      1.1  dholland  * Called to re-open a file. Basically get a vnode for the file handle
   4043      1.1  dholland  * and then call nfsrpc_openrpc() to do the rest.
   4044      1.1  dholland  */
   4045      1.1  dholland static int
   4046      1.1  dholland nfsrpc_reopen(struct nfsmount *nmp, u_int8_t *fhp, int fhlen,
   4047      1.1  dholland     u_int32_t mode, struct nfsclopen *op, struct nfscldeleg **dpp,
   4048      1.1  dholland     struct ucred *cred, NFSPROC_T *p)
   4049      1.1  dholland {
   4050      1.1  dholland 	struct nfsnode *np;
   4051      1.1  dholland 	vnode_t vp;
   4052      1.1  dholland 	int error;
   4053      1.1  dholland 
   4054      1.1  dholland 	error = nfscl_ngetreopen(nmp->nm_mountp, fhp, fhlen, p, &np);
   4055      1.1  dholland 	if (error)
   4056      1.1  dholland 		return (error);
   4057      1.1  dholland 	vp = NFSTOV(np);
   4058      1.1  dholland 	if (np->n_v4 != NULL) {
   4059      1.1  dholland 		error = nfscl_tryopen(nmp, vp, np->n_v4->n4_data,
   4060      1.1  dholland 		    np->n_v4->n4_fhlen, fhp, fhlen, mode, op,
   4061      1.1  dholland 		    NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, dpp, 0, 0,
   4062      1.1  dholland 		    cred, p);
   4063      1.1  dholland 	} else {
   4064      1.1  dholland 		error = EINVAL;
   4065      1.1  dholland 	}
   4066      1.1  dholland 	vrele(vp);
   4067      1.1  dholland 	return (error);
   4068      1.1  dholland }
   4069      1.1  dholland 
   4070      1.1  dholland /*
   4071      1.1  dholland  * Try an open against the server. Just call nfsrpc_openrpc(), retrying while
   4072      1.1  dholland  * NFSERR_DELAY. Also, try system credentials, if the passed in credentials
   4073      1.1  dholland  * fail.
   4074      1.1  dholland  */
   4075      1.1  dholland static int
   4076      1.1  dholland nfscl_tryopen(struct nfsmount *nmp, vnode_t vp, u_int8_t *fhp, int fhlen,
   4077      1.1  dholland     u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op,
   4078      1.1  dholland     u_int8_t *name, int namelen, struct nfscldeleg **ndpp,
   4079      1.1  dholland     int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p)
   4080      1.1  dholland {
   4081      1.1  dholland 	int error;
   4082      1.1  dholland 
   4083      1.1  dholland 	do {
   4084      1.1  dholland 		error = nfsrpc_openrpc(nmp, vp, fhp, fhlen, newfhp, newfhlen,
   4085      1.1  dholland 		    mode, op, name, namelen, ndpp, reclaim, delegtype, cred, p,
   4086      1.1  dholland 		    0, 0);
   4087      1.1  dholland 		if (error == NFSERR_DELAY)
   4088      1.1  dholland 			(void) nfs_catnap(PZERO, error, "nfstryop");
   4089      1.1  dholland 	} while (error == NFSERR_DELAY);
   4090      1.1  dholland 	if (error == EAUTH || error == EACCES) {
   4091      1.1  dholland 		/* Try again using system credentials */
   4092      1.1  dholland 		newnfs_setroot(cred);
   4093      1.1  dholland 		do {
   4094      1.1  dholland 		    error = nfsrpc_openrpc(nmp, vp, fhp, fhlen, newfhp,
   4095      1.1  dholland 			newfhlen, mode, op, name, namelen, ndpp, reclaim,
   4096      1.1  dholland 			delegtype, cred, p, 1, 0);
   4097      1.1  dholland 		    if (error == NFSERR_DELAY)
   4098      1.1  dholland 			(void) nfs_catnap(PZERO, error, "nfstryop");
   4099      1.1  dholland 		} while (error == NFSERR_DELAY);
   4100      1.1  dholland 	}
   4101      1.1  dholland 	return (error);
   4102      1.1  dholland }
   4103      1.1  dholland 
   4104      1.1  dholland /*
   4105      1.1  dholland  * Try a byte range lock. Just loop on nfsrpc_lock() while it returns
   4106      1.1  dholland  * NFSERR_DELAY. Also, retry with system credentials, if the provided
   4107      1.1  dholland  * cred don't work.
   4108      1.1  dholland  */
   4109      1.1  dholland static int
   4110      1.1  dholland nfscl_trylock(struct nfsmount *nmp, vnode_t vp, u_int8_t *fhp,
   4111      1.1  dholland     int fhlen, struct nfscllockowner *nlp, int newone, int reclaim,
   4112      1.1  dholland     u_int64_t off, u_int64_t len, short type, struct ucred *cred, NFSPROC_T *p)
   4113      1.1  dholland {
   4114      1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   4115      1.1  dholland 	int error;
   4116      1.1  dholland 
   4117      1.1  dholland 	do {
   4118      1.1  dholland 		error = nfsrpc_lock(nd, nmp, vp, fhp, fhlen, nlp, newone,
   4119      1.1  dholland 		    reclaim, off, len, type, cred, p, 0);
   4120      1.1  dholland 		if (!error && nd->nd_repstat == NFSERR_DELAY)
   4121      1.1  dholland 			(void) nfs_catnap(PZERO, (int)nd->nd_repstat,
   4122      1.1  dholland 			    "nfstrylck");
   4123      1.1  dholland 	} while (!error && nd->nd_repstat == NFSERR_DELAY);
   4124      1.1  dholland 	if (!error)
   4125      1.1  dholland 		error = nd->nd_repstat;
   4126      1.1  dholland 	if (error == EAUTH || error == EACCES) {
   4127      1.1  dholland 		/* Try again using root credentials */
   4128      1.1  dholland 		newnfs_setroot(cred);
   4129      1.1  dholland 		do {
   4130      1.1  dholland 			error = nfsrpc_lock(nd, nmp, vp, fhp, fhlen, nlp,
   4131      1.1  dholland 			    newone, reclaim, off, len, type, cred, p, 1);
   4132      1.1  dholland 			if (!error && nd->nd_repstat == NFSERR_DELAY)
   4133      1.1  dholland 				(void) nfs_catnap(PZERO, (int)nd->nd_repstat,
   4134      1.1  dholland 				    "nfstrylck");
   4135      1.1  dholland 		} while (!error && nd->nd_repstat == NFSERR_DELAY);
   4136      1.1  dholland 		if (!error)
   4137      1.1  dholland 			error = nd->nd_repstat;
   4138      1.1  dholland 	}
   4139      1.1  dholland 	return (error);
   4140      1.1  dholland }
   4141      1.1  dholland 
   4142      1.1  dholland /*
   4143      1.1  dholland  * Try a delegreturn against the server. Just call nfsrpc_delegreturn(),
   4144      1.1  dholland  * retrying while NFSERR_DELAY. Also, try system credentials, if the passed in
   4145      1.1  dholland  * credentials fail.
   4146      1.1  dholland  */
   4147      1.1  dholland static int
   4148      1.1  dholland nfscl_trydelegreturn(struct nfscldeleg *dp, struct ucred *cred,
   4149      1.1  dholland     struct nfsmount *nmp, NFSPROC_T *p)
   4150      1.1  dholland {
   4151      1.1  dholland 	int error;
   4152      1.1  dholland 
   4153      1.1  dholland 	do {
   4154      1.1  dholland 		error = nfsrpc_delegreturn(dp, cred, nmp, p, 0);
   4155      1.1  dholland 		if (error == NFSERR_DELAY)
   4156      1.1  dholland 			(void) nfs_catnap(PZERO, error, "nfstrydp");
   4157      1.1  dholland 	} while (error == NFSERR_DELAY);
   4158      1.1  dholland 	if (error == EAUTH || error == EACCES) {
   4159      1.1  dholland 		/* Try again using system credentials */
   4160      1.1  dholland 		newnfs_setroot(cred);
   4161      1.1  dholland 		do {
   4162      1.1  dholland 			error = nfsrpc_delegreturn(dp, cred, nmp, p, 1);
   4163      1.1  dholland 			if (error == NFSERR_DELAY)
   4164      1.1  dholland 				(void) nfs_catnap(PZERO, error, "nfstrydp");
   4165      1.1  dholland 		} while (error == NFSERR_DELAY);
   4166      1.1  dholland 	}
   4167      1.1  dholland 	return (error);
   4168      1.1  dholland }
   4169      1.1  dholland 
   4170      1.1  dholland /*
   4171      1.1  dholland  * Try a close against the server. Just call nfsrpc_closerpc(),
   4172      1.1  dholland  * retrying while NFSERR_DELAY. Also, try system credentials, if the passed in
   4173      1.1  dholland  * credentials fail.
   4174      1.1  dholland  */
   4175      1.1  dholland APPLESTATIC int
   4176      1.1  dholland nfscl_tryclose(struct nfsclopen *op, struct ucred *cred,
   4177      1.1  dholland     struct nfsmount *nmp, NFSPROC_T *p)
   4178      1.1  dholland {
   4179      1.1  dholland 	struct nfsrv_descript nfsd, *nd = &nfsd;
   4180      1.1  dholland 	int error;
   4181      1.1  dholland 
   4182      1.1  dholland 	do {
   4183      1.1  dholland 		error = nfsrpc_closerpc(nd, nmp, op, cred, p, 0);
   4184      1.1  dholland 		if (error == NFSERR_DELAY)
   4185      1.1  dholland 			(void) nfs_catnap(PZERO, error, "nfstrycl");
   4186      1.1  dholland 	} while (error == NFSERR_DELAY);
   4187      1.1  dholland 	if (error == EAUTH || error == EACCES) {
   4188      1.1  dholland 		/* Try again using system credentials */
   4189      1.1  dholland 		newnfs_setroot(cred);
   4190      1.1  dholland 		do {
   4191      1.1  dholland 			error = nfsrpc_closerpc(nd, nmp, op, cred, p, 1);
   4192      1.1  dholland 			if (error == NFSERR_DELAY)
   4193      1.1  dholland 				(void) nfs_catnap(PZERO, error, "nfstrycl");
   4194      1.1  dholland 		} while (error == NFSERR_DELAY);
   4195      1.1  dholland 	}
   4196      1.1  dholland 	return (error);
   4197      1.1  dholland }
   4198      1.1  dholland 
   4199      1.1  dholland /*
   4200      1.1  dholland  * Decide if a delegation on a file permits close without flushing writes
   4201      1.1  dholland  * to the server. This might be a big performance win in some environments.
   4202      1.1  dholland  * (Not useful until the client does caching on local stable storage.)
   4203      1.1  dholland  */
   4204      1.1  dholland APPLESTATIC int
   4205      1.1  dholland nfscl_mustflush(vnode_t vp)
   4206      1.1  dholland {
   4207      1.1  dholland 	struct nfsclclient *clp;
   4208      1.1  dholland 	struct nfscldeleg *dp;
   4209      1.1  dholland 	struct nfsnode *np;
   4210      1.1  dholland 	struct nfsmount *nmp;
   4211      1.1  dholland 
   4212      1.1  dholland 	np = VTONFS(vp);
   4213      1.1  dholland 	nmp = VFSTONFS(vnode_mount(vp));
   4214      1.1  dholland 	if (!NFSHASNFSV4(nmp))
   4215      1.1  dholland 		return (1);
   4216      1.1  dholland 	NFSLOCKCLSTATE();
   4217      1.1  dholland 	clp = nfscl_findcl(nmp);
   4218      1.1  dholland 	if (clp == NULL) {
   4219      1.1  dholland 		NFSUNLOCKCLSTATE();
   4220      1.1  dholland 		return (1);
   4221      1.1  dholland 	}
   4222      1.1  dholland 	dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
   4223      1.1  dholland 	if (dp != NULL && (dp->nfsdl_flags &
   4224      1.1  dholland 	    (NFSCLDL_WRITE | NFSCLDL_RECALL | NFSCLDL_DELEGRET)) ==
   4225      1.1  dholland 	     NFSCLDL_WRITE &&
   4226      1.1  dholland 	    (dp->nfsdl_sizelimit >= np->n_size ||
   4227      1.1  dholland 	     !NFSHASSTRICT3530(nmp))) {
   4228      1.1  dholland 		NFSUNLOCKCLSTATE();
   4229      1.1  dholland 		return (0);
   4230      1.1  dholland 	}
   4231      1.1  dholland 	NFSUNLOCKCLSTATE();
   4232      1.1  dholland 	return (1);
   4233      1.1  dholland }
   4234      1.1  dholland 
   4235      1.1  dholland /*
   4236      1.1  dholland  * See if a (write) delegation exists for this file.
   4237      1.1  dholland  */
   4238      1.1  dholland APPLESTATIC int
   4239      1.1  dholland nfscl_nodeleg(vnode_t vp, int writedeleg)
   4240      1.1  dholland {
   4241      1.1  dholland 	struct nfsclclient *clp;
   4242      1.1  dholland 	struct nfscldeleg *dp;
   4243      1.1  dholland 	struct nfsnode *np;
   4244      1.1  dholland 	struct nfsmount *nmp;
   4245      1.1  dholland 
   4246      1.1  dholland 	np = VTONFS(vp);
   4247      1.1  dholland 	nmp = VFSTONFS(vnode_mount(vp));
   4248      1.1  dholland 	if (!NFSHASNFSV4(nmp))
   4249      1.1  dholland 		return (1);
   4250      1.1  dholland 	NFSLOCKCLSTATE();
   4251      1.1  dholland 	clp = nfscl_findcl(nmp);
   4252      1.1  dholland 	if (clp == NULL) {
   4253      1.1  dholland 		NFSUNLOCKCLSTATE();
   4254      1.1  dholland 		return (1);
   4255      1.1  dholland 	}
   4256      1.1  dholland 	dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
   4257      1.1  dholland 	if (dp != NULL &&
   4258      1.1  dholland 	    (dp->nfsdl_flags & (NFSCLDL_RECALL | NFSCLDL_DELEGRET)) == 0 &&
   4259      1.1  dholland 	    (writedeleg == 0 || (dp->nfsdl_flags & NFSCLDL_WRITE) ==
   4260      1.1  dholland 	     NFSCLDL_WRITE)) {
   4261      1.1  dholland 		NFSUNLOCKCLSTATE();
   4262      1.1  dholland 		return (0);
   4263      1.1  dholland 	}
   4264      1.1  dholland 	NFSUNLOCKCLSTATE();
   4265      1.1  dholland 	return (1);
   4266      1.1  dholland }
   4267      1.1  dholland 
   4268      1.1  dholland /*
   4269      1.1  dholland  * Look for an associated delegation that should be DelegReturned.
   4270      1.1  dholland  */
   4271      1.1  dholland APPLESTATIC int
   4272      1.1  dholland nfscl_removedeleg(vnode_t vp, NFSPROC_T *p, nfsv4stateid_t *stp)
   4273      1.1  dholland {
   4274      1.1  dholland 	struct nfsclclient *clp;
   4275      1.1  dholland 	struct nfscldeleg *dp;
   4276      1.1  dholland 	struct nfsclowner *owp;
   4277      1.1  dholland 	struct nfscllockowner *lp;
   4278      1.1  dholland 	struct nfsmount *nmp;
   4279      1.1  dholland 	struct ucred *cred;
   4280      1.1  dholland 	struct nfsnode *np;
   4281      1.1  dholland 	int igotlock = 0, triedrecall = 0, needsrecall, retcnt = 0, islept;
   4282      1.1  dholland 
   4283      1.1  dholland 	nmp = VFSTONFS(vnode_mount(vp));
   4284      1.1  dholland 	np = VTONFS(vp);
   4285      1.1  dholland 	NFSLOCKCLSTATE();
   4286      1.1  dholland 	/*
   4287      1.1  dholland 	 * Loop around waiting for:
   4288      1.1  dholland 	 * - outstanding I/O operations on delegations to complete
   4289      1.1  dholland 	 * - for a delegation on vp that has state, lock the client and
   4290      1.1  dholland 	 *   do a recall
   4291      1.1  dholland 	 * - return delegation with no state
   4292      1.1  dholland 	 */
   4293      1.1  dholland 	while (1) {
   4294      1.1  dholland 		clp = nfscl_findcl(nmp);
   4295      1.1  dholland 		if (clp == NULL) {
   4296      1.1  dholland 			NFSUNLOCKCLSTATE();
   4297      1.1  dholland 			return (retcnt);
   4298      1.1  dholland 		}
   4299      1.1  dholland 		dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh,
   4300      1.1  dholland 		    np->n_fhp->nfh_len);
   4301      1.1  dholland 		if (dp != NULL) {
   4302      1.1  dholland 		    /*
   4303      1.1  dholland 		     * Wait for outstanding I/O ops to be done.
   4304      1.1  dholland 		     */
   4305      1.1  dholland 		    if (dp->nfsdl_rwlock.nfslock_usecnt > 0) {
   4306      1.1  dholland 			if (igotlock) {
   4307      1.1  dholland 			    nfsv4_unlock(&clp->nfsc_lock, 0);
   4308      1.1  dholland 			    igotlock = 0;
   4309      1.1  dholland 			}
   4310      1.1  dholland 			dp->nfsdl_rwlock.nfslock_lock |= NFSV4LOCK_WANTED;
   4311      1.1  dholland 			(void) nfsmsleep(&dp->nfsdl_rwlock,
   4312      1.1  dholland 			    NFSCLSTATEMUTEXPTR, PZERO, "nfscld", NULL);
   4313      1.1  dholland 			continue;
   4314      1.1  dholland 		    }
   4315      1.1  dholland 		    needsrecall = 0;
   4316      1.1  dholland 		    LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) {
   4317      1.1  dholland 			if (!LIST_EMPTY(&owp->nfsow_open)) {
   4318      1.1  dholland 			    needsrecall = 1;
   4319      1.1  dholland 			    break;
   4320      1.1  dholland 			}
   4321      1.1  dholland 		    }
   4322      1.1  dholland 		    if (!needsrecall) {
   4323      1.1  dholland 			LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) {
   4324      1.1  dholland 			    if (!LIST_EMPTY(&lp->nfsl_lock)) {
   4325      1.1  dholland 				needsrecall = 1;
   4326      1.1  dholland 				break;
   4327      1.1  dholland 			    }
   4328      1.1  dholland 			}
   4329      1.1  dholland 		    }
   4330      1.1  dholland 		    if (needsrecall && !triedrecall) {
   4331      1.1  dholland 			dp->nfsdl_flags |= NFSCLDL_DELEGRET;
   4332      1.1  dholland 			islept = 0;
   4333      1.1  dholland 			while (!igotlock) {
   4334      1.1  dholland 			    igotlock = nfsv4_lock(&clp->nfsc_lock, 1,
   4335      1.1  dholland 				&islept, NFSCLSTATEMUTEXPTR, NULL);
   4336      1.1  dholland 			    if (islept)
   4337      1.1  dholland 				break;
   4338      1.1  dholland 			}
   4339      1.1  dholland 			if (islept)
   4340      1.1  dholland 			    continue;
   4341      1.1  dholland 			NFSUNLOCKCLSTATE();
   4342      1.1  dholland 			cred = newnfs_getcred();
   4343      1.1  dholland 			newnfs_copycred(&dp->nfsdl_cred, cred);
   4344      1.1  dholland 			(void) nfscl_recalldeleg(clp, nmp, dp, vp, cred, p, 0);
   4345      1.1  dholland 			NFSFREECRED(cred);
   4346      1.1  dholland 			triedrecall = 1;
   4347      1.1  dholland 			NFSLOCKCLSTATE();
   4348      1.1  dholland 			nfsv4_unlock(&clp->nfsc_lock, 0);
   4349      1.1  dholland 			igotlock = 0;
   4350      1.1  dholland 			continue;
   4351      1.1  dholland 		    }
   4352      1.1  dholland 		    *stp = dp->nfsdl_stateid;
   4353      1.1  dholland 		    retcnt = 1;
   4354      1.1  dholland 		    nfscl_cleandeleg(dp);
   4355      1.1  dholland 		    nfscl_freedeleg(&clp->nfsc_deleg, dp);
   4356      1.1  dholland 		}
   4357      1.1  dholland 		if (igotlock)
   4358      1.1  dholland 		    nfsv4_unlock(&clp->nfsc_lock, 0);
   4359      1.1  dholland 		NFSUNLOCKCLSTATE();
   4360      1.1  dholland 		return (retcnt);
   4361      1.1  dholland 	}
   4362      1.1  dholland }
   4363      1.1  dholland 
   4364      1.1  dholland /*
   4365      1.1  dholland  * Look for associated delegation(s) that should be DelegReturned.
   4366      1.1  dholland  */
   4367      1.1  dholland APPLESTATIC int
   4368      1.1  dholland nfscl_renamedeleg(vnode_t fvp, nfsv4stateid_t *fstp, int *gotfdp, vnode_t tvp,
   4369      1.1  dholland     nfsv4stateid_t *tstp, int *gottdp, NFSPROC_T *p)
   4370      1.1  dholland {
   4371      1.1  dholland 	struct nfsclclient *clp;
   4372      1.1  dholland 	struct nfscldeleg *dp;
   4373      1.1  dholland 	struct nfsclowner *owp;
   4374      1.1  dholland 	struct nfscllockowner *lp;
   4375      1.1  dholland 	struct nfsmount *nmp;
   4376      1.1  dholland 	struct ucred *cred;
   4377      1.1  dholland 	struct nfsnode *np;
   4378      1.1  dholland 	int igotlock = 0, triedrecall = 0, needsrecall, retcnt = 0, islept;
   4379      1.1  dholland 
   4380      1.1  dholland 	nmp = VFSTONFS(vnode_mount(fvp));
   4381      1.1  dholland 	*gotfdp = 0;
   4382      1.1  dholland 	*gottdp = 0;
   4383      1.1  dholland 	NFSLOCKCLSTATE();
   4384      1.1  dholland 	/*
   4385      1.1  dholland 	 * Loop around waiting for:
   4386      1.1  dholland 	 * - outstanding I/O operations on delegations to complete
   4387      1.1  dholland 	 * - for a delegation on fvp that has state, lock the client and
   4388      1.1  dholland 	 *   do a recall
   4389      1.1  dholland 	 * - return delegation(s) with no state.
   4390      1.1  dholland 	 */
   4391      1.1  dholland 	while (1) {
   4392      1.1  dholland 		clp = nfscl_findcl(nmp);
   4393      1.1  dholland 		if (clp == NULL) {
   4394      1.1  dholland 			NFSUNLOCKCLSTATE();
   4395      1.1  dholland 			return (retcnt);
   4396      1.1  dholland 		}
   4397      1.1  dholland 		np = VTONFS(fvp);
   4398      1.1  dholland 		dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh,
   4399      1.1  dholland 		    np->n_fhp->nfh_len);
   4400      1.1  dholland 		if (dp != NULL && *gotfdp == 0) {
   4401      1.1  dholland 		    /*
   4402      1.1  dholland 		     * Wait for outstanding I/O ops to be done.
   4403      1.1  dholland 		     */
   4404      1.1  dholland 		    if (dp->nfsdl_rwlock.nfslock_usecnt > 0) {
   4405      1.1  dholland 			if (igotlock) {
   4406      1.1  dholland 			    nfsv4_unlock(&clp->nfsc_lock, 0);
   4407      1.1  dholland 			    igotlock = 0;
   4408      1.1  dholland 			}
   4409      1.1  dholland 			dp->nfsdl_rwlock.nfslock_lock |= NFSV4LOCK_WANTED;
   4410      1.1  dholland 			(void) nfsmsleep(&dp->nfsdl_rwlock,
   4411      1.1  dholland 			    NFSCLSTATEMUTEXPTR, PZERO, "nfscld", NULL);
   4412      1.1  dholland 			continue;
   4413      1.1  dholland 		    }
   4414      1.1  dholland 		    needsrecall = 0;
   4415      1.1  dholland 		    LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) {
   4416      1.1  dholland 			if (!LIST_EMPTY(&owp->nfsow_open)) {
   4417      1.1  dholland 			    needsrecall = 1;
   4418      1.1  dholland 			    break;
   4419      1.1  dholland 			}
   4420      1.1  dholland 		    }
   4421      1.1  dholland 		    if (!needsrecall) {
   4422      1.1  dholland 			LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) {
   4423      1.1  dholland 			    if (!LIST_EMPTY(&lp->nfsl_lock)) {
   4424      1.1  dholland 				needsrecall = 1;
   4425      1.1  dholland 				break;
   4426      1.1  dholland 			    }
   4427      1.1  dholland 			}
   4428      1.1  dholland 		    }
   4429      1.1  dholland 		    if (needsrecall && !triedrecall) {
   4430      1.1  dholland 			dp->nfsdl_flags |= NFSCLDL_DELEGRET;
   4431      1.1  dholland 			islept = 0;
   4432      1.1  dholland 			while (!igotlock) {
   4433      1.1  dholland 			    igotlock = nfsv4_lock(&clp->nfsc_lock, 1,
   4434      1.1  dholland 				&islept, NFSCLSTATEMUTEXPTR, NULL);
   4435      1.1  dholland 			    if (islept)
   4436      1.1  dholland 				break;
   4437      1.1  dholland 			}
   4438      1.1  dholland 			if (islept)
   4439      1.1  dholland 			    continue;
   4440      1.1  dholland 			NFSUNLOCKCLSTATE();
   4441      1.1  dholland 			cred = newnfs_getcred();
   4442      1.1  dholland 			newnfs_copycred(&dp->nfsdl_cred, cred);
   4443      1.1  dholland 			(void) nfscl_recalldeleg(clp, nmp, dp, fvp, cred, p, 0);
   4444      1.1  dholland 			NFSFREECRED(cred);
   4445      1.1  dholland 			triedrecall = 1;
   4446      1.1  dholland 			NFSLOCKCLSTATE();
   4447      1.1  dholland 			nfsv4_unlock(&clp->nfsc_lock, 0);
   4448      1.1  dholland 			igotlock = 0;
   4449      1.1  dholland 			continue;
   4450      1.1  dholland 		    }
   4451      1.1  dholland 		    *fstp = dp->nfsdl_stateid;
   4452      1.1  dholland 		    retcnt++;
   4453      1.1  dholland 		    *gotfdp = 1;
   4454      1.1  dholland 		    nfscl_cleandeleg(dp);
   4455      1.1  dholland 		    nfscl_freedeleg(&clp->nfsc_deleg, dp);
   4456      1.1  dholland 		}
   4457      1.1  dholland 		if (igotlock) {
   4458      1.1  dholland 		    nfsv4_unlock(&clp->nfsc_lock, 0);
   4459      1.1  dholland 		    igotlock = 0;
   4460      1.1  dholland 		}
   4461      1.1  dholland 		if (tvp != NULL) {
   4462      1.1  dholland 		    np = VTONFS(tvp);
   4463      1.1  dholland 		    dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh,
   4464      1.1  dholland 			np->n_fhp->nfh_len);
   4465      1.1  dholland 		    if (dp != NULL && *gottdp == 0) {
   4466      1.1  dholland 			/*
   4467      1.1  dholland 			 * Wait for outstanding I/O ops to be done.
   4468      1.1  dholland 			 */
   4469      1.1  dholland 			if (dp->nfsdl_rwlock.nfslock_usecnt > 0) {
   4470      1.1  dholland 			    dp->nfsdl_rwlock.nfslock_lock |= NFSV4LOCK_WANTED;
   4471      1.1  dholland 			    (void) nfsmsleep(&dp->nfsdl_rwlock,
   4472      1.1  dholland 				NFSCLSTATEMUTEXPTR, PZERO, "nfscld", NULL);
   4473      1.1  dholland 			    continue;
   4474      1.1  dholland 			}
   4475      1.1  dholland 			LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) {
   4476      1.1  dholland 			    if (!LIST_EMPTY(&owp->nfsow_open)) {
   4477      1.1  dholland 				NFSUNLOCKCLSTATE();
   4478      1.1  dholland 				return (retcnt);
   4479      1.1  dholland 			    }
   4480      1.1  dholland 			}
   4481      1.1  dholland 			LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) {
   4482      1.1  dholland 			    if (!LIST_EMPTY(&lp->nfsl_lock)) {
   4483      1.1  dholland 				NFSUNLOCKCLSTATE();
   4484      1.1  dholland 				return (retcnt);
   4485      1.1  dholland 			    }
   4486      1.1  dholland 			}
   4487      1.1  dholland 			*tstp = dp->nfsdl_stateid;
   4488      1.1  dholland 			retcnt++;
   4489      1.1  dholland 			*gottdp = 1;
   4490      1.1  dholland 			nfscl_cleandeleg(dp);
   4491      1.1  dholland 			nfscl_freedeleg(&clp->nfsc_deleg, dp);
   4492      1.1  dholland 		    }
   4493      1.1  dholland 		}
   4494      1.1  dholland 		NFSUNLOCKCLSTATE();
   4495      1.1  dholland 		return (retcnt);
   4496      1.1  dholland 	}
   4497      1.1  dholland }
   4498      1.1  dholland 
   4499      1.1  dholland /*
   4500      1.1  dholland  * Get a reference on the clientid associated with the mount point.
   4501      1.1  dholland  * Return 1 if success, 0 otherwise.
   4502      1.1  dholland  */
   4503      1.1  dholland APPLESTATIC int
   4504      1.1  dholland nfscl_getref(struct nfsmount *nmp)
   4505      1.1  dholland {
   4506      1.1  dholland 	struct nfsclclient *clp;
   4507      1.1  dholland 
   4508      1.1  dholland 	NFSLOCKCLSTATE();
   4509      1.1  dholland 	clp = nfscl_findcl(nmp);
   4510      1.1  dholland 	if (clp == NULL) {
   4511      1.1  dholland 		NFSUNLOCKCLSTATE();
   4512      1.1  dholland 		return (0);
   4513      1.1  dholland 	}
   4514      1.1  dholland 	nfsv4_getref(&clp->nfsc_lock, NULL, NFSCLSTATEMUTEXPTR, NULL);
   4515      1.1  dholland 	NFSUNLOCKCLSTATE();
   4516      1.1  dholland 	return (1);
   4517      1.1  dholland }
   4518      1.1  dholland 
   4519      1.1  dholland /*
   4520      1.1  dholland  * Release a reference on a clientid acquired with the above call.
   4521      1.1  dholland  */
   4522      1.1  dholland APPLESTATIC void
   4523      1.1  dholland nfscl_relref(struct nfsmount *nmp)
   4524      1.1  dholland {
   4525      1.1  dholland 	struct nfsclclient *clp;
   4526      1.1  dholland 
   4527      1.1  dholland 	NFSLOCKCLSTATE();
   4528      1.1  dholland 	clp = nfscl_findcl(nmp);
   4529      1.1  dholland 	if (clp == NULL) {
   4530      1.1  dholland 		NFSUNLOCKCLSTATE();
   4531      1.1  dholland 		return;
   4532      1.1  dholland 	}
   4533      1.1  dholland 	nfsv4_relref(&clp->nfsc_lock);
   4534      1.1  dholland 	NFSUNLOCKCLSTATE();
   4535      1.1  dholland }
   4536      1.1  dholland 
   4537      1.1  dholland /*
   4538      1.1  dholland  * Save the size attribute in the delegation, since the nfsnode
   4539      1.1  dholland  * is going away.
   4540      1.1  dholland  */
   4541      1.1  dholland APPLESTATIC void
   4542      1.1  dholland nfscl_reclaimnode(vnode_t vp)
   4543      1.1  dholland {
   4544      1.1  dholland 	struct nfsclclient *clp;
   4545      1.1  dholland 	struct nfscldeleg *dp;
   4546      1.1  dholland 	struct nfsnode *np = VTONFS(vp);
   4547      1.1  dholland 	struct nfsmount *nmp;
   4548      1.1  dholland 
   4549      1.1  dholland 	nmp = VFSTONFS(vnode_mount(vp));
   4550      1.1  dholland 	if (!NFSHASNFSV4(nmp))
   4551      1.1  dholland 		return;
   4552      1.1  dholland 	NFSLOCKCLSTATE();
   4553      1.1  dholland 	clp = nfscl_findcl(nmp);
   4554      1.1  dholland 	if (clp == NULL) {
   4555      1.1  dholland 		NFSUNLOCKCLSTATE();
   4556      1.1  dholland 		return;
   4557      1.1  dholland 	}
   4558      1.1  dholland 	dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
   4559      1.1  dholland 	if (dp != NULL && (dp->nfsdl_flags & NFSCLDL_WRITE))
   4560      1.1  dholland 		dp->nfsdl_size = np->n_size;
   4561      1.1  dholland 	NFSUNLOCKCLSTATE();
   4562      1.1  dholland }
   4563      1.1  dholland 
   4564      1.1  dholland /*
   4565      1.1  dholland  * Get the saved size attribute in the delegation, since it is a
   4566      1.1  dholland  * newly allocated nfsnode.
   4567      1.1  dholland  */
   4568      1.1  dholland APPLESTATIC void
   4569      1.1  dholland nfscl_newnode(vnode_t vp)
   4570      1.1  dholland {
   4571      1.1  dholland 	struct nfsclclient *clp;
   4572      1.1  dholland 	struct nfscldeleg *dp;
   4573      1.1  dholland 	struct nfsnode *np = VTONFS(vp);
   4574      1.1  dholland 	struct nfsmount *nmp;
   4575      1.1  dholland 
   4576      1.1  dholland 	nmp = VFSTONFS(vnode_mount(vp));
   4577      1.1  dholland 	if (!NFSHASNFSV4(nmp))
   4578      1.1  dholland 		return;
   4579      1.1  dholland 	NFSLOCKCLSTATE();
   4580      1.1  dholland 	clp = nfscl_findcl(nmp);
   4581      1.1  dholland 	if (clp == NULL) {
   4582      1.1  dholland 		NFSUNLOCKCLSTATE();
   4583      1.1  dholland 		return;
   4584      1.1  dholland 	}
   4585      1.1  dholland 	dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
   4586      1.1  dholland 	if (dp != NULL && (dp->nfsdl_flags & NFSCLDL_WRITE))
   4587      1.1  dholland 		np->n_size = dp->nfsdl_size;
   4588      1.1  dholland 	NFSUNLOCKCLSTATE();
   4589      1.1  dholland }
   4590      1.1  dholland 
   4591      1.1  dholland /*
   4592      1.1  dholland  * If there is a valid write delegation for this file, set the modtime
   4593      1.1  dholland  * to the local clock time.
   4594      1.1  dholland  */
   4595      1.1  dholland APPLESTATIC void
   4596      1.1  dholland nfscl_delegmodtime(vnode_t vp)
   4597      1.1  dholland {
   4598      1.1  dholland 	struct nfsclclient *clp;
   4599      1.1  dholland 	struct nfscldeleg *dp;
   4600      1.1  dholland 	struct nfsnode *np = VTONFS(vp);
   4601      1.1  dholland 	struct nfsmount *nmp;
   4602      1.1  dholland 
   4603      1.1  dholland 	nmp = VFSTONFS(vnode_mount(vp));
   4604      1.1  dholland 	if (!NFSHASNFSV4(nmp))
   4605      1.1  dholland 		return;
   4606      1.1  dholland 	NFSLOCKCLSTATE();
   4607      1.1  dholland 	clp = nfscl_findcl(nmp);
   4608      1.1  dholland 	if (clp == NULL) {
   4609      1.1  dholland 		NFSUNLOCKCLSTATE();
   4610      1.1  dholland 		return;
   4611      1.1  dholland 	}
   4612      1.1  dholland 	dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
   4613      1.1  dholland 	if (dp != NULL && (dp->nfsdl_flags & NFSCLDL_WRITE)) {
   4614      1.1  dholland 		nanotime(&dp->nfsdl_modtime);
   4615      1.1  dholland 		dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
   4616      1.1  dholland 	}
   4617      1.1  dholland 	NFSUNLOCKCLSTATE();
   4618      1.1  dholland }
   4619      1.1  dholland 
   4620      1.1  dholland /*
   4621      1.1  dholland  * If there is a valid write delegation for this file with a modtime set,
   4622      1.1  dholland  * put that modtime in mtime.
   4623      1.1  dholland  */
   4624      1.1  dholland APPLESTATIC void
   4625      1.1  dholland nfscl_deleggetmodtime(vnode_t vp, struct timespec *mtime)
   4626      1.1  dholland {
   4627      1.1  dholland 	struct nfsclclient *clp;
   4628      1.1  dholland 	struct nfscldeleg *dp;
   4629      1.1  dholland 	struct nfsnode *np = VTONFS(vp);
   4630      1.1  dholland 	struct nfsmount *nmp;
   4631      1.1  dholland 
   4632      1.1  dholland 	nmp = VFSTONFS(vnode_mount(vp));
   4633      1.1  dholland 	if (!NFSHASNFSV4(nmp))
   4634      1.1  dholland 		return;
   4635      1.1  dholland 	NFSLOCKCLSTATE();
   4636      1.1  dholland 	clp = nfscl_findcl(nmp);
   4637      1.1  dholland 	if (clp == NULL) {
   4638      1.1  dholland 		NFSUNLOCKCLSTATE();
   4639      1.1  dholland 		return;
   4640      1.1  dholland 	}
   4641      1.1  dholland 	dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
   4642      1.1  dholland 	if (dp != NULL &&
   4643      1.1  dholland 	    (dp->nfsdl_flags & (NFSCLDL_WRITE | NFSCLDL_MODTIMESET)) ==
   4644      1.1  dholland 	    (NFSCLDL_WRITE | NFSCLDL_MODTIMESET))
   4645      1.1  dholland 		*mtime = dp->nfsdl_modtime;
   4646      1.1  dholland 	NFSUNLOCKCLSTATE();
   4647      1.1  dholland }
   4648      1.1  dholland 
   4649      1.1  dholland static int
   4650  1.1.1.2  pgoyette nfscl_errmap(struct nfsrv_descript *nd, u_int32_t minorvers)
   4651      1.1  dholland {
   4652      1.1  dholland 	short *defaulterrp, *errp;
   4653      1.1  dholland 
   4654      1.1  dholland 	if (!nd->nd_repstat)
   4655      1.1  dholland 		return (0);
   4656      1.1  dholland 	if (nd->nd_procnum == NFSPROC_NOOP)
   4657      1.1  dholland 		return (txdr_unsigned(nd->nd_repstat & 0xffff));
   4658      1.1  dholland 	if (nd->nd_repstat == EBADRPC)
   4659      1.1  dholland 		return (txdr_unsigned(NFSERR_BADXDR));
   4660      1.1  dholland 	if (nd->nd_repstat == NFSERR_MINORVERMISMATCH ||
   4661      1.1  dholland 	    nd->nd_repstat == NFSERR_OPILLEGAL)
   4662      1.1  dholland 		return (txdr_unsigned(nd->nd_repstat));
   4663  1.1.1.2  pgoyette 	if (nd->nd_repstat >= NFSERR_BADIOMODE && nd->nd_repstat < 20000 &&
   4664  1.1.1.2  pgoyette 	    minorvers > NFSV4_MINORVERSION) {
   4665  1.1.1.2  pgoyette 		/* NFSv4.n error. */
   4666  1.1.1.2  pgoyette 		return (txdr_unsigned(nd->nd_repstat));
   4667  1.1.1.2  pgoyette 	}
   4668      1.1  dholland 	if (nd->nd_procnum < NFSV4OP_CBNOPS)
   4669      1.1  dholland 		errp = defaulterrp = nfscl_cberrmap[nd->nd_procnum];
   4670      1.1  dholland 	else
   4671      1.1  dholland 		return (txdr_unsigned(nd->nd_repstat));
   4672      1.1  dholland 	while (*++errp)
   4673      1.1  dholland 		if (*errp == (short)nd->nd_repstat)
   4674      1.1  dholland 			return (txdr_unsigned(nd->nd_repstat));
   4675      1.1  dholland 	return (txdr_unsigned(*defaulterrp));
   4676      1.1  dholland }
   4677      1.1  dholland 
   4678      1.1  dholland /*
   4679      1.1  dholland  * Called to find/add a layout to a client.
   4680      1.1  dholland  * This function returns the layout with a refcnt (shared lock) upon
   4681      1.1  dholland  * success (returns 0) or with no lock/refcnt on the layout when an
   4682      1.1  dholland  * error is returned.
   4683      1.1  dholland  * If a layout is passed in via lypp, it is locked (exclusively locked).
   4684      1.1  dholland  */
   4685      1.1  dholland APPLESTATIC int
   4686      1.1  dholland nfscl_layout(struct nfsmount *nmp, vnode_t vp, u_int8_t *fhp, int fhlen,
   4687      1.1  dholland     nfsv4stateid_t *stateidp, int retonclose,
   4688      1.1  dholland     struct nfsclflayouthead *fhlp, struct nfscllayout **lypp,
   4689      1.1  dholland     struct ucred *cred, NFSPROC_T *p)
   4690      1.1  dholland {
   4691      1.1  dholland 	struct nfsclclient *clp;
   4692      1.1  dholland 	struct nfscllayout *lyp, *tlyp;
   4693      1.1  dholland 	struct nfsclflayout *flp;
   4694      1.1  dholland 	struct nfsnode *np = VTONFS(vp);
   4695      1.1  dholland 	mount_t mp;
   4696      1.1  dholland 	int layout_passed_in;
   4697      1.1  dholland 
   4698      1.1  dholland 	mp = nmp->nm_mountp;
   4699      1.1  dholland 	layout_passed_in = 1;
   4700      1.1  dholland 	tlyp = NULL;
   4701      1.1  dholland 	lyp = *lypp;
   4702      1.1  dholland 	if (lyp == NULL) {
   4703      1.1  dholland 		layout_passed_in = 0;
   4704      1.1  dholland 		tlyp = malloc(sizeof(*tlyp) + fhlen - 1, M_NFSLAYOUT,
   4705      1.1  dholland 		    M_WAITOK | M_ZERO);
   4706      1.1  dholland 	}
   4707      1.1  dholland 
   4708      1.1  dholland 	NFSLOCKCLSTATE();
   4709      1.1  dholland 	clp = nmp->nm_clp;
   4710      1.1  dholland 	if (clp == NULL) {
   4711      1.1  dholland 		if (layout_passed_in != 0)
   4712      1.1  dholland 			nfsv4_unlock(&lyp->nfsly_lock, 0);
   4713      1.1  dholland 		NFSUNLOCKCLSTATE();
   4714      1.1  dholland 		if (tlyp != NULL)
   4715      1.1  dholland 			free(tlyp, M_NFSLAYOUT);
   4716      1.1  dholland 		return (EPERM);
   4717      1.1  dholland 	}
   4718      1.1  dholland 	if (lyp == NULL) {
   4719      1.1  dholland 		/*
   4720      1.1  dholland 		 * Although no lyp was passed in, another thread might have
   4721      1.1  dholland 		 * allocated one. If one is found, just increment it's ref
   4722      1.1  dholland 		 * count and return it.
   4723      1.1  dholland 		 */
   4724      1.1  dholland 		lyp = nfscl_findlayout(clp, fhp, fhlen);
   4725      1.1  dholland 		if (lyp == NULL) {
   4726      1.1  dholland 			lyp = tlyp;
   4727      1.1  dholland 			tlyp = NULL;
   4728      1.1  dholland 			lyp->nfsly_stateid.seqid = stateidp->seqid;
   4729      1.1  dholland 			lyp->nfsly_stateid.other[0] = stateidp->other[0];
   4730      1.1  dholland 			lyp->nfsly_stateid.other[1] = stateidp->other[1];
   4731      1.1  dholland 			lyp->nfsly_stateid.other[2] = stateidp->other[2];
   4732      1.1  dholland 			lyp->nfsly_lastbyte = 0;
   4733      1.1  dholland 			LIST_INIT(&lyp->nfsly_flayread);
   4734      1.1  dholland 			LIST_INIT(&lyp->nfsly_flayrw);
   4735      1.1  dholland 			LIST_INIT(&lyp->nfsly_recall);
   4736      1.1  dholland 			lyp->nfsly_filesid[0] = np->n_vattr.na_filesid[0];
   4737      1.1  dholland 			lyp->nfsly_filesid[1] = np->n_vattr.na_filesid[1];
   4738      1.1  dholland 			lyp->nfsly_clp = clp;
   4739      1.1  dholland 			lyp->nfsly_flags = (retonclose != 0) ?
   4740      1.1  dholland 			    (NFSLY_FILES | NFSLY_RETONCLOSE) : NFSLY_FILES;
   4741      1.1  dholland 			lyp->nfsly_fhlen = fhlen;
   4742      1.1  dholland 			NFSBCOPY(fhp, lyp->nfsly_fh, fhlen);
   4743      1.1  dholland 			TAILQ_INSERT_HEAD(&clp->nfsc_layout, lyp, nfsly_list);
   4744      1.1  dholland 			LIST_INSERT_HEAD(NFSCLLAYOUTHASH(clp, fhp, fhlen), lyp,
   4745      1.1  dholland 			    nfsly_hash);
   4746      1.1  dholland 			lyp->nfsly_timestamp = NFSD_MONOSEC + 120;
   4747      1.1  dholland 			nfscl_layoutcnt++;
   4748      1.1  dholland 		} else {
   4749      1.1  dholland 			if (retonclose != 0)
   4750      1.1  dholland 				lyp->nfsly_flags |= NFSLY_RETONCLOSE;
   4751      1.1  dholland 			TAILQ_REMOVE(&clp->nfsc_layout, lyp, nfsly_list);
   4752      1.1  dholland 			TAILQ_INSERT_HEAD(&clp->nfsc_layout, lyp, nfsly_list);
   4753      1.1  dholland 			lyp->nfsly_timestamp = NFSD_MONOSEC + 120;
   4754      1.1  dholland 		}
   4755      1.1  dholland 		nfsv4_getref(&lyp->nfsly_lock, NULL, NFSCLSTATEMUTEXPTR, mp);
   4756      1.1  dholland 		if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
   4757      1.1  dholland 			NFSUNLOCKCLSTATE();
   4758      1.1  dholland 			if (tlyp != NULL)
   4759      1.1  dholland 				free(tlyp, M_NFSLAYOUT);
   4760      1.1  dholland 			return (EPERM);
   4761      1.1  dholland 		}
   4762      1.1  dholland 		*lypp = lyp;
   4763      1.1  dholland 	} else
   4764      1.1  dholland 		lyp->nfsly_stateid.seqid = stateidp->seqid;
   4765      1.1  dholland 
   4766      1.1  dholland 	/* Merge the new list of File Layouts into the list. */
   4767      1.1  dholland 	flp = LIST_FIRST(fhlp);
   4768      1.1  dholland 	if (flp != NULL) {
   4769      1.1  dholland 		if (flp->nfsfl_iomode == NFSLAYOUTIOMODE_READ)
   4770      1.1  dholland 			nfscl_mergeflayouts(&lyp->nfsly_flayread, fhlp);
   4771      1.1  dholland 		else
   4772      1.1  dholland 			nfscl_mergeflayouts(&lyp->nfsly_flayrw, fhlp);
   4773      1.1  dholland 	}
   4774      1.1  dholland 	if (layout_passed_in != 0)
   4775      1.1  dholland 		nfsv4_unlock(&lyp->nfsly_lock, 1);
   4776      1.1  dholland 	NFSUNLOCKCLSTATE();
   4777      1.1  dholland 	if (tlyp != NULL)
   4778      1.1  dholland 		free(tlyp, M_NFSLAYOUT);
   4779      1.1  dholland 	return (0);
   4780      1.1  dholland }
   4781      1.1  dholland 
   4782      1.1  dholland /*
   4783      1.1  dholland  * Search for a layout by MDS file handle.
   4784      1.1  dholland  * If one is found, it is returned with a refcnt (shared lock) iff
   4785      1.1  dholland  * retflpp returned non-NULL and locked (exclusive locked) iff retflpp is
   4786      1.1  dholland  * returned NULL.
   4787      1.1  dholland  */
   4788      1.1  dholland struct nfscllayout *
   4789      1.1  dholland nfscl_getlayout(struct nfsclclient *clp, uint8_t *fhp, int fhlen,
   4790      1.1  dholland     uint64_t off, struct nfsclflayout **retflpp, int *recalledp)
   4791      1.1  dholland {
   4792      1.1  dholland 	struct nfscllayout *lyp;
   4793      1.1  dholland 	mount_t mp;
   4794      1.1  dholland 	int error, igotlock;
   4795      1.1  dholland 
   4796      1.1  dholland 	mp = clp->nfsc_nmp->nm_mountp;
   4797      1.1  dholland 	*recalledp = 0;
   4798      1.1  dholland 	*retflpp = NULL;
   4799      1.1  dholland 	NFSLOCKCLSTATE();
   4800      1.1  dholland 	lyp = nfscl_findlayout(clp, fhp, fhlen);
   4801      1.1  dholland 	if (lyp != NULL) {
   4802      1.1  dholland 		if ((lyp->nfsly_flags & NFSLY_RECALL) == 0) {
   4803      1.1  dholland 			TAILQ_REMOVE(&clp->nfsc_layout, lyp, nfsly_list);
   4804      1.1  dholland 			TAILQ_INSERT_HEAD(&clp->nfsc_layout, lyp, nfsly_list);
   4805      1.1  dholland 			lyp->nfsly_timestamp = NFSD_MONOSEC + 120;
   4806      1.1  dholland 			error = nfscl_findlayoutforio(lyp, off,
   4807      1.1  dholland 			    NFSV4OPEN_ACCESSREAD, retflpp);
   4808      1.1  dholland 			if (error == 0)
   4809      1.1  dholland 				nfsv4_getref(&lyp->nfsly_lock, NULL,
   4810      1.1  dholland 				    NFSCLSTATEMUTEXPTR, mp);
   4811      1.1  dholland 			else {
   4812      1.1  dholland 				do {
   4813      1.1  dholland 					igotlock = nfsv4_lock(&lyp->nfsly_lock,
   4814      1.1  dholland 					    1, NULL, NFSCLSTATEMUTEXPTR, mp);
   4815      1.1  dholland 				} while (igotlock == 0 &&
   4816      1.1  dholland 				    (mp->mnt_kern_flag & MNTK_UNMOUNTF) == 0);
   4817      1.1  dholland 				*retflpp = NULL;
   4818      1.1  dholland 			}
   4819      1.1  dholland 			if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
   4820      1.1  dholland 				lyp = NULL;
   4821      1.1  dholland 				*recalledp = 1;
   4822      1.1  dholland 			}
   4823      1.1  dholland 		} else {
   4824      1.1  dholland 			lyp = NULL;
   4825      1.1  dholland 			*recalledp = 1;
   4826      1.1  dholland 		}
   4827      1.1  dholland 	}
   4828      1.1  dholland 	NFSUNLOCKCLSTATE();
   4829      1.1  dholland 	return (lyp);
   4830      1.1  dholland }
   4831      1.1  dholland 
   4832      1.1  dholland /*
   4833      1.1  dholland  * Search for a layout by MDS file handle. If one is found that is marked
   4834      1.1  dholland  * "return on close", delete it, since it should now be forgotten.
   4835      1.1  dholland  */
   4836      1.1  dholland static void
   4837      1.1  dholland nfscl_retoncloselayout(struct nfsclclient *clp, uint8_t *fhp, int fhlen)
   4838      1.1  dholland {
   4839      1.1  dholland 	struct nfscllayout *lyp;
   4840      1.1  dholland 
   4841      1.1  dholland tryagain:
   4842      1.1  dholland 	lyp = nfscl_findlayout(clp, fhp, fhlen);
   4843      1.1  dholland 	if (lyp != NULL && (lyp->nfsly_flags & NFSLY_RETONCLOSE) != 0) {
   4844      1.1  dholland 		/*
   4845      1.1  dholland 		 * Wait for outstanding I/O ops to be done.
   4846      1.1  dholland 		 */
   4847      1.1  dholland 		if (lyp->nfsly_lock.nfslock_usecnt != 0 ||
   4848      1.1  dholland 		    lyp->nfsly_lock.nfslock_lock != 0) {
   4849      1.1  dholland 			lyp->nfsly_lock.nfslock_lock |= NFSV4LOCK_WANTED;
   4850      1.1  dholland 			(void)mtx_sleep(&lyp->nfsly_lock,
   4851      1.1  dholland 			    NFSCLSTATEMUTEXPTR, PZERO, "nfslyc", 0);
   4852      1.1  dholland 			goto tryagain;
   4853      1.1  dholland 		}
   4854      1.1  dholland 		nfscl_freelayout(lyp);
   4855      1.1  dholland 	}
   4856      1.1  dholland }
   4857      1.1  dholland 
   4858      1.1  dholland /*
   4859      1.1  dholland  * Dereference a layout.
   4860      1.1  dholland  */
   4861      1.1  dholland void
   4862      1.1  dholland nfscl_rellayout(struct nfscllayout *lyp, int exclocked)
   4863      1.1  dholland {
   4864      1.1  dholland 
   4865      1.1  dholland 	NFSLOCKCLSTATE();
   4866      1.1  dholland 	if (exclocked != 0)
   4867      1.1  dholland 		nfsv4_unlock(&lyp->nfsly_lock, 0);
   4868      1.1  dholland 	else
   4869      1.1  dholland 		nfsv4_relref(&lyp->nfsly_lock);
   4870      1.1  dholland 	NFSUNLOCKCLSTATE();
   4871      1.1  dholland }
   4872      1.1  dholland 
   4873      1.1  dholland /*
   4874      1.1  dholland  * Search for a devinfo by deviceid. If one is found, return it after
   4875      1.1  dholland  * acquiring a reference count on it.
   4876      1.1  dholland  */
   4877      1.1  dholland struct nfscldevinfo *
   4878      1.1  dholland nfscl_getdevinfo(struct nfsclclient *clp, uint8_t *deviceid,
   4879      1.1  dholland     struct nfscldevinfo *dip)
   4880      1.1  dholland {
   4881      1.1  dholland 
   4882      1.1  dholland 	NFSLOCKCLSTATE();
   4883      1.1  dholland 	if (dip == NULL)
   4884      1.1  dholland 		dip = nfscl_finddevinfo(clp, deviceid);
   4885      1.1  dholland 	if (dip != NULL)
   4886      1.1  dholland 		dip->nfsdi_refcnt++;
   4887      1.1  dholland 	NFSUNLOCKCLSTATE();
   4888      1.1  dholland 	return (dip);
   4889      1.1  dholland }
   4890      1.1  dholland 
   4891      1.1  dholland /*
   4892      1.1  dholland  * Dereference a devinfo structure.
   4893      1.1  dholland  */
   4894      1.1  dholland static void
   4895      1.1  dholland nfscl_reldevinfo_locked(struct nfscldevinfo *dip)
   4896      1.1  dholland {
   4897      1.1  dholland 
   4898      1.1  dholland 	dip->nfsdi_refcnt--;
   4899      1.1  dholland 	if (dip->nfsdi_refcnt == 0)
   4900      1.1  dholland 		wakeup(&dip->nfsdi_refcnt);
   4901      1.1  dholland }
   4902      1.1  dholland 
   4903      1.1  dholland /*
   4904      1.1  dholland  * Dereference a devinfo structure.
   4905      1.1  dholland  */
   4906      1.1  dholland void
   4907      1.1  dholland nfscl_reldevinfo(struct nfscldevinfo *dip)
   4908      1.1  dholland {
   4909      1.1  dholland 
   4910      1.1  dholland 	NFSLOCKCLSTATE();
   4911      1.1  dholland 	nfscl_reldevinfo_locked(dip);
   4912      1.1  dholland 	NFSUNLOCKCLSTATE();
   4913      1.1  dholland }
   4914      1.1  dholland 
   4915      1.1  dholland /*
   4916      1.1  dholland  * Find a layout for this file handle. Return NULL upon failure.
   4917      1.1  dholland  */
   4918      1.1  dholland static struct nfscllayout *
   4919      1.1  dholland nfscl_findlayout(struct nfsclclient *clp, u_int8_t *fhp, int fhlen)
   4920      1.1  dholland {
   4921      1.1  dholland 	struct nfscllayout *lyp;
   4922      1.1  dholland 
   4923      1.1  dholland 	LIST_FOREACH(lyp, NFSCLLAYOUTHASH(clp, fhp, fhlen), nfsly_hash)
   4924      1.1  dholland 		if (lyp->nfsly_fhlen == fhlen &&
   4925      1.1  dholland 		    !NFSBCMP(lyp->nfsly_fh, fhp, fhlen))
   4926      1.1  dholland 			break;
   4927      1.1  dholland 	return (lyp);
   4928      1.1  dholland }
   4929      1.1  dholland 
   4930      1.1  dholland /*
   4931      1.1  dholland  * Find a devinfo for this deviceid. Return NULL upon failure.
   4932      1.1  dholland  */
   4933      1.1  dholland static struct nfscldevinfo *
   4934      1.1  dholland nfscl_finddevinfo(struct nfsclclient *clp, uint8_t *deviceid)
   4935      1.1  dholland {
   4936      1.1  dholland 	struct nfscldevinfo *dip;
   4937      1.1  dholland 
   4938      1.1  dholland 	LIST_FOREACH(dip, &clp->nfsc_devinfo, nfsdi_list)
   4939      1.1  dholland 		if (NFSBCMP(dip->nfsdi_deviceid, deviceid, NFSX_V4DEVICEID)
   4940      1.1  dholland 		    == 0)
   4941      1.1  dholland 			break;
   4942      1.1  dholland 	return (dip);
   4943      1.1  dholland }
   4944      1.1  dholland 
   4945      1.1  dholland /*
   4946      1.1  dholland  * Merge the new file layout list into the main one, maintaining it in
   4947      1.1  dholland  * increasing offset order.
   4948      1.1  dholland  */
   4949      1.1  dholland static void
   4950      1.1  dholland nfscl_mergeflayouts(struct nfsclflayouthead *fhlp,
   4951      1.1  dholland     struct nfsclflayouthead *newfhlp)
   4952      1.1  dholland {
   4953      1.1  dholland 	struct nfsclflayout *flp, *nflp, *prevflp, *tflp;
   4954      1.1  dholland 
   4955      1.1  dholland 	flp = LIST_FIRST(fhlp);
   4956      1.1  dholland 	prevflp = NULL;
   4957      1.1  dholland 	LIST_FOREACH_SAFE(nflp, newfhlp, nfsfl_list, tflp) {
   4958      1.1  dholland 		while (flp != NULL && flp->nfsfl_off < nflp->nfsfl_off) {
   4959      1.1  dholland 			prevflp = flp;
   4960      1.1  dholland 			flp = LIST_NEXT(flp, nfsfl_list);
   4961      1.1  dholland 		}
   4962      1.1  dholland 		if (prevflp == NULL)
   4963      1.1  dholland 			LIST_INSERT_HEAD(fhlp, nflp, nfsfl_list);
   4964      1.1  dholland 		else
   4965      1.1  dholland 			LIST_INSERT_AFTER(prevflp, nflp, nfsfl_list);
   4966      1.1  dholland 		prevflp = nflp;
   4967      1.1  dholland 	}
   4968      1.1  dholland }
   4969      1.1  dholland 
   4970      1.1  dholland /*
   4971      1.1  dholland  * Add this nfscldevinfo to the client, if it doesn't already exist.
   4972      1.1  dholland  * This function consumes the structure pointed at by dip, if not NULL.
   4973      1.1  dholland  */
   4974      1.1  dholland APPLESTATIC int
   4975      1.1  dholland nfscl_adddevinfo(struct nfsmount *nmp, struct nfscldevinfo *dip,
   4976      1.1  dholland     struct nfsclflayout *flp)
   4977      1.1  dholland {
   4978      1.1  dholland 	struct nfsclclient *clp;
   4979      1.1  dholland 	struct nfscldevinfo *tdip;
   4980      1.1  dholland 
   4981      1.1  dholland 	NFSLOCKCLSTATE();
   4982      1.1  dholland 	clp = nmp->nm_clp;
   4983      1.1  dholland 	if (clp == NULL) {
   4984      1.1  dholland 		NFSUNLOCKCLSTATE();
   4985      1.1  dholland 		if (dip != NULL)
   4986      1.1  dholland 			free(dip, M_NFSDEVINFO);
   4987      1.1  dholland 		return (ENODEV);
   4988      1.1  dholland 	}
   4989      1.1  dholland 	tdip = nfscl_finddevinfo(clp, flp->nfsfl_dev);
   4990      1.1  dholland 	if (tdip != NULL) {
   4991      1.1  dholland 		tdip->nfsdi_layoutrefs++;
   4992      1.1  dholland 		flp->nfsfl_devp = tdip;
   4993      1.1  dholland 		nfscl_reldevinfo_locked(tdip);
   4994      1.1  dholland 		NFSUNLOCKCLSTATE();
   4995      1.1  dholland 		if (dip != NULL)
   4996      1.1  dholland 			free(dip, M_NFSDEVINFO);
   4997      1.1  dholland 		return (0);
   4998      1.1  dholland 	}
   4999      1.1  dholland 	if (dip != NULL) {
   5000      1.1  dholland 		LIST_INSERT_HEAD(&clp->nfsc_devinfo, dip, nfsdi_list);
   5001      1.1  dholland 		dip->nfsdi_layoutrefs = 1;
   5002      1.1  dholland 		flp->nfsfl_devp = dip;
   5003      1.1  dholland 	}
   5004      1.1  dholland 	NFSUNLOCKCLSTATE();
   5005      1.1  dholland 	if (dip == NULL)
   5006      1.1  dholland 		return (ENODEV);
   5007      1.1  dholland 	return (0);
   5008      1.1  dholland }
   5009      1.1  dholland 
   5010      1.1  dholland /*
   5011      1.1  dholland  * Free up a layout structure and associated file layout structure(s).
   5012      1.1  dholland  */
   5013      1.1  dholland APPLESTATIC void
   5014      1.1  dholland nfscl_freelayout(struct nfscllayout *layp)
   5015      1.1  dholland {
   5016      1.1  dholland 	struct nfsclflayout *flp, *nflp;
   5017      1.1  dholland 	struct nfsclrecalllayout *rp, *nrp;
   5018      1.1  dholland 
   5019      1.1  dholland 	LIST_FOREACH_SAFE(flp, &layp->nfsly_flayread, nfsfl_list, nflp) {
   5020      1.1  dholland 		LIST_REMOVE(flp, nfsfl_list);
   5021      1.1  dholland 		nfscl_freeflayout(flp);
   5022      1.1  dholland 	}
   5023      1.1  dholland 	LIST_FOREACH_SAFE(flp, &layp->nfsly_flayrw, nfsfl_list, nflp) {
   5024      1.1  dholland 		LIST_REMOVE(flp, nfsfl_list);
   5025      1.1  dholland 		nfscl_freeflayout(flp);
   5026      1.1  dholland 	}
   5027      1.1  dholland 	LIST_FOREACH_SAFE(rp, &layp->nfsly_recall, nfsrecly_list, nrp) {
   5028      1.1  dholland 		LIST_REMOVE(rp, nfsrecly_list);
   5029      1.1  dholland 		free(rp, M_NFSLAYRECALL);
   5030      1.1  dholland 	}
   5031      1.1  dholland 	nfscl_layoutcnt--;
   5032      1.1  dholland 	free(layp, M_NFSLAYOUT);
   5033      1.1  dholland }
   5034      1.1  dholland 
   5035      1.1  dholland /*
   5036      1.1  dholland  * Free up a file layout structure.
   5037      1.1  dholland  */
   5038      1.1  dholland APPLESTATIC void
   5039      1.1  dholland nfscl_freeflayout(struct nfsclflayout *flp)
   5040      1.1  dholland {
   5041      1.1  dholland 	int i;
   5042      1.1  dholland 
   5043      1.1  dholland 	for (i = 0; i < flp->nfsfl_fhcnt; i++)
   5044      1.1  dholland 		free(flp->nfsfl_fh[i], M_NFSFH);
   5045      1.1  dholland 	if (flp->nfsfl_devp != NULL)
   5046      1.1  dholland 		flp->nfsfl_devp->nfsdi_layoutrefs--;
   5047      1.1  dholland 	free(flp, M_NFSFLAYOUT);
   5048      1.1  dholland }
   5049      1.1  dholland 
   5050      1.1  dholland /*
   5051      1.1  dholland  * Free up a file layout devinfo structure.
   5052      1.1  dholland  */
   5053      1.1  dholland APPLESTATIC void
   5054      1.1  dholland nfscl_freedevinfo(struct nfscldevinfo *dip)
   5055      1.1  dholland {
   5056      1.1  dholland 
   5057      1.1  dholland 	free(dip, M_NFSDEVINFO);
   5058      1.1  dholland }
   5059      1.1  dholland 
   5060      1.1  dholland /*
   5061      1.1  dholland  * Mark any layouts that match as recalled.
   5062      1.1  dholland  */
   5063      1.1  dholland static int
   5064      1.1  dholland nfscl_layoutrecall(int recalltype, struct nfscllayout *lyp, uint32_t iomode,
   5065      1.1  dholland     uint64_t off, uint64_t len, uint32_t stateseqid,
   5066      1.1  dholland     struct nfsclrecalllayout *recallp)
   5067      1.1  dholland {
   5068      1.1  dholland 	struct nfsclrecalllayout *rp, *orp;
   5069      1.1  dholland 
   5070      1.1  dholland 	recallp->nfsrecly_recalltype = recalltype;
   5071      1.1  dholland 	recallp->nfsrecly_iomode = iomode;
   5072      1.1  dholland 	recallp->nfsrecly_stateseqid = stateseqid;
   5073      1.1  dholland 	recallp->nfsrecly_off = off;
   5074      1.1  dholland 	recallp->nfsrecly_len = len;
   5075      1.1  dholland 	/*
   5076      1.1  dholland 	 * Order the list as file returns first, followed by fsid and any
   5077      1.1  dholland 	 * returns, both in increasing stateseqid order.
   5078      1.1  dholland 	 * Note that the seqids wrap around, so 1 is after 0xffffffff.
   5079      1.1  dholland 	 * (I'm not sure this is correct because I find RFC5661 confusing
   5080      1.1  dholland 	 *  on this, but hopefully it will work ok.)
   5081      1.1  dholland 	 */
   5082      1.1  dholland 	orp = NULL;
   5083      1.1  dholland 	LIST_FOREACH(rp, &lyp->nfsly_recall, nfsrecly_list) {
   5084      1.1  dholland 		orp = rp;
   5085      1.1  dholland 		if ((recalltype == NFSLAYOUTRETURN_FILE &&
   5086      1.1  dholland 		     (rp->nfsrecly_recalltype != NFSLAYOUTRETURN_FILE ||
   5087      1.1  dholland 		      nfscl_seq(stateseqid, rp->nfsrecly_stateseqid) != 0)) ||
   5088      1.1  dholland 		    (recalltype != NFSLAYOUTRETURN_FILE &&
   5089      1.1  dholland 		     rp->nfsrecly_recalltype != NFSLAYOUTRETURN_FILE &&
   5090      1.1  dholland 		     nfscl_seq(stateseqid, rp->nfsrecly_stateseqid) != 0)) {
   5091      1.1  dholland 			LIST_INSERT_BEFORE(rp, recallp, nfsrecly_list);
   5092      1.1  dholland 			break;
   5093      1.1  dholland 		}
   5094      1.1  dholland 	}
   5095      1.1  dholland 	if (rp == NULL) {
   5096      1.1  dholland 		if (orp == NULL)
   5097      1.1  dholland 			LIST_INSERT_HEAD(&lyp->nfsly_recall, recallp,
   5098      1.1  dholland 			    nfsrecly_list);
   5099      1.1  dholland 		else
   5100      1.1  dholland 			LIST_INSERT_AFTER(orp, recallp, nfsrecly_list);
   5101      1.1  dholland 	}
   5102      1.1  dholland 	lyp->nfsly_flags |= NFSLY_RECALL;
   5103      1.1  dholland 	return (0);
   5104      1.1  dholland }
   5105      1.1  dholland 
   5106      1.1  dholland /*
   5107      1.1  dholland  * Compare the two seqids for ordering. The trick is that the seqids can
   5108      1.1  dholland  * wrap around from 0xffffffff->0, so check for the cases where one
   5109      1.1  dholland  * has wrapped around.
   5110      1.1  dholland  * Return 1 if seqid1 comes before seqid2, 0 otherwise.
   5111      1.1  dholland  */
   5112      1.1  dholland static int
   5113      1.1  dholland nfscl_seq(uint32_t seqid1, uint32_t seqid2)
   5114      1.1  dholland {
   5115      1.1  dholland 
   5116      1.1  dholland 	if (seqid2 > seqid1 && (seqid2 - seqid1) >= 0x7fffffff)
   5117      1.1  dholland 		/* seqid2 has wrapped around. */
   5118      1.1  dholland 		return (0);
   5119      1.1  dholland 	if (seqid1 > seqid2 && (seqid1 - seqid2) >= 0x7fffffff)
   5120      1.1  dholland 		/* seqid1 has wrapped around. */
   5121      1.1  dholland 		return (1);
   5122      1.1  dholland 	if (seqid1 <= seqid2)
   5123      1.1  dholland 		return (1);
   5124      1.1  dholland 	return (0);
   5125      1.1  dholland }
   5126      1.1  dholland 
   5127      1.1  dholland /*
   5128      1.1  dholland  * Do a layout return for each of the recalls.
   5129      1.1  dholland  */
   5130      1.1  dholland static void
   5131      1.1  dholland nfscl_layoutreturn(struct nfsmount *nmp, struct nfscllayout *lyp,
   5132      1.1  dholland     struct ucred *cred, NFSPROC_T *p)
   5133      1.1  dholland {
   5134      1.1  dholland 	struct nfsclrecalllayout *rp;
   5135      1.1  dholland 	nfsv4stateid_t stateid;
   5136      1.1  dholland 
   5137      1.1  dholland 	NFSBCOPY(lyp->nfsly_stateid.other, stateid.other, NFSX_STATEIDOTHER);
   5138      1.1  dholland 	LIST_FOREACH(rp, &lyp->nfsly_recall, nfsrecly_list) {
   5139      1.1  dholland 		stateid.seqid = rp->nfsrecly_stateseqid;
   5140      1.1  dholland 		(void)nfsrpc_layoutreturn(nmp, lyp->nfsly_fh,
   5141      1.1  dholland 		    lyp->nfsly_fhlen, 0, NFSLAYOUT_NFSV4_1_FILES,
   5142      1.1  dholland 		    rp->nfsrecly_iomode, rp->nfsrecly_recalltype,
   5143      1.1  dholland 		    rp->nfsrecly_off, rp->nfsrecly_len,
   5144      1.1  dholland 		    &stateid, 0, NULL, cred, p, NULL);
   5145      1.1  dholland 	}
   5146      1.1  dholland }
   5147      1.1  dholland 
   5148      1.1  dholland /*
   5149      1.1  dholland  * Do the layout commit for a file layout.
   5150      1.1  dholland  */
   5151      1.1  dholland static void
   5152      1.1  dholland nfscl_dolayoutcommit(struct nfsmount *nmp, struct nfscllayout *lyp,
   5153      1.1  dholland     struct ucred *cred, NFSPROC_T *p)
   5154      1.1  dholland {
   5155      1.1  dholland 	struct nfsclflayout *flp;
   5156      1.1  dholland 	uint64_t len;
   5157      1.1  dholland 	int error;
   5158      1.1  dholland 
   5159      1.1  dholland 	LIST_FOREACH(flp, &lyp->nfsly_flayrw, nfsfl_list) {
   5160      1.1  dholland 		if (flp->nfsfl_off <= lyp->nfsly_lastbyte) {
   5161      1.1  dholland 			len = flp->nfsfl_end - flp->nfsfl_off;
   5162      1.1  dholland 			error = nfsrpc_layoutcommit(nmp, lyp->nfsly_fh,
   5163      1.1  dholland 			    lyp->nfsly_fhlen, 0, flp->nfsfl_off, len,
   5164      1.1  dholland 			    lyp->nfsly_lastbyte, &lyp->nfsly_stateid,
   5165      1.1  dholland 			    NFSLAYOUT_NFSV4_1_FILES, 0, NULL, cred, p, NULL);
   5166      1.1  dholland 			NFSCL_DEBUG(4, "layoutcommit err=%d\n", error);
   5167      1.1  dholland 			if (error == NFSERR_NOTSUPP) {
   5168      1.1  dholland 				/* If not supported, don't bother doing it. */
   5169      1.1  dholland 				NFSLOCKMNT(nmp);
   5170      1.1  dholland 				nmp->nm_state |= NFSSTA_NOLAYOUTCOMMIT;
   5171      1.1  dholland 				NFSUNLOCKMNT(nmp);
   5172      1.1  dholland 				break;
   5173      1.1  dholland 			}
   5174      1.1  dholland 		}
   5175      1.1  dholland 	}
   5176      1.1  dholland }
   5177      1.1  dholland 
   5178      1.1  dholland /*
   5179      1.1  dholland  * Commit all layouts for a file (vnode).
   5180      1.1  dholland  */
   5181      1.1  dholland int
   5182      1.1  dholland nfscl_layoutcommit(vnode_t vp, NFSPROC_T *p)
   5183      1.1  dholland {
   5184      1.1  dholland 	struct nfsclclient *clp;
   5185      1.1  dholland 	struct nfscllayout *lyp;
   5186      1.1  dholland 	struct nfsnode *np = VTONFS(vp);
   5187      1.1  dholland 	mount_t mp;
   5188      1.1  dholland 	struct nfsmount *nmp;
   5189      1.1  dholland 
   5190      1.1  dholland 	mp = vnode_mount(vp);
   5191      1.1  dholland 	nmp = VFSTONFS(mp);
   5192      1.1  dholland 	if (NFSHASNOLAYOUTCOMMIT(nmp))
   5193      1.1  dholland 		return (0);
   5194      1.1  dholland 	NFSLOCKCLSTATE();
   5195      1.1  dholland 	clp = nmp->nm_clp;
   5196      1.1  dholland 	if (clp == NULL) {
   5197      1.1  dholland 		NFSUNLOCKCLSTATE();
   5198      1.1  dholland 		return (EPERM);
   5199      1.1  dholland 	}
   5200      1.1  dholland 	lyp = nfscl_findlayout(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
   5201      1.1  dholland 	if (lyp == NULL) {
   5202      1.1  dholland 		NFSUNLOCKCLSTATE();
   5203      1.1  dholland 		return (EPERM);
   5204      1.1  dholland 	}
   5205      1.1  dholland 	nfsv4_getref(&lyp->nfsly_lock, NULL, NFSCLSTATEMUTEXPTR, mp);
   5206      1.1  dholland 	if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
   5207      1.1  dholland 		NFSUNLOCKCLSTATE();
   5208      1.1  dholland 		return (EPERM);
   5209      1.1  dholland 	}
   5210      1.1  dholland tryagain:
   5211      1.1  dholland 	if ((lyp->nfsly_flags & NFSLY_WRITTEN) != 0) {
   5212      1.1  dholland 		lyp->nfsly_flags &= ~NFSLY_WRITTEN;
   5213      1.1  dholland 		NFSUNLOCKCLSTATE();
   5214      1.1  dholland 		NFSCL_DEBUG(4, "do layoutcommit2\n");
   5215      1.1  dholland 		nfscl_dolayoutcommit(clp->nfsc_nmp, lyp, NFSPROCCRED(p), p);
   5216      1.1  dholland 		NFSLOCKCLSTATE();
   5217      1.1  dholland 		goto tryagain;
   5218      1.1  dholland 	}
   5219      1.1  dholland 	nfsv4_relref(&lyp->nfsly_lock);
   5220      1.1  dholland 	NFSUNLOCKCLSTATE();
   5221      1.1  dholland 	return (0);
   5222      1.1  dholland }
   5223      1.1  dholland 
   5224