]> bbs.cooldavid.org Git - net-next-2.6.git/blame - fs/nfs/delegation.c
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[net-next-2.6.git] / fs / nfs / delegation.c
CommitLineData
1da177e4
LT
1/*
2 * linux/fs/nfs/delegation.c
3 *
4 * Copyright (C) 2004 Trond Myklebust
5 *
6 * NFS file delegation management
7 *
8 */
1da177e4 9#include <linux/completion.h>
58d9714a 10#include <linux/kthread.h>
1da177e4
LT
11#include <linux/module.h>
12#include <linux/sched.h>
5a0e3ad6 13#include <linux/slab.h>
405f5571 14#include <linux/smp_lock.h>
1da177e4
LT
15#include <linux/spinlock.h>
16
17#include <linux/nfs4.h>
18#include <linux/nfs_fs.h>
19#include <linux/nfs_xdr.h>
20
4ce79717 21#include "nfs4_fs.h"
1da177e4 22#include "delegation.h"
24c8dbbb 23#include "internal.h"
1da177e4 24
905f8d16 25static void nfs_do_free_delegation(struct nfs_delegation *delegation)
1da177e4 26{
1da177e4
LT
27 kfree(delegation);
28}
29
8383e460
TM
30static void nfs_free_delegation_callback(struct rcu_head *head)
31{
32 struct nfs_delegation *delegation = container_of(head, struct nfs_delegation, rcu);
33
905f8d16
TM
34 nfs_do_free_delegation(delegation);
35}
36
37static void nfs_free_delegation(struct nfs_delegation *delegation)
38{
39 struct rpc_cred *cred;
40
41 cred = rcu_dereference(delegation->cred);
42 rcu_assign_pointer(delegation->cred, NULL);
43 call_rcu(&delegation->rcu, nfs_free_delegation_callback);
44 if (cred)
45 put_rpccred(cred);
8383e460
TM
46}
47
b7391f44
TM
48void nfs_mark_delegation_referenced(struct nfs_delegation *delegation)
49{
50 set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags);
51}
52
bd7bf9d5 53int nfs_have_delegation(struct inode *inode, fmode_t flags)
b7391f44
TM
54{
55 struct nfs_delegation *delegation;
56 int ret = 0;
57
58 flags &= FMODE_READ|FMODE_WRITE;
59 rcu_read_lock();
60 delegation = rcu_dereference(NFS_I(inode)->delegation);
61 if (delegation != NULL && (delegation->type & flags) == flags) {
62 nfs_mark_delegation_referenced(delegation);
63 ret = 1;
64 }
65 rcu_read_unlock();
66 return ret;
67}
68
888e694c
TM
69static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state)
70{
71 struct inode *inode = state->inode;
72 struct file_lock *fl;
d5122201 73 int status = 0;
888e694c 74
3f09df70
TM
75 if (inode->i_flock == NULL)
76 goto out;
77
78 /* Protect inode->i_flock using the BKL */
79 lock_kernel();
90dc7d27 80 for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
888e694c
TM
81 if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
82 continue;
cd3758e3 83 if (nfs_file_open_context(fl->fl_file) != ctx)
888e694c 84 continue;
3f09df70 85 unlock_kernel();
888e694c 86 status = nfs4_lock_delegation_recall(state, fl);
d5122201 87 if (status < 0)
3f09df70
TM
88 goto out;
89 lock_kernel();
888e694c 90 }
3f09df70
TM
91 unlock_kernel();
92out:
888e694c
TM
93 return status;
94}
95
d18cc1fd 96static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid)
1da177e4
LT
97{
98 struct nfs_inode *nfsi = NFS_I(inode);
99 struct nfs_open_context *ctx;
100 struct nfs4_state *state;
888e694c 101 int err;
1da177e4
LT
102
103again:
104 spin_lock(&inode->i_lock);
105 list_for_each_entry(ctx, &nfsi->open_files, list) {
106 state = ctx->state;
107 if (state == NULL)
108 continue;
109 if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
110 continue;
90163027
TM
111 if (memcmp(state->stateid.data, stateid->data, sizeof(state->stateid.data)) != 0)
112 continue;
1da177e4
LT
113 get_nfs_open_context(ctx);
114 spin_unlock(&inode->i_lock);
13437e12 115 err = nfs4_open_delegation_recall(ctx, state, stateid);
888e694c
TM
116 if (err >= 0)
117 err = nfs_delegation_claim_locks(ctx, state);
1da177e4 118 put_nfs_open_context(ctx);
888e694c 119 if (err != 0)
d18cc1fd 120 return err;
1da177e4
LT
121 goto again;
122 }
123 spin_unlock(&inode->i_lock);
d18cc1fd 124 return 0;
1da177e4
LT
125}
126
127/*
128 * Set up a delegation on an inode
129 */
130void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
131{
132 struct nfs_delegation *delegation = NFS_I(inode)->delegation;
05c88bab 133 struct rpc_cred *oldcred;
1da177e4
LT
134
135 if (delegation == NULL)
136 return;
137 memcpy(delegation->stateid.data, res->delegation.data,
138 sizeof(delegation->stateid.data));
139 delegation->type = res->delegation_type;
140 delegation->maxsize = res->maxsize;
05c88bab 141 oldcred = delegation->cred;
1da177e4 142 delegation->cred = get_rpccred(cred);
15c831bf 143 clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
1da177e4
LT
144 NFS_I(inode)->delegation_state = delegation->type;
145 smp_wmb();
05c88bab 146 put_rpccred(oldcred);
1da177e4
LT
147}
148
57bfa891
TM
149static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync)
150{
151 int res = 0;
152
153 res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid, issync);
154 nfs_free_delegation(delegation);
155 return res;
156}
157
86e89489
TM
158static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation)
159{
160 struct inode *inode = NULL;
161
162 spin_lock(&delegation->lock);
163 if (delegation->inode != NULL)
164 inode = igrab(delegation->inode);
165 spin_unlock(&delegation->lock);
166 return inode;
167}
168
57bfa891
TM
169static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid)
170{
171 struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation);
172
173 if (delegation == NULL)
174 goto nomatch;
34310430 175 spin_lock(&delegation->lock);
57bfa891
TM
176 if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data,
177 sizeof(delegation->stateid.data)) != 0)
34310430 178 goto nomatch_unlock;
57bfa891 179 list_del_rcu(&delegation->super_list);
86e89489 180 delegation->inode = NULL;
57bfa891
TM
181 nfsi->delegation_state = 0;
182 rcu_assign_pointer(nfsi->delegation, NULL);
34310430 183 spin_unlock(&delegation->lock);
57bfa891 184 return delegation;
34310430
TM
185nomatch_unlock:
186 spin_unlock(&delegation->lock);
57bfa891
TM
187nomatch:
188 return NULL;
189}
190
1da177e4
LT
191/*
192 * Set up a delegation on an inode
193 */
194int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
195{
7539bbab 196 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
1da177e4
LT
197 struct nfs_inode *nfsi = NFS_I(inode);
198 struct nfs_delegation *delegation;
57bfa891 199 struct nfs_delegation *freeme = NULL;
1da177e4
LT
200 int status = 0;
201
f52720ca 202 delegation = kmalloc(sizeof(*delegation), GFP_KERNEL);
1da177e4
LT
203 if (delegation == NULL)
204 return -ENOMEM;
205 memcpy(delegation->stateid.data, res->delegation.data,
206 sizeof(delegation->stateid.data));
207 delegation->type = res->delegation_type;
208 delegation->maxsize = res->maxsize;
beb2a5ec 209 delegation->change_attr = nfsi->change_attr;
1da177e4
LT
210 delegation->cred = get_rpccred(cred);
211 delegation->inode = inode;
b7391f44 212 delegation->flags = 1<<NFS_DELEGATION_REFERENCED;
34310430 213 spin_lock_init(&delegation->lock);
1da177e4
LT
214
215 spin_lock(&clp->cl_lock);
57bfa891 216 if (rcu_dereference(nfsi->delegation) != NULL) {
1da177e4 217 if (memcmp(&delegation->stateid, &nfsi->delegation->stateid,
57bfa891
TM
218 sizeof(delegation->stateid)) == 0 &&
219 delegation->type == nfsi->delegation->type) {
220 goto out;
1da177e4 221 }
57bfa891
TM
222 /*
223 * Deal with broken servers that hand out two
224 * delegations for the same file.
225 */
226 dfprintk(FILE, "%s: server %s handed out "
227 "a duplicate delegation!\n",
3110ff80 228 __func__, clp->cl_hostname);
57bfa891
TM
229 if (delegation->type <= nfsi->delegation->type) {
230 freeme = delegation;
231 delegation = NULL;
232 goto out;
233 }
234 freeme = nfs_detach_delegation_locked(nfsi, NULL);
1da177e4 235 }
57bfa891
TM
236 list_add_rcu(&delegation->super_list, &clp->cl_delegations);
237 nfsi->delegation_state = delegation->type;
238 rcu_assign_pointer(nfsi->delegation, delegation);
239 delegation = NULL;
412c77ce
TM
240
241 /* Ensure we revalidate the attributes and page cache! */
242 spin_lock(&inode->i_lock);
243 nfsi->cache_validity |= NFS_INO_REVAL_FORCED;
244 spin_unlock(&inode->i_lock);
245
57bfa891 246out:
1da177e4 247 spin_unlock(&clp->cl_lock);
603c83da
TM
248 if (delegation != NULL)
249 nfs_free_delegation(delegation);
57bfa891
TM
250 if (freeme != NULL)
251 nfs_do_return_delegation(inode, freeme, 0);
1da177e4
LT
252 return status;
253}
254
1da177e4
LT
255/* Sync all data to disk upon delegation return */
256static void nfs_msync_inode(struct inode *inode)
257{
258 filemap_fdatawrite(inode->i_mapping);
259 nfs_wb_all(inode);
260 filemap_fdatawait(inode->i_mapping);
261}
262
263/*
264 * Basic procedure for returning a delegation to the server
265 */
d18cc1fd 266static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync)
1da177e4 267{
1da177e4 268 struct nfs_inode *nfsi = NFS_I(inode);
d18cc1fd 269 int err;
1da177e4 270
3f09df70
TM
271 /*
272 * Guard against new delegated open/lock/unlock calls and against
273 * state recovery
274 */
1da177e4 275 down_write(&nfsi->rwsem);
d18cc1fd 276 err = nfs_delegation_claim_opens(inode, &delegation->stateid);
1da177e4 277 up_write(&nfsi->rwsem);
d18cc1fd
TM
278 if (err)
279 goto out;
1da177e4 280
d18cc1fd
TM
281 err = nfs_do_return_delegation(inode, delegation, issync);
282out:
283 return err;
90163027
TM
284}
285
515d8611
TM
286/*
287 * Return all delegations that have been marked for return
288 */
d18cc1fd 289int nfs_client_return_marked_delegations(struct nfs_client *clp)
515d8611
TM
290{
291 struct nfs_delegation *delegation;
292 struct inode *inode;
d18cc1fd 293 int err = 0;
515d8611
TM
294
295restart:
296 rcu_read_lock();
297 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
298 if (!test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
299 continue;
300 inode = nfs_delegation_grab_inode(delegation);
301 if (inode == NULL)
302 continue;
303 spin_lock(&clp->cl_lock);
304 delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
305 spin_unlock(&clp->cl_lock);
306 rcu_read_unlock();
d18cc1fd
TM
307 if (delegation != NULL) {
308 filemap_flush(inode->i_mapping);
309 err = __nfs_inode_return_delegation(inode, delegation, 0);
310 }
515d8611 311 iput(inode);
d18cc1fd
TM
312 if (!err)
313 goto restart;
314 set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
315 return err;
515d8611
TM
316 }
317 rcu_read_unlock();
d18cc1fd 318 return 0;
515d8611
TM
319}
320
e6f81075
TM
321/*
322 * This function returns the delegation without reclaiming opens
323 * or protecting against delegation reclaims.
324 * It is therefore really only safe to be called from
325 * nfs4_clear_inode()
326 */
327void nfs_inode_return_delegation_noreclaim(struct inode *inode)
328{
329 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
330 struct nfs_inode *nfsi = NFS_I(inode);
331 struct nfs_delegation *delegation;
332
333 if (rcu_dereference(nfsi->delegation) != NULL) {
334 spin_lock(&clp->cl_lock);
335 delegation = nfs_detach_delegation_locked(nfsi, NULL);
336 spin_unlock(&clp->cl_lock);
337 if (delegation != NULL)
338 nfs_do_return_delegation(inode, delegation, 0);
339 }
340}
341
90163027
TM
342int nfs_inode_return_delegation(struct inode *inode)
343{
344 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
345 struct nfs_inode *nfsi = NFS_I(inode);
346 struct nfs_delegation *delegation;
347 int err = 0;
348
8383e460 349 if (rcu_dereference(nfsi->delegation) != NULL) {
90163027
TM
350 spin_lock(&clp->cl_lock);
351 delegation = nfs_detach_delegation_locked(nfsi, NULL);
352 spin_unlock(&clp->cl_lock);
d18cc1fd
TM
353 if (delegation != NULL) {
354 nfs_msync_inode(inode);
355 err = __nfs_inode_return_delegation(inode, delegation, 1);
356 }
90163027
TM
357 }
358 return err;
1da177e4
LT
359}
360
6411bd4a
TM
361static void nfs_mark_return_delegation(struct nfs_client *clp, struct nfs_delegation *delegation)
362{
363 set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
364 set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
365}
366
1da177e4
LT
367/*
368 * Return all delegations associated to a super block
369 */
515d8611 370void nfs_super_return_all_delegations(struct super_block *sb)
1da177e4 371{
7539bbab 372 struct nfs_client *clp = NFS_SB(sb)->nfs_client;
1da177e4 373 struct nfs_delegation *delegation;
1da177e4
LT
374
375 if (clp == NULL)
376 return;
8383e460
TM
377 rcu_read_lock();
378 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
86e89489
TM
379 spin_lock(&delegation->lock);
380 if (delegation->inode != NULL && delegation->inode->i_sb == sb)
515d8611 381 set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
86e89489 382 spin_unlock(&delegation->lock);
1da177e4 383 }
8383e460 384 rcu_read_unlock();
d18cc1fd
TM
385 if (nfs_client_return_marked_delegations(clp) != 0)
386 nfs4_schedule_state_manager(clp);
515d8611
TM
387}
388
c79571a5
AB
389static
390void nfs_client_mark_return_all_delegation_types(struct nfs_client *clp, fmode_t flags)
515d8611
TM
391{
392 struct nfs_delegation *delegation;
393
394 rcu_read_lock();
707fb4b3 395 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
c79571a5
AB
396 if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE))
397 continue;
398 if (delegation->type & flags)
399 nfs_mark_return_delegation(clp, delegation);
707fb4b3 400 }
515d8611 401 rcu_read_unlock();
1da177e4
LT
402}
403
c79571a5
AB
404static void nfs_client_mark_return_all_delegations(struct nfs_client *clp)
405{
406 nfs_client_mark_return_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
407}
408
b0d3ded1 409static void nfs_delegation_run_state_manager(struct nfs_client *clp)
58d9714a 410{
b0d3ded1
TM
411 if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
412 nfs4_schedule_state_manager(clp);
58d9714a
TM
413}
414
31f09607 415void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags)
58d9714a 416{
c79571a5 417 nfs_client_mark_return_all_delegation_types(clp, flags);
b0d3ded1 418 nfs_delegation_run_state_manager(clp);
58d9714a
TM
419}
420
c79571a5
AB
421void nfs_expire_all_delegations(struct nfs_client *clp)
422{
423 nfs_expire_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
424}
425
1da177e4
LT
426/*
427 * Return all delegations following an NFS4ERR_CB_PATH_DOWN error.
428 */
adfa6f98 429void nfs_handle_cb_pathdown(struct nfs_client *clp)
1da177e4 430{
1da177e4
LT
431 if (clp == NULL)
432 return;
707fb4b3 433 nfs_client_mark_return_all_delegations(clp);
1da177e4
LT
434}
435
b7391f44
TM
436static void nfs_client_mark_return_unreferenced_delegations(struct nfs_client *clp)
437{
438 struct nfs_delegation *delegation;
439
440 rcu_read_lock();
441 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
442 if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
443 continue;
b4a6f496 444 nfs_mark_return_delegation(clp, delegation);
b7391f44
TM
445 }
446 rcu_read_unlock();
447}
448
449void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
450{
451 nfs_client_mark_return_unreferenced_delegations(clp);
452 nfs_delegation_run_state_manager(clp);
453}
454
1da177e4
LT
455/*
456 * Asynchronous delegation recall!
457 */
2597641d
AB
458int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid,
459 int (*validate_stateid)(struct nfs_delegation *delegation,
460 const nfs4_stateid *stateid))
1da177e4 461{
6411bd4a
TM
462 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
463 struct nfs_delegation *delegation;
1da177e4 464
6411bd4a
TM
465 rcu_read_lock();
466 delegation = rcu_dereference(NFS_I(inode)->delegation);
2597641d
AB
467
468 if (!validate_stateid(delegation, stateid)) {
6411bd4a
TM
469 rcu_read_unlock();
470 return -ENOENT;
471 }
2597641d 472
6411bd4a
TM
473 nfs_mark_return_delegation(clp, delegation);
474 rcu_read_unlock();
475 nfs_delegation_run_state_manager(clp);
476 return 0;
1da177e4
LT
477}
478
479/*
480 * Retrieve the inode associated with a delegation
481 */
adfa6f98 482struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle)
1da177e4
LT
483{
484 struct nfs_delegation *delegation;
485 struct inode *res = NULL;
8383e460
TM
486 rcu_read_lock();
487 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
86e89489
TM
488 spin_lock(&delegation->lock);
489 if (delegation->inode != NULL &&
490 nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
1da177e4 491 res = igrab(delegation->inode);
1da177e4 492 }
86e89489
TM
493 spin_unlock(&delegation->lock);
494 if (res != NULL)
495 break;
1da177e4 496 }
8383e460 497 rcu_read_unlock();
1da177e4
LT
498 return res;
499}
500
501/*
502 * Mark all delegations as needing to be reclaimed
503 */
adfa6f98 504void nfs_delegation_mark_reclaim(struct nfs_client *clp)
1da177e4
LT
505{
506 struct nfs_delegation *delegation;
8383e460
TM
507 rcu_read_lock();
508 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list)
15c831bf 509 set_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
8383e460 510 rcu_read_unlock();
1da177e4
LT
511}
512
513/*
514 * Reap all unclaimed delegations after reboot recovery is done
515 */
adfa6f98 516void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
1da177e4 517{
8383e460 518 struct nfs_delegation *delegation;
86e89489 519 struct inode *inode;
8383e460
TM
520restart:
521 rcu_read_lock();
522 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
15c831bf 523 if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) == 0)
1da177e4 524 continue;
86e89489
TM
525 inode = nfs_delegation_grab_inode(delegation);
526 if (inode == NULL)
527 continue;
8383e460 528 spin_lock(&clp->cl_lock);
86e89489 529 delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
8383e460
TM
530 spin_unlock(&clp->cl_lock);
531 rcu_read_unlock();
532 if (delegation != NULL)
905f8d16 533 nfs_free_delegation(delegation);
86e89489 534 iput(inode);
8383e460 535 goto restart;
1da177e4 536 }
8383e460 537 rcu_read_unlock();
1da177e4 538}
3e4f6290
TM
539
540int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode)
541{
3e4f6290
TM
542 struct nfs_inode *nfsi = NFS_I(inode);
543 struct nfs_delegation *delegation;
8383e460 544 int ret = 0;
3e4f6290 545
8383e460
TM
546 rcu_read_lock();
547 delegation = rcu_dereference(nfsi->delegation);
3e4f6290
TM
548 if (delegation != NULL) {
549 memcpy(dst->data, delegation->stateid.data, sizeof(dst->data));
8383e460 550 ret = 1;
3e4f6290 551 }
8383e460
TM
552 rcu_read_unlock();
553 return ret;
3e4f6290 554}