diff options
Diffstat (limited to 'fs/nfs/nfs4state.c')
-rw-r--r-- | fs/nfs/nfs4state.c | 424 |
1 files changed, 311 insertions, 113 deletions
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 3e2f19b04c06..e97dd219f84f 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -40,12 +40,13 @@ | |||
40 | 40 | ||
41 | #include <linux/kernel.h> | 41 | #include <linux/kernel.h> |
42 | #include <linux/slab.h> | 42 | #include <linux/slab.h> |
43 | #include <linux/smp_lock.h> | 43 | #include <linux/fs.h> |
44 | #include <linux/nfs_fs.h> | 44 | #include <linux/nfs_fs.h> |
45 | #include <linux/nfs_idmap.h> | 45 | #include <linux/nfs_idmap.h> |
46 | #include <linux/kthread.h> | 46 | #include <linux/kthread.h> |
47 | #include <linux/module.h> | 47 | #include <linux/module.h> |
48 | #include <linux/random.h> | 48 | #include <linux/random.h> |
49 | #include <linux/ratelimit.h> | ||
49 | #include <linux/workqueue.h> | 50 | #include <linux/workqueue.h> |
50 | #include <linux/bitops.h> | 51 | #include <linux/bitops.h> |
51 | 52 | ||
@@ -53,6 +54,7 @@ | |||
53 | #include "callback.h" | 54 | #include "callback.h" |
54 | #include "delegation.h" | 55 | #include "delegation.h" |
55 | #include "internal.h" | 56 | #include "internal.h" |
57 | #include "pnfs.h" | ||
56 | 58 | ||
57 | #define OPENOWNER_POOL_SIZE 8 | 59 | #define OPENOWNER_POOL_SIZE 8 |
58 | 60 | ||
@@ -62,10 +64,15 @@ static LIST_HEAD(nfs4_clientid_list); | |||
62 | 64 | ||
63 | int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) | 65 | int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) |
64 | { | 66 | { |
65 | struct nfs4_setclientid_res clid; | 67 | struct nfs4_setclientid_res clid = { |
68 | .clientid = clp->cl_clientid, | ||
69 | .confirm = clp->cl_confirm, | ||
70 | }; | ||
66 | unsigned short port; | 71 | unsigned short port; |
67 | int status; | 72 | int status; |
68 | 73 | ||
74 | if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state)) | ||
75 | goto do_confirm; | ||
69 | port = nfs_callback_tcpport; | 76 | port = nfs_callback_tcpport; |
70 | if (clp->cl_addr.ss_family == AF_INET6) | 77 | if (clp->cl_addr.ss_family == AF_INET6) |
71 | port = nfs_callback_tcpport6; | 78 | port = nfs_callback_tcpport6; |
@@ -73,10 +80,14 @@ int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) | |||
73 | status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid); | 80 | status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid); |
74 | if (status != 0) | 81 | if (status != 0) |
75 | goto out; | 82 | goto out; |
83 | clp->cl_clientid = clid.clientid; | ||
84 | clp->cl_confirm = clid.confirm; | ||
85 | set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); | ||
86 | do_confirm: | ||
76 | status = nfs4_proc_setclientid_confirm(clp, &clid, cred); | 87 | status = nfs4_proc_setclientid_confirm(clp, &clid, cred); |
77 | if (status != 0) | 88 | if (status != 0) |
78 | goto out; | 89 | goto out; |
79 | clp->cl_clientid = clid.clientid; | 90 | clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); |
80 | nfs4_schedule_state_renewal(clp); | 91 | nfs4_schedule_state_renewal(clp); |
81 | out: | 92 | out: |
82 | return status; | 93 | return status; |
@@ -103,14 +114,17 @@ static void nfs4_clear_machine_cred(struct nfs_client *clp) | |||
103 | put_rpccred(cred); | 114 | put_rpccred(cred); |
104 | } | 115 | } |
105 | 116 | ||
106 | struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp) | 117 | static struct rpc_cred * |
118 | nfs4_get_renew_cred_server_locked(struct nfs_server *server) | ||
107 | { | 119 | { |
120 | struct rpc_cred *cred = NULL; | ||
108 | struct nfs4_state_owner *sp; | 121 | struct nfs4_state_owner *sp; |
109 | struct rb_node *pos; | 122 | struct rb_node *pos; |
110 | struct rpc_cred *cred = NULL; | ||
111 | 123 | ||
112 | for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { | 124 | for (pos = rb_first(&server->state_owners); |
113 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | 125 | pos != NULL; |
126 | pos = rb_next(pos)) { | ||
127 | sp = rb_entry(pos, struct nfs4_state_owner, so_server_node); | ||
114 | if (list_empty(&sp->so_states)) | 128 | if (list_empty(&sp->so_states)) |
115 | continue; | 129 | continue; |
116 | cred = get_rpccred(sp->so_cred); | 130 | cred = get_rpccred(sp->so_cred); |
@@ -119,6 +133,28 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp) | |||
119 | return cred; | 133 | return cred; |
120 | } | 134 | } |
121 | 135 | ||
136 | /** | ||
137 | * nfs4_get_renew_cred_locked - Acquire credential for a renew operation | ||
138 | * @clp: client state handle | ||
139 | * | ||
140 | * Returns an rpc_cred with reference count bumped, or NULL. | ||
141 | * Caller must hold clp->cl_lock. | ||
142 | */ | ||
143 | struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp) | ||
144 | { | ||
145 | struct rpc_cred *cred = NULL; | ||
146 | struct nfs_server *server; | ||
147 | |||
148 | rcu_read_lock(); | ||
149 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { | ||
150 | cred = nfs4_get_renew_cred_server_locked(server); | ||
151 | if (cred != NULL) | ||
152 | break; | ||
153 | } | ||
154 | rcu_read_unlock(); | ||
155 | return cred; | ||
156 | } | ||
157 | |||
122 | #if defined(CONFIG_NFS_V4_1) | 158 | #if defined(CONFIG_NFS_V4_1) |
123 | 159 | ||
124 | static int nfs41_setup_state_renewal(struct nfs_client *clp) | 160 | static int nfs41_setup_state_renewal(struct nfs_client *clp) |
@@ -126,6 +162,11 @@ static int nfs41_setup_state_renewal(struct nfs_client *clp) | |||
126 | int status; | 162 | int status; |
127 | struct nfs_fsinfo fsinfo; | 163 | struct nfs_fsinfo fsinfo; |
128 | 164 | ||
165 | if (!test_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state)) { | ||
166 | nfs4_schedule_state_renewal(clp); | ||
167 | return 0; | ||
168 | } | ||
169 | |||
129 | status = nfs4_proc_get_lease_time(clp, &fsinfo); | 170 | status = nfs4_proc_get_lease_time(clp, &fsinfo); |
130 | if (status == 0) { | 171 | if (status == 0) { |
131 | /* Update lease time and schedule renewal */ | 172 | /* Update lease time and schedule renewal */ |
@@ -140,6 +181,11 @@ static int nfs41_setup_state_renewal(struct nfs_client *clp) | |||
140 | return status; | 181 | return status; |
141 | } | 182 | } |
142 | 183 | ||
184 | /* | ||
185 | * Back channel returns NFS4ERR_DELAY for new requests when | ||
186 | * NFS4_SESSION_DRAINING is set so there is no work to be done when draining | ||
187 | * is ended. | ||
188 | */ | ||
143 | static void nfs4_end_drain_session(struct nfs_client *clp) | 189 | static void nfs4_end_drain_session(struct nfs_client *clp) |
144 | { | 190 | { |
145 | struct nfs4_session *ses = clp->cl_session; | 191 | struct nfs4_session *ses = clp->cl_session; |
@@ -163,33 +209,48 @@ static void nfs4_end_drain_session(struct nfs_client *clp) | |||
163 | } | 209 | } |
164 | } | 210 | } |
165 | 211 | ||
166 | static int nfs4_begin_drain_session(struct nfs_client *clp) | 212 | static int nfs4_wait_on_slot_tbl(struct nfs4_slot_table *tbl) |
167 | { | 213 | { |
168 | struct nfs4_session *ses = clp->cl_session; | ||
169 | struct nfs4_slot_table *tbl = &ses->fc_slot_table; | ||
170 | |||
171 | spin_lock(&tbl->slot_tbl_lock); | 214 | spin_lock(&tbl->slot_tbl_lock); |
172 | set_bit(NFS4_SESSION_DRAINING, &ses->session_state); | ||
173 | if (tbl->highest_used_slotid != -1) { | 215 | if (tbl->highest_used_slotid != -1) { |
174 | INIT_COMPLETION(ses->complete); | 216 | INIT_COMPLETION(tbl->complete); |
175 | spin_unlock(&tbl->slot_tbl_lock); | 217 | spin_unlock(&tbl->slot_tbl_lock); |
176 | return wait_for_completion_interruptible(&ses->complete); | 218 | return wait_for_completion_interruptible(&tbl->complete); |
177 | } | 219 | } |
178 | spin_unlock(&tbl->slot_tbl_lock); | 220 | spin_unlock(&tbl->slot_tbl_lock); |
179 | return 0; | 221 | return 0; |
180 | } | 222 | } |
181 | 223 | ||
224 | static int nfs4_begin_drain_session(struct nfs_client *clp) | ||
225 | { | ||
226 | struct nfs4_session *ses = clp->cl_session; | ||
227 | int ret = 0; | ||
228 | |||
229 | set_bit(NFS4_SESSION_DRAINING, &ses->session_state); | ||
230 | /* back channel */ | ||
231 | ret = nfs4_wait_on_slot_tbl(&ses->bc_slot_table); | ||
232 | if (ret) | ||
233 | return ret; | ||
234 | /* fore channel */ | ||
235 | return nfs4_wait_on_slot_tbl(&ses->fc_slot_table); | ||
236 | } | ||
237 | |||
182 | int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) | 238 | int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) |
183 | { | 239 | { |
184 | int status; | 240 | int status; |
185 | 241 | ||
242 | if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state)) | ||
243 | goto do_confirm; | ||
186 | nfs4_begin_drain_session(clp); | 244 | nfs4_begin_drain_session(clp); |
187 | status = nfs4_proc_exchange_id(clp, cred); | 245 | status = nfs4_proc_exchange_id(clp, cred); |
188 | if (status != 0) | 246 | if (status != 0) |
189 | goto out; | 247 | goto out; |
248 | set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); | ||
249 | do_confirm: | ||
190 | status = nfs4_proc_create_session(clp); | 250 | status = nfs4_proc_create_session(clp); |
191 | if (status != 0) | 251 | if (status != 0) |
192 | goto out; | 252 | goto out; |
253 | clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); | ||
193 | nfs41_setup_state_renewal(clp); | 254 | nfs41_setup_state_renewal(clp); |
194 | nfs_mark_client_ready(clp, NFS_CS_READY); | 255 | nfs_mark_client_ready(clp, NFS_CS_READY); |
195 | out: | 256 | out: |
@@ -208,28 +269,56 @@ struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp) | |||
208 | 269 | ||
209 | #endif /* CONFIG_NFS_V4_1 */ | 270 | #endif /* CONFIG_NFS_V4_1 */ |
210 | 271 | ||
211 | struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) | 272 | static struct rpc_cred * |
273 | nfs4_get_setclientid_cred_server(struct nfs_server *server) | ||
212 | { | 274 | { |
275 | struct nfs_client *clp = server->nfs_client; | ||
276 | struct rpc_cred *cred = NULL; | ||
213 | struct nfs4_state_owner *sp; | 277 | struct nfs4_state_owner *sp; |
214 | struct rb_node *pos; | 278 | struct rb_node *pos; |
279 | |||
280 | spin_lock(&clp->cl_lock); | ||
281 | pos = rb_first(&server->state_owners); | ||
282 | if (pos != NULL) { | ||
283 | sp = rb_entry(pos, struct nfs4_state_owner, so_server_node); | ||
284 | cred = get_rpccred(sp->so_cred); | ||
285 | } | ||
286 | spin_unlock(&clp->cl_lock); | ||
287 | return cred; | ||
288 | } | ||
289 | |||
290 | /** | ||
291 | * nfs4_get_setclientid_cred - Acquire credential for a setclientid operation | ||
292 | * @clp: client state handle | ||
293 | * | ||
294 | * Returns an rpc_cred with reference count bumped, or NULL. | ||
295 | */ | ||
296 | struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) | ||
297 | { | ||
298 | struct nfs_server *server; | ||
215 | struct rpc_cred *cred; | 299 | struct rpc_cred *cred; |
216 | 300 | ||
217 | spin_lock(&clp->cl_lock); | 301 | spin_lock(&clp->cl_lock); |
218 | cred = nfs4_get_machine_cred_locked(clp); | 302 | cred = nfs4_get_machine_cred_locked(clp); |
303 | spin_unlock(&clp->cl_lock); | ||
219 | if (cred != NULL) | 304 | if (cred != NULL) |
220 | goto out; | 305 | goto out; |
221 | pos = rb_first(&clp->cl_state_owners); | 306 | |
222 | if (pos != NULL) { | 307 | rcu_read_lock(); |
223 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | 308 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { |
224 | cred = get_rpccred(sp->so_cred); | 309 | cred = nfs4_get_setclientid_cred_server(server); |
310 | if (cred != NULL) | ||
311 | break; | ||
225 | } | 312 | } |
313 | rcu_read_unlock(); | ||
314 | |||
226 | out: | 315 | out: |
227 | spin_unlock(&clp->cl_lock); | ||
228 | return cred; | 316 | return cred; |
229 | } | 317 | } |
230 | 318 | ||
231 | static void nfs_alloc_unique_id(struct rb_root *root, struct nfs_unique_id *new, | 319 | static void nfs_alloc_unique_id_locked(struct rb_root *root, |
232 | __u64 minval, int maxbits) | 320 | struct nfs_unique_id *new, |
321 | __u64 minval, int maxbits) | ||
233 | { | 322 | { |
234 | struct rb_node **p, *parent; | 323 | struct rb_node **p, *parent; |
235 | struct nfs_unique_id *pos; | 324 | struct nfs_unique_id *pos; |
@@ -284,16 +373,15 @@ static void nfs_free_unique_id(struct rb_root *root, struct nfs_unique_id *id) | |||
284 | } | 373 | } |
285 | 374 | ||
286 | static struct nfs4_state_owner * | 375 | static struct nfs4_state_owner * |
287 | nfs4_find_state_owner(struct nfs_server *server, struct rpc_cred *cred) | 376 | nfs4_find_state_owner_locked(struct nfs_server *server, struct rpc_cred *cred) |
288 | { | 377 | { |
289 | struct nfs_client *clp = server->nfs_client; | 378 | struct rb_node **p = &server->state_owners.rb_node, |
290 | struct rb_node **p = &clp->cl_state_owners.rb_node, | ||
291 | *parent = NULL; | 379 | *parent = NULL; |
292 | struct nfs4_state_owner *sp, *res = NULL; | 380 | struct nfs4_state_owner *sp, *res = NULL; |
293 | 381 | ||
294 | while (*p != NULL) { | 382 | while (*p != NULL) { |
295 | parent = *p; | 383 | parent = *p; |
296 | sp = rb_entry(parent, struct nfs4_state_owner, so_client_node); | 384 | sp = rb_entry(parent, struct nfs4_state_owner, so_server_node); |
297 | 385 | ||
298 | if (server < sp->so_server) { | 386 | if (server < sp->so_server) { |
299 | p = &parent->rb_left; | 387 | p = &parent->rb_left; |
@@ -317,24 +405,17 @@ nfs4_find_state_owner(struct nfs_server *server, struct rpc_cred *cred) | |||
317 | } | 405 | } |
318 | 406 | ||
319 | static struct nfs4_state_owner * | 407 | static struct nfs4_state_owner * |
320 | nfs4_insert_state_owner(struct nfs_client *clp, struct nfs4_state_owner *new) | 408 | nfs4_insert_state_owner_locked(struct nfs4_state_owner *new) |
321 | { | 409 | { |
322 | struct rb_node **p = &clp->cl_state_owners.rb_node, | 410 | struct nfs_server *server = new->so_server; |
411 | struct rb_node **p = &server->state_owners.rb_node, | ||
323 | *parent = NULL; | 412 | *parent = NULL; |
324 | struct nfs4_state_owner *sp; | 413 | struct nfs4_state_owner *sp; |
325 | 414 | ||
326 | while (*p != NULL) { | 415 | while (*p != NULL) { |
327 | parent = *p; | 416 | parent = *p; |
328 | sp = rb_entry(parent, struct nfs4_state_owner, so_client_node); | 417 | sp = rb_entry(parent, struct nfs4_state_owner, so_server_node); |
329 | 418 | ||
330 | if (new->so_server < sp->so_server) { | ||
331 | p = &parent->rb_left; | ||
332 | continue; | ||
333 | } | ||
334 | if (new->so_server > sp->so_server) { | ||
335 | p = &parent->rb_right; | ||
336 | continue; | ||
337 | } | ||
338 | if (new->so_cred < sp->so_cred) | 419 | if (new->so_cred < sp->so_cred) |
339 | p = &parent->rb_left; | 420 | p = &parent->rb_left; |
340 | else if (new->so_cred > sp->so_cred) | 421 | else if (new->so_cred > sp->so_cred) |
@@ -344,18 +425,21 @@ nfs4_insert_state_owner(struct nfs_client *clp, struct nfs4_state_owner *new) | |||
344 | return sp; | 425 | return sp; |
345 | } | 426 | } |
346 | } | 427 | } |
347 | nfs_alloc_unique_id(&clp->cl_openowner_id, &new->so_owner_id, 1, 64); | 428 | nfs_alloc_unique_id_locked(&server->openowner_id, |
348 | rb_link_node(&new->so_client_node, parent, p); | 429 | &new->so_owner_id, 1, 64); |
349 | rb_insert_color(&new->so_client_node, &clp->cl_state_owners); | 430 | rb_link_node(&new->so_server_node, parent, p); |
431 | rb_insert_color(&new->so_server_node, &server->state_owners); | ||
350 | return new; | 432 | return new; |
351 | } | 433 | } |
352 | 434 | ||
353 | static void | 435 | static void |
354 | nfs4_remove_state_owner(struct nfs_client *clp, struct nfs4_state_owner *sp) | 436 | nfs4_remove_state_owner_locked(struct nfs4_state_owner *sp) |
355 | { | 437 | { |
356 | if (!RB_EMPTY_NODE(&sp->so_client_node)) | 438 | struct nfs_server *server = sp->so_server; |
357 | rb_erase(&sp->so_client_node, &clp->cl_state_owners); | 439 | |
358 | nfs_free_unique_id(&clp->cl_openowner_id, &sp->so_owner_id); | 440 | if (!RB_EMPTY_NODE(&sp->so_server_node)) |
441 | rb_erase(&sp->so_server_node, &server->state_owners); | ||
442 | nfs_free_unique_id(&server->openowner_id, &sp->so_owner_id); | ||
359 | } | 443 | } |
360 | 444 | ||
361 | /* | 445 | /* |
@@ -384,23 +468,32 @@ nfs4_alloc_state_owner(void) | |||
384 | static void | 468 | static void |
385 | nfs4_drop_state_owner(struct nfs4_state_owner *sp) | 469 | nfs4_drop_state_owner(struct nfs4_state_owner *sp) |
386 | { | 470 | { |
387 | if (!RB_EMPTY_NODE(&sp->so_client_node)) { | 471 | if (!RB_EMPTY_NODE(&sp->so_server_node)) { |
388 | struct nfs_client *clp = sp->so_server->nfs_client; | 472 | struct nfs_server *server = sp->so_server; |
473 | struct nfs_client *clp = server->nfs_client; | ||
389 | 474 | ||
390 | spin_lock(&clp->cl_lock); | 475 | spin_lock(&clp->cl_lock); |
391 | rb_erase(&sp->so_client_node, &clp->cl_state_owners); | 476 | rb_erase(&sp->so_server_node, &server->state_owners); |
392 | RB_CLEAR_NODE(&sp->so_client_node); | 477 | RB_CLEAR_NODE(&sp->so_server_node); |
393 | spin_unlock(&clp->cl_lock); | 478 | spin_unlock(&clp->cl_lock); |
394 | } | 479 | } |
395 | } | 480 | } |
396 | 481 | ||
397 | struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred) | 482 | /** |
483 | * nfs4_get_state_owner - Look up a state owner given a credential | ||
484 | * @server: nfs_server to search | ||
485 | * @cred: RPC credential to match | ||
486 | * | ||
487 | * Returns a pointer to an instantiated nfs4_state_owner struct, or NULL. | ||
488 | */ | ||
489 | struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, | ||
490 | struct rpc_cred *cred) | ||
398 | { | 491 | { |
399 | struct nfs_client *clp = server->nfs_client; | 492 | struct nfs_client *clp = server->nfs_client; |
400 | struct nfs4_state_owner *sp, *new; | 493 | struct nfs4_state_owner *sp, *new; |
401 | 494 | ||
402 | spin_lock(&clp->cl_lock); | 495 | spin_lock(&clp->cl_lock); |
403 | sp = nfs4_find_state_owner(server, cred); | 496 | sp = nfs4_find_state_owner_locked(server, cred); |
404 | spin_unlock(&clp->cl_lock); | 497 | spin_unlock(&clp->cl_lock); |
405 | if (sp != NULL) | 498 | if (sp != NULL) |
406 | return sp; | 499 | return sp; |
@@ -410,7 +503,7 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct | |||
410 | new->so_server = server; | 503 | new->so_server = server; |
411 | new->so_cred = cred; | 504 | new->so_cred = cred; |
412 | spin_lock(&clp->cl_lock); | 505 | spin_lock(&clp->cl_lock); |
413 | sp = nfs4_insert_state_owner(clp, new); | 506 | sp = nfs4_insert_state_owner_locked(new); |
414 | spin_unlock(&clp->cl_lock); | 507 | spin_unlock(&clp->cl_lock); |
415 | if (sp == new) | 508 | if (sp == new) |
416 | get_rpccred(cred); | 509 | get_rpccred(cred); |
@@ -421,6 +514,11 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct | |||
421 | return sp; | 514 | return sp; |
422 | } | 515 | } |
423 | 516 | ||
517 | /** | ||
518 | * nfs4_put_state_owner - Release a nfs4_state_owner | ||
519 | * @sp: state owner data to release | ||
520 | * | ||
521 | */ | ||
424 | void nfs4_put_state_owner(struct nfs4_state_owner *sp) | 522 | void nfs4_put_state_owner(struct nfs4_state_owner *sp) |
425 | { | 523 | { |
426 | struct nfs_client *clp = sp->so_server->nfs_client; | 524 | struct nfs_client *clp = sp->so_server->nfs_client; |
@@ -428,7 +526,7 @@ void nfs4_put_state_owner(struct nfs4_state_owner *sp) | |||
428 | 526 | ||
429 | if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock)) | 527 | if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock)) |
430 | return; | 528 | return; |
431 | nfs4_remove_state_owner(clp, sp); | 529 | nfs4_remove_state_owner_locked(sp); |
432 | spin_unlock(&clp->cl_lock); | 530 | spin_unlock(&clp->cl_lock); |
433 | rpc_destroy_wait_queue(&sp->so_sequence.wait); | 531 | rpc_destroy_wait_queue(&sp->so_sequence.wait); |
434 | put_rpccred(cred); | 532 | put_rpccred(cred); |
@@ -506,7 +604,8 @@ nfs4_get_open_state(struct inode *inode, struct nfs4_state_owner *owner) | |||
506 | state->owner = owner; | 604 | state->owner = owner; |
507 | atomic_inc(&owner->so_count); | 605 | atomic_inc(&owner->so_count); |
508 | list_add(&state->inode_states, &nfsi->open_states); | 606 | list_add(&state->inode_states, &nfsi->open_states); |
509 | state->inode = igrab(inode); | 607 | ihold(inode); |
608 | state->inode = inode; | ||
510 | spin_unlock(&inode->i_lock); | 609 | spin_unlock(&inode->i_lock); |
511 | /* Note: The reclaim code dictates that we add stateless | 610 | /* Note: The reclaim code dictates that we add stateless |
512 | * and read-only stateids to the end of the list */ | 611 | * and read-only stateids to the end of the list */ |
@@ -583,8 +682,11 @@ static void __nfs4_close(struct path *path, struct nfs4_state *state, | |||
583 | if (!call_close) { | 682 | if (!call_close) { |
584 | nfs4_put_open_state(state); | 683 | nfs4_put_open_state(state); |
585 | nfs4_put_state_owner(owner); | 684 | nfs4_put_state_owner(owner); |
586 | } else | 685 | } else { |
587 | nfs4_do_close(path, state, gfp_mask, wait); | 686 | bool roc = pnfs_roc(state->inode); |
687 | |||
688 | nfs4_do_close(path, state, gfp_mask, wait, roc); | ||
689 | } | ||
588 | } | 690 | } |
589 | 691 | ||
590 | void nfs4_close_state(struct path *path, struct nfs4_state *state, fmode_t fmode) | 692 | void nfs4_close_state(struct path *path, struct nfs4_state *state, fmode_t fmode) |
@@ -631,7 +733,8 @@ __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_p | |||
631 | static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid, unsigned int type) | 733 | static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid, unsigned int type) |
632 | { | 734 | { |
633 | struct nfs4_lock_state *lsp; | 735 | struct nfs4_lock_state *lsp; |
634 | struct nfs_client *clp = state->owner->so_server->nfs_client; | 736 | struct nfs_server *server = state->owner->so_server; |
737 | struct nfs_client *clp = server->nfs_client; | ||
635 | 738 | ||
636 | lsp = kzalloc(sizeof(*lsp), GFP_NOFS); | 739 | lsp = kzalloc(sizeof(*lsp), GFP_NOFS); |
637 | if (lsp == NULL) | 740 | if (lsp == NULL) |
@@ -655,7 +758,7 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |||
655 | return NULL; | 758 | return NULL; |
656 | } | 759 | } |
657 | spin_lock(&clp->cl_lock); | 760 | spin_lock(&clp->cl_lock); |
658 | nfs_alloc_unique_id(&clp->cl_lockowner_id, &lsp->ls_id, 1, 64); | 761 | nfs_alloc_unique_id_locked(&server->lockowner_id, &lsp->ls_id, 1, 64); |
659 | spin_unlock(&clp->cl_lock); | 762 | spin_unlock(&clp->cl_lock); |
660 | INIT_LIST_HEAD(&lsp->ls_locks); | 763 | INIT_LIST_HEAD(&lsp->ls_locks); |
661 | return lsp; | 764 | return lsp; |
@@ -663,10 +766,11 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |||
663 | 766 | ||
664 | static void nfs4_free_lock_state(struct nfs4_lock_state *lsp) | 767 | static void nfs4_free_lock_state(struct nfs4_lock_state *lsp) |
665 | { | 768 | { |
666 | struct nfs_client *clp = lsp->ls_state->owner->so_server->nfs_client; | 769 | struct nfs_server *server = lsp->ls_state->owner->so_server; |
770 | struct nfs_client *clp = server->nfs_client; | ||
667 | 771 | ||
668 | spin_lock(&clp->cl_lock); | 772 | spin_lock(&clp->cl_lock); |
669 | nfs_free_unique_id(&clp->cl_lockowner_id, &lsp->ls_id); | 773 | nfs_free_unique_id(&server->lockowner_id, &lsp->ls_id); |
670 | spin_unlock(&clp->cl_lock); | 774 | spin_unlock(&clp->cl_lock); |
671 | rpc_destroy_wait_queue(&lsp->ls_sequence.wait); | 775 | rpc_destroy_wait_queue(&lsp->ls_sequence.wait); |
672 | kfree(lsp); | 776 | kfree(lsp); |
@@ -923,9 +1027,9 @@ void nfs4_schedule_state_manager(struct nfs_client *clp) | |||
923 | } | 1027 | } |
924 | 1028 | ||
925 | /* | 1029 | /* |
926 | * Schedule a state recovery attempt | 1030 | * Schedule a lease recovery attempt |
927 | */ | 1031 | */ |
928 | void nfs4_schedule_state_recovery(struct nfs_client *clp) | 1032 | void nfs4_schedule_lease_recovery(struct nfs_client *clp) |
929 | { | 1033 | { |
930 | if (!clp) | 1034 | if (!clp) |
931 | return; | 1035 | return; |
@@ -934,7 +1038,7 @@ void nfs4_schedule_state_recovery(struct nfs_client *clp) | |||
934 | nfs4_schedule_state_manager(clp); | 1038 | nfs4_schedule_state_manager(clp); |
935 | } | 1039 | } |
936 | 1040 | ||
937 | int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state) | 1041 | static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state) |
938 | { | 1042 | { |
939 | 1043 | ||
940 | set_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags); | 1044 | set_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags); |
@@ -948,7 +1052,7 @@ int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *st | |||
948 | return 1; | 1052 | return 1; |
949 | } | 1053 | } |
950 | 1054 | ||
951 | int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state) | 1055 | static int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state) |
952 | { | 1056 | { |
953 | set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags); | 1057 | set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags); |
954 | clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags); | 1058 | clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags); |
@@ -957,6 +1061,14 @@ int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *s | |||
957 | return 1; | 1061 | return 1; |
958 | } | 1062 | } |
959 | 1063 | ||
1064 | void nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4_state *state) | ||
1065 | { | ||
1066 | struct nfs_client *clp = server->nfs_client; | ||
1067 | |||
1068 | nfs4_state_mark_reclaim_nograce(clp, state); | ||
1069 | nfs4_schedule_state_manager(clp); | ||
1070 | } | ||
1071 | |||
960 | static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops) | 1072 | static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops) |
961 | { | 1073 | { |
962 | struct inode *inode = state->inode; | 1074 | struct inode *inode = state->inode; |
@@ -970,13 +1082,13 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ | |||
970 | /* Guard against delegation returns and new lock/unlock calls */ | 1082 | /* Guard against delegation returns and new lock/unlock calls */ |
971 | down_write(&nfsi->rwsem); | 1083 | down_write(&nfsi->rwsem); |
972 | /* Protect inode->i_flock using the BKL */ | 1084 | /* Protect inode->i_flock using the BKL */ |
973 | lock_kernel(); | 1085 | lock_flocks(); |
974 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 1086 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { |
975 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) | 1087 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) |
976 | continue; | 1088 | continue; |
977 | if (nfs_file_open_context(fl->fl_file)->state != state) | 1089 | if (nfs_file_open_context(fl->fl_file)->state != state) |
978 | continue; | 1090 | continue; |
979 | unlock_kernel(); | 1091 | unlock_flocks(); |
980 | status = ops->recover_lock(state, fl); | 1092 | status = ops->recover_lock(state, fl); |
981 | switch (status) { | 1093 | switch (status) { |
982 | case 0: | 1094 | case 0: |
@@ -1003,9 +1115,9 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ | |||
1003 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ | 1115 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ |
1004 | status = 0; | 1116 | status = 0; |
1005 | } | 1117 | } |
1006 | lock_kernel(); | 1118 | lock_flocks(); |
1007 | } | 1119 | } |
1008 | unlock_kernel(); | 1120 | unlock_flocks(); |
1009 | out: | 1121 | out: |
1010 | up_write(&nfsi->rwsem); | 1122 | up_write(&nfsi->rwsem); |
1011 | return status; | 1123 | return status; |
@@ -1063,6 +1175,14 @@ restart: | |||
1063 | /* Mark the file as being 'closed' */ | 1175 | /* Mark the file as being 'closed' */ |
1064 | state->state = 0; | 1176 | state->state = 0; |
1065 | break; | 1177 | break; |
1178 | case -EKEYEXPIRED: | ||
1179 | /* | ||
1180 | * User RPCSEC_GSS context has expired. | ||
1181 | * We cannot recover this stateid now, so | ||
1182 | * skip it and allow recovery thread to | ||
1183 | * proceed. | ||
1184 | */ | ||
1185 | break; | ||
1066 | case -NFS4ERR_ADMIN_REVOKED: | 1186 | case -NFS4ERR_ADMIN_REVOKED: |
1067 | case -NFS4ERR_STALE_STATEID: | 1187 | case -NFS4ERR_STALE_STATEID: |
1068 | case -NFS4ERR_BAD_STATEID: | 1188 | case -NFS4ERR_BAD_STATEID: |
@@ -1104,15 +1224,19 @@ static void nfs4_clear_open_state(struct nfs4_state *state) | |||
1104 | } | 1224 | } |
1105 | } | 1225 | } |
1106 | 1226 | ||
1107 | static void nfs4_state_mark_reclaim_helper(struct nfs_client *clp, int (*mark_reclaim)(struct nfs_client *clp, struct nfs4_state *state)) | 1227 | static void nfs4_reset_seqids(struct nfs_server *server, |
1228 | int (*mark_reclaim)(struct nfs_client *clp, struct nfs4_state *state)) | ||
1108 | { | 1229 | { |
1230 | struct nfs_client *clp = server->nfs_client; | ||
1109 | struct nfs4_state_owner *sp; | 1231 | struct nfs4_state_owner *sp; |
1110 | struct rb_node *pos; | 1232 | struct rb_node *pos; |
1111 | struct nfs4_state *state; | 1233 | struct nfs4_state *state; |
1112 | 1234 | ||
1113 | /* Reset all sequence ids to zero */ | 1235 | spin_lock(&clp->cl_lock); |
1114 | for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { | 1236 | for (pos = rb_first(&server->state_owners); |
1115 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | 1237 | pos != NULL; |
1238 | pos = rb_next(pos)) { | ||
1239 | sp = rb_entry(pos, struct nfs4_state_owner, so_server_node); | ||
1116 | sp->so_seqid.flags = 0; | 1240 | sp->so_seqid.flags = 0; |
1117 | spin_lock(&sp->so_lock); | 1241 | spin_lock(&sp->so_lock); |
1118 | list_for_each_entry(state, &sp->so_states, open_states) { | 1242 | list_for_each_entry(state, &sp->so_states, open_states) { |
@@ -1121,6 +1245,18 @@ static void nfs4_state_mark_reclaim_helper(struct nfs_client *clp, int (*mark_re | |||
1121 | } | 1245 | } |
1122 | spin_unlock(&sp->so_lock); | 1246 | spin_unlock(&sp->so_lock); |
1123 | } | 1247 | } |
1248 | spin_unlock(&clp->cl_lock); | ||
1249 | } | ||
1250 | |||
1251 | static void nfs4_state_mark_reclaim_helper(struct nfs_client *clp, | ||
1252 | int (*mark_reclaim)(struct nfs_client *clp, struct nfs4_state *state)) | ||
1253 | { | ||
1254 | struct nfs_server *server; | ||
1255 | |||
1256 | rcu_read_lock(); | ||
1257 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) | ||
1258 | nfs4_reset_seqids(server, mark_reclaim); | ||
1259 | rcu_read_unlock(); | ||
1124 | } | 1260 | } |
1125 | 1261 | ||
1126 | static void nfs4_state_start_reclaim_reboot(struct nfs_client *clp) | 1262 | static void nfs4_state_start_reclaim_reboot(struct nfs_client *clp) |
@@ -1138,29 +1274,51 @@ static void nfs4_reclaim_complete(struct nfs_client *clp, | |||
1138 | (void)ops->reclaim_complete(clp); | 1274 | (void)ops->reclaim_complete(clp); |
1139 | } | 1275 | } |
1140 | 1276 | ||
1141 | static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp) | 1277 | static void nfs4_clear_reclaim_server(struct nfs_server *server) |
1142 | { | 1278 | { |
1279 | struct nfs_client *clp = server->nfs_client; | ||
1143 | struct nfs4_state_owner *sp; | 1280 | struct nfs4_state_owner *sp; |
1144 | struct rb_node *pos; | 1281 | struct rb_node *pos; |
1145 | struct nfs4_state *state; | 1282 | struct nfs4_state *state; |
1146 | 1283 | ||
1147 | if (!test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) | 1284 | spin_lock(&clp->cl_lock); |
1148 | return; | 1285 | for (pos = rb_first(&server->state_owners); |
1149 | 1286 | pos != NULL; | |
1150 | nfs4_reclaim_complete(clp, clp->cl_mvops->reboot_recovery_ops); | 1287 | pos = rb_next(pos)) { |
1151 | 1288 | sp = rb_entry(pos, struct nfs4_state_owner, so_server_node); | |
1152 | for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { | ||
1153 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | ||
1154 | spin_lock(&sp->so_lock); | 1289 | spin_lock(&sp->so_lock); |
1155 | list_for_each_entry(state, &sp->so_states, open_states) { | 1290 | list_for_each_entry(state, &sp->so_states, open_states) { |
1156 | if (!test_and_clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags)) | 1291 | if (!test_and_clear_bit(NFS_STATE_RECLAIM_REBOOT, |
1292 | &state->flags)) | ||
1157 | continue; | 1293 | continue; |
1158 | nfs4_state_mark_reclaim_nograce(clp, state); | 1294 | nfs4_state_mark_reclaim_nograce(clp, state); |
1159 | } | 1295 | } |
1160 | spin_unlock(&sp->so_lock); | 1296 | spin_unlock(&sp->so_lock); |
1161 | } | 1297 | } |
1298 | spin_unlock(&clp->cl_lock); | ||
1299 | } | ||
1300 | |||
1301 | static int nfs4_state_clear_reclaim_reboot(struct nfs_client *clp) | ||
1302 | { | ||
1303 | struct nfs_server *server; | ||
1304 | |||
1305 | if (!test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) | ||
1306 | return 0; | ||
1307 | |||
1308 | rcu_read_lock(); | ||
1309 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) | ||
1310 | nfs4_clear_reclaim_server(server); | ||
1311 | rcu_read_unlock(); | ||
1162 | 1312 | ||
1163 | nfs_delegation_reap_unclaimed(clp); | 1313 | nfs_delegation_reap_unclaimed(clp); |
1314 | return 1; | ||
1315 | } | ||
1316 | |||
1317 | static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp) | ||
1318 | { | ||
1319 | if (!nfs4_state_clear_reclaim_reboot(clp)) | ||
1320 | return; | ||
1321 | nfs4_reclaim_complete(clp, clp->cl_mvops->reboot_recovery_ops); | ||
1164 | } | 1322 | } |
1165 | 1323 | ||
1166 | static void nfs_delegation_clear_all(struct nfs_client *clp) | 1324 | static void nfs_delegation_clear_all(struct nfs_client *clp) |
@@ -1175,6 +1333,14 @@ static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp) | |||
1175 | nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce); | 1333 | nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce); |
1176 | } | 1334 | } |
1177 | 1335 | ||
1336 | static void nfs4_warn_keyexpired(const char *s) | ||
1337 | { | ||
1338 | printk_ratelimited(KERN_WARNING "Error: state manager" | ||
1339 | " encountered RPCSEC_GSS session" | ||
1340 | " expired against NFSv4 server %s.\n", | ||
1341 | s); | ||
1342 | } | ||
1343 | |||
1178 | static int nfs4_recovery_handle_error(struct nfs_client *clp, int error) | 1344 | static int nfs4_recovery_handle_error(struct nfs_client *clp, int error) |
1179 | { | 1345 | { |
1180 | switch (error) { | 1346 | switch (error) { |
@@ -1187,7 +1353,7 @@ static int nfs4_recovery_handle_error(struct nfs_client *clp, int error) | |||
1187 | case -NFS4ERR_STALE_CLIENTID: | 1353 | case -NFS4ERR_STALE_CLIENTID: |
1188 | case -NFS4ERR_LEASE_MOVED: | 1354 | case -NFS4ERR_LEASE_MOVED: |
1189 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1355 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
1190 | nfs4_state_end_reclaim_reboot(clp); | 1356 | nfs4_state_clear_reclaim_reboot(clp); |
1191 | nfs4_state_start_reclaim_reboot(clp); | 1357 | nfs4_state_start_reclaim_reboot(clp); |
1192 | break; | 1358 | break; |
1193 | case -NFS4ERR_EXPIRED: | 1359 | case -NFS4ERR_EXPIRED: |
@@ -1204,33 +1370,50 @@ static int nfs4_recovery_handle_error(struct nfs_client *clp, int error) | |||
1204 | set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); | 1370 | set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); |
1205 | /* Zero session reset errors */ | 1371 | /* Zero session reset errors */ |
1206 | return 0; | 1372 | return 0; |
1373 | case -EKEYEXPIRED: | ||
1374 | /* Nothing we can do */ | ||
1375 | nfs4_warn_keyexpired(clp->cl_hostname); | ||
1376 | return 0; | ||
1207 | } | 1377 | } |
1208 | return error; | 1378 | return error; |
1209 | } | 1379 | } |
1210 | 1380 | ||
1211 | static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops) | 1381 | static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops) |
1212 | { | 1382 | { |
1383 | struct nfs4_state_owner *sp; | ||
1384 | struct nfs_server *server; | ||
1213 | struct rb_node *pos; | 1385 | struct rb_node *pos; |
1214 | int status = 0; | 1386 | int status = 0; |
1215 | 1387 | ||
1216 | restart: | 1388 | restart: |
1217 | spin_lock(&clp->cl_lock); | 1389 | rcu_read_lock(); |
1218 | for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { | 1390 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { |
1219 | struct nfs4_state_owner *sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | 1391 | spin_lock(&clp->cl_lock); |
1220 | if (!test_and_clear_bit(ops->owner_flag_bit, &sp->so_flags)) | 1392 | for (pos = rb_first(&server->state_owners); |
1221 | continue; | 1393 | pos != NULL; |
1222 | atomic_inc(&sp->so_count); | 1394 | pos = rb_next(pos)) { |
1223 | spin_unlock(&clp->cl_lock); | 1395 | sp = rb_entry(pos, |
1224 | status = nfs4_reclaim_open_state(sp, ops); | 1396 | struct nfs4_state_owner, so_server_node); |
1225 | if (status < 0) { | 1397 | if (!test_and_clear_bit(ops->owner_flag_bit, |
1226 | set_bit(ops->owner_flag_bit, &sp->so_flags); | 1398 | &sp->so_flags)) |
1399 | continue; | ||
1400 | atomic_inc(&sp->so_count); | ||
1401 | spin_unlock(&clp->cl_lock); | ||
1402 | rcu_read_unlock(); | ||
1403 | |||
1404 | status = nfs4_reclaim_open_state(sp, ops); | ||
1405 | if (status < 0) { | ||
1406 | set_bit(ops->owner_flag_bit, &sp->so_flags); | ||
1407 | nfs4_put_state_owner(sp); | ||
1408 | return nfs4_recovery_handle_error(clp, status); | ||
1409 | } | ||
1410 | |||
1227 | nfs4_put_state_owner(sp); | 1411 | nfs4_put_state_owner(sp); |
1228 | return nfs4_recovery_handle_error(clp, status); | 1412 | goto restart; |
1229 | } | 1413 | } |
1230 | nfs4_put_state_owner(sp); | 1414 | spin_unlock(&clp->cl_lock); |
1231 | goto restart; | ||
1232 | } | 1415 | } |
1233 | spin_unlock(&clp->cl_lock); | 1416 | rcu_read_unlock(); |
1234 | return status; | 1417 | return status; |
1235 | } | 1418 | } |
1236 | 1419 | ||
@@ -1281,10 +1464,19 @@ static int nfs4_reclaim_lease(struct nfs_client *clp) | |||
1281 | } | 1464 | } |
1282 | 1465 | ||
1283 | #ifdef CONFIG_NFS_V4_1 | 1466 | #ifdef CONFIG_NFS_V4_1 |
1467 | void nfs4_schedule_session_recovery(struct nfs4_session *session) | ||
1468 | { | ||
1469 | struct nfs_client *clp = session->clp; | ||
1470 | |||
1471 | set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); | ||
1472 | nfs4_schedule_lease_recovery(clp); | ||
1473 | } | ||
1474 | EXPORT_SYMBOL_GPL(nfs4_schedule_session_recovery); | ||
1475 | |||
1284 | void nfs41_handle_recall_slot(struct nfs_client *clp) | 1476 | void nfs41_handle_recall_slot(struct nfs_client *clp) |
1285 | { | 1477 | { |
1286 | set_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state); | 1478 | set_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state); |
1287 | nfs4_schedule_state_recovery(clp); | 1479 | nfs4_schedule_state_manager(clp); |
1288 | } | 1480 | } |
1289 | 1481 | ||
1290 | static void nfs4_reset_all_state(struct nfs_client *clp) | 1482 | static void nfs4_reset_all_state(struct nfs_client *clp) |
@@ -1292,7 +1484,7 @@ static void nfs4_reset_all_state(struct nfs_client *clp) | |||
1292 | if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) { | 1484 | if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) { |
1293 | clp->cl_boot_time = CURRENT_TIME; | 1485 | clp->cl_boot_time = CURRENT_TIME; |
1294 | nfs4_state_start_reclaim_nograce(clp); | 1486 | nfs4_state_start_reclaim_nograce(clp); |
1295 | nfs4_schedule_state_recovery(clp); | 1487 | nfs4_schedule_state_manager(clp); |
1296 | } | 1488 | } |
1297 | } | 1489 | } |
1298 | 1490 | ||
@@ -1300,7 +1492,7 @@ static void nfs41_handle_server_reboot(struct nfs_client *clp) | |||
1300 | { | 1492 | { |
1301 | if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) { | 1493 | if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) { |
1302 | nfs4_state_start_reclaim_reboot(clp); | 1494 | nfs4_state_start_reclaim_reboot(clp); |
1303 | nfs4_schedule_state_recovery(clp); | 1495 | nfs4_schedule_state_manager(clp); |
1304 | } | 1496 | } |
1305 | } | 1497 | } |
1306 | 1498 | ||
@@ -1320,7 +1512,7 @@ static void nfs41_handle_cb_path_down(struct nfs_client *clp) | |||
1320 | { | 1512 | { |
1321 | nfs_expire_all_delegations(clp); | 1513 | nfs_expire_all_delegations(clp); |
1322 | if (test_and_set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) == 0) | 1514 | if (test_and_set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) == 0) |
1323 | nfs4_schedule_state_recovery(clp); | 1515 | nfs4_schedule_state_manager(clp); |
1324 | } | 1516 | } |
1325 | 1517 | ||
1326 | void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags) | 1518 | void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags) |
@@ -1360,6 +1552,7 @@ static int nfs4_reset_session(struct nfs_client *clp) | |||
1360 | status = nfs4_recovery_handle_error(clp, status); | 1552 | status = nfs4_recovery_handle_error(clp, status); |
1361 | goto out; | 1553 | goto out; |
1362 | } | 1554 | } |
1555 | clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); | ||
1363 | /* create_session negotiated new slot table */ | 1556 | /* create_session negotiated new slot table */ |
1364 | clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state); | 1557 | clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state); |
1365 | 1558 | ||
@@ -1409,19 +1602,23 @@ static int nfs4_recall_slot(struct nfs_client *clp) { return 0; } | |||
1409 | */ | 1602 | */ |
1410 | static void nfs4_set_lease_expired(struct nfs_client *clp, int status) | 1603 | static void nfs4_set_lease_expired(struct nfs_client *clp, int status) |
1411 | { | 1604 | { |
1412 | if (nfs4_has_session(clp)) { | 1605 | switch (status) { |
1413 | switch (status) { | 1606 | case -NFS4ERR_CLID_INUSE: |
1414 | case -NFS4ERR_DELAY: | 1607 | case -NFS4ERR_STALE_CLIENTID: |
1415 | case -NFS4ERR_CLID_INUSE: | 1608 | clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); |
1416 | case -EAGAIN: | 1609 | break; |
1417 | case -EKEYEXPIRED: | 1610 | case -NFS4ERR_DELAY: |
1418 | break; | 1611 | case -ETIMEDOUT: |
1612 | case -EAGAIN: | ||
1613 | ssleep(1); | ||
1614 | break; | ||
1419 | 1615 | ||
1420 | case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery | 1616 | case -EKEYEXPIRED: |
1421 | * in nfs4_exchange_id */ | 1617 | nfs4_warn_keyexpired(clp->cl_hostname); |
1422 | default: | 1618 | case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery |
1423 | return; | 1619 | * in nfs4_exchange_id */ |
1424 | } | 1620 | default: |
1621 | return; | ||
1425 | } | 1622 | } |
1426 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1623 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
1427 | } | 1624 | } |
@@ -1431,7 +1628,7 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1431 | int status = 0; | 1628 | int status = 0; |
1432 | 1629 | ||
1433 | /* Ensure exclusive access to NFSv4 state */ | 1630 | /* Ensure exclusive access to NFSv4 state */ |
1434 | for(;;) { | 1631 | do { |
1435 | if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) { | 1632 | if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) { |
1436 | /* We're going to have to re-establish a clientid */ | 1633 | /* We're going to have to re-establish a clientid */ |
1437 | status = nfs4_reclaim_lease(clp); | 1634 | status = nfs4_reclaim_lease(clp); |
@@ -1447,6 +1644,7 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1447 | } | 1644 | } |
1448 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); | 1645 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); |
1449 | set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state); | 1646 | set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state); |
1647 | pnfs_destroy_all_layouts(clp); | ||
1450 | } | 1648 | } |
1451 | 1649 | ||
1452 | if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) { | 1650 | if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) { |
@@ -1514,7 +1712,7 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1514 | break; | 1712 | break; |
1515 | if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) | 1713 | if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) |
1516 | break; | 1714 | break; |
1517 | } | 1715 | } while (atomic_read(&clp->cl_count) > 1); |
1518 | return; | 1716 | return; |
1519 | out_error: | 1717 | out_error: |
1520 | printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s" | 1718 | printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s" |