Blame view
fs/nfs/delegation.c
29 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 |
/* * linux/fs/nfs/delegation.c * * Copyright (C) 2004 Trond Myklebust * * NFS file delegation management * */ |
1da177e4c Linux-2.6.12-rc2 |
9 |
#include <linux/completion.h> |
58d9714a4 NFSv4: Send RENEW... |
10 |
#include <linux/kthread.h> |
1da177e4c Linux-2.6.12-rc2 |
11 12 |
#include <linux/module.h> #include <linux/sched.h> |
5a0e3ad6a include cleanup: ... |
13 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
14 15 16 17 18 |
#include <linux/spinlock.h> #include <linux/nfs4.h> #include <linux/nfs_fs.h> #include <linux/nfs_xdr.h> |
4ce79717c [PATCH] NFS: Head... |
19 |
#include "nfs4_fs.h" |
1da177e4c Linux-2.6.12-rc2 |
20 |
#include "delegation.h" |
24c8dbbb5 NFS: Generalise t... |
21 |
#include "internal.h" |
ca8acf8d8 NFSv4: Add tracep... |
22 |
#include "nfs4trace.h" |
1da177e4c Linux-2.6.12-rc2 |
23 |
|
905f8d16e NFSv4: Don't call... |
24 25 |
static void nfs_free_delegation(struct nfs_delegation *delegation) { |
e00b8a240 NFS: Fix an NFS c... |
26 27 28 29 |
if (delegation->cred) { put_rpccred(delegation->cred); delegation->cred = NULL; } |
26f04dde6 nfs,rcu: convert ... |
30 |
kfree_rcu(delegation, rcu); |
8383e4602 NFSv4: Use RCU to... |
31 |
} |
d3978bb32 NFS: Move cl_dele... |
32 33 34 35 36 |
/** * nfs_mark_delegation_referenced - set delegation's REFERENCED flag * @delegation: delegation to process * */ |
b7391f44f NFSv4: Return unr... |
37 38 39 40 |
void nfs_mark_delegation_referenced(struct nfs_delegation *delegation) { set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags); } |
aa05c87f2 NFSv4: nfs4_copy_... |
41 42 43 44 45 46 47 48 49 50 |
static bool nfs4_is_valid_delegation(const struct nfs_delegation *delegation, fmode_t flags) { if (delegation != NULL && (delegation->type & flags) == flags && !test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) && !test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) return true; return false; } |
15bb3afe9 nfs4: add nfs4_ch... |
51 52 |
static int nfs4_do_check_delegation(struct inode *inode, fmode_t flags, bool mark) |
b7391f44f NFSv4: Return unr... |
53 54 55 56 57 58 59 |
{ struct nfs_delegation *delegation; int ret = 0; flags &= FMODE_READ|FMODE_WRITE; rcu_read_lock(); delegation = rcu_dereference(NFS_I(inode)->delegation); |
aa05c87f2 NFSv4: nfs4_copy_... |
60 |
if (nfs4_is_valid_delegation(delegation, flags)) { |
15bb3afe9 nfs4: add nfs4_ch... |
61 62 |
if (mark) nfs_mark_delegation_referenced(delegation); |
b7391f44f NFSv4: Return unr... |
63 64 65 66 67 |
ret = 1; } rcu_read_unlock(); return ret; } |
15bb3afe9 nfs4: add nfs4_ch... |
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
/** * nfs_have_delegation - check if inode has a delegation, mark it * NFS_DELEGATION_REFERENCED if there is one. * @inode: inode to check * @flags: delegation types to check for * * Returns one if inode has the indicated delegation, otherwise zero. */ int nfs4_have_delegation(struct inode *inode, fmode_t flags) { return nfs4_do_check_delegation(inode, flags, true); } /* * nfs4_check_delegation - check if inode has a delegation, do not mark * NFS_DELEGATION_REFERENCED if it has one. */ int nfs4_check_delegation(struct inode *inode, fmode_t flags) { return nfs4_do_check_delegation(inode, flags, false); } |
b7391f44f NFSv4: Return unr... |
89 |
|
db4f2e637 NFSv4: Clean up d... |
90 |
static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) |
888e694c1 NFSv4: Recover lo... |
91 92 93 |
{ struct inode *inode = state->inode; struct file_lock *fl; |
bd61e0a9c locks: convert po... |
94 95 |
struct file_lock_context *flctx = inode->i_flctx; struct list_head *list; |
d5122201a NFSv4: Move error... |
96 |
int status = 0; |
888e694c1 NFSv4: Recover lo... |
97 |
|
bd61e0a9c locks: convert po... |
98 |
if (flctx == NULL) |
65b62a29f NFSv4: Ensure del... |
99 |
goto out; |
314d7cc05 nfs: remove unnec... |
100 |
|
bd61e0a9c locks: convert po... |
101 |
list = &flctx->flc_posix; |
6109c8503 locks: add a dedi... |
102 |
spin_lock(&flctx->flc_lock); |
bd61e0a9c locks: convert po... |
103 104 |
restart: list_for_each_entry(fl, list, fl_list) { |
cd3758e37 NFS: Replace file... |
105 |
if (nfs_file_open_context(fl->fl_file) != ctx) |
888e694c1 NFSv4: Recover lo... |
106 |
continue; |
6109c8503 locks: add a dedi... |
107 |
spin_unlock(&flctx->flc_lock); |
db4f2e637 NFSv4: Clean up d... |
108 |
status = nfs4_lock_delegation_recall(fl, state, stateid); |
d5122201a NFSv4: Move error... |
109 |
if (status < 0) |
3f09df70e NFS: Ensure we al... |
110 |
goto out; |
6109c8503 locks: add a dedi... |
111 |
spin_lock(&flctx->flc_lock); |
888e694c1 NFSv4: Recover lo... |
112 |
} |
bd61e0a9c locks: convert po... |
113 114 115 |
if (list == &flctx->flc_posix) { list = &flctx->flc_flock; goto restart; |
888e694c1 NFSv4: Recover lo... |
116 |
} |
6109c8503 locks: add a dedi... |
117 |
spin_unlock(&flctx->flc_lock); |
3f09df70e NFS: Ensure we al... |
118 |
out: |
888e694c1 NFSv4: Recover lo... |
119 120 |
return status; } |
24311f884 NFSv4: Recovery o... |
121 122 |
static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid, fmode_t type) |
1da177e4c Linux-2.6.12-rc2 |
123 124 125 |
{ struct nfs_inode *nfsi = NFS_I(inode); struct nfs_open_context *ctx; |
d25be546a NFSv4.1: Don't lo... |
126 |
struct nfs4_state_owner *sp; |
1da177e4c Linux-2.6.12-rc2 |
127 |
struct nfs4_state *state; |
d25be546a NFSv4.1: Don't lo... |
128 |
unsigned int seq; |
888e694c1 NFSv4: Recover lo... |
129 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
130 131 132 133 134 135 136 137 138 |
again: spin_lock(&inode->i_lock); list_for_each_entry(ctx, &nfsi->open_files, list) { state = ctx->state; if (state == NULL) continue; if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) continue; |
f8ebf7a8c NFS: Don't try to... |
139 140 |
if (!nfs4_valid_open_stateid(state)) continue; |
f597c5379 NFSv4: Add helper... |
141 |
if (!nfs4_stateid_match(&state->stateid, stateid)) |
901630278 NFSv4: Support re... |
142 |
continue; |
1da177e4c Linux-2.6.12-rc2 |
143 144 |
get_nfs_open_context(ctx); spin_unlock(&inode->i_lock); |
d25be546a NFSv4.1: Don't lo... |
145 |
sp = state->owner; |
65b62a29f NFSv4: Ensure del... |
146 147 |
/* Block nfs4_proc_unlck */ mutex_lock(&sp->so_delegreturn_mutex); |
d25be546a NFSv4.1: Don't lo... |
148 |
seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); |
24311f884 NFSv4: Recovery o... |
149 |
err = nfs4_open_delegation_recall(ctx, state, stateid, type); |
d25be546a NFSv4.1: Don't lo... |
150 |
if (!err) |
db4f2e637 NFSv4: Clean up d... |
151 |
err = nfs_delegation_claim_locks(ctx, state, stateid); |
d25be546a NFSv4.1: Don't lo... |
152 153 |
if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) err = -EAGAIN; |
65b62a29f NFSv4: Ensure del... |
154 |
mutex_unlock(&sp->so_delegreturn_mutex); |
1da177e4c Linux-2.6.12-rc2 |
155 |
put_nfs_open_context(ctx); |
888e694c1 NFSv4: Recover lo... |
156 |
if (err != 0) |
d18cc1fda NFSv4: Fix a pote... |
157 |
return err; |
1da177e4c Linux-2.6.12-rc2 |
158 159 160 |
goto again; } spin_unlock(&inode->i_lock); |
d18cc1fda NFSv4: Fix a pote... |
161 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
162 |
} |
d3978bb32 NFS: Move cl_dele... |
163 164 165 166 167 168 |
/** * nfs_inode_reclaim_delegation - process a delegation reclaim request * @inode: inode to process * @cred: credential to use for request * @res: new delegation state from server * |
1da177e4c Linux-2.6.12-rc2 |
169 |
*/ |
d3978bb32 NFS: Move cl_dele... |
170 171 |
void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res) |
1da177e4c Linux-2.6.12-rc2 |
172 |
{ |
8f649c376 NFSv4: Fix the lo... |
173 174 |
struct nfs_delegation *delegation; struct rpc_cred *oldcred = NULL; |
1da177e4c Linux-2.6.12-rc2 |
175 |
|
8f649c376 NFSv4: Fix the lo... |
176 177 178 179 180 |
rcu_read_lock(); delegation = rcu_dereference(NFS_I(inode)->delegation); if (delegation != NULL) { spin_lock(&delegation->lock); if (delegation->inode != NULL) { |
f597c5379 NFSv4: Add helper... |
181 |
nfs4_stateid_copy(&delegation->stateid, &res->delegation); |
8f649c376 NFSv4: Fix the lo... |
182 |
delegation->type = res->delegation_type; |
7d160a6c4 NFSv4: Express de... |
183 |
delegation->pagemod_limit = res->pagemod_limit; |
8f649c376 NFSv4: Fix the lo... |
184 185 186 187 |
oldcred = delegation->cred; delegation->cred = get_rpccred(cred); clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags); |
8f649c376 NFSv4: Fix the lo... |
188 |
spin_unlock(&delegation->lock); |
8f649c376 NFSv4: Fix the lo... |
189 |
rcu_read_unlock(); |
7c0af9ffb NFSv4: Don't call... |
190 |
put_rpccred(oldcred); |
ca8acf8d8 NFSv4: Add tracep... |
191 |
trace_nfs4_reclaim_delegation(inode, res->delegation_type); |
b1a318de9 NFSv4: Fix a race... |
192 |
return; |
8f649c376 NFSv4: Fix the lo... |
193 |
} |
b1a318de9 NFSv4: Fix a race... |
194 195 |
/* We appear to have raced with a delegation return. */ spin_unlock(&delegation->lock); |
8f649c376 NFSv4: Fix the lo... |
196 |
} |
b1a318de9 NFSv4: Fix a race... |
197 198 |
rcu_read_unlock(); nfs_inode_set_delegation(inode, cred, res); |
1da177e4c Linux-2.6.12-rc2 |
199 |
} |
57bfa8917 NFSv4: Deal more ... |
200 201 202 |
static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync) { int res = 0; |
869f9dfa4 NFSv4: Fix races ... |
203 204 205 206 207 |
if (!test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid, issync); |
57bfa8917 NFSv4: Deal more ... |
208 209 210 |
nfs_free_delegation(delegation); return res; } |
86e894899 NFSv4: Fix up the... |
211 212 213 214 215 216 217 218 219 220 |
static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation) { struct inode *inode = NULL; spin_lock(&delegation->lock); if (delegation->inode != NULL) inode = igrab(delegation->inode); spin_unlock(&delegation->lock); return inode; } |
dda4b2256 NFS: Introduce nf... |
221 |
static struct nfs_delegation * |
d25be546a NFSv4.1: Don't lo... |
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
nfs_start_delegation_return_locked(struct nfs_inode *nfsi) { struct nfs_delegation *ret = NULL; struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation); if (delegation == NULL) goto out; spin_lock(&delegation->lock); if (!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) ret = delegation; spin_unlock(&delegation->lock); out: return ret; } static struct nfs_delegation * nfs_start_delegation_return(struct nfs_inode *nfsi) { struct nfs_delegation *delegation; rcu_read_lock(); delegation = nfs_start_delegation_return_locked(nfsi); rcu_read_unlock(); return delegation; } static void nfs_abort_delegation_return(struct nfs_delegation *delegation, struct nfs_client *clp) { spin_lock(&delegation->lock); clear_bit(NFS_DELEGATION_RETURNING, &delegation->flags); set_bit(NFS_DELEGATION_RETURN, &delegation->flags); spin_unlock(&delegation->lock); set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state); } static struct nfs_delegation * |
dda4b2256 NFS: Introduce nf... |
261 |
nfs_detach_delegation_locked(struct nfs_inode *nfsi, |
d25be546a NFSv4.1: Don't lo... |
262 263 |
struct nfs_delegation *delegation, struct nfs_client *clp) |
57bfa8917 NFSv4: Deal more ... |
264 |
{ |
d25be546a NFSv4.1: Don't lo... |
265 |
struct nfs_delegation *deleg_cur = |
17d2c0a0c NFS: Fix RCU issu... |
266 |
rcu_dereference_protected(nfsi->delegation, |
d25be546a NFSv4.1: Don't lo... |
267 |
lockdep_is_held(&clp->cl_lock)); |
57bfa8917 NFSv4: Deal more ... |
268 |
|
d25be546a NFSv4.1: Don't lo... |
269 270 |
if (deleg_cur == NULL || delegation != deleg_cur) return NULL; |
dda4b2256 NFS: Introduce nf... |
271 |
|
343104308 NFSv4: Fix up ano... |
272 |
spin_lock(&delegation->lock); |
d25be546a NFSv4.1: Don't lo... |
273 |
set_bit(NFS_DELEGATION_RETURNING, &delegation->flags); |
57bfa8917 NFSv4: Deal more ... |
274 |
list_del_rcu(&delegation->super_list); |
86e894899 NFSv4: Fix up the... |
275 |
delegation->inode = NULL; |
57bfa8917 NFSv4: Deal more ... |
276 |
rcu_assign_pointer(nfsi->delegation, NULL); |
343104308 NFSv4: Fix up ano... |
277 |
spin_unlock(&delegation->lock); |
57bfa8917 NFSv4: Deal more ... |
278 |
return delegation; |
57bfa8917 NFSv4: Deal more ... |
279 |
} |
dda4b2256 NFS: Introduce nf... |
280 |
static struct nfs_delegation *nfs_detach_delegation(struct nfs_inode *nfsi, |
d25be546a NFSv4.1: Don't lo... |
281 282 |
struct nfs_delegation *delegation, struct nfs_server *server) |
dda4b2256 NFS: Introduce nf... |
283 |
{ |
d3978bb32 NFS: Move cl_dele... |
284 |
struct nfs_client *clp = server->nfs_client; |
dda4b2256 NFS: Introduce nf... |
285 286 |
spin_lock(&clp->cl_lock); |
d25be546a NFSv4.1: Don't lo... |
287 |
delegation = nfs_detach_delegation_locked(nfsi, delegation, clp); |
dda4b2256 NFS: Introduce nf... |
288 289 290 |
spin_unlock(&clp->cl_lock); return delegation; } |
d25be546a NFSv4.1: Don't lo... |
291 292 293 294 295 296 297 298 299 300 301 302 |
static struct nfs_delegation * nfs_inode_detach_delegation(struct inode *inode) { struct nfs_inode *nfsi = NFS_I(inode); struct nfs_server *server = NFS_SERVER(inode); struct nfs_delegation *delegation; delegation = nfs_start_delegation_return(nfsi); if (delegation == NULL) return NULL; return nfs_detach_delegation(nfsi, delegation, server); } |
cf6726e2e NFSv4: Deal with ... |
303 304 305 306 307 308 309 310 311 312 |
static void nfs_update_inplace_delegation(struct nfs_delegation *delegation, const struct nfs_delegation *update) { if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid)) { delegation->stateid.seqid = update->stateid.seqid; smp_wmb(); delegation->type = update->type; } } |
d3978bb32 NFS: Move cl_dele... |
313 314 315 316 317 318 319 |
/** * nfs_inode_set_delegation - set up a delegation on an inode * @inode: inode to which delegation applies * @cred: cred to use for subsequent delegation processing * @res: new delegation state from server * * Returns zero on success, or a negative errno value. |
1da177e4c Linux-2.6.12-rc2 |
320 321 322 |
*/ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res) { |
d3978bb32 NFS: Move cl_dele... |
323 324 |
struct nfs_server *server = NFS_SERVER(inode); struct nfs_client *clp = server->nfs_client; |
1da177e4c Linux-2.6.12-rc2 |
325 |
struct nfs_inode *nfsi = NFS_I(inode); |
17d2c0a0c NFS: Fix RCU issu... |
326 |
struct nfs_delegation *delegation, *old_delegation; |
57bfa8917 NFSv4: Deal more ... |
327 |
struct nfs_delegation *freeme = NULL; |
1da177e4c Linux-2.6.12-rc2 |
328 |
int status = 0; |
8535b2be5 NFSv4: Don't use ... |
329 |
delegation = kmalloc(sizeof(*delegation), GFP_NOFS); |
1da177e4c Linux-2.6.12-rc2 |
330 331 |
if (delegation == NULL) return -ENOMEM; |
f597c5379 NFSv4: Add helper... |
332 |
nfs4_stateid_copy(&delegation->stateid, &res->delegation); |
1da177e4c Linux-2.6.12-rc2 |
333 |
delegation->type = res->delegation_type; |
7d160a6c4 NFSv4: Express de... |
334 |
delegation->pagemod_limit = res->pagemod_limit; |
a9a4a87a5 NFS: Use the inod... |
335 |
delegation->change_attr = inode->i_version; |
1da177e4c Linux-2.6.12-rc2 |
336 337 |
delegation->cred = get_rpccred(cred); delegation->inode = inode; |
b7391f44f NFSv4: Return unr... |
338 |
delegation->flags = 1<<NFS_DELEGATION_REFERENCED; |
343104308 NFSv4: Fix up ano... |
339 |
spin_lock_init(&delegation->lock); |
1da177e4c Linux-2.6.12-rc2 |
340 341 |
spin_lock(&clp->cl_lock); |
17d2c0a0c NFS: Fix RCU issu... |
342 |
old_delegation = rcu_dereference_protected(nfsi->delegation, |
d3978bb32 NFS: Move cl_dele... |
343 |
lockdep_is_held(&clp->cl_lock)); |
17d2c0a0c NFS: Fix RCU issu... |
344 |
if (old_delegation != NULL) { |
cf6726e2e NFSv4: Deal with ... |
345 346 347 348 349 |
/* Is this an update of the existing delegation? */ if (nfs4_stateid_match_other(&old_delegation->stateid, &delegation->stateid)) { nfs_update_inplace_delegation(old_delegation, delegation); |
57bfa8917 NFSv4: Deal more ... |
350 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
351 |
} |
57bfa8917 NFSv4: Deal more ... |
352 353 354 |
/* * Deal with broken servers that hand out two * delegations for the same file. |
17280175c NFS: Fix a number... |
355 356 |
* Allow for upgrades to a WRITE delegation, but * nothing else. |
57bfa8917 NFSv4: Deal more ... |
357 358 359 360 |
*/ dfprintk(FILE, "%s: server %s handed out " "a duplicate delegation! ", |
3110ff804 nfs: replace rema... |
361 |
__func__, clp->cl_hostname); |
17280175c NFS: Fix a number... |
362 363 |
if (delegation->type == old_delegation->type || !(delegation->type & FMODE_WRITE)) { |
57bfa8917 NFSv4: Deal more ... |
364 365 366 367 |
freeme = delegation; delegation = NULL; goto out; } |
ade04647d NFSv4: Ensure we ... |
368 369 370 371 |
if (test_and_set_bit(NFS_DELEGATION_RETURNING, &old_delegation->flags)) goto out; freeme = nfs_detach_delegation_locked(nfsi, |
d25be546a NFSv4.1: Don't lo... |
372 373 374 |
old_delegation, clp); if (freeme == NULL) goto out; |
1da177e4c Linux-2.6.12-rc2 |
375 |
} |
38942ba20 NFSv4: Append del... |
376 |
list_add_tail_rcu(&delegation->super_list, &server->delegations); |
57bfa8917 NFSv4: Deal more ... |
377 378 |
rcu_assign_pointer(nfsi->delegation, delegation); delegation = NULL; |
412c77cee NFSv4: Defer inod... |
379 |
|
ca8acf8d8 NFSv4: Add tracep... |
380 |
trace_nfs4_set_delegation(inode, res->delegation_type); |
412c77cee NFSv4: Defer inod... |
381 |
|
57bfa8917 NFSv4: Deal more ... |
382 |
out: |
1da177e4c Linux-2.6.12-rc2 |
383 |
spin_unlock(&clp->cl_lock); |
603c83da1 NFSv4: Fix an rpc... |
384 385 |
if (delegation != NULL) nfs_free_delegation(delegation); |
57bfa8917 NFSv4: Deal more ... |
386 387 |
if (freeme != NULL) nfs_do_return_delegation(inode, freeme, 0); |
1da177e4c Linux-2.6.12-rc2 |
388 389 |
return status; } |
1da177e4c Linux-2.6.12-rc2 |
390 391 392 |
/* * Basic procedure for returning a delegation to the server */ |
d25be546a NFSv4.1: Don't lo... |
393 |
static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation *delegation, int issync) |
1da177e4c Linux-2.6.12-rc2 |
394 |
{ |
d25be546a NFSv4.1: Don't lo... |
395 |
struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
1da177e4c Linux-2.6.12-rc2 |
396 |
struct nfs_inode *nfsi = NFS_I(inode); |
869f9dfa4 NFSv4: Fix races ... |
397 |
int err = 0; |
1da177e4c Linux-2.6.12-rc2 |
398 |
|
d25be546a NFSv4.1: Don't lo... |
399 400 401 |
if (delegation == NULL) return 0; do { |
869f9dfa4 NFSv4: Fix races ... |
402 403 |
if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) break; |
24311f884 NFSv4: Recovery o... |
404 405 |
err = nfs_delegation_claim_opens(inode, &delegation->stateid, delegation->type); |
d25be546a NFSv4.1: Don't lo... |
406 407 408 409 410 411 412 413 414 415 416 417 418 |
if (!issync || err != -EAGAIN) break; /* * Guard against state recovery */ err = nfs4_wait_clnt_recover(clp); } while (err == 0); if (err) { nfs_abort_delegation_return(delegation, clp); goto out; } if (!nfs_detach_delegation(nfsi, delegation, NFS_SERVER(inode))) |
d18cc1fda NFSv4: Fix a pote... |
419 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
420 |
|
d18cc1fda NFSv4: Fix a pote... |
421 422 423 |
err = nfs_do_return_delegation(inode, delegation, issync); out: return err; |
901630278 NFSv4: Support re... |
424 |
} |
b757144fd NFSv4: Be less ag... |
425 426 427 |
static bool nfs_delegation_need_return(struct nfs_delegation *delegation) { bool ret = false; |
ec3ca4e57 NFSv4: Ensure we ... |
428 429 |
if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) goto out; |
b757144fd NFSv4: Be less ag... |
430 431 432 433 434 435 436 437 438 439 440 |
if (test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags)) ret = true; if (test_and_clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags) && !ret) { struct inode *inode; spin_lock(&delegation->lock); inode = delegation->inode; if (inode && list_empty(&NFS_I(inode)->open_files)) ret = true; spin_unlock(&delegation->lock); } |
ec3ca4e57 NFSv4: Ensure we ... |
441 |
out: |
b757144fd NFSv4: Be less ag... |
442 443 |
return ret; } |
d3978bb32 NFS: Move cl_dele... |
444 445 446 447 |
/** * nfs_client_return_marked_delegations - return previously marked delegations * @clp: nfs_client to process * |
dc327ed4c NFSv4: nfs_client... |
448 449 450 451 |
* Note that this function is designed to be called by the state * manager thread. For this reason, it cannot flush the dirty data, * since that could deadlock in case of a state recovery error. * |
d3978bb32 NFS: Move cl_dele... |
452 |
* Returns zero on success, or a negative errno value. |
515d86117 NFSv4: Clean up t... |
453 |
*/ |
d18cc1fda NFSv4: Fix a pote... |
454 |
int nfs_client_return_marked_delegations(struct nfs_client *clp) |
515d86117 NFSv4: Clean up t... |
455 456 |
{ struct nfs_delegation *delegation; |
d3978bb32 NFS: Move cl_dele... |
457 |
struct nfs_server *server; |
515d86117 NFSv4: Clean up t... |
458 |
struct inode *inode; |
d18cc1fda NFSv4: Fix a pote... |
459 |
int err = 0; |
515d86117 NFSv4: Clean up t... |
460 461 462 |
restart: rcu_read_lock(); |
d3978bb32 NFS: Move cl_dele... |
463 464 465 |
list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { list_for_each_entry_rcu(delegation, &server->delegations, super_list) { |
b757144fd NFSv4: Be less ag... |
466 |
if (!nfs_delegation_need_return(delegation)) |
d3978bb32 NFS: Move cl_dele... |
467 |
continue; |
9f0f8e12c NFSv4: Pin the su... |
468 |
if (!nfs_sb_active(server->super)) |
d3978bb32 NFS: Move cl_dele... |
469 |
continue; |
9f0f8e12c NFSv4: Pin the su... |
470 471 472 473 474 475 |
inode = nfs_delegation_grab_inode(delegation); if (inode == NULL) { rcu_read_unlock(); nfs_sb_deactive(server->super); goto restart; } |
d25be546a NFSv4.1: Don't lo... |
476 |
delegation = nfs_start_delegation_return_locked(NFS_I(inode)); |
d3978bb32 NFS: Move cl_dele... |
477 |
rcu_read_unlock(); |
d25be546a NFSv4.1: Don't lo... |
478 |
err = nfs_end_delegation_return(inode, delegation, 0); |
d3978bb32 NFS: Move cl_dele... |
479 |
iput(inode); |
9f0f8e12c NFSv4: Pin the su... |
480 |
nfs_sb_deactive(server->super); |
d3978bb32 NFS: Move cl_dele... |
481 482 483 484 |
if (!err) goto restart; set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state); return err; |
d18cc1fda NFSv4: Fix a pote... |
485 |
} |
515d86117 NFSv4: Clean up t... |
486 487 |
} rcu_read_unlock(); |
d18cc1fda NFSv4: Fix a pote... |
488 |
return 0; |
515d86117 NFSv4: Clean up t... |
489 |
} |
d3978bb32 NFS: Move cl_dele... |
490 491 492 493 494 495 |
/** * nfs_inode_return_delegation_noreclaim - return delegation, don't reclaim opens * @inode: inode to process * * Does not protect against delegation reclaims, therefore really only safe * to be called from nfs4_clear_inode(). |
e6f810759 NFS: Add an async... |
496 497 498 |
*/ void nfs_inode_return_delegation_noreclaim(struct inode *inode) { |
e6f810759 NFS: Add an async... |
499 |
struct nfs_delegation *delegation; |
d25be546a NFSv4.1: Don't lo... |
500 501 |
delegation = nfs_inode_detach_delegation(inode); if (delegation != NULL) |
5fcdfacc0 NFSv4: Return del... |
502 |
nfs_do_return_delegation(inode, delegation, 1); |
e6f810759 NFS: Add an async... |
503 |
} |
d3978bb32 NFS: Move cl_dele... |
504 505 506 507 |
/** * nfs_inode_return_delegation - synchronously return a delegation * @inode: inode to process * |
c57d1bc5e NFS: nfs_inode_re... |
508 509 510 511 |
* This routine will always flush any dirty data to disk on the * assumption that if we need to return the delegation, then * we should stop caching. * |
d3978bb32 NFS: Move cl_dele... |
512 513 |
* Returns zero on success, or a negative errno value. */ |
57ec14c55 NFS: Create a ret... |
514 |
int nfs4_inode_return_delegation(struct inode *inode) |
901630278 NFSv4: Support re... |
515 |
{ |
901630278 NFSv4: Support re... |
516 517 518 |
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_delegation *delegation; int err = 0; |
c57d1bc5e NFS: nfs_inode_re... |
519 |
nfs_wb_all(inode); |
d25be546a NFSv4.1: Don't lo... |
520 521 522 |
delegation = nfs_start_delegation_return(nfsi); if (delegation != NULL) err = nfs_end_delegation_return(inode, delegation, 1); |
901630278 NFSv4: Support re... |
523 |
return err; |
1da177e4c Linux-2.6.12-rc2 |
524 |
} |
b757144fd NFSv4: Be less ag... |
525 526 527 528 529 530 |
static void nfs_mark_return_if_closed_delegation(struct nfs_server *server, struct nfs_delegation *delegation) { set_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags); set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state); } |
ed1e6211a NFSv4: Don't use ... |
531 532 |
static void nfs_mark_return_delegation(struct nfs_server *server, struct nfs_delegation *delegation) |
6411bd4a4 NFSv4: Clean up t... |
533 534 |
{ set_bit(NFS_DELEGATION_RETURN, &delegation->flags); |
ed1e6211a NFSv4: Don't use ... |
535 |
set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state); |
6411bd4a4 NFSv4: Clean up t... |
536 |
} |
5c31e2368 NFSv4: Fix nfs_se... |
537 538 539 540 541 542 543 544 545 546 547 |
static bool nfs_server_mark_return_all_delegations(struct nfs_server *server) { struct nfs_delegation *delegation; bool ret = false; list_for_each_entry_rcu(delegation, &server->delegations, super_list) { nfs_mark_return_delegation(server, delegation); ret = true; } return ret; } |
b02ba0b66 NFSv4: Clean up n... |
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 |
static void nfs_client_mark_return_all_delegations(struct nfs_client *clp) { struct nfs_server *server; rcu_read_lock(); list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) nfs_server_mark_return_all_delegations(server); rcu_read_unlock(); } static void nfs_delegation_run_state_manager(struct nfs_client *clp) { if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) nfs4_schedule_state_manager(clp); } /** * nfs_expire_all_delegations * @clp: client to process * */ void nfs_expire_all_delegations(struct nfs_client *clp) { nfs_client_mark_return_all_delegations(clp); nfs_delegation_run_state_manager(clp); } |
d3978bb32 NFS: Move cl_dele... |
574 575 576 577 |
/** * nfs_super_return_all_delegations - return delegations for one superblock * @sb: sb to process * |
1da177e4c Linux-2.6.12-rc2 |
578 |
*/ |
eeebf9167 NFS: Use nfs4_des... |
579 |
void nfs_server_return_all_delegations(struct nfs_server *server) |
1da177e4c Linux-2.6.12-rc2 |
580 |
{ |
d3978bb32 NFS: Move cl_dele... |
581 |
struct nfs_client *clp = server->nfs_client; |
5c31e2368 NFSv4: Fix nfs_se... |
582 |
bool need_wait; |
1da177e4c Linux-2.6.12-rc2 |
583 584 585 |
if (clp == NULL) return; |
d3978bb32 NFS: Move cl_dele... |
586 |
|
8383e4602 NFSv4: Use RCU to... |
587 |
rcu_read_lock(); |
5c31e2368 NFSv4: Fix nfs_se... |
588 |
need_wait = nfs_server_mark_return_all_delegations(server); |
8383e4602 NFSv4: Use RCU to... |
589 |
rcu_read_unlock(); |
d3978bb32 NFS: Move cl_dele... |
590 |
|
5c31e2368 NFSv4: Fix nfs_se... |
591 |
if (need_wait) { |
d18cc1fda NFSv4: Fix a pote... |
592 |
nfs4_schedule_state_manager(clp); |
5c31e2368 NFSv4: Fix nfs_se... |
593 594 |
nfs4_wait_clnt_recover(clp); } |
515d86117 NFSv4: Clean up t... |
595 |
} |
826e00130 NFSv4: Fix CB_REC... |
596 |
static void nfs_mark_return_unused_delegation_types(struct nfs_server *server, |
d3978bb32 NFS: Move cl_dele... |
597 |
fmode_t flags) |
515d86117 NFSv4: Clean up t... |
598 599 |
{ struct nfs_delegation *delegation; |
d3978bb32 NFS: Move cl_dele... |
600 |
list_for_each_entry_rcu(delegation, &server->delegations, super_list) { |
c79571a50 nfs4: V2 return/e... |
601 602 603 |
if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE)) continue; if (delegation->type & flags) |
826e00130 NFSv4: Fix CB_REC... |
604 |
nfs_mark_return_if_closed_delegation(server, delegation); |
707fb4b32 NFSv4: Clean up N... |
605 |
} |
d3978bb32 NFS: Move cl_dele... |
606 |
} |
826e00130 NFSv4: Fix CB_REC... |
607 |
static void nfs_client_mark_return_unused_delegation_types(struct nfs_client *clp, |
d3978bb32 NFS: Move cl_dele... |
608 609 610 611 612 613 |
fmode_t flags) { struct nfs_server *server; rcu_read_lock(); list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) |
826e00130 NFSv4: Fix CB_REC... |
614 |
nfs_mark_return_unused_delegation_types(server, flags); |
515d86117 NFSv4: Clean up t... |
615 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
616 |
} |
41020b671 NFSv4.x: Allow ca... |
617 618 619 620 |
static void nfs_mark_delegation_revoked(struct nfs_server *server, struct nfs_delegation *delegation) { set_bit(NFS_DELEGATION_REVOKED, &delegation->flags); |
059b43e97 NFSv4: Ensure we ... |
621 |
delegation->stateid.type = NFS4_INVALID_STATEID_TYPE; |
41020b671 NFSv4.x: Allow ca... |
622 623 624 625 626 |
nfs_mark_return_delegation(server, delegation); } static bool nfs_revoke_delegation(struct inode *inode, const nfs4_stateid *stateid) |
869f9dfa4 NFSv4: Fix races ... |
627 628 |
{ struct nfs_delegation *delegation; |
7f0488314 NFS: Always call ... |
629 |
nfs4_stateid tmp; |
41020b671 NFSv4.x: Allow ca... |
630 |
bool ret = false; |
869f9dfa4 NFSv4: Fix races ... |
631 632 |
rcu_read_lock(); delegation = rcu_dereference(NFS_I(inode)->delegation); |
41020b671 NFSv4.x: Allow ca... |
633 634 |
if (delegation == NULL) goto out; |
7f0488314 NFS: Always call ... |
635 636 637 638 |
if (stateid == NULL) { nfs4_stateid_copy(&tmp, &delegation->stateid); stateid = &tmp; } else if (!nfs4_stateid_match(stateid, &delegation->stateid)) |
41020b671 NFSv4.x: Allow ca... |
639 640 641 642 |
goto out; nfs_mark_delegation_revoked(NFS_SERVER(inode), delegation); ret = true; out: |
869f9dfa4 NFSv4: Fix races ... |
643 |
rcu_read_unlock(); |
7f0488314 NFS: Always call ... |
644 645 |
if (ret) nfs_inode_find_state_and_recover(inode, stateid); |
41020b671 NFSv4.x: Allow ca... |
646 |
return ret; |
869f9dfa4 NFSv4: Fix races ... |
647 |
} |
41020b671 NFSv4.x: Allow ca... |
648 649 |
void nfs_remove_bad_delegation(struct inode *inode, const nfs4_stateid *stateid) |
a1d0b5eeb NFS: Properly han... |
650 651 |
{ struct nfs_delegation *delegation; |
41020b671 NFSv4.x: Allow ca... |
652 653 |
if (!nfs_revoke_delegation(inode, stateid)) return; |
d25be546a NFSv4.1: Don't lo... |
654 |
delegation = nfs_inode_detach_delegation(inode); |
7f0488314 NFS: Always call ... |
655 |
if (delegation) |
a1d0b5eeb NFS: Properly han... |
656 |
nfs_free_delegation(delegation); |
a1d0b5eeb NFS: Properly han... |
657 |
} |
9cb819683 NFSv4.1 handle DS... |
658 |
EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation); |
a1d0b5eeb NFS: Properly han... |
659 |
|
d3978bb32 NFS: Move cl_dele... |
660 |
/** |
826e00130 NFSv4: Fix CB_REC... |
661 |
* nfs_expire_unused_delegation_types |
d3978bb32 NFS: Move cl_dele... |
662 663 664 665 |
* @clp: client to process * @flags: delegation types to expire * */ |
826e00130 NFSv4: Fix CB_REC... |
666 |
void nfs_expire_unused_delegation_types(struct nfs_client *clp, fmode_t flags) |
58d9714a4 NFSv4: Send RENEW... |
667 |
{ |
826e00130 NFSv4: Fix CB_REC... |
668 |
nfs_client_mark_return_unused_delegation_types(clp, flags); |
b0d3ded1a NFSv4: Clean up n... |
669 |
nfs_delegation_run_state_manager(clp); |
58d9714a4 NFSv4: Send RENEW... |
670 |
} |
d3978bb32 NFS: Move cl_dele... |
671 |
static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server) |
b7391f44f NFSv4: Return unr... |
672 673 |
{ struct nfs_delegation *delegation; |
d3978bb32 NFS: Move cl_dele... |
674 |
list_for_each_entry_rcu(delegation, &server->delegations, super_list) { |
b7391f44f NFSv4: Return unr... |
675 676 |
if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags)) continue; |
b757144fd NFSv4: Be less ag... |
677 |
nfs_mark_return_if_closed_delegation(server, delegation); |
b7391f44f NFSv4: Return unr... |
678 |
} |
b7391f44f NFSv4: Return unr... |
679 |
} |
d3978bb32 NFS: Move cl_dele... |
680 681 682 683 684 |
/** * nfs_expire_unreferenced_delegations - Eliminate unused delegations * @clp: nfs_client to process * */ |
b7391f44f NFSv4: Return unr... |
685 686 |
void nfs_expire_unreferenced_delegations(struct nfs_client *clp) { |
d3978bb32 NFS: Move cl_dele... |
687 688 689 690 691 692 |
struct nfs_server *server; rcu_read_lock(); list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) nfs_mark_return_unreferenced_delegations(server); rcu_read_unlock(); |
b7391f44f NFSv4: Return unr... |
693 694 |
nfs_delegation_run_state_manager(clp); } |
d3978bb32 NFS: Move cl_dele... |
695 696 697 |
/** * nfs_async_inode_return_delegation - asynchronously return a delegation * @inode: inode to process |
8e663f0e5 NFSv4.1: Fix matc... |
698 |
* @stateid: state ID information |
d3978bb32 NFS: Move cl_dele... |
699 700 |
* * Returns zero on success, or a negative errno value. |
1da177e4c Linux-2.6.12-rc2 |
701 |
*/ |
d3978bb32 NFS: Move cl_dele... |
702 703 |
int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid) |
1da177e4c Linux-2.6.12-rc2 |
704 |
{ |
ed1e6211a NFSv4: Don't use ... |
705 706 |
struct nfs_server *server = NFS_SERVER(inode); struct nfs_client *clp = server->nfs_client; |
6411bd4a4 NFSv4: Clean up t... |
707 |
struct nfs_delegation *delegation; |
1da177e4c Linux-2.6.12-rc2 |
708 |
|
6411bd4a4 NFSv4: Clean up t... |
709 710 |
rcu_read_lock(); delegation = rcu_dereference(NFS_I(inode)->delegation); |
755a48a7a NFS: Fix a delega... |
711 712 |
if (delegation == NULL) goto out_enoent; |
4816fdada NFSv4: Don't use ... |
713 714 |
if (stateid != NULL && !clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) |
755a48a7a NFS: Fix a delega... |
715 |
goto out_enoent; |
ed1e6211a NFSv4: Don't use ... |
716 |
nfs_mark_return_delegation(server, delegation); |
6411bd4a4 NFSv4: Clean up t... |
717 |
rcu_read_unlock(); |
d3978bb32 NFS: Move cl_dele... |
718 |
|
6411bd4a4 NFSv4: Clean up t... |
719 720 |
nfs_delegation_run_state_manager(clp); return 0; |
755a48a7a NFS: Fix a delega... |
721 722 723 |
out_enoent: rcu_read_unlock(); return -ENOENT; |
1da177e4c Linux-2.6.12-rc2 |
724 |
} |
d3978bb32 NFS: Move cl_dele... |
725 726 727 |
static struct inode * nfs_delegation_find_inode_server(struct nfs_server *server, const struct nfs_fh *fhandle) |
1da177e4c Linux-2.6.12-rc2 |
728 729 730 |
{ struct nfs_delegation *delegation; struct inode *res = NULL; |
d3978bb32 NFS: Move cl_dele... |
731 732 |
list_for_each_entry_rcu(delegation, &server->delegations, super_list) { |
86e894899 NFSv4: Fix up the... |
733 734 735 |
spin_lock(&delegation->lock); if (delegation->inode != NULL && nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) { |
1da177e4c Linux-2.6.12-rc2 |
736 |
res = igrab(delegation->inode); |
1da177e4c Linux-2.6.12-rc2 |
737 |
} |
86e894899 NFSv4: Fix up the... |
738 739 740 |
spin_unlock(&delegation->lock); if (res != NULL) break; |
1da177e4c Linux-2.6.12-rc2 |
741 |
} |
d3978bb32 NFS: Move cl_dele... |
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 |
return res; } /** * nfs_delegation_find_inode - retrieve the inode associated with a delegation * @clp: client state handle * @fhandle: filehandle from a delegation recall * * Returns pointer to inode matching "fhandle," or NULL if a matching inode * cannot be found. */ struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle) { struct nfs_server *server; struct inode *res = NULL; rcu_read_lock(); list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { res = nfs_delegation_find_inode_server(server, fhandle); if (res != NULL) break; } |
8383e4602 NFSv4: Use RCU to... |
765 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
766 767 |
return res; } |
d3978bb32 NFS: Move cl_dele... |
768 769 770 |
static void nfs_delegation_mark_reclaim_server(struct nfs_server *server) { struct nfs_delegation *delegation; |
45870d690 NFSv4.1: Test del... |
771 772 773 774 775 776 777 |
list_for_each_entry_rcu(delegation, &server->delegations, super_list) { /* * If the delegation may have been admin revoked, then we * cannot reclaim it. */ if (test_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags)) continue; |
d3978bb32 NFS: Move cl_dele... |
778 |
set_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags); |
45870d690 NFSv4.1: Test del... |
779 |
} |
d3978bb32 NFS: Move cl_dele... |
780 781 782 783 784 785 |
} /** * nfs_delegation_mark_reclaim - mark all delegations as needing to be reclaimed * @clp: nfs_client to process * |
1da177e4c Linux-2.6.12-rc2 |
786 |
*/ |
adfa6f980 NFS: Rename struc... |
787 |
void nfs_delegation_mark_reclaim(struct nfs_client *clp) |
1da177e4c Linux-2.6.12-rc2 |
788 |
{ |
d3978bb32 NFS: Move cl_dele... |
789 |
struct nfs_server *server; |
8383e4602 NFSv4: Use RCU to... |
790 |
rcu_read_lock(); |
d3978bb32 NFS: Move cl_dele... |
791 792 |
list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) nfs_delegation_mark_reclaim_server(server); |
8383e4602 NFSv4: Use RCU to... |
793 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
794 |
} |
d3978bb32 NFS: Move cl_dele... |
795 796 797 798 |
/** * nfs_delegation_reap_unclaimed - reap unclaimed delegations after reboot recovery is done * @clp: nfs_client to process * |
1da177e4c Linux-2.6.12-rc2 |
799 |
*/ |
adfa6f980 NFS: Rename struc... |
800 |
void nfs_delegation_reap_unclaimed(struct nfs_client *clp) |
1da177e4c Linux-2.6.12-rc2 |
801 |
{ |
8383e4602 NFSv4: Use RCU to... |
802 |
struct nfs_delegation *delegation; |
d3978bb32 NFS: Move cl_dele... |
803 |
struct nfs_server *server; |
86e894899 NFSv4: Fix up the... |
804 |
struct inode *inode; |
d3978bb32 NFS: Move cl_dele... |
805 |
|
8383e4602 NFSv4: Use RCU to... |
806 807 |
restart: rcu_read_lock(); |
d3978bb32 NFS: Move cl_dele... |
808 809 810 |
list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { list_for_each_entry_rcu(delegation, &server->delegations, super_list) { |
ec3ca4e57 NFSv4: Ensure we ... |
811 812 813 |
if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) continue; |
d3978bb32 NFS: Move cl_dele... |
814 815 816 |
if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) == 0) continue; |
9f0f8e12c NFSv4: Pin the su... |
817 |
if (!nfs_sb_active(server->super)) |
d3978bb32 NFS: Move cl_dele... |
818 |
continue; |
9f0f8e12c NFSv4: Pin the su... |
819 820 821 822 823 824 |
inode = nfs_delegation_grab_inode(delegation); if (inode == NULL) { rcu_read_unlock(); nfs_sb_deactive(server->super); goto restart; } |
b04b22f4c NFSv4: Ensure tha... |
825 |
delegation = nfs_start_delegation_return_locked(NFS_I(inode)); |
d3978bb32 NFS: Move cl_dele... |
826 |
rcu_read_unlock(); |
b04b22f4c NFSv4: Ensure tha... |
827 828 829 830 831 832 |
if (delegation != NULL) { delegation = nfs_detach_delegation(NFS_I(inode), delegation, server); if (delegation != NULL) nfs_free_delegation(delegation); } |
d3978bb32 NFS: Move cl_dele... |
833 |
iput(inode); |
9f0f8e12c NFSv4: Pin the su... |
834 |
nfs_sb_deactive(server->super); |
d3978bb32 NFS: Move cl_dele... |
835 836 |
goto restart; } |
1da177e4c Linux-2.6.12-rc2 |
837 |
} |
8383e4602 NFSv4: Use RCU to... |
838 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
839 |
} |
3e4f6290c NFSv4: Send the d... |
840 |
|
bb3d1a3b2 NFSv4.1: Deal wit... |
841 842 843 844 845 846 |
static inline bool nfs4_server_rebooted(const struct nfs_client *clp) { return (clp->cl_state & (BIT(NFS4CLNT_CHECK_LEASE) | BIT(NFS4CLNT_LEASE_EXPIRED) | BIT(NFS4CLNT_SESSION_RESET))) != 0; } |
45870d690 NFSv4.1: Test del... |
847 848 849 |
static void nfs_mark_test_expired_delegation(struct nfs_server *server, struct nfs_delegation *delegation) { |
059b43e97 NFSv4: Ensure we ... |
850 851 |
if (delegation->stateid.type == NFS4_INVALID_STATEID_TYPE) return; |
45870d690 NFSv4.1: Test del... |
852 853 854 855 |
clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags); set_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags); set_bit(NFS4CLNT_DELEGATION_EXPIRED, &server->nfs_client->cl_state); } |
bb3d1a3b2 NFSv4.1: Deal wit... |
856 857 858 859 860 861 862 863 864 865 866 867 |
static void nfs_inode_mark_test_expired_delegation(struct nfs_server *server, struct inode *inode) { struct nfs_delegation *delegation; rcu_read_lock(); delegation = rcu_dereference(NFS_I(inode)->delegation); if (delegation) nfs_mark_test_expired_delegation(server, delegation); rcu_read_unlock(); } |
45870d690 NFSv4.1: Test del... |
868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 |
static void nfs_delegation_mark_test_expired_server(struct nfs_server *server) { struct nfs_delegation *delegation; list_for_each_entry_rcu(delegation, &server->delegations, super_list) nfs_mark_test_expired_delegation(server, delegation); } /** * nfs_mark_test_expired_all_delegations - mark all delegations for testing * @clp: nfs_client to process * * Iterates through all the delegations associated with this server and * marks them as needing to be checked for validity. */ void nfs_mark_test_expired_all_delegations(struct nfs_client *clp) { struct nfs_server *server; rcu_read_lock(); list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) nfs_delegation_mark_test_expired_server(server); rcu_read_unlock(); } /** * nfs_reap_expired_delegations - reap expired delegations * @clp: nfs_client to process * * Iterates through all the delegations associated with this server and * checks if they have may have been revoked. This function is usually * expected to be called in cases where the server may have lost its * lease. */ void nfs_reap_expired_delegations(struct nfs_client *clp) { const struct nfs4_minor_version_ops *ops = clp->cl_mvops; struct nfs_delegation *delegation; struct nfs_server *server; struct inode *inode; struct rpc_cred *cred; nfs4_stateid stateid; restart: rcu_read_lock(); list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { list_for_each_entry_rcu(delegation, &server->delegations, super_list) { if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) continue; if (test_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags) == 0) continue; if (!nfs_sb_active(server->super)) continue; inode = nfs_delegation_grab_inode(delegation); if (inode == NULL) { rcu_read_unlock(); nfs_sb_deactive(server->super); goto restart; } cred = get_rpccred_rcu(delegation->cred); nfs4_stateid_copy(&stateid, &delegation->stateid); clear_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags); rcu_read_unlock(); if (cred != NULL && ops->test_and_free_expired(server, &stateid, cred) < 0) { nfs_revoke_delegation(inode, &stateid); nfs_inode_find_state_and_recover(inode, &stateid); } put_rpccred(cred); |
bb3d1a3b2 NFSv4.1: Deal wit... |
940 941 942 943 944 945 |
if (nfs4_server_rebooted(clp)) { nfs_inode_mark_test_expired_delegation(server,inode); iput(inode); nfs_sb_deactive(server->super); return; } |
45870d690 NFSv4.1: Test del... |
946 947 948 949 950 951 952 |
iput(inode); nfs_sb_deactive(server->super); goto restart; } } rcu_read_unlock(); } |
6c2d8f8d3 NFSv4: nfs_inode_... |
953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 |
void nfs_inode_find_delegation_state_and_recover(struct inode *inode, const nfs4_stateid *stateid) { struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; struct nfs_delegation *delegation; bool found = false; rcu_read_lock(); delegation = rcu_dereference(NFS_I(inode)->delegation); if (delegation && nfs4_stateid_match_other(&delegation->stateid, stateid)) { nfs_mark_test_expired_delegation(NFS_SERVER(inode), delegation); found = true; } rcu_read_unlock(); if (found) nfs4_schedule_state_manager(clp); } |
d3978bb32 NFS: Move cl_dele... |
971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 |
/** * nfs_delegations_present - check for existence of delegations * @clp: client state handle * * Returns one if there are any nfs_delegation structures attached * to this nfs_client. */ int nfs_delegations_present(struct nfs_client *clp) { struct nfs_server *server; int ret = 0; rcu_read_lock(); list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) if (!list_empty(&server->delegations)) { ret = 1; break; } rcu_read_unlock(); return ret; } /** * nfs4_copy_delegation_stateid - Copy inode's state ID information |
d3978bb32 NFS: Move cl_dele... |
995 |
* @inode: inode to check |
0032a7a74 NFS: Don't copy r... |
996 |
* @flags: delegation type requirement |
abf4e13cc NFSv4: Use the ri... |
997 998 |
* @dst: stateid data structure to fill in * @cred: optional argument to retrieve credential |
d3978bb32 NFS: Move cl_dele... |
999 |
* |
0032a7a74 NFS: Don't copy r... |
1000 1001 |
* Returns "true" and fills in "dst->data" * if inode had a delegation, * otherwise "false" is returned. |
d3978bb32 NFS: Move cl_dele... |
1002 |
*/ |
abf4e13cc NFSv4: Use the ri... |
1003 1004 |
bool nfs4_copy_delegation_stateid(struct inode *inode, fmode_t flags, nfs4_stateid *dst, struct rpc_cred **cred) |
3e4f6290c NFSv4: Send the d... |
1005 |
{ |
3e4f6290c NFSv4: Send the d... |
1006 1007 |
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_delegation *delegation; |
0032a7a74 NFS: Don't copy r... |
1008 |
bool ret; |
3e4f6290c NFSv4: Send the d... |
1009 |
|
0032a7a74 NFS: Don't copy r... |
1010 |
flags &= FMODE_READ|FMODE_WRITE; |
8383e4602 NFSv4: Use RCU to... |
1011 1012 |
rcu_read_lock(); delegation = rcu_dereference(nfsi->delegation); |
aa05c87f2 NFSv4: nfs4_copy_... |
1013 |
ret = nfs4_is_valid_delegation(delegation, flags); |
0032a7a74 NFS: Don't copy r... |
1014 |
if (ret) { |
f597c5379 NFSv4: Add helper... |
1015 |
nfs4_stateid_copy(dst, &delegation->stateid); |
0032a7a74 NFS: Don't copy r... |
1016 |
nfs_mark_delegation_referenced(delegation); |
abf4e13cc NFSv4: Use the ri... |
1017 1018 |
if (cred) *cred = get_rpccred(delegation->cred); |
3e4f6290c NFSv4: Send the d... |
1019 |
} |
8383e4602 NFSv4: Use RCU to... |
1020 1021 |
rcu_read_unlock(); return ret; |
3e4f6290c NFSv4: Send the d... |
1022 |
} |
5445b1fbd NFSv4: Respect th... |
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 |
/** * nfs4_delegation_flush_on_close - Check if we must flush file on close * @inode: inode to check * * This function checks the number of outstanding writes to the file * against the delegation 'space_limit' field to see if * the spec requires us to flush the file on close. */ bool nfs4_delegation_flush_on_close(const struct inode *inode) { struct nfs_inode *nfsi = NFS_I(inode); struct nfs_delegation *delegation; bool ret = true; rcu_read_lock(); delegation = rcu_dereference(nfsi->delegation); if (delegation == NULL || !(delegation->type & FMODE_WRITE)) goto out; |
a6b6d5b85 NFS: Use an atomi... |
1042 |
if (atomic_long_read(&nfsi->nrequests) < delegation->pagemod_limit) |
5445b1fbd NFSv4: Respect th... |
1043 1044 1045 1046 1047 |
ret = false; out: rcu_read_unlock(); return ret; } |