nfs_clstate.c revision 1.2 1 1.2 snj /* $NetBSD: nfs_clstate.c,v 1.2 2014/10/18 08:33:28 snj 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 dholland /* __FBSDID("FreeBSD: head/sys/fs/nfsclient/nfs_clstate.c 252100 2013-06-22 21:58:21Z rmacklem "); */
31 1.2 snj __RCSID("$NetBSD: nfs_clstate.c,v 1.2 2014/10/18 08:33:28 snj 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 dholland extern struct nfsstats newnfsstats;
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 dholland static int nfscl_errmap(struct nfsrv_descript *);
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 dholland * Serialize modifications to the open owner for multiple threads
287 1.1 dholland * within the same process using a read/write sleep lock.
288 1.1 dholland */
289 1.1 dholland if (lockit)
290 1.1 dholland nfscl_lockexcl(&owp->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
291 1.1 dholland NFSUNLOCKCLSTATE();
292 1.1 dholland if (nowp != NULL)
293 1.1 dholland FREE((caddr_t)nowp, M_NFSCLOWNER);
294 1.1 dholland if (nop != NULL)
295 1.1 dholland FREE((caddr_t)nop, M_NFSCLOPEN);
296 1.1 dholland if (owpp != NULL)
297 1.1 dholland *owpp = owp;
298 1.1 dholland if (opp != NULL)
299 1.1 dholland *opp = op;
300 1.1 dholland if (retp != NULL) {
301 1.1 dholland if (nfhp != NULL && dp != NULL && nop == NULL)
302 1.1 dholland /* new local open on delegation */
303 1.1 dholland *retp = NFSCLOPEN_SETCRED;
304 1.1 dholland else
305 1.1 dholland *retp = NFSCLOPEN_OK;
306 1.1 dholland }
307 1.1 dholland
308 1.1 dholland /*
309 1.1 dholland * Now, check the mode on the open and return the appropriate
310 1.1 dholland * value.
311 1.1 dholland */
312 1.1 dholland if (op != NULL && (amode & ~(op->nfso_mode))) {
313 1.1 dholland op->nfso_mode |= amode;
314 1.1 dholland if (retp != NULL && dp == NULL)
315 1.1 dholland *retp = NFSCLOPEN_DOOPEN;
316 1.1 dholland }
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 dholland newnfsstats.cllocalopenowners++;
349 1.1 dholland LIST_INSERT_HEAD(&dp->nfsdl_owner, nowp, nfsow_list);
350 1.1 dholland } else {
351 1.1 dholland newnfsstats.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 dholland newnfsstats.cllocalopens++;
386 1.1 dholland } else {
387 1.1 dholland newnfsstats.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 dholland newnfsstats.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 dholland * but will release that lock and return the clientid with a refernce
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 dholland newnfsstats.cllocallockowners++;
1077 1.1 dholland } else {
1078 1.1 dholland nlp->nfsl_open = op;
1079 1.1 dholland newnfsstats.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 dholland };
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 dholland newnfsstats.cllocalopens--;
1408 1.1 dholland else
1409 1.1 dholland newnfsstats.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 dholland newnfsstats.cllocalopenowners--;
1489 1.1 dholland else
1490 1.1 dholland newnfsstats.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 dholland newnfsstats.cllocallockowners--;
1508 1.1 dholland else
1509 1.1 dholland newnfsstats.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 dholland newnfsstats.cllocallocks--;
1523 1.1 dholland else
1524 1.1 dholland newnfsstats.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 dholland newnfsstats.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 dholland newnfsstats.cllocalopens--;
1627 1.1 dholland newnfsstats.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 dholland newnfsstats.cllocalopenowners--;
1635 1.1 dholland newnfsstats.clopenowners++;
1636 1.1 dholland newnfsstats.cllocalopens--;
1637 1.1 dholland newnfsstats.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 dholland newnfsstats.cllocallocks++;
2288 1.1 dholland else
2289 1.1 dholland newnfsstats.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 dholland newnfsstats.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 dholland newnfsstats.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 dholland u_int32_t minorvers, 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 dholland *repp = nfscl_errmap(nd);
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 dholland if (op < NFSV4OP_CBNOPS)
3221 1.1 dholland newnfsstats.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 dholland NULL, 0, &rattrbits, NULL, NULL, 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 dholland };
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 dholland *repp = nfscl_errmap(nd);
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 dholland *nd->nd_errp = nfscl_errmap(nd);
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 dholland 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 dholland nfscl_errmap(struct nfsrv_descript *nd)
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 dholland if (nd->nd_procnum < NFSV4OP_CBNOPS)
4664 1.1 dholland errp = defaulterrp = nfscl_cberrmap[nd->nd_procnum];
4665 1.1 dholland else
4666 1.1 dholland return (txdr_unsigned(nd->nd_repstat));
4667 1.1 dholland while (*++errp)
4668 1.1 dholland if (*errp == (short)nd->nd_repstat)
4669 1.1 dholland return (txdr_unsigned(nd->nd_repstat));
4670 1.1 dholland return (txdr_unsigned(*defaulterrp));
4671 1.1 dholland }
4672 1.1 dholland
4673 1.1 dholland /*
4674 1.1 dholland * Called to find/add a layout to a client.
4675 1.1 dholland * This function returns the layout with a refcnt (shared lock) upon
4676 1.1 dholland * success (returns 0) or with no lock/refcnt on the layout when an
4677 1.1 dholland * error is returned.
4678 1.1 dholland * If a layout is passed in via lypp, it is locked (exclusively locked).
4679 1.1 dholland */
4680 1.1 dholland APPLESTATIC int
4681 1.1 dholland nfscl_layout(struct nfsmount *nmp, vnode_t vp, u_int8_t *fhp, int fhlen,
4682 1.1 dholland nfsv4stateid_t *stateidp, int retonclose,
4683 1.1 dholland struct nfsclflayouthead *fhlp, struct nfscllayout **lypp,
4684 1.1 dholland struct ucred *cred, NFSPROC_T *p)
4685 1.1 dholland {
4686 1.1 dholland struct nfsclclient *clp;
4687 1.1 dholland struct nfscllayout *lyp, *tlyp;
4688 1.1 dholland struct nfsclflayout *flp;
4689 1.1 dholland struct nfsnode *np = VTONFS(vp);
4690 1.1 dholland mount_t mp;
4691 1.1 dholland int layout_passed_in;
4692 1.1 dholland
4693 1.1 dholland mp = nmp->nm_mountp;
4694 1.1 dholland layout_passed_in = 1;
4695 1.1 dholland tlyp = NULL;
4696 1.1 dholland lyp = *lypp;
4697 1.1 dholland if (lyp == NULL) {
4698 1.1 dholland layout_passed_in = 0;
4699 1.1 dholland tlyp = malloc(sizeof(*tlyp) + fhlen - 1, M_NFSLAYOUT,
4700 1.1 dholland M_WAITOK | M_ZERO);
4701 1.1 dholland }
4702 1.1 dholland
4703 1.1 dholland NFSLOCKCLSTATE();
4704 1.1 dholland clp = nmp->nm_clp;
4705 1.1 dholland if (clp == NULL) {
4706 1.1 dholland if (layout_passed_in != 0)
4707 1.1 dholland nfsv4_unlock(&lyp->nfsly_lock, 0);
4708 1.1 dholland NFSUNLOCKCLSTATE();
4709 1.1 dholland if (tlyp != NULL)
4710 1.1 dholland free(tlyp, M_NFSLAYOUT);
4711 1.1 dholland return (EPERM);
4712 1.1 dholland }
4713 1.1 dholland if (lyp == NULL) {
4714 1.1 dholland /*
4715 1.1 dholland * Although no lyp was passed in, another thread might have
4716 1.2 snj * allocated one. If one is found, just increment its ref
4717 1.1 dholland * count and return it.
4718 1.1 dholland */
4719 1.1 dholland lyp = nfscl_findlayout(clp, fhp, fhlen);
4720 1.1 dholland if (lyp == NULL) {
4721 1.1 dholland lyp = tlyp;
4722 1.1 dholland tlyp = NULL;
4723 1.1 dholland lyp->nfsly_stateid.seqid = stateidp->seqid;
4724 1.1 dholland lyp->nfsly_stateid.other[0] = stateidp->other[0];
4725 1.1 dholland lyp->nfsly_stateid.other[1] = stateidp->other[1];
4726 1.1 dholland lyp->nfsly_stateid.other[2] = stateidp->other[2];
4727 1.1 dholland lyp->nfsly_lastbyte = 0;
4728 1.1 dholland LIST_INIT(&lyp->nfsly_flayread);
4729 1.1 dholland LIST_INIT(&lyp->nfsly_flayrw);
4730 1.1 dholland LIST_INIT(&lyp->nfsly_recall);
4731 1.1 dholland lyp->nfsly_filesid[0] = np->n_vattr.na_filesid[0];
4732 1.1 dholland lyp->nfsly_filesid[1] = np->n_vattr.na_filesid[1];
4733 1.1 dholland lyp->nfsly_clp = clp;
4734 1.1 dholland lyp->nfsly_flags = (retonclose != 0) ?
4735 1.1 dholland (NFSLY_FILES | NFSLY_RETONCLOSE) : NFSLY_FILES;
4736 1.1 dholland lyp->nfsly_fhlen = fhlen;
4737 1.1 dholland NFSBCOPY(fhp, lyp->nfsly_fh, fhlen);
4738 1.1 dholland TAILQ_INSERT_HEAD(&clp->nfsc_layout, lyp, nfsly_list);
4739 1.1 dholland LIST_INSERT_HEAD(NFSCLLAYOUTHASH(clp, fhp, fhlen), lyp,
4740 1.1 dholland nfsly_hash);
4741 1.1 dholland lyp->nfsly_timestamp = NFSD_MONOSEC + 120;
4742 1.1 dholland nfscl_layoutcnt++;
4743 1.1 dholland } else {
4744 1.1 dholland if (retonclose != 0)
4745 1.1 dholland lyp->nfsly_flags |= NFSLY_RETONCLOSE;
4746 1.1 dholland TAILQ_REMOVE(&clp->nfsc_layout, lyp, nfsly_list);
4747 1.1 dholland TAILQ_INSERT_HEAD(&clp->nfsc_layout, lyp, nfsly_list);
4748 1.1 dholland lyp->nfsly_timestamp = NFSD_MONOSEC + 120;
4749 1.1 dholland }
4750 1.1 dholland nfsv4_getref(&lyp->nfsly_lock, NULL, NFSCLSTATEMUTEXPTR, mp);
4751 1.1 dholland if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
4752 1.1 dholland NFSUNLOCKCLSTATE();
4753 1.1 dholland if (tlyp != NULL)
4754 1.1 dholland free(tlyp, M_NFSLAYOUT);
4755 1.1 dholland return (EPERM);
4756 1.1 dholland }
4757 1.1 dholland *lypp = lyp;
4758 1.1 dholland } else
4759 1.1 dholland lyp->nfsly_stateid.seqid = stateidp->seqid;
4760 1.1 dholland
4761 1.1 dholland /* Merge the new list of File Layouts into the list. */
4762 1.1 dholland flp = LIST_FIRST(fhlp);
4763 1.1 dholland if (flp != NULL) {
4764 1.1 dholland if (flp->nfsfl_iomode == NFSLAYOUTIOMODE_READ)
4765 1.1 dholland nfscl_mergeflayouts(&lyp->nfsly_flayread, fhlp);
4766 1.1 dholland else
4767 1.1 dholland nfscl_mergeflayouts(&lyp->nfsly_flayrw, fhlp);
4768 1.1 dholland }
4769 1.1 dholland if (layout_passed_in != 0)
4770 1.1 dholland nfsv4_unlock(&lyp->nfsly_lock, 1);
4771 1.1 dholland NFSUNLOCKCLSTATE();
4772 1.1 dholland if (tlyp != NULL)
4773 1.1 dholland free(tlyp, M_NFSLAYOUT);
4774 1.1 dholland return (0);
4775 1.1 dholland }
4776 1.1 dholland
4777 1.1 dholland /*
4778 1.1 dholland * Search for a layout by MDS file handle.
4779 1.1 dholland * If one is found, it is returned with a refcnt (shared lock) iff
4780 1.1 dholland * retflpp returned non-NULL and locked (exclusive locked) iff retflpp is
4781 1.1 dholland * returned NULL.
4782 1.1 dholland */
4783 1.1 dholland struct nfscllayout *
4784 1.1 dholland nfscl_getlayout(struct nfsclclient *clp, uint8_t *fhp, int fhlen,
4785 1.1 dholland uint64_t off, struct nfsclflayout **retflpp, int *recalledp)
4786 1.1 dholland {
4787 1.1 dholland struct nfscllayout *lyp;
4788 1.1 dholland mount_t mp;
4789 1.1 dholland int error, igotlock;
4790 1.1 dholland
4791 1.1 dholland mp = clp->nfsc_nmp->nm_mountp;
4792 1.1 dholland *recalledp = 0;
4793 1.1 dholland *retflpp = NULL;
4794 1.1 dholland NFSLOCKCLSTATE();
4795 1.1 dholland lyp = nfscl_findlayout(clp, fhp, fhlen);
4796 1.1 dholland if (lyp != NULL) {
4797 1.1 dholland if ((lyp->nfsly_flags & NFSLY_RECALL) == 0) {
4798 1.1 dholland TAILQ_REMOVE(&clp->nfsc_layout, lyp, nfsly_list);
4799 1.1 dholland TAILQ_INSERT_HEAD(&clp->nfsc_layout, lyp, nfsly_list);
4800 1.1 dholland lyp->nfsly_timestamp = NFSD_MONOSEC + 120;
4801 1.1 dholland error = nfscl_findlayoutforio(lyp, off,
4802 1.1 dholland NFSV4OPEN_ACCESSREAD, retflpp);
4803 1.1 dholland if (error == 0)
4804 1.1 dholland nfsv4_getref(&lyp->nfsly_lock, NULL,
4805 1.1 dholland NFSCLSTATEMUTEXPTR, mp);
4806 1.1 dholland else {
4807 1.1 dholland do {
4808 1.1 dholland igotlock = nfsv4_lock(&lyp->nfsly_lock,
4809 1.1 dholland 1, NULL, NFSCLSTATEMUTEXPTR, mp);
4810 1.1 dholland } while (igotlock == 0 &&
4811 1.1 dholland (mp->mnt_kern_flag & MNTK_UNMOUNTF) == 0);
4812 1.1 dholland *retflpp = NULL;
4813 1.1 dholland }
4814 1.1 dholland if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
4815 1.1 dholland lyp = NULL;
4816 1.1 dholland *recalledp = 1;
4817 1.1 dholland }
4818 1.1 dholland } else {
4819 1.1 dholland lyp = NULL;
4820 1.1 dholland *recalledp = 1;
4821 1.1 dholland }
4822 1.1 dholland }
4823 1.1 dholland NFSUNLOCKCLSTATE();
4824 1.1 dholland return (lyp);
4825 1.1 dholland }
4826 1.1 dholland
4827 1.1 dholland /*
4828 1.1 dholland * Search for a layout by MDS file handle. If one is found that is marked
4829 1.1 dholland * "return on close", delete it, since it should now be forgotten.
4830 1.1 dholland */
4831 1.1 dholland static void
4832 1.1 dholland nfscl_retoncloselayout(struct nfsclclient *clp, uint8_t *fhp, int fhlen)
4833 1.1 dholland {
4834 1.1 dholland struct nfscllayout *lyp;
4835 1.1 dholland
4836 1.1 dholland tryagain:
4837 1.1 dholland lyp = nfscl_findlayout(clp, fhp, fhlen);
4838 1.1 dholland if (lyp != NULL && (lyp->nfsly_flags & NFSLY_RETONCLOSE) != 0) {
4839 1.1 dholland /*
4840 1.1 dholland * Wait for outstanding I/O ops to be done.
4841 1.1 dholland */
4842 1.1 dholland if (lyp->nfsly_lock.nfslock_usecnt != 0 ||
4843 1.1 dholland lyp->nfsly_lock.nfslock_lock != 0) {
4844 1.1 dholland lyp->nfsly_lock.nfslock_lock |= NFSV4LOCK_WANTED;
4845 1.1 dholland (void)mtx_sleep(&lyp->nfsly_lock,
4846 1.1 dholland NFSCLSTATEMUTEXPTR, PZERO, "nfslyc", 0);
4847 1.1 dholland goto tryagain;
4848 1.1 dholland }
4849 1.1 dholland nfscl_freelayout(lyp);
4850 1.1 dholland }
4851 1.1 dholland }
4852 1.1 dholland
4853 1.1 dholland /*
4854 1.1 dholland * Dereference a layout.
4855 1.1 dholland */
4856 1.1 dholland void
4857 1.1 dholland nfscl_rellayout(struct nfscllayout *lyp, int exclocked)
4858 1.1 dholland {
4859 1.1 dholland
4860 1.1 dholland NFSLOCKCLSTATE();
4861 1.1 dholland if (exclocked != 0)
4862 1.1 dholland nfsv4_unlock(&lyp->nfsly_lock, 0);
4863 1.1 dholland else
4864 1.1 dholland nfsv4_relref(&lyp->nfsly_lock);
4865 1.1 dholland NFSUNLOCKCLSTATE();
4866 1.1 dholland }
4867 1.1 dholland
4868 1.1 dholland /*
4869 1.1 dholland * Search for a devinfo by deviceid. If one is found, return it after
4870 1.1 dholland * acquiring a reference count on it.
4871 1.1 dholland */
4872 1.1 dholland struct nfscldevinfo *
4873 1.1 dholland nfscl_getdevinfo(struct nfsclclient *clp, uint8_t *deviceid,
4874 1.1 dholland struct nfscldevinfo *dip)
4875 1.1 dholland {
4876 1.1 dholland
4877 1.1 dholland NFSLOCKCLSTATE();
4878 1.1 dholland if (dip == NULL)
4879 1.1 dholland dip = nfscl_finddevinfo(clp, deviceid);
4880 1.1 dholland if (dip != NULL)
4881 1.1 dholland dip->nfsdi_refcnt++;
4882 1.1 dholland NFSUNLOCKCLSTATE();
4883 1.1 dholland return (dip);
4884 1.1 dholland }
4885 1.1 dholland
4886 1.1 dholland /*
4887 1.1 dholland * Dereference a devinfo structure.
4888 1.1 dholland */
4889 1.1 dholland static void
4890 1.1 dholland nfscl_reldevinfo_locked(struct nfscldevinfo *dip)
4891 1.1 dholland {
4892 1.1 dholland
4893 1.1 dholland dip->nfsdi_refcnt--;
4894 1.1 dholland if (dip->nfsdi_refcnt == 0)
4895 1.1 dholland wakeup(&dip->nfsdi_refcnt);
4896 1.1 dholland }
4897 1.1 dholland
4898 1.1 dholland /*
4899 1.1 dholland * Dereference a devinfo structure.
4900 1.1 dholland */
4901 1.1 dholland void
4902 1.1 dholland nfscl_reldevinfo(struct nfscldevinfo *dip)
4903 1.1 dholland {
4904 1.1 dholland
4905 1.1 dholland NFSLOCKCLSTATE();
4906 1.1 dholland nfscl_reldevinfo_locked(dip);
4907 1.1 dholland NFSUNLOCKCLSTATE();
4908 1.1 dholland }
4909 1.1 dholland
4910 1.1 dholland /*
4911 1.1 dholland * Find a layout for this file handle. Return NULL upon failure.
4912 1.1 dholland */
4913 1.1 dholland static struct nfscllayout *
4914 1.1 dholland nfscl_findlayout(struct nfsclclient *clp, u_int8_t *fhp, int fhlen)
4915 1.1 dholland {
4916 1.1 dholland struct nfscllayout *lyp;
4917 1.1 dholland
4918 1.1 dholland LIST_FOREACH(lyp, NFSCLLAYOUTHASH(clp, fhp, fhlen), nfsly_hash)
4919 1.1 dholland if (lyp->nfsly_fhlen == fhlen &&
4920 1.1 dholland !NFSBCMP(lyp->nfsly_fh, fhp, fhlen))
4921 1.1 dholland break;
4922 1.1 dholland return (lyp);
4923 1.1 dholland }
4924 1.1 dholland
4925 1.1 dholland /*
4926 1.1 dholland * Find a devinfo for this deviceid. Return NULL upon failure.
4927 1.1 dholland */
4928 1.1 dholland static struct nfscldevinfo *
4929 1.1 dholland nfscl_finddevinfo(struct nfsclclient *clp, uint8_t *deviceid)
4930 1.1 dholland {
4931 1.1 dholland struct nfscldevinfo *dip;
4932 1.1 dholland
4933 1.1 dholland LIST_FOREACH(dip, &clp->nfsc_devinfo, nfsdi_list)
4934 1.1 dholland if (NFSBCMP(dip->nfsdi_deviceid, deviceid, NFSX_V4DEVICEID)
4935 1.1 dholland == 0)
4936 1.1 dholland break;
4937 1.1 dholland return (dip);
4938 1.1 dholland }
4939 1.1 dholland
4940 1.1 dholland /*
4941 1.1 dholland * Merge the new file layout list into the main one, maintaining it in
4942 1.1 dholland * increasing offset order.
4943 1.1 dholland */
4944 1.1 dholland static void
4945 1.1 dholland nfscl_mergeflayouts(struct nfsclflayouthead *fhlp,
4946 1.1 dholland struct nfsclflayouthead *newfhlp)
4947 1.1 dholland {
4948 1.1 dholland struct nfsclflayout *flp, *nflp, *prevflp, *tflp;
4949 1.1 dholland
4950 1.1 dholland flp = LIST_FIRST(fhlp);
4951 1.1 dholland prevflp = NULL;
4952 1.1 dholland LIST_FOREACH_SAFE(nflp, newfhlp, nfsfl_list, tflp) {
4953 1.1 dholland while (flp != NULL && flp->nfsfl_off < nflp->nfsfl_off) {
4954 1.1 dholland prevflp = flp;
4955 1.1 dholland flp = LIST_NEXT(flp, nfsfl_list);
4956 1.1 dholland }
4957 1.1 dholland if (prevflp == NULL)
4958 1.1 dholland LIST_INSERT_HEAD(fhlp, nflp, nfsfl_list);
4959 1.1 dholland else
4960 1.1 dholland LIST_INSERT_AFTER(prevflp, nflp, nfsfl_list);
4961 1.1 dholland prevflp = nflp;
4962 1.1 dholland }
4963 1.1 dholland }
4964 1.1 dholland
4965 1.1 dholland /*
4966 1.1 dholland * Add this nfscldevinfo to the client, if it doesn't already exist.
4967 1.1 dholland * This function consumes the structure pointed at by dip, if not NULL.
4968 1.1 dholland */
4969 1.1 dholland APPLESTATIC int
4970 1.1 dholland nfscl_adddevinfo(struct nfsmount *nmp, struct nfscldevinfo *dip,
4971 1.1 dholland struct nfsclflayout *flp)
4972 1.1 dholland {
4973 1.1 dholland struct nfsclclient *clp;
4974 1.1 dholland struct nfscldevinfo *tdip;
4975 1.1 dholland
4976 1.1 dholland NFSLOCKCLSTATE();
4977 1.1 dholland clp = nmp->nm_clp;
4978 1.1 dholland if (clp == NULL) {
4979 1.1 dholland NFSUNLOCKCLSTATE();
4980 1.1 dholland if (dip != NULL)
4981 1.1 dholland free(dip, M_NFSDEVINFO);
4982 1.1 dholland return (ENODEV);
4983 1.1 dholland }
4984 1.1 dholland tdip = nfscl_finddevinfo(clp, flp->nfsfl_dev);
4985 1.1 dholland if (tdip != NULL) {
4986 1.1 dholland tdip->nfsdi_layoutrefs++;
4987 1.1 dholland flp->nfsfl_devp = tdip;
4988 1.1 dholland nfscl_reldevinfo_locked(tdip);
4989 1.1 dholland NFSUNLOCKCLSTATE();
4990 1.1 dholland if (dip != NULL)
4991 1.1 dholland free(dip, M_NFSDEVINFO);
4992 1.1 dholland return (0);
4993 1.1 dholland }
4994 1.1 dholland if (dip != NULL) {
4995 1.1 dholland LIST_INSERT_HEAD(&clp->nfsc_devinfo, dip, nfsdi_list);
4996 1.1 dholland dip->nfsdi_layoutrefs = 1;
4997 1.1 dholland flp->nfsfl_devp = dip;
4998 1.1 dholland }
4999 1.1 dholland NFSUNLOCKCLSTATE();
5000 1.1 dholland if (dip == NULL)
5001 1.1 dholland return (ENODEV);
5002 1.1 dholland return (0);
5003 1.1 dholland }
5004 1.1 dholland
5005 1.1 dholland /*
5006 1.1 dholland * Free up a layout structure and associated file layout structure(s).
5007 1.1 dholland */
5008 1.1 dholland APPLESTATIC void
5009 1.1 dholland nfscl_freelayout(struct nfscllayout *layp)
5010 1.1 dholland {
5011 1.1 dholland struct nfsclflayout *flp, *nflp;
5012 1.1 dholland struct nfsclrecalllayout *rp, *nrp;
5013 1.1 dholland
5014 1.1 dholland LIST_FOREACH_SAFE(flp, &layp->nfsly_flayread, nfsfl_list, nflp) {
5015 1.1 dholland LIST_REMOVE(flp, nfsfl_list);
5016 1.1 dholland nfscl_freeflayout(flp);
5017 1.1 dholland }
5018 1.1 dholland LIST_FOREACH_SAFE(flp, &layp->nfsly_flayrw, nfsfl_list, nflp) {
5019 1.1 dholland LIST_REMOVE(flp, nfsfl_list);
5020 1.1 dholland nfscl_freeflayout(flp);
5021 1.1 dholland }
5022 1.1 dholland LIST_FOREACH_SAFE(rp, &layp->nfsly_recall, nfsrecly_list, nrp) {
5023 1.1 dholland LIST_REMOVE(rp, nfsrecly_list);
5024 1.1 dholland free(rp, M_NFSLAYRECALL);
5025 1.1 dholland }
5026 1.1 dholland nfscl_layoutcnt--;
5027 1.1 dholland free(layp, M_NFSLAYOUT);
5028 1.1 dholland }
5029 1.1 dholland
5030 1.1 dholland /*
5031 1.1 dholland * Free up a file layout structure.
5032 1.1 dholland */
5033 1.1 dholland APPLESTATIC void
5034 1.1 dholland nfscl_freeflayout(struct nfsclflayout *flp)
5035 1.1 dholland {
5036 1.1 dholland int i;
5037 1.1 dholland
5038 1.1 dholland for (i = 0; i < flp->nfsfl_fhcnt; i++)
5039 1.1 dholland free(flp->nfsfl_fh[i], M_NFSFH);
5040 1.1 dholland if (flp->nfsfl_devp != NULL)
5041 1.1 dholland flp->nfsfl_devp->nfsdi_layoutrefs--;
5042 1.1 dholland free(flp, M_NFSFLAYOUT);
5043 1.1 dholland }
5044 1.1 dholland
5045 1.1 dholland /*
5046 1.1 dholland * Free up a file layout devinfo structure.
5047 1.1 dholland */
5048 1.1 dholland APPLESTATIC void
5049 1.1 dholland nfscl_freedevinfo(struct nfscldevinfo *dip)
5050 1.1 dholland {
5051 1.1 dholland
5052 1.1 dholland free(dip, M_NFSDEVINFO);
5053 1.1 dholland }
5054 1.1 dholland
5055 1.1 dholland /*
5056 1.1 dholland * Mark any layouts that match as recalled.
5057 1.1 dholland */
5058 1.1 dholland static int
5059 1.1 dholland nfscl_layoutrecall(int recalltype, struct nfscllayout *lyp, uint32_t iomode,
5060 1.1 dholland uint64_t off, uint64_t len, uint32_t stateseqid,
5061 1.1 dholland struct nfsclrecalllayout *recallp)
5062 1.1 dholland {
5063 1.1 dholland struct nfsclrecalllayout *rp, *orp;
5064 1.1 dholland
5065 1.1 dholland recallp->nfsrecly_recalltype = recalltype;
5066 1.1 dholland recallp->nfsrecly_iomode = iomode;
5067 1.1 dholland recallp->nfsrecly_stateseqid = stateseqid;
5068 1.1 dholland recallp->nfsrecly_off = off;
5069 1.1 dholland recallp->nfsrecly_len = len;
5070 1.1 dholland /*
5071 1.1 dholland * Order the list as file returns first, followed by fsid and any
5072 1.1 dholland * returns, both in increasing stateseqid order.
5073 1.1 dholland * Note that the seqids wrap around, so 1 is after 0xffffffff.
5074 1.1 dholland * (I'm not sure this is correct because I find RFC5661 confusing
5075 1.1 dholland * on this, but hopefully it will work ok.)
5076 1.1 dholland */
5077 1.1 dholland orp = NULL;
5078 1.1 dholland LIST_FOREACH(rp, &lyp->nfsly_recall, nfsrecly_list) {
5079 1.1 dholland orp = rp;
5080 1.1 dholland if ((recalltype == NFSLAYOUTRETURN_FILE &&
5081 1.1 dholland (rp->nfsrecly_recalltype != NFSLAYOUTRETURN_FILE ||
5082 1.1 dholland nfscl_seq(stateseqid, rp->nfsrecly_stateseqid) != 0)) ||
5083 1.1 dholland (recalltype != NFSLAYOUTRETURN_FILE &&
5084 1.1 dholland rp->nfsrecly_recalltype != NFSLAYOUTRETURN_FILE &&
5085 1.1 dholland nfscl_seq(stateseqid, rp->nfsrecly_stateseqid) != 0)) {
5086 1.1 dholland LIST_INSERT_BEFORE(rp, recallp, nfsrecly_list);
5087 1.1 dholland break;
5088 1.1 dholland }
5089 1.1 dholland }
5090 1.1 dholland if (rp == NULL) {
5091 1.1 dholland if (orp == NULL)
5092 1.1 dholland LIST_INSERT_HEAD(&lyp->nfsly_recall, recallp,
5093 1.1 dholland nfsrecly_list);
5094 1.1 dholland else
5095 1.1 dholland LIST_INSERT_AFTER(orp, recallp, nfsrecly_list);
5096 1.1 dholland }
5097 1.1 dholland lyp->nfsly_flags |= NFSLY_RECALL;
5098 1.1 dholland return (0);
5099 1.1 dholland }
5100 1.1 dholland
5101 1.1 dholland /*
5102 1.1 dholland * Compare the two seqids for ordering. The trick is that the seqids can
5103 1.1 dholland * wrap around from 0xffffffff->0, so check for the cases where one
5104 1.1 dholland * has wrapped around.
5105 1.1 dholland * Return 1 if seqid1 comes before seqid2, 0 otherwise.
5106 1.1 dholland */
5107 1.1 dholland static int
5108 1.1 dholland nfscl_seq(uint32_t seqid1, uint32_t seqid2)
5109 1.1 dholland {
5110 1.1 dholland
5111 1.1 dholland if (seqid2 > seqid1 && (seqid2 - seqid1) >= 0x7fffffff)
5112 1.1 dholland /* seqid2 has wrapped around. */
5113 1.1 dholland return (0);
5114 1.1 dholland if (seqid1 > seqid2 && (seqid1 - seqid2) >= 0x7fffffff)
5115 1.1 dholland /* seqid1 has wrapped around. */
5116 1.1 dholland return (1);
5117 1.1 dholland if (seqid1 <= seqid2)
5118 1.1 dholland return (1);
5119 1.1 dholland return (0);
5120 1.1 dholland }
5121 1.1 dholland
5122 1.1 dholland /*
5123 1.1 dholland * Do a layout return for each of the recalls.
5124 1.1 dholland */
5125 1.1 dholland static void
5126 1.1 dholland nfscl_layoutreturn(struct nfsmount *nmp, struct nfscllayout *lyp,
5127 1.1 dholland struct ucred *cred, NFSPROC_T *p)
5128 1.1 dholland {
5129 1.1 dholland struct nfsclrecalllayout *rp;
5130 1.1 dholland nfsv4stateid_t stateid;
5131 1.1 dholland
5132 1.1 dholland NFSBCOPY(lyp->nfsly_stateid.other, stateid.other, NFSX_STATEIDOTHER);
5133 1.1 dholland LIST_FOREACH(rp, &lyp->nfsly_recall, nfsrecly_list) {
5134 1.1 dholland stateid.seqid = rp->nfsrecly_stateseqid;
5135 1.1 dholland (void)nfsrpc_layoutreturn(nmp, lyp->nfsly_fh,
5136 1.1 dholland lyp->nfsly_fhlen, 0, NFSLAYOUT_NFSV4_1_FILES,
5137 1.1 dholland rp->nfsrecly_iomode, rp->nfsrecly_recalltype,
5138 1.1 dholland rp->nfsrecly_off, rp->nfsrecly_len,
5139 1.1 dholland &stateid, 0, NULL, cred, p, NULL);
5140 1.1 dholland }
5141 1.1 dholland }
5142 1.1 dholland
5143 1.1 dholland /*
5144 1.1 dholland * Do the layout commit for a file layout.
5145 1.1 dholland */
5146 1.1 dholland static void
5147 1.1 dholland nfscl_dolayoutcommit(struct nfsmount *nmp, struct nfscllayout *lyp,
5148 1.1 dholland struct ucred *cred, NFSPROC_T *p)
5149 1.1 dholland {
5150 1.1 dholland struct nfsclflayout *flp;
5151 1.1 dholland uint64_t len;
5152 1.1 dholland int error;
5153 1.1 dholland
5154 1.1 dholland LIST_FOREACH(flp, &lyp->nfsly_flayrw, nfsfl_list) {
5155 1.1 dholland if (flp->nfsfl_off <= lyp->nfsly_lastbyte) {
5156 1.1 dholland len = flp->nfsfl_end - flp->nfsfl_off;
5157 1.1 dholland error = nfsrpc_layoutcommit(nmp, lyp->nfsly_fh,
5158 1.1 dholland lyp->nfsly_fhlen, 0, flp->nfsfl_off, len,
5159 1.1 dholland lyp->nfsly_lastbyte, &lyp->nfsly_stateid,
5160 1.1 dholland NFSLAYOUT_NFSV4_1_FILES, 0, NULL, cred, p, NULL);
5161 1.1 dholland NFSCL_DEBUG(4, "layoutcommit err=%d\n", error);
5162 1.1 dholland if (error == NFSERR_NOTSUPP) {
5163 1.1 dholland /* If not supported, don't bother doing it. */
5164 1.1 dholland NFSLOCKMNT(nmp);
5165 1.1 dholland nmp->nm_state |= NFSSTA_NOLAYOUTCOMMIT;
5166 1.1 dholland NFSUNLOCKMNT(nmp);
5167 1.1 dholland break;
5168 1.1 dholland }
5169 1.1 dholland }
5170 1.1 dholland }
5171 1.1 dholland }
5172 1.1 dholland
5173 1.1 dholland /*
5174 1.1 dholland * Commit all layouts for a file (vnode).
5175 1.1 dholland */
5176 1.1 dholland int
5177 1.1 dholland nfscl_layoutcommit(vnode_t vp, NFSPROC_T *p)
5178 1.1 dholland {
5179 1.1 dholland struct nfsclclient *clp;
5180 1.1 dholland struct nfscllayout *lyp;
5181 1.1 dholland struct nfsnode *np = VTONFS(vp);
5182 1.1 dholland mount_t mp;
5183 1.1 dholland struct nfsmount *nmp;
5184 1.1 dholland
5185 1.1 dholland mp = vnode_mount(vp);
5186 1.1 dholland nmp = VFSTONFS(mp);
5187 1.1 dholland if (NFSHASNOLAYOUTCOMMIT(nmp))
5188 1.1 dholland return (0);
5189 1.1 dholland NFSLOCKCLSTATE();
5190 1.1 dholland clp = nmp->nm_clp;
5191 1.1 dholland if (clp == NULL) {
5192 1.1 dholland NFSUNLOCKCLSTATE();
5193 1.1 dholland return (EPERM);
5194 1.1 dholland }
5195 1.1 dholland lyp = nfscl_findlayout(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
5196 1.1 dholland if (lyp == NULL) {
5197 1.1 dholland NFSUNLOCKCLSTATE();
5198 1.1 dholland return (EPERM);
5199 1.1 dholland }
5200 1.1 dholland nfsv4_getref(&lyp->nfsly_lock, NULL, NFSCLSTATEMUTEXPTR, mp);
5201 1.1 dholland if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
5202 1.1 dholland NFSUNLOCKCLSTATE();
5203 1.1 dholland return (EPERM);
5204 1.1 dholland }
5205 1.1 dholland tryagain:
5206 1.1 dholland if ((lyp->nfsly_flags & NFSLY_WRITTEN) != 0) {
5207 1.1 dholland lyp->nfsly_flags &= ~NFSLY_WRITTEN;
5208 1.1 dholland NFSUNLOCKCLSTATE();
5209 1.1 dholland NFSCL_DEBUG(4, "do layoutcommit2\n");
5210 1.1 dholland nfscl_dolayoutcommit(clp->nfsc_nmp, lyp, NFSPROCCRED(p), p);
5211 1.1 dholland NFSLOCKCLSTATE();
5212 1.1 dholland goto tryagain;
5213 1.1 dholland }
5214 1.1 dholland nfsv4_relref(&lyp->nfsly_lock);
5215 1.1 dholland NFSUNLOCKCLSTATE();
5216 1.1 dholland return (0);
5217 1.1 dholland }
5218 1.1 dholland
5219