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