Branch data Line data Source code
1 : : /*
2 : : * linux/fs/nfs/delegation.c
3 : : *
4 : : * Copyright (C) 2004 Trond Myklebust
5 : : *
6 : : * NFS file delegation management
7 : : *
8 : : */
9 : : #include <linux/completion.h>
10 : : #include <linux/kthread.h>
11 : : #include <linux/module.h>
12 : : #include <linux/sched.h>
13 : : #include <linux/slab.h>
14 : : #include <linux/spinlock.h>
15 : :
16 : : #include <linux/nfs4.h>
17 : : #include <linux/nfs_fs.h>
18 : : #include <linux/nfs_xdr.h>
19 : :
20 : : #include "nfs4_fs.h"
21 : : #include "delegation.h"
22 : : #include "internal.h"
23 : : #include "nfs4trace.h"
24 : :
25 : 0 : static void nfs_free_delegation(struct nfs_delegation *delegation)
26 : : {
27 [ # # ]: 0 : if (delegation->cred) {
28 : 0 : put_rpccred(delegation->cred);
29 : 0 : delegation->cred = NULL;
30 : : }
31 : 0 : kfree_rcu(delegation, rcu);
32 : 0 : }
33 : :
34 : : /**
35 : : * nfs_mark_delegation_referenced - set delegation's REFERENCED flag
36 : : * @delegation: delegation to process
37 : : *
38 : : */
39 : 0 : void nfs_mark_delegation_referenced(struct nfs_delegation *delegation)
40 : : {
41 : 0 : set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags);
42 : 0 : }
43 : :
44 : : /**
45 : : * nfs_have_delegation - check if inode has a delegation
46 : : * @inode: inode to check
47 : : * @flags: delegation types to check for
48 : : *
49 : : * Returns one if inode has the indicated delegation, otherwise zero.
50 : : */
51 : 0 : int nfs4_have_delegation(struct inode *inode, fmode_t flags)
52 : : {
53 : : struct nfs_delegation *delegation;
54 : : int ret = 0;
55 : :
56 : 0 : flags &= FMODE_READ|FMODE_WRITE;
57 : : rcu_read_lock();
58 : 0 : delegation = rcu_dereference(NFS_I(inode)->delegation);
59 [ # # ][ # # ]: 0 : if (delegation != NULL && (delegation->type & flags) == flags &&
[ # # ]
60 : : !test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) {
61 : : nfs_mark_delegation_referenced(delegation);
62 : : ret = 1;
63 : : }
64 : : rcu_read_unlock();
65 : 0 : return ret;
66 : : }
67 : :
68 : 0 : static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid)
69 : : {
70 : 0 : struct inode *inode = state->inode;
71 : : struct file_lock *fl;
72 : : int status = 0;
73 : :
74 [ # # ]: 0 : if (inode->i_flock == NULL)
75 : : goto out;
76 : :
77 : : /* Protect inode->i_flock using the i_lock */
78 : : spin_lock(&inode->i_lock);
79 [ # # ]: 0 : for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
80 [ # # ]: 0 : if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
81 : 0 : continue;
82 [ # # ]: 0 : if (nfs_file_open_context(fl->fl_file) != ctx)
83 : 0 : continue;
84 : : spin_unlock(&inode->i_lock);
85 : 0 : status = nfs4_lock_delegation_recall(fl, state, stateid);
86 [ # # ]: 0 : if (status < 0)
87 : : goto out;
88 : : spin_lock(&inode->i_lock);
89 : : }
90 : : spin_unlock(&inode->i_lock);
91 : : out:
92 : 0 : return status;
93 : : }
94 : :
95 : 0 : static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid)
96 : : {
97 : : struct nfs_inode *nfsi = NFS_I(inode);
98 : : struct nfs_open_context *ctx;
99 : : struct nfs4_state_owner *sp;
100 : : struct nfs4_state *state;
101 : : unsigned int seq;
102 : : int err;
103 : :
104 : : again:
105 : : spin_lock(&inode->i_lock);
106 [ # # ]: 0 : list_for_each_entry(ctx, &nfsi->open_files, list) {
107 : 0 : state = ctx->state;
108 [ # # ]: 0 : if (state == NULL)
109 : 0 : continue;
110 [ # # ]: 0 : if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
111 : 0 : continue;
112 [ # # ]: 0 : if (!nfs4_stateid_match(&state->stateid, stateid))
113 : 0 : continue;
114 : 0 : get_nfs_open_context(ctx);
115 : : spin_unlock(&inode->i_lock);
116 : 0 : sp = state->owner;
117 : : /* Block nfs4_proc_unlck */
118 : 0 : mutex_lock(&sp->so_delegreturn_mutex);
119 : : seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
120 : 0 : err = nfs4_open_delegation_recall(ctx, state, stateid);
121 [ # # ]: 0 : if (!err)
122 : 0 : err = nfs_delegation_claim_locks(ctx, state, stateid);
123 [ # # # # ]: 0 : if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
124 : : err = -EAGAIN;
125 : 0 : mutex_unlock(&sp->so_delegreturn_mutex);
126 : 0 : put_nfs_open_context(ctx);
127 [ # # ]: 0 : if (err != 0)
128 : : return err;
129 : : goto again;
130 : : }
131 : : spin_unlock(&inode->i_lock);
132 : 0 : return 0;
133 : : }
134 : :
135 : : /**
136 : : * nfs_inode_reclaim_delegation - process a delegation reclaim request
137 : : * @inode: inode to process
138 : : * @cred: credential to use for request
139 : : * @res: new delegation state from server
140 : : *
141 : : */
142 : 0 : void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred,
143 : : struct nfs_openres *res)
144 : : {
145 : : struct nfs_delegation *delegation;
146 : : struct rpc_cred *oldcred = NULL;
147 : :
148 : : rcu_read_lock();
149 : 0 : delegation = rcu_dereference(NFS_I(inode)->delegation);
150 [ # # ]: 0 : if (delegation != NULL) {
151 : : spin_lock(&delegation->lock);
152 [ # # ]: 0 : if (delegation->inode != NULL) {
153 : 0 : nfs4_stateid_copy(&delegation->stateid, &res->delegation);
154 : 0 : delegation->type = res->delegation_type;
155 : 0 : delegation->maxsize = res->maxsize;
156 : 0 : oldcred = delegation->cred;
157 : 0 : delegation->cred = get_rpccred(cred);
158 : 0 : clear_bit(NFS_DELEGATION_NEED_RECLAIM,
159 : : &delegation->flags);
160 : 0 : NFS_I(inode)->delegation_state = delegation->type;
161 : : spin_unlock(&delegation->lock);
162 : 0 : put_rpccred(oldcred);
163 : : rcu_read_unlock();
164 : 0 : trace_nfs4_reclaim_delegation(inode, res->delegation_type);
165 : : } else {
166 : : /* We appear to have raced with a delegation return. */
167 : : spin_unlock(&delegation->lock);
168 : : rcu_read_unlock();
169 : 0 : nfs_inode_set_delegation(inode, cred, res);
170 : : }
171 : : } else {
172 : : rcu_read_unlock();
173 : : }
174 : 0 : }
175 : :
176 : 0 : static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync)
177 : : {
178 : : int res = 0;
179 : :
180 : 0 : res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid, issync);
181 : 0 : nfs_free_delegation(delegation);
182 : 0 : return res;
183 : : }
184 : :
185 : 0 : static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation)
186 : : {
187 : : struct inode *inode = NULL;
188 : :
189 : : spin_lock(&delegation->lock);
190 [ # # ]: 0 : if (delegation->inode != NULL)
191 : 0 : inode = igrab(delegation->inode);
192 : : spin_unlock(&delegation->lock);
193 : 0 : return inode;
194 : : }
195 : :
196 : : static struct nfs_delegation *
197 : 0 : nfs_start_delegation_return_locked(struct nfs_inode *nfsi)
198 : : {
199 : : struct nfs_delegation *ret = NULL;
200 : 0 : struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation);
201 : :
202 [ # # ]: 0 : if (delegation == NULL)
203 : : goto out;
204 : : spin_lock(&delegation->lock);
205 [ # # ]: 0 : if (!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
206 : : ret = delegation;
207 : : spin_unlock(&delegation->lock);
208 : : out:
209 : 0 : return ret;
210 : : }
211 : :
212 : : static struct nfs_delegation *
213 : 0 : nfs_start_delegation_return(struct nfs_inode *nfsi)
214 : : {
215 : : struct nfs_delegation *delegation;
216 : :
217 : : rcu_read_lock();
218 : 0 : delegation = nfs_start_delegation_return_locked(nfsi);
219 : : rcu_read_unlock();
220 : : return delegation;
221 : : }
222 : :
223 : : static void
224 : 0 : nfs_abort_delegation_return(struct nfs_delegation *delegation,
225 : : struct nfs_client *clp)
226 : : {
227 : :
228 : : spin_lock(&delegation->lock);
229 : 0 : clear_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
230 : 0 : set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
231 : : spin_unlock(&delegation->lock);
232 : 0 : set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
233 : 0 : }
234 : :
235 : : static struct nfs_delegation *
236 : 0 : nfs_detach_delegation_locked(struct nfs_inode *nfsi,
237 : : struct nfs_delegation *delegation,
238 : : struct nfs_client *clp)
239 : : {
240 : : struct nfs_delegation *deleg_cur =
241 : 0 : rcu_dereference_protected(nfsi->delegation,
242 : : lockdep_is_held(&clp->cl_lock));
243 : :
244 [ # # ]: 0 : if (deleg_cur == NULL || delegation != deleg_cur)
245 : : return NULL;
246 : :
247 : : spin_lock(&delegation->lock);
248 : 0 : set_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
249 : : list_del_rcu(&delegation->super_list);
250 : 0 : delegation->inode = NULL;
251 : 0 : nfsi->delegation_state = 0;
252 : 0 : rcu_assign_pointer(nfsi->delegation, NULL);
253 : : spin_unlock(&delegation->lock);
254 : : return delegation;
255 : : }
256 : :
257 : 0 : static struct nfs_delegation *nfs_detach_delegation(struct nfs_inode *nfsi,
258 : : struct nfs_delegation *delegation,
259 : : struct nfs_server *server)
260 : : {
261 : 0 : struct nfs_client *clp = server->nfs_client;
262 : :
263 : : spin_lock(&clp->cl_lock);
264 : 0 : delegation = nfs_detach_delegation_locked(nfsi, delegation, clp);
265 : : spin_unlock(&clp->cl_lock);
266 : 0 : return delegation;
267 : : }
268 : :
269 : : static struct nfs_delegation *
270 : 0 : nfs_inode_detach_delegation(struct inode *inode)
271 : : {
272 : 0 : struct nfs_inode *nfsi = NFS_I(inode);
273 : 0 : struct nfs_server *server = NFS_SERVER(inode);
274 : : struct nfs_delegation *delegation;
275 : :
276 : : delegation = nfs_start_delegation_return(nfsi);
277 [ # # ]: 0 : if (delegation == NULL)
278 : : return NULL;
279 : 0 : return nfs_detach_delegation(nfsi, delegation, server);
280 : : }
281 : :
282 : : /**
283 : : * nfs_inode_set_delegation - set up a delegation on an inode
284 : : * @inode: inode to which delegation applies
285 : : * @cred: cred to use for subsequent delegation processing
286 : : * @res: new delegation state from server
287 : : *
288 : : * Returns zero on success, or a negative errno value.
289 : : */
290 : 0 : int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
291 : : {
292 : : struct nfs_server *server = NFS_SERVER(inode);
293 : 0 : struct nfs_client *clp = server->nfs_client;
294 : 0 : struct nfs_inode *nfsi = NFS_I(inode);
295 : : struct nfs_delegation *delegation, *old_delegation;
296 : : struct nfs_delegation *freeme = NULL;
297 : : int status = 0;
298 : :
299 : : delegation = kmalloc(sizeof(*delegation), GFP_NOFS);
300 [ # # ]: 0 : if (delegation == NULL)
301 : : return -ENOMEM;
302 : 0 : nfs4_stateid_copy(&delegation->stateid, &res->delegation);
303 : 0 : delegation->type = res->delegation_type;
304 : 0 : delegation->maxsize = res->maxsize;
305 : 0 : delegation->change_attr = inode->i_version;
306 : 0 : delegation->cred = get_rpccred(cred);
307 : 0 : delegation->inode = inode;
308 : 0 : delegation->flags = 1<<NFS_DELEGATION_REFERENCED;
309 : 0 : spin_lock_init(&delegation->lock);
310 : :
311 : : spin_lock(&clp->cl_lock);
312 : 0 : old_delegation = rcu_dereference_protected(nfsi->delegation,
313 : : lockdep_is_held(&clp->cl_lock));
314 [ # # ]: 0 : if (old_delegation != NULL) {
315 [ # # ]: 0 : if (nfs4_stateid_match(&delegation->stateid,
316 [ # # ]: 0 : &old_delegation->stateid) &&
317 : 0 : delegation->type == old_delegation->type) {
318 : : goto out;
319 : : }
320 : : /*
321 : : * Deal with broken servers that hand out two
322 : : * delegations for the same file.
323 : : * Allow for upgrades to a WRITE delegation, but
324 : : * nothing else.
325 : : */
326 : : dfprintk(FILE, "%s: server %s handed out "
327 : : "a duplicate delegation!\n",
328 : : __func__, clp->cl_hostname);
329 [ # # ][ # # ]: 0 : if (delegation->type == old_delegation->type ||
330 : 0 : !(delegation->type & FMODE_WRITE)) {
331 : : freeme = delegation;
332 : : delegation = NULL;
333 : : goto out;
334 : : }
335 : 0 : freeme = nfs_detach_delegation_locked(nfsi,
336 : : old_delegation, clp);
337 [ # # ]: 0 : if (freeme == NULL)
338 : : goto out;
339 : : }
340 : 0 : list_add_rcu(&delegation->super_list, &server->delegations);
341 : 0 : nfsi->delegation_state = delegation->type;
342 : 0 : rcu_assign_pointer(nfsi->delegation, delegation);
343 : : delegation = NULL;
344 : :
345 : : /* Ensure we revalidate the attributes and page cache! */
346 : : spin_lock(&inode->i_lock);
347 : 0 : nfsi->cache_validity |= NFS_INO_REVAL_FORCED;
348 : : spin_unlock(&inode->i_lock);
349 : 0 : trace_nfs4_set_delegation(inode, res->delegation_type);
350 : :
351 : : out:
352 : : spin_unlock(&clp->cl_lock);
353 [ # # ]: 0 : if (delegation != NULL)
354 : 0 : nfs_free_delegation(delegation);
355 [ # # ]: 0 : if (freeme != NULL)
356 : 0 : nfs_do_return_delegation(inode, freeme, 0);
357 : : return status;
358 : : }
359 : :
360 : : /*
361 : : * Basic procedure for returning a delegation to the server
362 : : */
363 : 0 : static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation *delegation, int issync)
364 : : {
365 : 0 : struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
366 : 0 : struct nfs_inode *nfsi = NFS_I(inode);
367 : : int err;
368 : :
369 [ # # ]: 0 : if (delegation == NULL)
370 : : return 0;
371 : : do {
372 : 0 : err = nfs_delegation_claim_opens(inode, &delegation->stateid);
373 [ # # ]: 0 : if (!issync || err != -EAGAIN)
374 : : break;
375 : : /*
376 : : * Guard against state recovery
377 : : */
378 : 0 : err = nfs4_wait_clnt_recover(clp);
379 [ # # ]: 0 : } while (err == 0);
380 : :
381 [ # # ]: 0 : if (err) {
382 : 0 : nfs_abort_delegation_return(delegation, clp);
383 : 0 : goto out;
384 : : }
385 [ # # ]: 0 : if (!nfs_detach_delegation(nfsi, delegation, NFS_SERVER(inode)))
386 : : goto out;
387 : :
388 : 0 : err = nfs_do_return_delegation(inode, delegation, issync);
389 : : out:
390 : 0 : return err;
391 : : }
392 : :
393 : 0 : static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
394 : : {
395 : : bool ret = false;
396 : :
397 [ # # ]: 0 : if (test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
398 : : ret = true;
399 [ # # ][ # # ]: 0 : if (test_and_clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags) && !ret) {
400 : : struct inode *inode;
401 : :
402 : : spin_lock(&delegation->lock);
403 : 0 : inode = delegation->inode;
404 [ # # ][ # # ]: 0 : if (inode && list_empty(&NFS_I(inode)->open_files))
405 : : ret = true;
406 : : spin_unlock(&delegation->lock);
407 : : }
408 : 0 : return ret;
409 : : }
410 : :
411 : : /**
412 : : * nfs_client_return_marked_delegations - return previously marked delegations
413 : : * @clp: nfs_client to process
414 : : *
415 : : * Note that this function is designed to be called by the state
416 : : * manager thread. For this reason, it cannot flush the dirty data,
417 : : * since that could deadlock in case of a state recovery error.
418 : : *
419 : : * Returns zero on success, or a negative errno value.
420 : : */
421 : 0 : int nfs_client_return_marked_delegations(struct nfs_client *clp)
422 : : {
423 : : struct nfs_delegation *delegation;
424 : : struct nfs_server *server;
425 : : struct inode *inode;
426 : : int err = 0;
427 : :
428 : : restart:
429 : : rcu_read_lock();
430 [ # # ]: 0 : list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
431 [ # # ]: 0 : list_for_each_entry_rcu(delegation, &server->delegations,
432 : : super_list) {
433 [ # # ]: 0 : if (!nfs_delegation_need_return(delegation))
434 : 0 : continue;
435 : 0 : inode = nfs_delegation_grab_inode(delegation);
436 [ # # ]: 0 : if (inode == NULL)
437 : 0 : continue;
438 : 0 : delegation = nfs_start_delegation_return_locked(NFS_I(inode));
439 : : rcu_read_unlock();
440 : :
441 : 0 : err = nfs_end_delegation_return(inode, delegation, 0);
442 : 0 : iput(inode);
443 [ # # ]: 0 : if (!err)
444 : : goto restart;
445 : 0 : set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
446 : 0 : return err;
447 : : }
448 : : }
449 : : rcu_read_unlock();
450 : 0 : return 0;
451 : : }
452 : :
453 : : /**
454 : : * nfs_inode_return_delegation_noreclaim - return delegation, don't reclaim opens
455 : : * @inode: inode to process
456 : : *
457 : : * Does not protect against delegation reclaims, therefore really only safe
458 : : * to be called from nfs4_clear_inode().
459 : : */
460 : 0 : void nfs_inode_return_delegation_noreclaim(struct inode *inode)
461 : : {
462 : : struct nfs_delegation *delegation;
463 : :
464 : 0 : delegation = nfs_inode_detach_delegation(inode);
465 [ # # ]: 0 : if (delegation != NULL)
466 : 0 : nfs_do_return_delegation(inode, delegation, 0);
467 : 0 : }
468 : :
469 : : /**
470 : : * nfs_inode_return_delegation - synchronously return a delegation
471 : : * @inode: inode to process
472 : : *
473 : : * This routine will always flush any dirty data to disk on the
474 : : * assumption that if we need to return the delegation, then
475 : : * we should stop caching.
476 : : *
477 : : * Returns zero on success, or a negative errno value.
478 : : */
479 : 0 : int nfs4_inode_return_delegation(struct inode *inode)
480 : : {
481 : : struct nfs_inode *nfsi = NFS_I(inode);
482 : : struct nfs_delegation *delegation;
483 : : int err = 0;
484 : :
485 : 0 : nfs_wb_all(inode);
486 : : delegation = nfs_start_delegation_return(nfsi);
487 [ # # ]: 0 : if (delegation != NULL)
488 : 0 : err = nfs_end_delegation_return(inode, delegation, 1);
489 : 0 : return err;
490 : : }
491 : :
492 : 0 : static void nfs_mark_return_if_closed_delegation(struct nfs_server *server,
493 : : struct nfs_delegation *delegation)
494 : : {
495 : 0 : set_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags);
496 : 0 : set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
497 : 0 : }
498 : :
499 : 0 : static void nfs_mark_return_delegation(struct nfs_server *server,
500 : : struct nfs_delegation *delegation)
501 : : {
502 : 0 : set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
503 : 0 : set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
504 : 0 : }
505 : :
506 : 0 : static bool nfs_server_mark_return_all_delegations(struct nfs_server *server)
507 : : {
508 : : struct nfs_delegation *delegation;
509 : : bool ret = false;
510 : :
511 [ # # ]: 0 : list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
512 : 0 : nfs_mark_return_delegation(server, delegation);
513 : : ret = true;
514 : : }
515 : 0 : return ret;
516 : : }
517 : :
518 : 0 : static void nfs_client_mark_return_all_delegations(struct nfs_client *clp)
519 : : {
520 : : struct nfs_server *server;
521 : :
522 : : rcu_read_lock();
523 [ # # ]: 0 : list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
524 : 0 : nfs_server_mark_return_all_delegations(server);
525 : : rcu_read_unlock();
526 : 0 : }
527 : :
528 : : static void nfs_delegation_run_state_manager(struct nfs_client *clp)
529 : : {
530 [ # # # # : 0 : if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
# # # # ]
531 : 0 : nfs4_schedule_state_manager(clp);
532 : : }
533 : :
534 : : /**
535 : : * nfs_expire_all_delegations
536 : : * @clp: client to process
537 : : *
538 : : */
539 : 0 : void nfs_expire_all_delegations(struct nfs_client *clp)
540 : : {
541 : 0 : nfs_client_mark_return_all_delegations(clp);
542 : : nfs_delegation_run_state_manager(clp);
543 : 0 : }
544 : :
545 : : /**
546 : : * nfs_super_return_all_delegations - return delegations for one superblock
547 : : * @sb: sb to process
548 : : *
549 : : */
550 : 0 : void nfs_server_return_all_delegations(struct nfs_server *server)
551 : : {
552 : 0 : struct nfs_client *clp = server->nfs_client;
553 : : bool need_wait;
554 : :
555 [ # # ]: 0 : if (clp == NULL)
556 : 0 : return;
557 : :
558 : : rcu_read_lock();
559 : 0 : need_wait = nfs_server_mark_return_all_delegations(server);
560 : : rcu_read_unlock();
561 : :
562 [ # # ]: 0 : if (need_wait) {
563 : 0 : nfs4_schedule_state_manager(clp);
564 : 0 : nfs4_wait_clnt_recover(clp);
565 : : }
566 : : }
567 : :
568 : 0 : static void nfs_mark_return_unused_delegation_types(struct nfs_server *server,
569 : : fmode_t flags)
570 : : {
571 : : struct nfs_delegation *delegation;
572 : :
573 [ # # ]: 0 : list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
574 [ # # ][ # # ]: 0 : if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE))
575 : 0 : continue;
576 [ # # ]: 0 : if (delegation->type & flags)
577 : 0 : nfs_mark_return_if_closed_delegation(server, delegation);
578 : : }
579 : 0 : }
580 : :
581 : 0 : static void nfs_client_mark_return_unused_delegation_types(struct nfs_client *clp,
582 : : fmode_t flags)
583 : : {
584 : : struct nfs_server *server;
585 : :
586 : : rcu_read_lock();
587 [ # # ]: 0 : list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
588 : 0 : nfs_mark_return_unused_delegation_types(server, flags);
589 : : rcu_read_unlock();
590 : 0 : }
591 : :
592 : 0 : void nfs_remove_bad_delegation(struct inode *inode)
593 : : {
594 : : struct nfs_delegation *delegation;
595 : :
596 : 0 : delegation = nfs_inode_detach_delegation(inode);
597 [ # # ]: 0 : if (delegation) {
598 : 0 : nfs_inode_find_state_and_recover(inode, &delegation->stateid);
599 : 0 : nfs_free_delegation(delegation);
600 : : }
601 : 0 : }
602 : : EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation);
603 : :
604 : : /**
605 : : * nfs_expire_unused_delegation_types
606 : : * @clp: client to process
607 : : * @flags: delegation types to expire
608 : : *
609 : : */
610 : 0 : void nfs_expire_unused_delegation_types(struct nfs_client *clp, fmode_t flags)
611 : : {
612 : 0 : nfs_client_mark_return_unused_delegation_types(clp, flags);
613 : : nfs_delegation_run_state_manager(clp);
614 : 0 : }
615 : :
616 : 0 : static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
617 : : {
618 : : struct nfs_delegation *delegation;
619 : :
620 [ # # ]: 0 : list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
621 [ # # ]: 0 : if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
622 : 0 : continue;
623 : 0 : nfs_mark_return_if_closed_delegation(server, delegation);
624 : : }
625 : 0 : }
626 : :
627 : : /**
628 : : * nfs_expire_unreferenced_delegations - Eliminate unused delegations
629 : : * @clp: nfs_client to process
630 : : *
631 : : */
632 : 0 : void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
633 : : {
634 : : struct nfs_server *server;
635 : :
636 : : rcu_read_lock();
637 [ # # ]: 0 : list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
638 : 0 : nfs_mark_return_unreferenced_delegations(server);
639 : : rcu_read_unlock();
640 : :
641 : : nfs_delegation_run_state_manager(clp);
642 : 0 : }
643 : :
644 : : /**
645 : : * nfs_async_inode_return_delegation - asynchronously return a delegation
646 : : * @inode: inode to process
647 : : * @stateid: state ID information
648 : : *
649 : : * Returns zero on success, or a negative errno value.
650 : : */
651 : 0 : int nfs_async_inode_return_delegation(struct inode *inode,
652 : : const nfs4_stateid *stateid)
653 : : {
654 : : struct nfs_server *server = NFS_SERVER(inode);
655 : 0 : struct nfs_client *clp = server->nfs_client;
656 : : struct nfs_delegation *delegation;
657 : :
658 : 0 : filemap_flush(inode->i_mapping);
659 : :
660 : : rcu_read_lock();
661 : 0 : delegation = rcu_dereference(NFS_I(inode)->delegation);
662 [ # # ]: 0 : if (delegation == NULL)
663 : : goto out_enoent;
664 : :
665 [ # # ]: 0 : if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid))
666 : : goto out_enoent;
667 : 0 : nfs_mark_return_delegation(server, delegation);
668 : : rcu_read_unlock();
669 : :
670 : : nfs_delegation_run_state_manager(clp);
671 : : return 0;
672 : : out_enoent:
673 : : rcu_read_unlock();
674 : 0 : return -ENOENT;
675 : : }
676 : :
677 : : static struct inode *
678 : 0 : nfs_delegation_find_inode_server(struct nfs_server *server,
679 : : const struct nfs_fh *fhandle)
680 : : {
681 : : struct nfs_delegation *delegation;
682 : : struct inode *res = NULL;
683 : :
684 [ # # ]: 0 : list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
685 : : spin_lock(&delegation->lock);
686 [ # # ][ # # ]: 0 : if (delegation->inode != NULL &&
687 : : nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
688 : 0 : res = igrab(delegation->inode);
689 : : }
690 : : spin_unlock(&delegation->lock);
691 [ # # ]: 0 : if (res != NULL)
692 : : break;
693 : : }
694 : 0 : return res;
695 : : }
696 : :
697 : : /**
698 : : * nfs_delegation_find_inode - retrieve the inode associated with a delegation
699 : : * @clp: client state handle
700 : : * @fhandle: filehandle from a delegation recall
701 : : *
702 : : * Returns pointer to inode matching "fhandle," or NULL if a matching inode
703 : : * cannot be found.
704 : : */
705 : 0 : struct inode *nfs_delegation_find_inode(struct nfs_client *clp,
706 : : const struct nfs_fh *fhandle)
707 : : {
708 : : struct nfs_server *server;
709 : : struct inode *res = NULL;
710 : :
711 : : rcu_read_lock();
712 [ # # ]: 0 : list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
713 : 0 : res = nfs_delegation_find_inode_server(server, fhandle);
714 [ # # ]: 0 : if (res != NULL)
715 : : break;
716 : : }
717 : : rcu_read_unlock();
718 : 0 : return res;
719 : : }
720 : :
721 : 0 : static void nfs_delegation_mark_reclaim_server(struct nfs_server *server)
722 : : {
723 : : struct nfs_delegation *delegation;
724 : :
725 [ # # ]: 0 : list_for_each_entry_rcu(delegation, &server->delegations, super_list)
726 : 0 : set_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
727 : 0 : }
728 : :
729 : : /**
730 : : * nfs_delegation_mark_reclaim - mark all delegations as needing to be reclaimed
731 : : * @clp: nfs_client to process
732 : : *
733 : : */
734 : 0 : void nfs_delegation_mark_reclaim(struct nfs_client *clp)
735 : : {
736 : : struct nfs_server *server;
737 : :
738 : : rcu_read_lock();
739 [ # # ]: 0 : list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
740 : 0 : nfs_delegation_mark_reclaim_server(server);
741 : : rcu_read_unlock();
742 : 0 : }
743 : :
744 : : /**
745 : : * nfs_delegation_reap_unclaimed - reap unclaimed delegations after reboot recovery is done
746 : : * @clp: nfs_client to process
747 : : *
748 : : */
749 : 0 : void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
750 : : {
751 : : struct nfs_delegation *delegation;
752 : 0 : struct nfs_server *server;
753 : : struct inode *inode;
754 : :
755 : : restart:
756 : : rcu_read_lock();
757 [ # # ]: 0 : list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
758 [ # # ]: 0 : list_for_each_entry_rcu(delegation, &server->delegations,
759 : : super_list) {
760 [ # # ]: 0 : if (test_bit(NFS_DELEGATION_NEED_RECLAIM,
761 : : &delegation->flags) == 0)
762 : 0 : continue;
763 : 0 : inode = nfs_delegation_grab_inode(delegation);
764 [ # # ]: 0 : if (inode == NULL)
765 : 0 : continue;
766 : 0 : delegation = nfs_detach_delegation(NFS_I(inode),
767 : : delegation, server);
768 : : rcu_read_unlock();
769 : :
770 [ # # ]: 0 : if (delegation != NULL)
771 : 0 : nfs_free_delegation(delegation);
772 : 0 : iput(inode);
773 : 0 : goto restart;
774 : : }
775 : : }
776 : : rcu_read_unlock();
777 : 0 : }
778 : :
779 : : /**
780 : : * nfs_delegations_present - check for existence of delegations
781 : : * @clp: client state handle
782 : : *
783 : : * Returns one if there are any nfs_delegation structures attached
784 : : * to this nfs_client.
785 : : */
786 : 0 : int nfs_delegations_present(struct nfs_client *clp)
787 : : {
788 : : struct nfs_server *server;
789 : : int ret = 0;
790 : :
791 : : rcu_read_lock();
792 [ # # ]: 0 : list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
793 [ # # ]: 0 : if (!list_empty(&server->delegations)) {
794 : : ret = 1;
795 : : break;
796 : : }
797 : : rcu_read_unlock();
798 : 0 : return ret;
799 : : }
800 : :
801 : : /**
802 : : * nfs4_copy_delegation_stateid - Copy inode's state ID information
803 : : * @dst: stateid data structure to fill in
804 : : * @inode: inode to check
805 : : * @flags: delegation type requirement
806 : : *
807 : : * Returns "true" and fills in "dst->data" * if inode had a delegation,
808 : : * otherwise "false" is returned.
809 : : */
810 : 0 : bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode,
811 : : fmode_t flags)
812 : : {
813 : : struct nfs_inode *nfsi = NFS_I(inode);
814 : : struct nfs_delegation *delegation;
815 : : bool ret;
816 : :
817 : 0 : flags &= FMODE_READ|FMODE_WRITE;
818 : : rcu_read_lock();
819 : 0 : delegation = rcu_dereference(nfsi->delegation);
820 [ # # ][ # # ]: 0 : ret = (delegation != NULL && (delegation->type & flags) == flags);
821 [ # # ]: 0 : if (ret) {
822 : 0 : nfs4_stateid_copy(dst, &delegation->stateid);
823 : : nfs_mark_delegation_referenced(delegation);
824 : : }
825 : : rcu_read_unlock();
826 : 0 : return ret;
827 : : }
|