Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * linux/fs/nfs/delegation.c
4 : : *
5 : : * Copyright (C) 2004 Trond Myklebust
6 : : *
7 : : * NFS file delegation management
8 : : *
9 : : */
10 : : #include <linux/completion.h>
11 : : #include <linux/kthread.h>
12 : : #include <linux/module.h>
13 : : #include <linux/sched.h>
14 : : #include <linux/slab.h>
15 : : #include <linux/spinlock.h>
16 : : #include <linux/iversion.h>
17 : :
18 : : #include <linux/nfs4.h>
19 : : #include <linux/nfs_fs.h>
20 : : #include <linux/nfs_xdr.h>
21 : :
22 : : #include "nfs4_fs.h"
23 : : #include "nfs4session.h"
24 : : #include "delegation.h"
25 : : #include "internal.h"
26 : : #include "nfs4trace.h"
27 : :
28 : 0 : static void nfs_free_delegation(struct nfs_delegation *delegation)
29 : : {
30 : 0 : put_cred(delegation->cred);
31 : 0 : delegation->cred = NULL;
32 [ # # ]: 0 : kfree_rcu(delegation, rcu);
33 : 0 : }
34 : :
35 : : /**
36 : : * nfs_mark_delegation_referenced - set delegation's REFERENCED flag
37 : : * @delegation: delegation to process
38 : : *
39 : : */
40 : 0 : void nfs_mark_delegation_referenced(struct nfs_delegation *delegation)
41 : : {
42 : 0 : set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags);
43 : 0 : }
44 : :
45 : : static bool
46 : : nfs4_is_valid_delegation(const struct nfs_delegation *delegation,
47 : : fmode_t flags)
48 : : {
49 [ # # # # : 0 : if (delegation != NULL && (delegation->type & flags) == flags &&
# # # # #
# # # # #
# # ]
50 [ # # # # : 0 : !test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) &&
# # ]
51 : : !test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
52 : : return true;
53 : : return false;
54 : : }
55 : :
56 : 0 : struct nfs_delegation *nfs4_get_valid_delegation(const struct inode *inode)
57 : : {
58 : : struct nfs_delegation *delegation;
59 : :
60 : 0 : delegation = rcu_dereference(NFS_I(inode)->delegation);
61 [ # # ]: 0 : if (nfs4_is_valid_delegation(delegation, 0))
62 : 0 : return delegation;
63 : : return NULL;
64 : : }
65 : :
66 : : static int
67 : 0 : nfs4_do_check_delegation(struct inode *inode, fmode_t flags, bool mark)
68 : : {
69 : : struct nfs_delegation *delegation;
70 : : int ret = 0;
71 : :
72 : 0 : flags &= FMODE_READ|FMODE_WRITE;
73 : : rcu_read_lock();
74 : 0 : delegation = rcu_dereference(NFS_I(inode)->delegation);
75 [ # # ]: 0 : if (nfs4_is_valid_delegation(delegation, flags)) {
76 [ # # ]: 0 : if (mark)
77 : : nfs_mark_delegation_referenced(delegation);
78 : : ret = 1;
79 : : }
80 : : rcu_read_unlock();
81 : 0 : return ret;
82 : : }
83 : : /**
84 : : * nfs_have_delegation - check if inode has a delegation, mark it
85 : : * NFS_DELEGATION_REFERENCED if there is one.
86 : : * @inode: inode to check
87 : : * @flags: delegation types to check for
88 : : *
89 : : * Returns one if inode has the indicated delegation, otherwise zero.
90 : : */
91 : 0 : int nfs4_have_delegation(struct inode *inode, fmode_t flags)
92 : : {
93 : 0 : return nfs4_do_check_delegation(inode, flags, true);
94 : : }
95 : :
96 : : /*
97 : : * nfs4_check_delegation - check if inode has a delegation, do not mark
98 : : * NFS_DELEGATION_REFERENCED if it has one.
99 : : */
100 : 0 : int nfs4_check_delegation(struct inode *inode, fmode_t flags)
101 : : {
102 : 0 : return nfs4_do_check_delegation(inode, flags, false);
103 : : }
104 : :
105 : 0 : static int nfs_delegation_claim_locks(struct nfs4_state *state, const nfs4_stateid *stateid)
106 : : {
107 : 0 : struct inode *inode = state->inode;
108 : : struct file_lock *fl;
109 : 0 : struct file_lock_context *flctx = inode->i_flctx;
110 : : struct list_head *list;
111 : : int status = 0;
112 : :
113 [ # # ]: 0 : if (flctx == NULL)
114 : : goto out;
115 : :
116 : 0 : list = &flctx->flc_posix;
117 : : spin_lock(&flctx->flc_lock);
118 : : restart:
119 [ # # ]: 0 : list_for_each_entry(fl, list, fl_list) {
120 [ # # ]: 0 : if (nfs_file_open_context(fl->fl_file)->state != state)
121 : 0 : continue;
122 : : spin_unlock(&flctx->flc_lock);
123 : 0 : status = nfs4_lock_delegation_recall(fl, state, stateid);
124 [ # # ]: 0 : if (status < 0)
125 : : goto out;
126 : : spin_lock(&flctx->flc_lock);
127 : : }
128 [ # # ]: 0 : if (list == &flctx->flc_posix) {
129 : 0 : list = &flctx->flc_flock;
130 : 0 : goto restart;
131 : : }
132 : : spin_unlock(&flctx->flc_lock);
133 : : out:
134 : 0 : return status;
135 : : }
136 : :
137 : 0 : static int nfs_delegation_claim_opens(struct inode *inode,
138 : : const nfs4_stateid *stateid, fmode_t type)
139 : : {
140 : : struct nfs_inode *nfsi = NFS_I(inode);
141 : : struct nfs_open_context *ctx;
142 : : struct nfs4_state_owner *sp;
143 : : struct nfs4_state *state;
144 : : unsigned int seq;
145 : : int err;
146 : :
147 : : again:
148 : : rcu_read_lock();
149 [ # # ]: 0 : list_for_each_entry_rcu(ctx, &nfsi->open_files, list) {
150 : 0 : state = ctx->state;
151 [ # # ]: 0 : if (state == NULL)
152 : 0 : continue;
153 [ # # ]: 0 : if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
154 : 0 : continue;
155 [ # # ]: 0 : if (!nfs4_valid_open_stateid(state))
156 : 0 : continue;
157 [ # # ]: 0 : if (!nfs4_stateid_match(&state->stateid, stateid))
158 : 0 : continue;
159 [ # # ]: 0 : if (!get_nfs_open_context(ctx))
160 : 0 : continue;
161 : : rcu_read_unlock();
162 : 0 : sp = state->owner;
163 : : /* Block nfs4_proc_unlck */
164 : 0 : mutex_lock(&sp->so_delegreturn_mutex);
165 : : seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
166 : 0 : err = nfs4_open_delegation_recall(ctx, state, stateid);
167 [ # # ]: 0 : if (!err)
168 : 0 : err = nfs_delegation_claim_locks(state, stateid);
169 [ # # # # ]: 0 : if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
170 : : err = -EAGAIN;
171 : 0 : mutex_unlock(&sp->so_delegreturn_mutex);
172 : 0 : put_nfs_open_context(ctx);
173 [ # # ]: 0 : if (err != 0)
174 : 0 : return err;
175 : : goto again;
176 : : }
177 : : rcu_read_unlock();
178 : 0 : return 0;
179 : : }
180 : :
181 : : /**
182 : : * nfs_inode_reclaim_delegation - process a delegation reclaim request
183 : : * @inode: inode to process
184 : : * @cred: credential to use for request
185 : : * @type: delegation type
186 : : * @stateid: delegation stateid
187 : : * @pagemod_limit: write delegation "space_limit"
188 : : *
189 : : */
190 : 0 : void nfs_inode_reclaim_delegation(struct inode *inode, const struct cred *cred,
191 : : fmode_t type,
192 : : const nfs4_stateid *stateid,
193 : : unsigned long pagemod_limit)
194 : : {
195 : : struct nfs_delegation *delegation;
196 : : const struct cred *oldcred = NULL;
197 : :
198 : : rcu_read_lock();
199 : : delegation = rcu_dereference(NFS_I(inode)->delegation);
200 [ # # ]: 0 : if (delegation != NULL) {
201 : : spin_lock(&delegation->lock);
202 [ # # ]: 0 : if (delegation->inode != NULL) {
203 : : nfs4_stateid_copy(&delegation->stateid, stateid);
204 : 0 : delegation->type = type;
205 : 0 : delegation->pagemod_limit = pagemod_limit;
206 : 0 : oldcred = delegation->cred;
207 : 0 : delegation->cred = get_cred(cred);
208 : 0 : clear_bit(NFS_DELEGATION_NEED_RECLAIM,
209 : : &delegation->flags);
210 : : spin_unlock(&delegation->lock);
211 : : rcu_read_unlock();
212 : 0 : put_cred(oldcred);
213 : 0 : trace_nfs4_reclaim_delegation(inode, type);
214 : 0 : return;
215 : : }
216 : : /* We appear to have raced with a delegation return. */
217 : : spin_unlock(&delegation->lock);
218 : : }
219 : : rcu_read_unlock();
220 : 0 : nfs_inode_set_delegation(inode, cred, type, stateid, pagemod_limit);
221 : : }
222 : :
223 : 0 : static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync)
224 : : {
225 : : int res = 0;
226 : :
227 [ # # ]: 0 : if (!test_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
228 : 0 : res = nfs4_proc_delegreturn(inode,
229 : : delegation->cred,
230 : 0 : &delegation->stateid,
231 : : issync);
232 : 0 : nfs_free_delegation(delegation);
233 : 0 : return res;
234 : : }
235 : :
236 : 0 : static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation)
237 : : {
238 : : struct inode *inode = NULL;
239 : :
240 : : spin_lock(&delegation->lock);
241 [ # # ]: 0 : if (delegation->inode != NULL)
242 : 0 : inode = igrab(delegation->inode);
243 [ # # ]: 0 : if (!inode)
244 : 0 : set_bit(NFS_DELEGATION_INODE_FREEING, &delegation->flags);
245 : : spin_unlock(&delegation->lock);
246 : 0 : return inode;
247 : : }
248 : :
249 : : static struct nfs_delegation *
250 : 0 : nfs_start_delegation_return_locked(struct nfs_inode *nfsi)
251 : : {
252 : : struct nfs_delegation *ret = NULL;
253 : 0 : struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation);
254 : :
255 [ # # ]: 0 : if (delegation == NULL)
256 : : goto out;
257 : : spin_lock(&delegation->lock);
258 [ # # ]: 0 : if (!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
259 : : ret = delegation;
260 : : spin_unlock(&delegation->lock);
261 : : out:
262 : 0 : return ret;
263 : : }
264 : :
265 : : static struct nfs_delegation *
266 : : nfs_start_delegation_return(struct nfs_inode *nfsi)
267 : : {
268 : : struct nfs_delegation *delegation;
269 : :
270 : : rcu_read_lock();
271 : 0 : delegation = nfs_start_delegation_return_locked(nfsi);
272 : : rcu_read_unlock();
273 : : return delegation;
274 : : }
275 : :
276 : : static void
277 : 0 : nfs_abort_delegation_return(struct nfs_delegation *delegation,
278 : : struct nfs_client *clp)
279 : : {
280 : :
281 : : spin_lock(&delegation->lock);
282 : 0 : clear_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
283 : 0 : set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
284 : : spin_unlock(&delegation->lock);
285 : 0 : set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
286 : 0 : }
287 : :
288 : : static struct nfs_delegation *
289 : 0 : nfs_detach_delegation_locked(struct nfs_inode *nfsi,
290 : : struct nfs_delegation *delegation,
291 : : struct nfs_client *clp)
292 : : {
293 : : struct nfs_delegation *deleg_cur =
294 : 0 : rcu_dereference_protected(nfsi->delegation,
295 : : lockdep_is_held(&clp->cl_lock));
296 : :
297 [ # # ]: 0 : if (deleg_cur == NULL || delegation != deleg_cur)
298 : : return NULL;
299 : :
300 : : spin_lock(&delegation->lock);
301 : 0 : set_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
302 : : list_del_rcu(&delegation->super_list);
303 : 0 : delegation->inode = NULL;
304 : : rcu_assign_pointer(nfsi->delegation, NULL);
305 : : spin_unlock(&delegation->lock);
306 : 0 : return delegation;
307 : : }
308 : :
309 : 0 : static struct nfs_delegation *nfs_detach_delegation(struct nfs_inode *nfsi,
310 : : struct nfs_delegation *delegation,
311 : : struct nfs_server *server)
312 : : {
313 : 0 : struct nfs_client *clp = server->nfs_client;
314 : :
315 : : spin_lock(&clp->cl_lock);
316 : 0 : delegation = nfs_detach_delegation_locked(nfsi, delegation, clp);
317 : : spin_unlock(&clp->cl_lock);
318 : 0 : return delegation;
319 : : }
320 : :
321 : : static struct nfs_delegation *
322 : 0 : nfs_inode_detach_delegation(struct inode *inode)
323 : : {
324 : : struct nfs_inode *nfsi = NFS_I(inode);
325 : : struct nfs_server *server = NFS_SERVER(inode);
326 : : struct nfs_delegation *delegation;
327 : :
328 : : delegation = nfs_start_delegation_return(nfsi);
329 [ # # ]: 0 : if (delegation == NULL)
330 : : return NULL;
331 : 0 : return nfs_detach_delegation(nfsi, delegation, server);
332 : : }
333 : :
334 : : static void
335 : : nfs_update_inplace_delegation(struct nfs_delegation *delegation,
336 : : const struct nfs_delegation *update)
337 : : {
338 [ # # ]: 0 : if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid)) {
339 : 0 : delegation->stateid.seqid = update->stateid.seqid;
340 : 0 : smp_wmb();
341 : 0 : delegation->type = update->type;
342 : : }
343 : : }
344 : :
345 : : /**
346 : : * nfs_inode_set_delegation - set up a delegation on an inode
347 : : * @inode: inode to which delegation applies
348 : : * @cred: cred to use for subsequent delegation processing
349 : : * @type: delegation type
350 : : * @stateid: delegation stateid
351 : : * @pagemod_limit: write delegation "space_limit"
352 : : *
353 : : * Returns zero on success, or a negative errno value.
354 : : */
355 : 0 : int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
356 : : fmode_t type,
357 : : const nfs4_stateid *stateid,
358 : : unsigned long pagemod_limit)
359 : : {
360 : : struct nfs_server *server = NFS_SERVER(inode);
361 : 0 : struct nfs_client *clp = server->nfs_client;
362 : : struct nfs_inode *nfsi = NFS_I(inode);
363 : : struct nfs_delegation *delegation, *old_delegation;
364 : : struct nfs_delegation *freeme = NULL;
365 : : int status = 0;
366 : :
367 : : delegation = kmalloc(sizeof(*delegation), GFP_NOFS);
368 [ # # ]: 0 : if (delegation == NULL)
369 : : return -ENOMEM;
370 : : nfs4_stateid_copy(&delegation->stateid, stateid);
371 : 0 : delegation->type = type;
372 : 0 : delegation->pagemod_limit = pagemod_limit;
373 : 0 : delegation->change_attr = inode_peek_iversion_raw(inode);
374 : 0 : delegation->cred = get_cred(cred);
375 : 0 : delegation->inode = inode;
376 : 0 : delegation->flags = 1<<NFS_DELEGATION_REFERENCED;
377 : 0 : spin_lock_init(&delegation->lock);
378 : :
379 : : spin_lock(&clp->cl_lock);
380 : 0 : old_delegation = rcu_dereference_protected(nfsi->delegation,
381 : : lockdep_is_held(&clp->cl_lock));
382 [ # # ]: 0 : if (old_delegation != NULL) {
383 : : /* Is this an update of the existing delegation? */
384 [ # # ]: 0 : if (nfs4_stateid_match_other(&old_delegation->stateid,
385 : : &delegation->stateid)) {
386 : : nfs_update_inplace_delegation(old_delegation,
387 : : delegation);
388 : : goto out;
389 : : }
390 : : /*
391 : : * Deal with broken servers that hand out two
392 : : * delegations for the same file.
393 : : * Allow for upgrades to a WRITE delegation, but
394 : : * nothing else.
395 : : */
396 : : dfprintk(FILE, "%s: server %s handed out "
397 : : "a duplicate delegation!\n",
398 : : __func__, clp->cl_hostname);
399 [ # # # # ]: 0 : if (delegation->type == old_delegation->type ||
400 : 0 : !(delegation->type & FMODE_WRITE)) {
401 : : freeme = delegation;
402 : : delegation = NULL;
403 : : goto out;
404 : : }
405 [ # # ]: 0 : if (test_and_set_bit(NFS_DELEGATION_RETURNING,
406 : : &old_delegation->flags))
407 : : goto out;
408 : 0 : freeme = nfs_detach_delegation_locked(nfsi,
409 : : old_delegation, clp);
410 [ # # ]: 0 : if (freeme == NULL)
411 : : goto out;
412 : : }
413 : 0 : list_add_tail_rcu(&delegation->super_list, &server->delegations);
414 : 0 : rcu_assign_pointer(nfsi->delegation, delegation);
415 : : delegation = NULL;
416 : :
417 : 0 : trace_nfs4_set_delegation(inode, type);
418 : :
419 : : spin_lock(&inode->i_lock);
420 [ # # ]: 0 : if (NFS_I(inode)->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME))
421 : 0 : NFS_I(inode)->cache_validity |= NFS_INO_REVAL_FORCED;
422 : : spin_unlock(&inode->i_lock);
423 : : out:
424 : : spin_unlock(&clp->cl_lock);
425 [ # # ]: 0 : if (delegation != NULL)
426 : 0 : nfs_free_delegation(delegation);
427 [ # # ]: 0 : if (freeme != NULL)
428 : 0 : nfs_do_return_delegation(inode, freeme, 0);
429 : : return status;
430 : : }
431 : :
432 : : /*
433 : : * Basic procedure for returning a delegation to the server
434 : : */
435 : 0 : static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation *delegation, int issync)
436 : : {
437 : 0 : struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
438 : : struct nfs_inode *nfsi = NFS_I(inode);
439 : : int err = 0;
440 : :
441 [ # # ]: 0 : if (delegation == NULL)
442 : : return 0;
443 : : do {
444 [ # # ]: 0 : if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
445 : : break;
446 : 0 : err = nfs_delegation_claim_opens(inode, &delegation->stateid,
447 : : delegation->type);
448 [ # # ]: 0 : if (!issync || err != -EAGAIN)
449 : : break;
450 : : /*
451 : : * Guard against state recovery
452 : : */
453 : 0 : err = nfs4_wait_clnt_recover(clp);
454 [ # # ]: 0 : } while (err == 0);
455 : :
456 [ # # ]: 0 : if (err) {
457 : 0 : nfs_abort_delegation_return(delegation, clp);
458 : 0 : goto out;
459 : : }
460 [ # # ]: 0 : if (!nfs_detach_delegation(nfsi, delegation, NFS_SERVER(inode)))
461 : : goto out;
462 : :
463 : 0 : err = nfs_do_return_delegation(inode, delegation, issync);
464 : : out:
465 : 0 : return err;
466 : : }
467 : :
468 : 0 : static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
469 : : {
470 : : bool ret = false;
471 : :
472 [ # # ]: 0 : if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
473 : : goto out;
474 [ # # ]: 0 : if (test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
475 : : ret = true;
476 [ # # # # ]: 0 : if (test_and_clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags) && !ret) {
477 : : struct inode *inode;
478 : :
479 : : spin_lock(&delegation->lock);
480 : 0 : inode = delegation->inode;
481 [ # # # # ]: 0 : if (inode && list_empty(&NFS_I(inode)->open_files))
482 : : ret = true;
483 : : spin_unlock(&delegation->lock);
484 : : }
485 : : out:
486 : 0 : return ret;
487 : : }
488 : :
489 : : /**
490 : : * nfs_client_return_marked_delegations - return previously marked delegations
491 : : * @clp: nfs_client to process
492 : : *
493 : : * Note that this function is designed to be called by the state
494 : : * manager thread. For this reason, it cannot flush the dirty data,
495 : : * since that could deadlock in case of a state recovery error.
496 : : *
497 : : * Returns zero on success, or a negative errno value.
498 : : */
499 : 0 : int nfs_client_return_marked_delegations(struct nfs_client *clp)
500 : : {
501 : : struct nfs_delegation *delegation;
502 : : struct nfs_delegation *prev;
503 : : struct nfs_server *server;
504 : : struct inode *inode;
505 : : struct inode *place_holder = NULL;
506 : : struct nfs_delegation *place_holder_deleg = NULL;
507 : : int err = 0;
508 : :
509 : : restart:
510 : : /*
511 : : * To avoid quadratic looping we hold a reference
512 : : * to an inode place_holder. Each time we restart, we
513 : : * list nfs_servers from the server of that inode, and
514 : : * delegation in the server from the delegations of that
515 : : * inode.
516 : : * prev is an RCU-protected pointer to a delegation which
517 : : * wasn't marked for return and might be a good choice for
518 : : * the next place_holder.
519 : : */
520 : : rcu_read_lock();
521 : : prev = NULL;
522 [ # # ]: 0 : if (place_holder)
523 : : server = NFS_SERVER(place_holder);
524 : : else
525 : 0 : server = list_entry_rcu(clp->cl_superblocks.next,
526 : : struct nfs_server, client_link);
527 [ # # ]: 0 : list_for_each_entry_from_rcu(server, &clp->cl_superblocks, client_link) {
528 : : delegation = NULL;
529 [ # # # # ]: 0 : if (place_holder && server == NFS_SERVER(place_holder))
530 : 0 : delegation = rcu_dereference(NFS_I(place_holder)->delegation);
531 [ # # ]: 0 : if (!delegation || delegation != place_holder_deleg)
532 : 0 : delegation = list_entry_rcu(server->delegations.next,
533 : : struct nfs_delegation, super_list);
534 [ # # ]: 0 : list_for_each_entry_from_rcu(delegation, &server->delegations, super_list) {
535 : : struct inode *to_put = NULL;
536 : :
537 [ # # ]: 0 : if (!nfs_delegation_need_return(delegation)) {
538 : : prev = delegation;
539 : 0 : continue;
540 : : }
541 [ # # ]: 0 : if (!nfs_sb_active(server->super))
542 : : break; /* continue in outer loop */
543 : :
544 [ # # ]: 0 : if (prev) {
545 : : struct inode *tmp;
546 : :
547 : 0 : tmp = nfs_delegation_grab_inode(prev);
548 [ # # ]: 0 : if (tmp) {
549 : : to_put = place_holder;
550 : : place_holder = tmp;
551 : 0 : place_holder_deleg = prev;
552 : : }
553 : : }
554 : :
555 : 0 : inode = nfs_delegation_grab_inode(delegation);
556 [ # # ]: 0 : if (inode == NULL) {
557 : : rcu_read_unlock();
558 [ # # ]: 0 : if (to_put)
559 : 0 : iput(to_put);
560 : 0 : nfs_sb_deactive(server->super);
561 : 0 : goto restart;
562 : : }
563 : 0 : delegation = nfs_start_delegation_return_locked(NFS_I(inode));
564 : : rcu_read_unlock();
565 : :
566 [ # # ]: 0 : if (to_put)
567 : 0 : iput(to_put);
568 : :
569 : 0 : err = nfs_end_delegation_return(inode, delegation, 0);
570 : 0 : iput(inode);
571 : 0 : nfs_sb_deactive(server->super);
572 : 0 : cond_resched();
573 [ # # ]: 0 : if (!err)
574 : : goto restart;
575 : 0 : set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
576 [ # # ]: 0 : if (place_holder)
577 : 0 : iput(place_holder);
578 : 0 : return err;
579 : : }
580 : : }
581 : : rcu_read_unlock();
582 [ # # ]: 0 : if (place_holder)
583 : 0 : iput(place_holder);
584 : : return 0;
585 : : }
586 : :
587 : : /**
588 : : * nfs_inode_return_delegation_noreclaim - return delegation, don't reclaim opens
589 : : * @inode: inode to process
590 : : *
591 : : * Does not protect against delegation reclaims, therefore really only safe
592 : : * to be called from nfs4_clear_inode().
593 : : */
594 : 0 : void nfs_inode_return_delegation_noreclaim(struct inode *inode)
595 : : {
596 : : struct nfs_delegation *delegation;
597 : :
598 : 0 : delegation = nfs_inode_detach_delegation(inode);
599 [ # # ]: 0 : if (delegation != NULL)
600 : 0 : nfs_do_return_delegation(inode, delegation, 1);
601 : 0 : }
602 : :
603 : : /**
604 : : * nfs_inode_return_delegation - synchronously return a delegation
605 : : * @inode: inode to process
606 : : *
607 : : * This routine will always flush any dirty data to disk on the
608 : : * assumption that if we need to return the delegation, then
609 : : * we should stop caching.
610 : : *
611 : : * Returns zero on success, or a negative errno value.
612 : : */
613 : 0 : int nfs4_inode_return_delegation(struct inode *inode)
614 : : {
615 : : struct nfs_inode *nfsi = NFS_I(inode);
616 : : struct nfs_delegation *delegation;
617 : : int err = 0;
618 : :
619 : 0 : nfs_wb_all(inode);
620 : : delegation = nfs_start_delegation_return(nfsi);
621 [ # # ]: 0 : if (delegation != NULL)
622 : 0 : err = nfs_end_delegation_return(inode, delegation, 1);
623 : 0 : return err;
624 : : }
625 : :
626 : : /**
627 : : * nfs4_inode_make_writeable
628 : : * @inode: pointer to inode
629 : : *
630 : : * Make the inode writeable by returning the delegation if necessary
631 : : *
632 : : * Returns zero on success, or a negative errno value.
633 : : */
634 : 0 : int nfs4_inode_make_writeable(struct inode *inode)
635 : : {
636 [ # # # # ]: 0 : if (!nfs4_has_session(NFS_SERVER(inode)->nfs_client) ||
637 : : !nfs4_check_delegation(inode, FMODE_WRITE))
638 : 0 : return nfs4_inode_return_delegation(inode);
639 : : return 0;
640 : : }
641 : :
642 : 0 : static void nfs_mark_return_if_closed_delegation(struct nfs_server *server,
643 : : struct nfs_delegation *delegation)
644 : : {
645 : 0 : set_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags);
646 : 0 : set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
647 : 0 : }
648 : :
649 : 0 : static void nfs_mark_return_delegation(struct nfs_server *server,
650 : : struct nfs_delegation *delegation)
651 : : {
652 : 0 : set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
653 : 0 : set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
654 : 0 : }
655 : :
656 : : static bool nfs_server_mark_return_all_delegations(struct nfs_server *server)
657 : : {
658 : : struct nfs_delegation *delegation;
659 : : bool ret = false;
660 : :
661 [ # # # # ]: 0 : list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
662 : 0 : nfs_mark_return_delegation(server, delegation);
663 : : ret = true;
664 : : }
665 : 0 : return ret;
666 : : }
667 : :
668 : 0 : static void nfs_client_mark_return_all_delegations(struct nfs_client *clp)
669 : : {
670 : : struct nfs_server *server;
671 : :
672 : : rcu_read_lock();
673 [ # # ]: 0 : list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
674 : : nfs_server_mark_return_all_delegations(server);
675 : : rcu_read_unlock();
676 : 0 : }
677 : :
678 : : static void nfs_delegation_run_state_manager(struct nfs_client *clp)
679 : : {
680 [ # # # # : 0 : if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
# # # # ]
681 : 0 : nfs4_schedule_state_manager(clp);
682 : : }
683 : :
684 : : /**
685 : : * nfs_expire_all_delegations
686 : : * @clp: client to process
687 : : *
688 : : */
689 : 0 : void nfs_expire_all_delegations(struct nfs_client *clp)
690 : : {
691 : 0 : nfs_client_mark_return_all_delegations(clp);
692 : : nfs_delegation_run_state_manager(clp);
693 : 0 : }
694 : :
695 : : /**
696 : : * nfs_super_return_all_delegations - return delegations for one superblock
697 : : * @server: pointer to nfs_server to process
698 : : *
699 : : */
700 : 0 : void nfs_server_return_all_delegations(struct nfs_server *server)
701 : : {
702 : 0 : struct nfs_client *clp = server->nfs_client;
703 : : bool need_wait;
704 : :
705 [ # # ]: 0 : if (clp == NULL)
706 : 0 : return;
707 : :
708 : : rcu_read_lock();
709 : : need_wait = nfs_server_mark_return_all_delegations(server);
710 : : rcu_read_unlock();
711 : :
712 [ # # ]: 0 : if (need_wait) {
713 : 0 : nfs4_schedule_state_manager(clp);
714 : 0 : nfs4_wait_clnt_recover(clp);
715 : : }
716 : : }
717 : :
718 : 0 : static void nfs_mark_return_unused_delegation_types(struct nfs_server *server,
719 : : fmode_t flags)
720 : : {
721 : : struct nfs_delegation *delegation;
722 : :
723 [ # # ]: 0 : list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
724 [ # # # # ]: 0 : if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE))
725 : 0 : continue;
726 [ # # ]: 0 : if (delegation->type & flags)
727 : 0 : nfs_mark_return_if_closed_delegation(server, delegation);
728 : : }
729 : 0 : }
730 : :
731 : 0 : static void nfs_client_mark_return_unused_delegation_types(struct nfs_client *clp,
732 : : fmode_t flags)
733 : : {
734 : : struct nfs_server *server;
735 : :
736 : : rcu_read_lock();
737 [ # # ]: 0 : list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
738 : 0 : nfs_mark_return_unused_delegation_types(server, flags);
739 : : rcu_read_unlock();
740 : 0 : }
741 : :
742 : 0 : static void nfs_mark_delegation_revoked(struct nfs_server *server,
743 : : struct nfs_delegation *delegation)
744 : : {
745 : 0 : set_bit(NFS_DELEGATION_REVOKED, &delegation->flags);
746 : 0 : delegation->stateid.type = NFS4_INVALID_STATEID_TYPE;
747 : 0 : nfs_mark_return_delegation(server, delegation);
748 : 0 : }
749 : :
750 : 0 : static bool nfs_revoke_delegation(struct inode *inode,
751 : : const nfs4_stateid *stateid)
752 : : {
753 : : struct nfs_delegation *delegation;
754 : : nfs4_stateid tmp;
755 : : bool ret = false;
756 : :
757 : : rcu_read_lock();
758 : 0 : delegation = rcu_dereference(NFS_I(inode)->delegation);
759 [ # # ]: 0 : if (delegation == NULL)
760 : : goto out;
761 [ # # ]: 0 : if (stateid == NULL) {
762 : : nfs4_stateid_copy(&tmp, &delegation->stateid);
763 : : stateid = &tmp;
764 [ # # ]: 0 : } else if (!nfs4_stateid_match(stateid, &delegation->stateid))
765 : : goto out;
766 : 0 : nfs_mark_delegation_revoked(NFS_SERVER(inode), delegation);
767 : : ret = true;
768 : : out:
769 : : rcu_read_unlock();
770 [ # # ]: 0 : if (ret)
771 : 0 : nfs_inode_find_state_and_recover(inode, stateid);
772 : 0 : return ret;
773 : : }
774 : :
775 : 0 : void nfs_remove_bad_delegation(struct inode *inode,
776 : : const nfs4_stateid *stateid)
777 : : {
778 : : struct nfs_delegation *delegation;
779 : :
780 [ # # ]: 0 : if (!nfs_revoke_delegation(inode, stateid))
781 : 0 : return;
782 : 0 : delegation = nfs_inode_detach_delegation(inode);
783 [ # # ]: 0 : if (delegation)
784 : 0 : nfs_free_delegation(delegation);
785 : : }
786 : : EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation);
787 : :
788 : : /**
789 : : * nfs_expire_unused_delegation_types
790 : : * @clp: client to process
791 : : * @flags: delegation types to expire
792 : : *
793 : : */
794 : 0 : void nfs_expire_unused_delegation_types(struct nfs_client *clp, fmode_t flags)
795 : : {
796 : 0 : nfs_client_mark_return_unused_delegation_types(clp, flags);
797 : : nfs_delegation_run_state_manager(clp);
798 : 0 : }
799 : :
800 : 0 : static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
801 : : {
802 : : struct nfs_delegation *delegation;
803 : :
804 [ # # ]: 0 : list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
805 [ # # ]: 0 : if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
806 : 0 : continue;
807 : 0 : nfs_mark_return_if_closed_delegation(server, delegation);
808 : : }
809 : 0 : }
810 : :
811 : : /**
812 : : * nfs_expire_unreferenced_delegations - Eliminate unused delegations
813 : : * @clp: nfs_client to process
814 : : *
815 : : */
816 : 0 : void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
817 : : {
818 : : struct nfs_server *server;
819 : :
820 : : rcu_read_lock();
821 [ # # ]: 0 : list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
822 : 0 : nfs_mark_return_unreferenced_delegations(server);
823 : : rcu_read_unlock();
824 : :
825 : : nfs_delegation_run_state_manager(clp);
826 : 0 : }
827 : :
828 : : /**
829 : : * nfs_async_inode_return_delegation - asynchronously return a delegation
830 : : * @inode: inode to process
831 : : * @stateid: state ID information
832 : : *
833 : : * Returns zero on success, or a negative errno value.
834 : : */
835 : 0 : int nfs_async_inode_return_delegation(struct inode *inode,
836 : : const nfs4_stateid *stateid)
837 : : {
838 : : struct nfs_server *server = NFS_SERVER(inode);
839 : 0 : struct nfs_client *clp = server->nfs_client;
840 : : struct nfs_delegation *delegation;
841 : :
842 : : rcu_read_lock();
843 : 0 : delegation = rcu_dereference(NFS_I(inode)->delegation);
844 [ # # ]: 0 : if (delegation == NULL)
845 : : goto out_enoent;
846 [ # # # # ]: 0 : if (stateid != NULL &&
847 : 0 : !clp->cl_mvops->match_stateid(&delegation->stateid, stateid))
848 : : goto out_enoent;
849 : 0 : nfs_mark_return_delegation(server, delegation);
850 : : rcu_read_unlock();
851 : :
852 : : nfs_delegation_run_state_manager(clp);
853 : : return 0;
854 : : out_enoent:
855 : : rcu_read_unlock();
856 : 0 : return -ENOENT;
857 : : }
858 : :
859 : : static struct inode *
860 : 0 : nfs_delegation_find_inode_server(struct nfs_server *server,
861 : : const struct nfs_fh *fhandle)
862 : : {
863 : : struct nfs_delegation *delegation;
864 : : struct inode *freeme, *res = NULL;
865 : :
866 [ # # ]: 0 : list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
867 : : spin_lock(&delegation->lock);
868 [ # # # # ]: 0 : if (delegation->inode != NULL &&
869 : 0 : nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
870 : 0 : freeme = igrab(delegation->inode);
871 [ # # # # ]: 0 : if (freeme && nfs_sb_active(freeme->i_sb))
872 : : res = freeme;
873 : : spin_unlock(&delegation->lock);
874 [ # # ]: 0 : if (res != NULL)
875 : : return res;
876 [ # # ]: 0 : if (freeme) {
877 : : rcu_read_unlock();
878 : 0 : iput(freeme);
879 : : rcu_read_lock();
880 : : }
881 : : return ERR_PTR(-EAGAIN);
882 : : }
883 : : spin_unlock(&delegation->lock);
884 : : }
885 : : return ERR_PTR(-ENOENT);
886 : : }
887 : :
888 : : /**
889 : : * nfs_delegation_find_inode - retrieve the inode associated with a delegation
890 : : * @clp: client state handle
891 : : * @fhandle: filehandle from a delegation recall
892 : : *
893 : : * Returns pointer to inode matching "fhandle," or NULL if a matching inode
894 : : * cannot be found.
895 : : */
896 : 0 : struct inode *nfs_delegation_find_inode(struct nfs_client *clp,
897 : : const struct nfs_fh *fhandle)
898 : : {
899 : : struct nfs_server *server;
900 : : struct inode *res;
901 : :
902 : : rcu_read_lock();
903 [ # # ]: 0 : list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
904 : 0 : res = nfs_delegation_find_inode_server(server, fhandle);
905 [ # # ]: 0 : if (res != ERR_PTR(-ENOENT)) {
906 : : rcu_read_unlock();
907 : 0 : return res;
908 : : }
909 : : }
910 : : rcu_read_unlock();
911 : 0 : return ERR_PTR(-ENOENT);
912 : : }
913 : :
914 : 0 : static void nfs_delegation_mark_reclaim_server(struct nfs_server *server)
915 : : {
916 : : struct nfs_delegation *delegation;
917 : :
918 [ # # ]: 0 : list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
919 : : /*
920 : : * If the delegation may have been admin revoked, then we
921 : : * cannot reclaim it.
922 : : */
923 [ # # ]: 0 : if (test_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags))
924 : 0 : continue;
925 : 0 : set_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
926 : : }
927 : 0 : }
928 : :
929 : : /**
930 : : * nfs_delegation_mark_reclaim - mark all delegations as needing to be reclaimed
931 : : * @clp: nfs_client to process
932 : : *
933 : : */
934 : 0 : void nfs_delegation_mark_reclaim(struct nfs_client *clp)
935 : : {
936 : : struct nfs_server *server;
937 : :
938 : : rcu_read_lock();
939 [ # # ]: 0 : list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
940 : 0 : nfs_delegation_mark_reclaim_server(server);
941 : : rcu_read_unlock();
942 : 0 : }
943 : :
944 : : /**
945 : : * nfs_delegation_reap_unclaimed - reap unclaimed delegations after reboot recovery is done
946 : : * @clp: nfs_client to process
947 : : *
948 : : */
949 : 0 : void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
950 : : {
951 : : struct nfs_delegation *delegation;
952 : : struct nfs_server *server;
953 : : struct inode *inode;
954 : :
955 : : restart:
956 : : rcu_read_lock();
957 [ # # ]: 0 : list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
958 [ # # ]: 0 : list_for_each_entry_rcu(delegation, &server->delegations,
959 : : super_list) {
960 [ # # ]: 0 : if (test_bit(NFS_DELEGATION_INODE_FREEING,
961 [ # # ]: 0 : &delegation->flags) ||
962 : : test_bit(NFS_DELEGATION_RETURNING,
963 [ # # ]: 0 : &delegation->flags) ||
964 : : test_bit(NFS_DELEGATION_NEED_RECLAIM,
965 : : &delegation->flags) == 0)
966 : 0 : continue;
967 [ # # ]: 0 : if (!nfs_sb_active(server->super))
968 : : break; /* continue in outer loop */
969 : 0 : inode = nfs_delegation_grab_inode(delegation);
970 [ # # ]: 0 : if (inode == NULL) {
971 : : rcu_read_unlock();
972 : 0 : nfs_sb_deactive(server->super);
973 : 0 : goto restart;
974 : : }
975 : 0 : delegation = nfs_start_delegation_return_locked(NFS_I(inode));
976 : : rcu_read_unlock();
977 [ # # ]: 0 : if (delegation != NULL) {
978 : 0 : delegation = nfs_detach_delegation(NFS_I(inode),
979 : : delegation, server);
980 [ # # ]: 0 : if (delegation != NULL)
981 : 0 : nfs_free_delegation(delegation);
982 : : }
983 : 0 : iput(inode);
984 : 0 : nfs_sb_deactive(server->super);
985 : 0 : cond_resched();
986 : 0 : goto restart;
987 : : }
988 : : }
989 : : rcu_read_unlock();
990 : 0 : }
991 : :
992 : : static inline bool nfs4_server_rebooted(const struct nfs_client *clp)
993 : : {
994 : 0 : return (clp->cl_state & (BIT(NFS4CLNT_CHECK_LEASE) |
995 : : BIT(NFS4CLNT_LEASE_EXPIRED) |
996 : : BIT(NFS4CLNT_SESSION_RESET))) != 0;
997 : : }
998 : :
999 : 0 : static void nfs_mark_test_expired_delegation(struct nfs_server *server,
1000 : : struct nfs_delegation *delegation)
1001 : : {
1002 [ # # ]: 0 : if (delegation->stateid.type == NFS4_INVALID_STATEID_TYPE)
1003 : 0 : return;
1004 : 0 : clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
1005 : 0 : set_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags);
1006 : 0 : set_bit(NFS4CLNT_DELEGATION_EXPIRED, &server->nfs_client->cl_state);
1007 : : }
1008 : :
1009 : 0 : static void nfs_inode_mark_test_expired_delegation(struct nfs_server *server,
1010 : : struct inode *inode)
1011 : : {
1012 : : struct nfs_delegation *delegation;
1013 : :
1014 : : rcu_read_lock();
1015 : 0 : delegation = rcu_dereference(NFS_I(inode)->delegation);
1016 [ # # ]: 0 : if (delegation)
1017 : 0 : nfs_mark_test_expired_delegation(server, delegation);
1018 : : rcu_read_unlock();
1019 : :
1020 : 0 : }
1021 : :
1022 : : static void nfs_delegation_mark_test_expired_server(struct nfs_server *server)
1023 : : {
1024 : : struct nfs_delegation *delegation;
1025 : :
1026 [ # # ]: 0 : list_for_each_entry_rcu(delegation, &server->delegations, super_list)
1027 : 0 : nfs_mark_test_expired_delegation(server, delegation);
1028 : : }
1029 : :
1030 : : /**
1031 : : * nfs_mark_test_expired_all_delegations - mark all delegations for testing
1032 : : * @clp: nfs_client to process
1033 : : *
1034 : : * Iterates through all the delegations associated with this server and
1035 : : * marks them as needing to be checked for validity.
1036 : : */
1037 : 0 : void nfs_mark_test_expired_all_delegations(struct nfs_client *clp)
1038 : : {
1039 : : struct nfs_server *server;
1040 : :
1041 : : rcu_read_lock();
1042 [ # # ]: 0 : list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
1043 : : nfs_delegation_mark_test_expired_server(server);
1044 : : rcu_read_unlock();
1045 : 0 : }
1046 : :
1047 : : /**
1048 : : * nfs_test_expired_all_delegations - test all delegations for a client
1049 : : * @clp: nfs_client to process
1050 : : *
1051 : : * Helper for handling "recallable state revoked" status from server.
1052 : : */
1053 : 0 : void nfs_test_expired_all_delegations(struct nfs_client *clp)
1054 : : {
1055 : 0 : nfs_mark_test_expired_all_delegations(clp);
1056 : 0 : nfs4_schedule_state_manager(clp);
1057 : 0 : }
1058 : :
1059 : : static void
1060 : 0 : nfs_delegation_test_free_expired(struct inode *inode,
1061 : : nfs4_stateid *stateid,
1062 : : const struct cred *cred)
1063 : : {
1064 : : struct nfs_server *server = NFS_SERVER(inode);
1065 : 0 : const struct nfs4_minor_version_ops *ops = server->nfs_client->cl_mvops;
1066 : : int status;
1067 : :
1068 [ # # ]: 0 : if (!cred)
1069 : 0 : return;
1070 : 0 : status = ops->test_and_free_expired(server, stateid, cred);
1071 [ # # ]: 0 : if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID)
1072 : 0 : nfs_remove_bad_delegation(inode, stateid);
1073 : : }
1074 : :
1075 : : /**
1076 : : * nfs_reap_expired_delegations - reap expired delegations
1077 : : * @clp: nfs_client to process
1078 : : *
1079 : : * Iterates through all the delegations associated with this server and
1080 : : * checks if they have may have been revoked. This function is usually
1081 : : * expected to be called in cases where the server may have lost its
1082 : : * lease.
1083 : : */
1084 : 0 : void nfs_reap_expired_delegations(struct nfs_client *clp)
1085 : : {
1086 : : struct nfs_delegation *delegation;
1087 : : struct nfs_server *server;
1088 : : struct inode *inode;
1089 : : const struct cred *cred;
1090 : : nfs4_stateid stateid;
1091 : :
1092 : : restart:
1093 : : rcu_read_lock();
1094 [ # # ]: 0 : list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
1095 [ # # ]: 0 : list_for_each_entry_rcu(delegation, &server->delegations,
1096 : : super_list) {
1097 [ # # ]: 0 : if (test_bit(NFS_DELEGATION_INODE_FREEING,
1098 [ # # ]: 0 : &delegation->flags) ||
1099 : : test_bit(NFS_DELEGATION_RETURNING,
1100 [ # # ]: 0 : &delegation->flags) ||
1101 : : test_bit(NFS_DELEGATION_TEST_EXPIRED,
1102 : : &delegation->flags) == 0)
1103 : 0 : continue;
1104 [ # # ]: 0 : if (!nfs_sb_active(server->super))
1105 : : break; /* continue in outer loop */
1106 : 0 : inode = nfs_delegation_grab_inode(delegation);
1107 [ # # ]: 0 : if (inode == NULL) {
1108 : : rcu_read_unlock();
1109 : 0 : nfs_sb_deactive(server->super);
1110 : 0 : goto restart;
1111 : : }
1112 : 0 : cred = get_cred_rcu(delegation->cred);
1113 : : nfs4_stateid_copy(&stateid, &delegation->stateid);
1114 : 0 : clear_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags);
1115 : : rcu_read_unlock();
1116 : 0 : nfs_delegation_test_free_expired(inode, &stateid, cred);
1117 : 0 : put_cred(cred);
1118 [ # # ]: 0 : if (nfs4_server_rebooted(clp)) {
1119 : 0 : nfs_inode_mark_test_expired_delegation(server,inode);
1120 : 0 : iput(inode);
1121 : 0 : nfs_sb_deactive(server->super);
1122 : 0 : return;
1123 : : }
1124 : 0 : iput(inode);
1125 : 0 : nfs_sb_deactive(server->super);
1126 : 0 : cond_resched();
1127 : 0 : goto restart;
1128 : : }
1129 : : }
1130 : : rcu_read_unlock();
1131 : : }
1132 : :
1133 : 0 : void nfs_inode_find_delegation_state_and_recover(struct inode *inode,
1134 : : const nfs4_stateid *stateid)
1135 : : {
1136 : 0 : struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
1137 : : struct nfs_delegation *delegation;
1138 : : bool found = false;
1139 : :
1140 : : rcu_read_lock();
1141 : 0 : delegation = rcu_dereference(NFS_I(inode)->delegation);
1142 [ # # # # ]: 0 : if (delegation &&
1143 : : nfs4_stateid_match_other(&delegation->stateid, stateid)) {
1144 : 0 : nfs_mark_test_expired_delegation(NFS_SERVER(inode), delegation);
1145 : : found = true;
1146 : : }
1147 : : rcu_read_unlock();
1148 [ # # ]: 0 : if (found)
1149 : 0 : nfs4_schedule_state_manager(clp);
1150 : 0 : }
1151 : :
1152 : : /**
1153 : : * nfs_delegations_present - check for existence of delegations
1154 : : * @clp: client state handle
1155 : : *
1156 : : * Returns one if there are any nfs_delegation structures attached
1157 : : * to this nfs_client.
1158 : : */
1159 : 0 : int nfs_delegations_present(struct nfs_client *clp)
1160 : : {
1161 : : struct nfs_server *server;
1162 : : int ret = 0;
1163 : :
1164 : : rcu_read_lock();
1165 [ # # ]: 0 : list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
1166 [ # # ]: 0 : if (!list_empty(&server->delegations)) {
1167 : : ret = 1;
1168 : : break;
1169 : : }
1170 : : rcu_read_unlock();
1171 : 0 : return ret;
1172 : : }
1173 : :
1174 : : /**
1175 : : * nfs4_refresh_delegation_stateid - Update delegation stateid seqid
1176 : : * @dst: stateid to refresh
1177 : : * @inode: inode to check
1178 : : *
1179 : : * Returns "true" and updates "dst->seqid" * if inode had a delegation
1180 : : * that matches our delegation stateid. Otherwise "false" is returned.
1181 : : */
1182 : 0 : bool nfs4_refresh_delegation_stateid(nfs4_stateid *dst, struct inode *inode)
1183 : : {
1184 : : struct nfs_delegation *delegation;
1185 : : bool ret = false;
1186 [ # # ]: 0 : if (!inode)
1187 : : goto out;
1188 : :
1189 : : rcu_read_lock();
1190 : 0 : delegation = rcu_dereference(NFS_I(inode)->delegation);
1191 [ # # # # ]: 0 : if (delegation != NULL &&
1192 : : nfs4_stateid_match_other(dst, &delegation->stateid)) {
1193 : 0 : dst->seqid = delegation->stateid.seqid;
1194 : : ret = true;
1195 : : }
1196 : : rcu_read_unlock();
1197 : : out:
1198 : 0 : return ret;
1199 : : }
1200 : :
1201 : : /**
1202 : : * nfs4_copy_delegation_stateid - Copy inode's state ID information
1203 : : * @inode: inode to check
1204 : : * @flags: delegation type requirement
1205 : : * @dst: stateid data structure to fill in
1206 : : * @cred: optional argument to retrieve credential
1207 : : *
1208 : : * Returns "true" and fills in "dst->data" * if inode had a delegation,
1209 : : * otherwise "false" is returned.
1210 : : */
1211 : 0 : bool nfs4_copy_delegation_stateid(struct inode *inode, fmode_t flags,
1212 : : nfs4_stateid *dst, const struct cred **cred)
1213 : : {
1214 : : struct nfs_inode *nfsi = NFS_I(inode);
1215 : : struct nfs_delegation *delegation;
1216 : : bool ret;
1217 : :
1218 : 0 : flags &= FMODE_READ|FMODE_WRITE;
1219 : : rcu_read_lock();
1220 : 0 : delegation = rcu_dereference(nfsi->delegation);
1221 : : ret = nfs4_is_valid_delegation(delegation, flags);
1222 [ # # ]: 0 : if (ret) {
1223 : : nfs4_stateid_copy(dst, &delegation->stateid);
1224 : : nfs_mark_delegation_referenced(delegation);
1225 [ # # ]: 0 : if (cred)
1226 : 0 : *cred = get_cred(delegation->cred);
1227 : : }
1228 : : rcu_read_unlock();
1229 : 0 : return ret;
1230 : : }
1231 : :
1232 : : /**
1233 : : * nfs4_delegation_flush_on_close - Check if we must flush file on close
1234 : : * @inode: inode to check
1235 : : *
1236 : : * This function checks the number of outstanding writes to the file
1237 : : * against the delegation 'space_limit' field to see if
1238 : : * the spec requires us to flush the file on close.
1239 : : */
1240 : 0 : bool nfs4_delegation_flush_on_close(const struct inode *inode)
1241 : : {
1242 : : struct nfs_inode *nfsi = NFS_I(inode);
1243 : : struct nfs_delegation *delegation;
1244 : : bool ret = true;
1245 : :
1246 : : rcu_read_lock();
1247 : 0 : delegation = rcu_dereference(nfsi->delegation);
1248 [ # # # # ]: 0 : if (delegation == NULL || !(delegation->type & FMODE_WRITE))
1249 : : goto out;
1250 [ # # ]: 0 : if (atomic_long_read(&nfsi->nrequests) < delegation->pagemod_limit)
1251 : : ret = false;
1252 : : out:
1253 : : rcu_read_unlock();
1254 : 0 : return ret;
1255 : : }
|