diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /fs/nfs/nfs4proc.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 830 |
1 files changed, 564 insertions, 266 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 741a562177fc..071fcedd517c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/delay.h> | 39 | #include <linux/delay.h> |
40 | #include <linux/errno.h> | 40 | #include <linux/errno.h> |
41 | #include <linux/string.h> | 41 | #include <linux/string.h> |
42 | #include <linux/slab.h> | ||
42 | #include <linux/sunrpc/clnt.h> | 43 | #include <linux/sunrpc/clnt.h> |
43 | #include <linux/nfs.h> | 44 | #include <linux/nfs.h> |
44 | #include <linux/nfs4.h> | 45 | #include <linux/nfs4.h> |
@@ -64,6 +65,7 @@ | |||
64 | 65 | ||
65 | struct nfs4_opendata; | 66 | struct nfs4_opendata; |
66 | static int _nfs4_proc_open(struct nfs4_opendata *data); | 67 | static int _nfs4_proc_open(struct nfs4_opendata *data); |
68 | static int _nfs4_recover_proc_open(struct nfs4_opendata *data); | ||
67 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 69 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
68 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); | 70 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); |
69 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 71 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); |
@@ -248,19 +250,15 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
248 | if (state == NULL) | 250 | if (state == NULL) |
249 | break; | 251 | break; |
250 | nfs4_state_mark_reclaim_nograce(clp, state); | 252 | nfs4_state_mark_reclaim_nograce(clp, state); |
251 | case -NFS4ERR_STALE_CLIENTID: | 253 | goto do_state_recovery; |
252 | case -NFS4ERR_STALE_STATEID: | 254 | case -NFS4ERR_STALE_STATEID: |
253 | case -NFS4ERR_EXPIRED: | 255 | if (state == NULL) |
254 | nfs4_schedule_state_recovery(clp); | ||
255 | ret = nfs4_wait_clnt_recover(clp); | ||
256 | if (ret == 0) | ||
257 | exception->retry = 1; | ||
258 | #if !defined(CONFIG_NFS_V4_1) | ||
259 | break; | ||
260 | #else /* !defined(CONFIG_NFS_V4_1) */ | ||
261 | if (!nfs4_has_session(server->nfs_client)) | ||
262 | break; | 256 | break; |
263 | /* FALLTHROUGH */ | 257 | nfs4_state_mark_reclaim_reboot(clp, state); |
258 | case -NFS4ERR_STALE_CLIENTID: | ||
259 | case -NFS4ERR_EXPIRED: | ||
260 | goto do_state_recovery; | ||
261 | #if defined(CONFIG_NFS_V4_1) | ||
264 | case -NFS4ERR_BADSESSION: | 262 | case -NFS4ERR_BADSESSION: |
265 | case -NFS4ERR_BADSLOT: | 263 | case -NFS4ERR_BADSLOT: |
266 | case -NFS4ERR_BAD_HIGH_SLOT: | 264 | case -NFS4ERR_BAD_HIGH_SLOT: |
@@ -270,13 +268,21 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
270 | case -NFS4ERR_SEQ_MISORDERED: | 268 | case -NFS4ERR_SEQ_MISORDERED: |
271 | dprintk("%s ERROR: %d Reset session\n", __func__, | 269 | dprintk("%s ERROR: %d Reset session\n", __func__, |
272 | errorcode); | 270 | errorcode); |
273 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | 271 | nfs4_schedule_state_recovery(clp); |
274 | exception->retry = 1; | 272 | exception->retry = 1; |
275 | /* FALLTHROUGH */ | 273 | break; |
276 | #endif /* !defined(CONFIG_NFS_V4_1) */ | 274 | #endif /* defined(CONFIG_NFS_V4_1) */ |
277 | case -NFS4ERR_FILE_OPEN: | 275 | case -NFS4ERR_FILE_OPEN: |
276 | if (exception->timeout > HZ) { | ||
277 | /* We have retried a decent amount, time to | ||
278 | * fail | ||
279 | */ | ||
280 | ret = -EBUSY; | ||
281 | break; | ||
282 | } | ||
278 | case -NFS4ERR_GRACE: | 283 | case -NFS4ERR_GRACE: |
279 | case -NFS4ERR_DELAY: | 284 | case -NFS4ERR_DELAY: |
285 | case -EKEYEXPIRED: | ||
280 | ret = nfs4_delay(server->client, &exception->timeout); | 286 | ret = nfs4_delay(server->client, &exception->timeout); |
281 | if (ret != 0) | 287 | if (ret != 0) |
282 | break; | 288 | break; |
@@ -285,6 +291,12 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
285 | } | 291 | } |
286 | /* We failed to handle the error */ | 292 | /* We failed to handle the error */ |
287 | return nfs4_map_errors(ret); | 293 | return nfs4_map_errors(ret); |
294 | do_state_recovery: | ||
295 | nfs4_schedule_state_recovery(clp); | ||
296 | ret = nfs4_wait_clnt_recover(clp); | ||
297 | if (ret == 0) | ||
298 | exception->retry = 1; | ||
299 | return ret; | ||
288 | } | 300 | } |
289 | 301 | ||
290 | 302 | ||
@@ -311,48 +323,67 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp | |||
311 | * so we need to scan down from highest_used_slotid to 0 looking for the now | 323 | * so we need to scan down from highest_used_slotid to 0 looking for the now |
312 | * highest slotid in use. | 324 | * highest slotid in use. |
313 | * If none found, highest_used_slotid is set to -1. | 325 | * If none found, highest_used_slotid is set to -1. |
326 | * | ||
327 | * Must be called while holding tbl->slot_tbl_lock | ||
314 | */ | 328 | */ |
315 | static void | 329 | static void |
316 | nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) | 330 | nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) |
317 | { | 331 | { |
318 | int slotid = free_slotid; | 332 | int slotid = free_slotid; |
319 | 333 | ||
320 | spin_lock(&tbl->slot_tbl_lock); | ||
321 | /* clear used bit in bitmap */ | 334 | /* clear used bit in bitmap */ |
322 | __clear_bit(slotid, tbl->used_slots); | 335 | __clear_bit(slotid, tbl->used_slots); |
323 | 336 | ||
324 | /* update highest_used_slotid when it is freed */ | 337 | /* update highest_used_slotid when it is freed */ |
325 | if (slotid == tbl->highest_used_slotid) { | 338 | if (slotid == tbl->highest_used_slotid) { |
326 | slotid = find_last_bit(tbl->used_slots, tbl->max_slots); | 339 | slotid = find_last_bit(tbl->used_slots, tbl->max_slots); |
327 | if (slotid >= 0 && slotid < tbl->max_slots) | 340 | if (slotid < tbl->max_slots) |
328 | tbl->highest_used_slotid = slotid; | 341 | tbl->highest_used_slotid = slotid; |
329 | else | 342 | else |
330 | tbl->highest_used_slotid = -1; | 343 | tbl->highest_used_slotid = -1; |
331 | } | 344 | } |
332 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | ||
333 | spin_unlock(&tbl->slot_tbl_lock); | ||
334 | dprintk("%s: free_slotid %u highest_used_slotid %d\n", __func__, | 345 | dprintk("%s: free_slotid %u highest_used_slotid %d\n", __func__, |
335 | free_slotid, tbl->highest_used_slotid); | 346 | free_slotid, tbl->highest_used_slotid); |
336 | } | 347 | } |
337 | 348 | ||
338 | void nfs41_sequence_free_slot(const struct nfs_client *clp, | 349 | /* |
339 | struct nfs4_sequence_res *res) | 350 | * Signal state manager thread if session is drained |
351 | */ | ||
352 | static void nfs41_check_drain_session_complete(struct nfs4_session *ses) | ||
340 | { | 353 | { |
341 | struct nfs4_slot_table *tbl; | 354 | struct rpc_task *task; |
342 | 355 | ||
343 | if (!nfs4_has_session(clp)) { | 356 | if (!test_bit(NFS4CLNT_SESSION_DRAINING, &ses->clp->cl_state)) { |
344 | dprintk("%s: No session\n", __func__); | 357 | task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq); |
358 | if (task) | ||
359 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
345 | return; | 360 | return; |
346 | } | 361 | } |
362 | |||
363 | if (ses->fc_slot_table.highest_used_slotid != -1) | ||
364 | return; | ||
365 | |||
366 | dprintk("%s COMPLETE: Session Drained\n", __func__); | ||
367 | complete(&ses->complete); | ||
368 | } | ||
369 | |||
370 | static void nfs41_sequence_free_slot(const struct nfs_client *clp, | ||
371 | struct nfs4_sequence_res *res) | ||
372 | { | ||
373 | struct nfs4_slot_table *tbl; | ||
374 | |||
347 | tbl = &clp->cl_session->fc_slot_table; | 375 | tbl = &clp->cl_session->fc_slot_table; |
348 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { | 376 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { |
349 | dprintk("%s: No slot\n", __func__); | ||
350 | /* just wake up the next guy waiting since | 377 | /* just wake up the next guy waiting since |
351 | * we may have not consumed a slot after all */ | 378 | * we may have not consumed a slot after all */ |
352 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | 379 | dprintk("%s: No slot\n", __func__); |
353 | return; | 380 | return; |
354 | } | 381 | } |
382 | |||
383 | spin_lock(&tbl->slot_tbl_lock); | ||
355 | nfs4_free_slot(tbl, res->sr_slotid); | 384 | nfs4_free_slot(tbl, res->sr_slotid); |
385 | nfs41_check_drain_session_complete(clp->cl_session); | ||
386 | spin_unlock(&tbl->slot_tbl_lock); | ||
356 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 387 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; |
357 | } | 388 | } |
358 | 389 | ||
@@ -377,10 +408,10 @@ static void nfs41_sequence_done(struct nfs_client *clp, | |||
377 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) | 408 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) |
378 | goto out; | 409 | goto out; |
379 | 410 | ||
380 | tbl = &clp->cl_session->fc_slot_table; | 411 | /* Check the SEQUENCE operation status */ |
381 | slot = tbl->slots + res->sr_slotid; | ||
382 | |||
383 | if (res->sr_status == 0) { | 412 | if (res->sr_status == 0) { |
413 | tbl = &clp->cl_session->fc_slot_table; | ||
414 | slot = tbl->slots + res->sr_slotid; | ||
384 | /* Update the slot's sequence and clientid lease timer */ | 415 | /* Update the slot's sequence and clientid lease timer */ |
385 | ++slot->seq_nr; | 416 | ++slot->seq_nr; |
386 | timestamp = res->sr_renewal_time; | 417 | timestamp = res->sr_renewal_time; |
@@ -388,7 +419,9 @@ static void nfs41_sequence_done(struct nfs_client *clp, | |||
388 | if (time_before(clp->cl_last_renewal, timestamp)) | 419 | if (time_before(clp->cl_last_renewal, timestamp)) |
389 | clp->cl_last_renewal = timestamp; | 420 | clp->cl_last_renewal = timestamp; |
390 | spin_unlock(&clp->cl_lock); | 421 | spin_unlock(&clp->cl_lock); |
391 | return; | 422 | /* Check sequence flags */ |
423 | if (atomic_read(&clp->cl_count) > 1) | ||
424 | nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags); | ||
392 | } | 425 | } |
393 | out: | 426 | out: |
394 | /* The session may be reset by one of the error handlers. */ | 427 | /* The session may be reset by one of the error handlers. */ |
@@ -407,7 +440,7 @@ out: | |||
407 | * Note: must be called with under the slot_tbl_lock. | 440 | * Note: must be called with under the slot_tbl_lock. |
408 | */ | 441 | */ |
409 | static u8 | 442 | static u8 |
410 | nfs4_find_slot(struct nfs4_slot_table *tbl, struct rpc_task *task) | 443 | nfs4_find_slot(struct nfs4_slot_table *tbl) |
411 | { | 444 | { |
412 | int slotid; | 445 | int slotid; |
413 | u8 ret_id = NFS4_MAX_SLOT_TABLE; | 446 | u8 ret_id = NFS4_MAX_SLOT_TABLE; |
@@ -429,24 +462,6 @@ out: | |||
429 | return ret_id; | 462 | return ret_id; |
430 | } | 463 | } |
431 | 464 | ||
432 | static int nfs4_recover_session(struct nfs4_session *session) | ||
433 | { | ||
434 | struct nfs_client *clp = session->clp; | ||
435 | unsigned int loop; | ||
436 | int ret; | ||
437 | |||
438 | for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) { | ||
439 | ret = nfs4_wait_clnt_recover(clp); | ||
440 | if (ret != 0) | ||
441 | break; | ||
442 | if (!test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) | ||
443 | break; | ||
444 | nfs4_schedule_state_manager(clp); | ||
445 | ret = -EIO; | ||
446 | } | ||
447 | return ret; | ||
448 | } | ||
449 | |||
450 | static int nfs41_setup_sequence(struct nfs4_session *session, | 465 | static int nfs41_setup_sequence(struct nfs4_session *session, |
451 | struct nfs4_sequence_args *args, | 466 | struct nfs4_sequence_args *args, |
452 | struct nfs4_sequence_res *res, | 467 | struct nfs4_sequence_res *res, |
@@ -455,7 +470,6 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
455 | { | 470 | { |
456 | struct nfs4_slot *slot; | 471 | struct nfs4_slot *slot; |
457 | struct nfs4_slot_table *tbl; | 472 | struct nfs4_slot_table *tbl; |
458 | int status = 0; | ||
459 | u8 slotid; | 473 | u8 slotid; |
460 | 474 | ||
461 | dprintk("--> %s\n", __func__); | 475 | dprintk("--> %s\n", __func__); |
@@ -468,24 +482,27 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
468 | tbl = &session->fc_slot_table; | 482 | tbl = &session->fc_slot_table; |
469 | 483 | ||
470 | spin_lock(&tbl->slot_tbl_lock); | 484 | spin_lock(&tbl->slot_tbl_lock); |
471 | if (test_bit(NFS4CLNT_SESSION_SETUP, &session->clp->cl_state)) { | 485 | if (test_bit(NFS4CLNT_SESSION_DRAINING, &session->clp->cl_state) && |
472 | if (tbl->highest_used_slotid != -1) { | 486 | !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { |
473 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | 487 | /* |
474 | spin_unlock(&tbl->slot_tbl_lock); | 488 | * The state manager will wait until the slot table is empty. |
475 | dprintk("<-- %s: Session reset: draining\n", __func__); | 489 | * Schedule the reset thread |
476 | return -EAGAIN; | 490 | */ |
477 | } | 491 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); |
492 | spin_unlock(&tbl->slot_tbl_lock); | ||
493 | dprintk("%s Schedule Session Reset\n", __func__); | ||
494 | return -EAGAIN; | ||
495 | } | ||
478 | 496 | ||
479 | /* The slot table is empty; start the reset thread */ | 497 | if (!rpc_queue_empty(&tbl->slot_tbl_waitq) && |
480 | dprintk("%s Session Reset\n", __func__); | 498 | !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { |
499 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | ||
481 | spin_unlock(&tbl->slot_tbl_lock); | 500 | spin_unlock(&tbl->slot_tbl_lock); |
482 | status = nfs4_recover_session(session); | 501 | dprintk("%s enforce FIFO order\n", __func__); |
483 | if (status) | 502 | return -EAGAIN; |
484 | return status; | ||
485 | spin_lock(&tbl->slot_tbl_lock); | ||
486 | } | 503 | } |
487 | 504 | ||
488 | slotid = nfs4_find_slot(tbl, task); | 505 | slotid = nfs4_find_slot(tbl); |
489 | if (slotid == NFS4_MAX_SLOT_TABLE) { | 506 | if (slotid == NFS4_MAX_SLOT_TABLE) { |
490 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | 507 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); |
491 | spin_unlock(&tbl->slot_tbl_lock); | 508 | spin_unlock(&tbl->slot_tbl_lock); |
@@ -494,6 +511,7 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
494 | } | 511 | } |
495 | spin_unlock(&tbl->slot_tbl_lock); | 512 | spin_unlock(&tbl->slot_tbl_lock); |
496 | 513 | ||
514 | rpc_task_set_priority(task, RPC_PRIORITY_NORMAL); | ||
497 | slot = tbl->slots + slotid; | 515 | slot = tbl->slots + slotid; |
498 | args->sa_session = session; | 516 | args->sa_session = session; |
499 | args->sa_slotid = slotid; | 517 | args->sa_slotid = slotid; |
@@ -527,7 +545,7 @@ int nfs4_setup_sequence(struct nfs_client *clp, | |||
527 | goto out; | 545 | goto out; |
528 | ret = nfs41_setup_sequence(clp->cl_session, args, res, cache_reply, | 546 | ret = nfs41_setup_sequence(clp->cl_session, args, res, cache_reply, |
529 | task); | 547 | task); |
530 | if (ret != -EAGAIN) { | 548 | if (ret && ret != -EAGAIN) { |
531 | /* terminate rpc task */ | 549 | /* terminate rpc task */ |
532 | task->tk_status = ret; | 550 | task->tk_status = ret; |
533 | task->tk_action = NULL; | 551 | task->tk_action = NULL; |
@@ -556,12 +574,17 @@ static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) | |||
556 | rpc_call_start(task); | 574 | rpc_call_start(task); |
557 | } | 575 | } |
558 | 576 | ||
577 | static void nfs41_call_priv_sync_prepare(struct rpc_task *task, void *calldata) | ||
578 | { | ||
579 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
580 | nfs41_call_sync_prepare(task, calldata); | ||
581 | } | ||
582 | |||
559 | static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) | 583 | static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) |
560 | { | 584 | { |
561 | struct nfs41_call_sync_data *data = calldata; | 585 | struct nfs41_call_sync_data *data = calldata; |
562 | 586 | ||
563 | nfs41_sequence_done(data->clp, data->seq_res, task->tk_status); | 587 | nfs41_sequence_done(data->clp, data->seq_res, task->tk_status); |
564 | nfs41_sequence_free_slot(data->clp, data->seq_res); | ||
565 | } | 588 | } |
566 | 589 | ||
567 | struct rpc_call_ops nfs41_call_sync_ops = { | 590 | struct rpc_call_ops nfs41_call_sync_ops = { |
@@ -569,12 +592,18 @@ struct rpc_call_ops nfs41_call_sync_ops = { | |||
569 | .rpc_call_done = nfs41_call_sync_done, | 592 | .rpc_call_done = nfs41_call_sync_done, |
570 | }; | 593 | }; |
571 | 594 | ||
595 | struct rpc_call_ops nfs41_call_priv_sync_ops = { | ||
596 | .rpc_call_prepare = nfs41_call_priv_sync_prepare, | ||
597 | .rpc_call_done = nfs41_call_sync_done, | ||
598 | }; | ||
599 | |||
572 | static int nfs4_call_sync_sequence(struct nfs_client *clp, | 600 | static int nfs4_call_sync_sequence(struct nfs_client *clp, |
573 | struct rpc_clnt *clnt, | 601 | struct rpc_clnt *clnt, |
574 | struct rpc_message *msg, | 602 | struct rpc_message *msg, |
575 | struct nfs4_sequence_args *args, | 603 | struct nfs4_sequence_args *args, |
576 | struct nfs4_sequence_res *res, | 604 | struct nfs4_sequence_res *res, |
577 | int cache_reply) | 605 | int cache_reply, |
606 | int privileged) | ||
578 | { | 607 | { |
579 | int ret; | 608 | int ret; |
580 | struct rpc_task *task; | 609 | struct rpc_task *task; |
@@ -592,6 +621,8 @@ static int nfs4_call_sync_sequence(struct nfs_client *clp, | |||
592 | }; | 621 | }; |
593 | 622 | ||
594 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 623 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; |
624 | if (privileged) | ||
625 | task_setup.callback_ops = &nfs41_call_priv_sync_ops; | ||
595 | task = rpc_run_task(&task_setup); | 626 | task = rpc_run_task(&task_setup); |
596 | if (IS_ERR(task)) | 627 | if (IS_ERR(task)) |
597 | ret = PTR_ERR(task); | 628 | ret = PTR_ERR(task); |
@@ -609,7 +640,7 @@ int _nfs4_call_sync_session(struct nfs_server *server, | |||
609 | int cache_reply) | 640 | int cache_reply) |
610 | { | 641 | { |
611 | return nfs4_call_sync_sequence(server->nfs_client, server->client, | 642 | return nfs4_call_sync_sequence(server->nfs_client, server->client, |
612 | msg, args, res, cache_reply); | 643 | msg, args, res, cache_reply, 0); |
613 | } | 644 | } |
614 | 645 | ||
615 | #endif /* CONFIG_NFS_V4_1 */ | 646 | #endif /* CONFIG_NFS_V4_1 */ |
@@ -637,15 +668,6 @@ static void nfs4_sequence_done(const struct nfs_server *server, | |||
637 | #endif /* CONFIG_NFS_V4_1 */ | 668 | #endif /* CONFIG_NFS_V4_1 */ |
638 | } | 669 | } |
639 | 670 | ||
640 | /* no restart, therefore free slot here */ | ||
641 | static void nfs4_sequence_done_free_slot(const struct nfs_server *server, | ||
642 | struct nfs4_sequence_res *res, | ||
643 | int rpc_status) | ||
644 | { | ||
645 | nfs4_sequence_done(server, res, rpc_status); | ||
646 | nfs4_sequence_free_slot(server->nfs_client, res); | ||
647 | } | ||
648 | |||
649 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | 671 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) |
650 | { | 672 | { |
651 | struct nfs_inode *nfsi = NFS_I(dir); | 673 | struct nfs_inode *nfsi = NFS_I(dir); |
@@ -705,8 +727,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |||
705 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | 727 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); |
706 | if (p->o_arg.seqid == NULL) | 728 | if (p->o_arg.seqid == NULL) |
707 | goto err_free; | 729 | goto err_free; |
708 | p->path.mnt = mntget(path->mnt); | 730 | path_get(path); |
709 | p->path.dentry = dget(path->dentry); | 731 | p->path = *path; |
710 | p->dir = parent; | 732 | p->dir = parent; |
711 | p->owner = sp; | 733 | p->owner = sp; |
712 | atomic_inc(&sp->so_count); | 734 | atomic_inc(&sp->so_count); |
@@ -720,9 +742,15 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |||
720 | p->o_arg.bitmask = server->attr_bitmask; | 742 | p->o_arg.bitmask = server->attr_bitmask; |
721 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | 743 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; |
722 | if (flags & O_EXCL) { | 744 | if (flags & O_EXCL) { |
723 | u32 *s = (u32 *) p->o_arg.u.verifier.data; | 745 | if (nfs4_has_persistent_session(server->nfs_client)) { |
724 | s[0] = jiffies; | 746 | /* GUARDED */ |
725 | s[1] = current->pid; | 747 | p->o_arg.u.attrs = &p->attrs; |
748 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); | ||
749 | } else { /* EXCLUSIVE4_1 */ | ||
750 | u32 *s = (u32 *) p->o_arg.u.verifier.data; | ||
751 | s[0] = jiffies; | ||
752 | s[1] = current->pid; | ||
753 | } | ||
726 | } else if (flags & O_CREAT) { | 754 | } else if (flags & O_CREAT) { |
727 | p->o_arg.u.attrs = &p->attrs; | 755 | p->o_arg.u.attrs = &p->attrs; |
728 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); | 756 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); |
@@ -776,13 +804,16 @@ static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode | |||
776 | goto out; | 804 | goto out; |
777 | switch (mode & (FMODE_READ|FMODE_WRITE)) { | 805 | switch (mode & (FMODE_READ|FMODE_WRITE)) { |
778 | case FMODE_READ: | 806 | case FMODE_READ: |
779 | ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0; | 807 | ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0 |
808 | && state->n_rdonly != 0; | ||
780 | break; | 809 | break; |
781 | case FMODE_WRITE: | 810 | case FMODE_WRITE: |
782 | ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0; | 811 | ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0 |
812 | && state->n_wronly != 0; | ||
783 | break; | 813 | break; |
784 | case FMODE_READ|FMODE_WRITE: | 814 | case FMODE_READ|FMODE_WRITE: |
785 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; | 815 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0 |
816 | && state->n_rdwr != 0; | ||
786 | } | 817 | } |
787 | out: | 818 | out: |
788 | return ret; | 819 | return ret; |
@@ -1047,7 +1078,7 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmod | |||
1047 | memset(&opendata->o_res, 0, sizeof(opendata->o_res)); | 1078 | memset(&opendata->o_res, 0, sizeof(opendata->o_res)); |
1048 | memset(&opendata->c_res, 0, sizeof(opendata->c_res)); | 1079 | memset(&opendata->c_res, 0, sizeof(opendata->c_res)); |
1049 | nfs4_init_opendata_res(opendata); | 1080 | nfs4_init_opendata_res(opendata); |
1050 | ret = _nfs4_proc_open(opendata); | 1081 | ret = _nfs4_recover_proc_open(opendata); |
1051 | if (ret != 0) | 1082 | if (ret != 0) |
1052 | return ret; | 1083 | return ret; |
1053 | newstate = nfs4_opendata_to_nfs4_state(opendata); | 1084 | newstate = nfs4_opendata_to_nfs4_state(opendata); |
@@ -1135,7 +1166,7 @@ static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state | |||
1135 | int err; | 1166 | int err; |
1136 | do { | 1167 | do { |
1137 | err = _nfs4_do_open_reclaim(ctx, state); | 1168 | err = _nfs4_do_open_reclaim(ctx, state); |
1138 | if (err != -NFS4ERR_DELAY) | 1169 | if (err != -NFS4ERR_DELAY && err != -EKEYEXPIRED) |
1139 | break; | 1170 | break; |
1140 | nfs4_handle_exception(server, err, &exception); | 1171 | nfs4_handle_exception(server, err, &exception); |
1141 | } while (exception.retry); | 1172 | } while (exception.retry); |
@@ -1183,6 +1214,14 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state | |||
1183 | case -ENOENT: | 1214 | case -ENOENT: |
1184 | case -ESTALE: | 1215 | case -ESTALE: |
1185 | goto out; | 1216 | goto out; |
1217 | case -NFS4ERR_BADSESSION: | ||
1218 | case -NFS4ERR_BADSLOT: | ||
1219 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
1220 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
1221 | case -NFS4ERR_DEADSESSION: | ||
1222 | nfs4_schedule_state_recovery( | ||
1223 | server->nfs_client); | ||
1224 | goto out; | ||
1186 | case -NFS4ERR_STALE_CLIENTID: | 1225 | case -NFS4ERR_STALE_CLIENTID: |
1187 | case -NFS4ERR_STALE_STATEID: | 1226 | case -NFS4ERR_STALE_STATEID: |
1188 | case -NFS4ERR_EXPIRED: | 1227 | case -NFS4ERR_EXPIRED: |
@@ -1330,14 +1369,20 @@ out_no_action: | |||
1330 | 1369 | ||
1331 | } | 1370 | } |
1332 | 1371 | ||
1372 | static void nfs4_recover_open_prepare(struct rpc_task *task, void *calldata) | ||
1373 | { | ||
1374 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
1375 | nfs4_open_prepare(task, calldata); | ||
1376 | } | ||
1377 | |||
1333 | static void nfs4_open_done(struct rpc_task *task, void *calldata) | 1378 | static void nfs4_open_done(struct rpc_task *task, void *calldata) |
1334 | { | 1379 | { |
1335 | struct nfs4_opendata *data = calldata; | 1380 | struct nfs4_opendata *data = calldata; |
1336 | 1381 | ||
1337 | data->rpc_status = task->tk_status; | 1382 | data->rpc_status = task->tk_status; |
1338 | 1383 | ||
1339 | nfs4_sequence_done_free_slot(data->o_arg.server, &data->o_res.seq_res, | 1384 | nfs4_sequence_done(data->o_arg.server, &data->o_res.seq_res, |
1340 | task->tk_status); | 1385 | task->tk_status); |
1341 | 1386 | ||
1342 | if (RPC_ASSASSINATED(task)) | 1387 | if (RPC_ASSASSINATED(task)) |
1343 | return; | 1388 | return; |
@@ -1388,10 +1433,13 @@ static const struct rpc_call_ops nfs4_open_ops = { | |||
1388 | .rpc_release = nfs4_open_release, | 1433 | .rpc_release = nfs4_open_release, |
1389 | }; | 1434 | }; |
1390 | 1435 | ||
1391 | /* | 1436 | static const struct rpc_call_ops nfs4_recover_open_ops = { |
1392 | * Note: On error, nfs4_proc_open will free the struct nfs4_opendata | 1437 | .rpc_call_prepare = nfs4_recover_open_prepare, |
1393 | */ | 1438 | .rpc_call_done = nfs4_open_done, |
1394 | static int _nfs4_proc_open(struct nfs4_opendata *data) | 1439 | .rpc_release = nfs4_open_release, |
1440 | }; | ||
1441 | |||
1442 | static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover) | ||
1395 | { | 1443 | { |
1396 | struct inode *dir = data->dir->d_inode; | 1444 | struct inode *dir = data->dir->d_inode; |
1397 | struct nfs_server *server = NFS_SERVER(dir); | 1445 | struct nfs_server *server = NFS_SERVER(dir); |
@@ -1418,27 +1466,65 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
1418 | data->rpc_done = 0; | 1466 | data->rpc_done = 0; |
1419 | data->rpc_status = 0; | 1467 | data->rpc_status = 0; |
1420 | data->cancelled = 0; | 1468 | data->cancelled = 0; |
1469 | if (isrecover) | ||
1470 | task_setup_data.callback_ops = &nfs4_recover_open_ops; | ||
1421 | task = rpc_run_task(&task_setup_data); | 1471 | task = rpc_run_task(&task_setup_data); |
1422 | if (IS_ERR(task)) | 1472 | if (IS_ERR(task)) |
1423 | return PTR_ERR(task); | 1473 | return PTR_ERR(task); |
1424 | status = nfs4_wait_for_completion_rpc_task(task); | 1474 | status = nfs4_wait_for_completion_rpc_task(task); |
1425 | if (status != 0) { | 1475 | if (status != 0) { |
1426 | data->cancelled = 1; | 1476 | data->cancelled = 1; |
1427 | smp_wmb(); | 1477 | smp_wmb(); |
1428 | } else | 1478 | } else |
1429 | status = data->rpc_status; | 1479 | status = data->rpc_status; |
1430 | rpc_put_task(task); | 1480 | rpc_put_task(task); |
1481 | |||
1482 | return status; | ||
1483 | } | ||
1484 | |||
1485 | static int _nfs4_recover_proc_open(struct nfs4_opendata *data) | ||
1486 | { | ||
1487 | struct inode *dir = data->dir->d_inode; | ||
1488 | struct nfs_openres *o_res = &data->o_res; | ||
1489 | int status; | ||
1490 | |||
1491 | status = nfs4_run_open_task(data, 1); | ||
1431 | if (status != 0 || !data->rpc_done) | 1492 | if (status != 0 || !data->rpc_done) |
1432 | return status; | 1493 | return status; |
1433 | 1494 | ||
1434 | if (o_res->fh.size == 0) | 1495 | nfs_refresh_inode(dir, o_res->dir_attr); |
1435 | _nfs4_proc_lookup(dir, o_arg->name, &o_res->fh, o_res->f_attr); | 1496 | |
1497 | if (o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { | ||
1498 | status = _nfs4_proc_open_confirm(data); | ||
1499 | if (status != 0) | ||
1500 | return status; | ||
1501 | } | ||
1502 | |||
1503 | return status; | ||
1504 | } | ||
1505 | |||
1506 | /* | ||
1507 | * Note: On error, nfs4_proc_open will free the struct nfs4_opendata | ||
1508 | */ | ||
1509 | static int _nfs4_proc_open(struct nfs4_opendata *data) | ||
1510 | { | ||
1511 | struct inode *dir = data->dir->d_inode; | ||
1512 | struct nfs_server *server = NFS_SERVER(dir); | ||
1513 | struct nfs_openargs *o_arg = &data->o_arg; | ||
1514 | struct nfs_openres *o_res = &data->o_res; | ||
1515 | int status; | ||
1516 | |||
1517 | status = nfs4_run_open_task(data, 0); | ||
1518 | if (status != 0 || !data->rpc_done) | ||
1519 | return status; | ||
1436 | 1520 | ||
1437 | if (o_arg->open_flags & O_CREAT) { | 1521 | if (o_arg->open_flags & O_CREAT) { |
1438 | update_changeattr(dir, &o_res->cinfo); | 1522 | update_changeattr(dir, &o_res->cinfo); |
1439 | nfs_post_op_update_inode(dir, o_res->dir_attr); | 1523 | nfs_post_op_update_inode(dir, o_res->dir_attr); |
1440 | } else | 1524 | } else |
1441 | nfs_refresh_inode(dir, o_res->dir_attr); | 1525 | nfs_refresh_inode(dir, o_res->dir_attr); |
1526 | if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0) | ||
1527 | server->caps &= ~NFS_CAP_POSIX_LOCK; | ||
1442 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { | 1528 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { |
1443 | status = _nfs4_proc_open_confirm(data); | 1529 | status = _nfs4_proc_open_confirm(data); |
1444 | if (status != 0) | 1530 | if (status != 0) |
@@ -1488,7 +1574,7 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s | |||
1488 | return ret; | 1574 | return ret; |
1489 | } | 1575 | } |
1490 | 1576 | ||
1491 | static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state) | 1577 | static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state) |
1492 | { | 1578 | { |
1493 | struct nfs_server *server = NFS_SERVER(state->inode); | 1579 | struct nfs_server *server = NFS_SERVER(state->inode); |
1494 | struct nfs4_exception exception = { }; | 1580 | struct nfs4_exception exception = { }; |
@@ -1496,10 +1582,17 @@ static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4 | |||
1496 | 1582 | ||
1497 | do { | 1583 | do { |
1498 | err = _nfs4_open_expired(ctx, state); | 1584 | err = _nfs4_open_expired(ctx, state); |
1499 | if (err != -NFS4ERR_DELAY) | 1585 | switch (err) { |
1500 | break; | 1586 | default: |
1501 | nfs4_handle_exception(server, err, &exception); | 1587 | goto out; |
1588 | case -NFS4ERR_GRACE: | ||
1589 | case -NFS4ERR_DELAY: | ||
1590 | case -EKEYEXPIRED: | ||
1591 | nfs4_handle_exception(server, err, &exception); | ||
1592 | err = 0; | ||
1593 | } | ||
1502 | } while (exception.retry); | 1594 | } while (exception.retry); |
1595 | out: | ||
1503 | return err; | 1596 | return err; |
1504 | } | 1597 | } |
1505 | 1598 | ||
@@ -1573,6 +1666,8 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, in | |||
1573 | status = PTR_ERR(state); | 1666 | status = PTR_ERR(state); |
1574 | if (IS_ERR(state)) | 1667 | if (IS_ERR(state)) |
1575 | goto err_opendata_put; | 1668 | goto err_opendata_put; |
1669 | if (server->caps & NFS_CAP_POSIX_LOCK) | ||
1670 | set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); | ||
1576 | nfs4_opendata_put(opendata); | 1671 | nfs4_opendata_put(opendata); |
1577 | nfs4_put_state_owner(sp); | 1672 | nfs4_put_state_owner(sp); |
1578 | *res = state; | 1673 | *res = state; |
@@ -1712,6 +1807,18 @@ static void nfs4_free_closedata(void *data) | |||
1712 | kfree(calldata); | 1807 | kfree(calldata); |
1713 | } | 1808 | } |
1714 | 1809 | ||
1810 | static void nfs4_close_clear_stateid_flags(struct nfs4_state *state, | ||
1811 | fmode_t fmode) | ||
1812 | { | ||
1813 | spin_lock(&state->owner->so_lock); | ||
1814 | if (!(fmode & FMODE_READ)) | ||
1815 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
1816 | if (!(fmode & FMODE_WRITE)) | ||
1817 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
1818 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
1819 | spin_unlock(&state->owner->so_lock); | ||
1820 | } | ||
1821 | |||
1715 | static void nfs4_close_done(struct rpc_task *task, void *data) | 1822 | static void nfs4_close_done(struct rpc_task *task, void *data) |
1716 | { | 1823 | { |
1717 | struct nfs4_closedata *calldata = data; | 1824 | struct nfs4_closedata *calldata = data; |
@@ -1728,6 +1835,8 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1728 | case 0: | 1835 | case 0: |
1729 | nfs_set_open_stateid(state, &calldata->res.stateid, 0); | 1836 | nfs_set_open_stateid(state, &calldata->res.stateid, 0); |
1730 | renew_lease(server, calldata->timestamp); | 1837 | renew_lease(server, calldata->timestamp); |
1838 | nfs4_close_clear_stateid_flags(state, | ||
1839 | calldata->arg.fmode); | ||
1731 | break; | 1840 | break; |
1732 | case -NFS4ERR_STALE_STATEID: | 1841 | case -NFS4ERR_STALE_STATEID: |
1733 | case -NFS4ERR_OLD_STATEID: | 1842 | case -NFS4ERR_OLD_STATEID: |
@@ -1736,12 +1845,10 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1736 | if (calldata->arg.fmode == 0) | 1845 | if (calldata->arg.fmode == 0) |
1737 | break; | 1846 | break; |
1738 | default: | 1847 | default: |
1739 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { | 1848 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) |
1740 | nfs4_restart_rpc(task, server->nfs_client); | 1849 | rpc_restart_call_prepare(task); |
1741 | return; | ||
1742 | } | ||
1743 | } | 1850 | } |
1744 | nfs4_sequence_free_slot(server->nfs_client, &calldata->res.seq_res); | 1851 | nfs_release_seqid(calldata->arg.seqid); |
1745 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); | 1852 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); |
1746 | } | 1853 | } |
1747 | 1854 | ||
@@ -1749,38 +1856,39 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1749 | { | 1856 | { |
1750 | struct nfs4_closedata *calldata = data; | 1857 | struct nfs4_closedata *calldata = data; |
1751 | struct nfs4_state *state = calldata->state; | 1858 | struct nfs4_state *state = calldata->state; |
1752 | int clear_rd, clear_wr, clear_rdwr; | 1859 | int call_close = 0; |
1753 | 1860 | ||
1754 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) | 1861 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) |
1755 | return; | 1862 | return; |
1756 | 1863 | ||
1757 | clear_rd = clear_wr = clear_rdwr = 0; | 1864 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; |
1865 | calldata->arg.fmode = FMODE_READ|FMODE_WRITE; | ||
1758 | spin_lock(&state->owner->so_lock); | 1866 | spin_lock(&state->owner->so_lock); |
1759 | /* Calculate the change in open mode */ | 1867 | /* Calculate the change in open mode */ |
1760 | if (state->n_rdwr == 0) { | 1868 | if (state->n_rdwr == 0) { |
1761 | if (state->n_rdonly == 0) { | 1869 | if (state->n_rdonly == 0) { |
1762 | clear_rd |= test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags); | 1870 | call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags); |
1763 | clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); | 1871 | call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags); |
1872 | calldata->arg.fmode &= ~FMODE_READ; | ||
1764 | } | 1873 | } |
1765 | if (state->n_wronly == 0) { | 1874 | if (state->n_wronly == 0) { |
1766 | clear_wr |= test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags); | 1875 | call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags); |
1767 | clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); | 1876 | call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags); |
1877 | calldata->arg.fmode &= ~FMODE_WRITE; | ||
1768 | } | 1878 | } |
1769 | } | 1879 | } |
1770 | spin_unlock(&state->owner->so_lock); | 1880 | spin_unlock(&state->owner->so_lock); |
1771 | if (!clear_rd && !clear_wr && !clear_rdwr) { | 1881 | |
1882 | if (!call_close) { | ||
1772 | /* Note: exit _without_ calling nfs4_close_done */ | 1883 | /* Note: exit _without_ calling nfs4_close_done */ |
1773 | task->tk_action = NULL; | 1884 | task->tk_action = NULL; |
1774 | return; | 1885 | return; |
1775 | } | 1886 | } |
1887 | |||
1888 | if (calldata->arg.fmode == 0) | ||
1889 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE]; | ||
1890 | |||
1776 | nfs_fattr_init(calldata->res.fattr); | 1891 | nfs_fattr_init(calldata->res.fattr); |
1777 | if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) { | ||
1778 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | ||
1779 | calldata->arg.fmode = FMODE_READ; | ||
1780 | } else if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) { | ||
1781 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | ||
1782 | calldata->arg.fmode = FMODE_WRITE; | ||
1783 | } | ||
1784 | calldata->timestamp = jiffies; | 1892 | calldata->timestamp = jiffies; |
1785 | if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client, | 1893 | if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client, |
1786 | &calldata->arg.seq_args, &calldata->res.seq_res, | 1894 | &calldata->arg.seq_args, &calldata->res.seq_res, |
@@ -1832,8 +1940,6 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1832 | calldata->state = state; | 1940 | calldata->state = state; |
1833 | calldata->arg.fh = NFS_FH(state->inode); | 1941 | calldata->arg.fh = NFS_FH(state->inode); |
1834 | calldata->arg.stateid = &state->open_stateid; | 1942 | calldata->arg.stateid = &state->open_stateid; |
1835 | if (nfs4_has_session(server->nfs_client)) | ||
1836 | memset(calldata->arg.stateid->data, 0, 4); /* clear seqid */ | ||
1837 | /* Serialization for the sequence id */ | 1943 | /* Serialization for the sequence id */ |
1838 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 1944 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); |
1839 | if (calldata->arg.seqid == NULL) | 1945 | if (calldata->arg.seqid == NULL) |
@@ -1844,8 +1950,8 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1844 | calldata->res.seqid = calldata->arg.seqid; | 1950 | calldata->res.seqid = calldata->arg.seqid; |
1845 | calldata->res.server = server; | 1951 | calldata->res.server = server; |
1846 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | 1952 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; |
1847 | calldata->path.mnt = mntget(path->mnt); | 1953 | path_get(path); |
1848 | calldata->path.dentry = dget(path->dentry); | 1954 | calldata->path = *path; |
1849 | 1955 | ||
1850 | msg.rpc_argp = &calldata->arg, | 1956 | msg.rpc_argp = &calldata->arg, |
1851 | msg.rpc_resp = &calldata->res, | 1957 | msg.rpc_resp = &calldata->res, |
@@ -1964,8 +2070,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
1964 | case -EDQUOT: | 2070 | case -EDQUOT: |
1965 | case -ENOSPC: | 2071 | case -ENOSPC: |
1966 | case -EROFS: | 2072 | case -EROFS: |
1967 | lookup_instantiate_filp(nd, (struct dentry *)state, NULL); | 2073 | return PTR_ERR(state); |
1968 | return 1; | ||
1969 | default: | 2074 | default: |
1970 | goto out_drop; | 2075 | goto out_drop; |
1971 | } | 2076 | } |
@@ -1981,7 +2086,7 @@ out_drop: | |||
1981 | return 0; | 2086 | return 0; |
1982 | } | 2087 | } |
1983 | 2088 | ||
1984 | void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) | 2089 | static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) |
1985 | { | 2090 | { |
1986 | if (ctx->state == NULL) | 2091 | if (ctx->state == NULL) |
1987 | return; | 2092 | return; |
@@ -2532,7 +2637,6 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
2532 | nfs4_sequence_done(res->server, &res->seq_res, task->tk_status); | 2637 | nfs4_sequence_done(res->server, &res->seq_res, task->tk_status); |
2533 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) | 2638 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) |
2534 | return 0; | 2639 | return 0; |
2535 | nfs4_sequence_free_slot(res->server->nfs_client, &res->seq_res); | ||
2536 | update_changeattr(dir, &res->cinfo); | 2640 | update_changeattr(dir, &res->cinfo); |
2537 | nfs_post_op_update_inode(dir, &res->dir_attr); | 2641 | nfs_post_op_update_inode(dir, &res->dir_attr); |
2538 | return 1; | 2642 | return 1; |
@@ -2971,11 +3075,10 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
2971 | 3075 | ||
2972 | dprintk("--> %s\n", __func__); | 3076 | dprintk("--> %s\n", __func__); |
2973 | 3077 | ||
2974 | /* nfs4_sequence_free_slot called in the read rpc_call_done */ | ||
2975 | nfs4_sequence_done(server, &data->res.seq_res, task->tk_status); | 3078 | nfs4_sequence_done(server, &data->res.seq_res, task->tk_status); |
2976 | 3079 | ||
2977 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { | 3080 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { |
2978 | nfs4_restart_rpc(task, server->nfs_client); | 3081 | nfs_restart_rpc(task, server->nfs_client); |
2979 | return -EAGAIN; | 3082 | return -EAGAIN; |
2980 | } | 3083 | } |
2981 | 3084 | ||
@@ -2995,12 +3098,11 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2995 | { | 3098 | { |
2996 | struct inode *inode = data->inode; | 3099 | struct inode *inode = data->inode; |
2997 | 3100 | ||
2998 | /* slot is freed in nfs_writeback_done */ | ||
2999 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | 3101 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, |
3000 | task->tk_status); | 3102 | task->tk_status); |
3001 | 3103 | ||
3002 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { | 3104 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { |
3003 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); | 3105 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
3004 | return -EAGAIN; | 3106 | return -EAGAIN; |
3005 | } | 3107 | } |
3006 | if (task->tk_status >= 0) { | 3108 | if (task->tk_status >= 0) { |
@@ -3028,11 +3130,9 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
3028 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | 3130 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, |
3029 | task->tk_status); | 3131 | task->tk_status); |
3030 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { | 3132 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { |
3031 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); | 3133 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
3032 | return -EAGAIN; | 3134 | return -EAGAIN; |
3033 | } | 3135 | } |
3034 | nfs4_sequence_free_slot(NFS_SERVER(inode)->nfs_client, | ||
3035 | &data->res.seq_res); | ||
3036 | nfs_refresh_inode(inode, data->res.fattr); | 3136 | nfs_refresh_inode(inode, data->res.fattr); |
3037 | return 0; | 3137 | return 0; |
3038 | } | 3138 | } |
@@ -3050,10 +3150,19 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_messa | |||
3050 | * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special | 3150 | * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special |
3051 | * standalone procedure for queueing an asynchronous RENEW. | 3151 | * standalone procedure for queueing an asynchronous RENEW. |
3052 | */ | 3152 | */ |
3153 | static void nfs4_renew_release(void *data) | ||
3154 | { | ||
3155 | struct nfs_client *clp = data; | ||
3156 | |||
3157 | if (atomic_read(&clp->cl_count) > 1) | ||
3158 | nfs4_schedule_state_renewal(clp); | ||
3159 | nfs_put_client(clp); | ||
3160 | } | ||
3161 | |||
3053 | static void nfs4_renew_done(struct rpc_task *task, void *data) | 3162 | static void nfs4_renew_done(struct rpc_task *task, void *data) |
3054 | { | 3163 | { |
3055 | struct nfs_client *clp = (struct nfs_client *)task->tk_msg.rpc_argp; | 3164 | struct nfs_client *clp = data; |
3056 | unsigned long timestamp = (unsigned long)data; | 3165 | unsigned long timestamp = task->tk_start; |
3057 | 3166 | ||
3058 | if (task->tk_status < 0) { | 3167 | if (task->tk_status < 0) { |
3059 | /* Unless we're shutting down, schedule state recovery! */ | 3168 | /* Unless we're shutting down, schedule state recovery! */ |
@@ -3069,6 +3178,7 @@ static void nfs4_renew_done(struct rpc_task *task, void *data) | |||
3069 | 3178 | ||
3070 | static const struct rpc_call_ops nfs4_renew_ops = { | 3179 | static const struct rpc_call_ops nfs4_renew_ops = { |
3071 | .rpc_call_done = nfs4_renew_done, | 3180 | .rpc_call_done = nfs4_renew_done, |
3181 | .rpc_release = nfs4_renew_release, | ||
3072 | }; | 3182 | }; |
3073 | 3183 | ||
3074 | int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) | 3184 | int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) |
@@ -3079,8 +3189,10 @@ int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) | |||
3079 | .rpc_cred = cred, | 3189 | .rpc_cred = cred, |
3080 | }; | 3190 | }; |
3081 | 3191 | ||
3192 | if (!atomic_inc_not_zero(&clp->cl_count)) | ||
3193 | return -EIO; | ||
3082 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | 3194 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, |
3083 | &nfs4_renew_ops, (void *)jiffies); | 3195 | &nfs4_renew_ops, clp); |
3084 | } | 3196 | } |
3085 | 3197 | ||
3086 | int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) | 3198 | int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) |
@@ -3331,15 +3443,14 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3331 | if (state == NULL) | 3443 | if (state == NULL) |
3332 | break; | 3444 | break; |
3333 | nfs4_state_mark_reclaim_nograce(clp, state); | 3445 | nfs4_state_mark_reclaim_nograce(clp, state); |
3334 | case -NFS4ERR_STALE_CLIENTID: | 3446 | goto do_state_recovery; |
3335 | case -NFS4ERR_STALE_STATEID: | 3447 | case -NFS4ERR_STALE_STATEID: |
3448 | if (state == NULL) | ||
3449 | break; | ||
3450 | nfs4_state_mark_reclaim_reboot(clp, state); | ||
3451 | case -NFS4ERR_STALE_CLIENTID: | ||
3336 | case -NFS4ERR_EXPIRED: | 3452 | case -NFS4ERR_EXPIRED: |
3337 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); | 3453 | goto do_state_recovery; |
3338 | nfs4_schedule_state_recovery(clp); | ||
3339 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) | ||
3340 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | ||
3341 | task->tk_status = 0; | ||
3342 | return -EAGAIN; | ||
3343 | #if defined(CONFIG_NFS_V4_1) | 3454 | #if defined(CONFIG_NFS_V4_1) |
3344 | case -NFS4ERR_BADSESSION: | 3455 | case -NFS4ERR_BADSESSION: |
3345 | case -NFS4ERR_BADSLOT: | 3456 | case -NFS4ERR_BADSLOT: |
@@ -3350,7 +3461,7 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3350 | case -NFS4ERR_SEQ_MISORDERED: | 3461 | case -NFS4ERR_SEQ_MISORDERED: |
3351 | dprintk("%s ERROR %d, Reset session\n", __func__, | 3462 | dprintk("%s ERROR %d, Reset session\n", __func__, |
3352 | task->tk_status); | 3463 | task->tk_status); |
3353 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | 3464 | nfs4_schedule_state_recovery(clp); |
3354 | task->tk_status = 0; | 3465 | task->tk_status = 0; |
3355 | return -EAGAIN; | 3466 | return -EAGAIN; |
3356 | #endif /* CONFIG_NFS_V4_1 */ | 3467 | #endif /* CONFIG_NFS_V4_1 */ |
@@ -3358,6 +3469,7 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3358 | if (server) | 3469 | if (server) |
3359 | nfs_inc_server_stats(server, NFSIOS_DELAY); | 3470 | nfs_inc_server_stats(server, NFSIOS_DELAY); |
3360 | case -NFS4ERR_GRACE: | 3471 | case -NFS4ERR_GRACE: |
3472 | case -EKEYEXPIRED: | ||
3361 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 3473 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
3362 | task->tk_status = 0; | 3474 | task->tk_status = 0; |
3363 | return -EAGAIN; | 3475 | return -EAGAIN; |
@@ -3367,6 +3479,13 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3367 | } | 3479 | } |
3368 | task->tk_status = nfs4_map_errors(task->tk_status); | 3480 | task->tk_status = nfs4_map_errors(task->tk_status); |
3369 | return 0; | 3481 | return 0; |
3482 | do_state_recovery: | ||
3483 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); | ||
3484 | nfs4_schedule_state_recovery(clp); | ||
3485 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) | ||
3486 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | ||
3487 | task->tk_status = 0; | ||
3488 | return -EAGAIN; | ||
3370 | } | 3489 | } |
3371 | 3490 | ||
3372 | static int | 3491 | static int |
@@ -3463,6 +3582,7 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred) | |||
3463 | case -NFS4ERR_RESOURCE: | 3582 | case -NFS4ERR_RESOURCE: |
3464 | /* The IBM lawyers misread another document! */ | 3583 | /* The IBM lawyers misread another document! */ |
3465 | case -NFS4ERR_DELAY: | 3584 | case -NFS4ERR_DELAY: |
3585 | case -EKEYEXPIRED: | ||
3466 | err = nfs4_delay(clp->cl_rpcclient, &timeout); | 3586 | err = nfs4_delay(clp->cl_rpcclient, &timeout); |
3467 | } | 3587 | } |
3468 | } while (err == 0); | 3588 | } while (err == 0); |
@@ -3483,12 +3603,23 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | |||
3483 | { | 3603 | { |
3484 | struct nfs4_delegreturndata *data = calldata; | 3604 | struct nfs4_delegreturndata *data = calldata; |
3485 | 3605 | ||
3486 | nfs4_sequence_done_free_slot(data->res.server, &data->res.seq_res, | 3606 | nfs4_sequence_done(data->res.server, &data->res.seq_res, |
3487 | task->tk_status); | 3607 | task->tk_status); |
3488 | 3608 | ||
3489 | data->rpc_status = task->tk_status; | 3609 | switch (task->tk_status) { |
3490 | if (data->rpc_status == 0) | 3610 | case -NFS4ERR_STALE_STATEID: |
3611 | case -NFS4ERR_EXPIRED: | ||
3612 | case 0: | ||
3491 | renew_lease(data->res.server, data->timestamp); | 3613 | renew_lease(data->res.server, data->timestamp); |
3614 | break; | ||
3615 | default: | ||
3616 | if (nfs4_async_handle_error(task, data->res.server, NULL) == | ||
3617 | -EAGAIN) { | ||
3618 | nfs_restart_rpc(task, data->res.server->nfs_client); | ||
3619 | return; | ||
3620 | } | ||
3621 | } | ||
3622 | data->rpc_status = task->tk_status; | ||
3492 | } | 3623 | } |
3493 | 3624 | ||
3494 | static void nfs4_delegreturn_release(void *calldata) | 3625 | static void nfs4_delegreturn_release(void *calldata) |
@@ -3741,11 +3872,9 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3741 | break; | 3872 | break; |
3742 | default: | 3873 | default: |
3743 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) | 3874 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) |
3744 | nfs4_restart_rpc(task, | 3875 | nfs_restart_rpc(task, |
3745 | calldata->server->nfs_client); | 3876 | calldata->server->nfs_client); |
3746 | } | 3877 | } |
3747 | nfs4_sequence_free_slot(calldata->server->nfs_client, | ||
3748 | &calldata->res.seq_res); | ||
3749 | } | 3878 | } |
3750 | 3879 | ||
3751 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) | 3880 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) |
@@ -3921,14 +4050,20 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
3921 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); | 4050 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); |
3922 | } | 4051 | } |
3923 | 4052 | ||
4053 | static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata) | ||
4054 | { | ||
4055 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
4056 | nfs4_lock_prepare(task, calldata); | ||
4057 | } | ||
4058 | |||
3924 | static void nfs4_lock_done(struct rpc_task *task, void *calldata) | 4059 | static void nfs4_lock_done(struct rpc_task *task, void *calldata) |
3925 | { | 4060 | { |
3926 | struct nfs4_lockdata *data = calldata; | 4061 | struct nfs4_lockdata *data = calldata; |
3927 | 4062 | ||
3928 | dprintk("%s: begin!\n", __func__); | 4063 | dprintk("%s: begin!\n", __func__); |
3929 | 4064 | ||
3930 | nfs4_sequence_done_free_slot(data->server, &data->res.seq_res, | 4065 | nfs4_sequence_done(data->server, &data->res.seq_res, |
3931 | task->tk_status); | 4066 | task->tk_status); |
3932 | 4067 | ||
3933 | data->rpc_status = task->tk_status; | 4068 | data->rpc_status = task->tk_status; |
3934 | if (RPC_ASSASSINATED(task)) | 4069 | if (RPC_ASSASSINATED(task)) |
@@ -3976,7 +4111,35 @@ static const struct rpc_call_ops nfs4_lock_ops = { | |||
3976 | .rpc_release = nfs4_lock_release, | 4111 | .rpc_release = nfs4_lock_release, |
3977 | }; | 4112 | }; |
3978 | 4113 | ||
3979 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int reclaim) | 4114 | static const struct rpc_call_ops nfs4_recover_lock_ops = { |
4115 | .rpc_call_prepare = nfs4_recover_lock_prepare, | ||
4116 | .rpc_call_done = nfs4_lock_done, | ||
4117 | .rpc_release = nfs4_lock_release, | ||
4118 | }; | ||
4119 | |||
4120 | static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_state *lsp, int new_lock_owner, int error) | ||
4121 | { | ||
4122 | struct nfs_client *clp = server->nfs_client; | ||
4123 | struct nfs4_state *state = lsp->ls_state; | ||
4124 | |||
4125 | switch (error) { | ||
4126 | case -NFS4ERR_ADMIN_REVOKED: | ||
4127 | case -NFS4ERR_BAD_STATEID: | ||
4128 | case -NFS4ERR_EXPIRED: | ||
4129 | if (new_lock_owner != 0 || | ||
4130 | (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) | ||
4131 | nfs4_state_mark_reclaim_nograce(clp, state); | ||
4132 | lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED; | ||
4133 | break; | ||
4134 | case -NFS4ERR_STALE_STATEID: | ||
4135 | if (new_lock_owner != 0 || | ||
4136 | (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) | ||
4137 | nfs4_state_mark_reclaim_reboot(clp, state); | ||
4138 | lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED; | ||
4139 | }; | ||
4140 | } | ||
4141 | |||
4142 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int recovery_type) | ||
3980 | { | 4143 | { |
3981 | struct nfs4_lockdata *data; | 4144 | struct nfs4_lockdata *data; |
3982 | struct rpc_task *task; | 4145 | struct rpc_task *task; |
@@ -4000,8 +4163,11 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
4000 | return -ENOMEM; | 4163 | return -ENOMEM; |
4001 | if (IS_SETLKW(cmd)) | 4164 | if (IS_SETLKW(cmd)) |
4002 | data->arg.block = 1; | 4165 | data->arg.block = 1; |
4003 | if (reclaim != 0) | 4166 | if (recovery_type > NFS_LOCK_NEW) { |
4004 | data->arg.reclaim = 1; | 4167 | if (recovery_type == NFS_LOCK_RECLAIM) |
4168 | data->arg.reclaim = NFS_LOCK_RECLAIM; | ||
4169 | task_setup_data.callback_ops = &nfs4_recover_lock_ops; | ||
4170 | } | ||
4005 | msg.rpc_argp = &data->arg, | 4171 | msg.rpc_argp = &data->arg, |
4006 | msg.rpc_resp = &data->res, | 4172 | msg.rpc_resp = &data->res, |
4007 | task_setup_data.callback_data = data; | 4173 | task_setup_data.callback_data = data; |
@@ -4011,6 +4177,9 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
4011 | ret = nfs4_wait_for_completion_rpc_task(task); | 4177 | ret = nfs4_wait_for_completion_rpc_task(task); |
4012 | if (ret == 0) { | 4178 | if (ret == 0) { |
4013 | ret = data->rpc_status; | 4179 | ret = data->rpc_status; |
4180 | if (ret) | ||
4181 | nfs4_handle_setlk_error(data->server, data->lsp, | ||
4182 | data->arg.new_lock_owner, ret); | ||
4014 | } else | 4183 | } else |
4015 | data->cancelled = 1; | 4184 | data->cancelled = 1; |
4016 | rpc_put_task(task); | 4185 | rpc_put_task(task); |
@@ -4028,8 +4197,8 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request | |||
4028 | /* Cache the lock if possible... */ | 4197 | /* Cache the lock if possible... */ |
4029 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) | 4198 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) |
4030 | return 0; | 4199 | return 0; |
4031 | err = _nfs4_do_setlk(state, F_SETLK, request, 1); | 4200 | err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM); |
4032 | if (err != -NFS4ERR_DELAY) | 4201 | if (err != -NFS4ERR_DELAY && err != -EKEYEXPIRED) |
4033 | break; | 4202 | break; |
4034 | nfs4_handle_exception(server, err, &exception); | 4203 | nfs4_handle_exception(server, err, &exception); |
4035 | } while (exception.retry); | 4204 | } while (exception.retry); |
@@ -4048,11 +4217,18 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request | |||
4048 | do { | 4217 | do { |
4049 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) | 4218 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) |
4050 | return 0; | 4219 | return 0; |
4051 | err = _nfs4_do_setlk(state, F_SETLK, request, 0); | 4220 | err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_EXPIRED); |
4052 | if (err != -NFS4ERR_DELAY) | 4221 | switch (err) { |
4053 | break; | 4222 | default: |
4054 | nfs4_handle_exception(server, err, &exception); | 4223 | goto out; |
4224 | case -NFS4ERR_GRACE: | ||
4225 | case -NFS4ERR_DELAY: | ||
4226 | case -EKEYEXPIRED: | ||
4227 | nfs4_handle_exception(server, err, &exception); | ||
4228 | err = 0; | ||
4229 | } | ||
4055 | } while (exception.retry); | 4230 | } while (exception.retry); |
4231 | out: | ||
4056 | return err; | 4232 | return err; |
4057 | } | 4233 | } |
4058 | 4234 | ||
@@ -4060,8 +4236,11 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock | |||
4060 | { | 4236 | { |
4061 | struct nfs_inode *nfsi = NFS_I(state->inode); | 4237 | struct nfs_inode *nfsi = NFS_I(state->inode); |
4062 | unsigned char fl_flags = request->fl_flags; | 4238 | unsigned char fl_flags = request->fl_flags; |
4063 | int status; | 4239 | int status = -ENOLCK; |
4064 | 4240 | ||
4241 | if ((fl_flags & FL_POSIX) && | ||
4242 | !test_bit(NFS_STATE_POSIX_LOCKS, &state->flags)) | ||
4243 | goto out; | ||
4065 | /* Is this a delegated open? */ | 4244 | /* Is this a delegated open? */ |
4066 | status = nfs4_set_lock_state(state, request); | 4245 | status = nfs4_set_lock_state(state, request); |
4067 | if (status != 0) | 4246 | if (status != 0) |
@@ -4078,7 +4257,7 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock | |||
4078 | status = do_vfs_lock(request->fl_file, request); | 4257 | status = do_vfs_lock(request->fl_file, request); |
4079 | goto out_unlock; | 4258 | goto out_unlock; |
4080 | } | 4259 | } |
4081 | status = _nfs4_do_setlk(state, cmd, request, 0); | 4260 | status = _nfs4_do_setlk(state, cmd, request, NFS_LOCK_NEW); |
4082 | if (status != 0) | 4261 | if (status != 0) |
4083 | goto out_unlock; | 4262 | goto out_unlock; |
4084 | /* Note: we always want to sleep here! */ | 4263 | /* Note: we always want to sleep here! */ |
@@ -4161,7 +4340,7 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | |||
4161 | if (err != 0) | 4340 | if (err != 0) |
4162 | goto out; | 4341 | goto out; |
4163 | do { | 4342 | do { |
4164 | err = _nfs4_do_setlk(state, F_SETLK, fl, 0); | 4343 | err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW); |
4165 | switch (err) { | 4344 | switch (err) { |
4166 | default: | 4345 | default: |
4167 | printk(KERN_ERR "%s: unhandled error %d.\n", | 4346 | printk(KERN_ERR "%s: unhandled error %d.\n", |
@@ -4172,6 +4351,11 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | |||
4172 | case -NFS4ERR_EXPIRED: | 4351 | case -NFS4ERR_EXPIRED: |
4173 | case -NFS4ERR_STALE_CLIENTID: | 4352 | case -NFS4ERR_STALE_CLIENTID: |
4174 | case -NFS4ERR_STALE_STATEID: | 4353 | case -NFS4ERR_STALE_STATEID: |
4354 | case -NFS4ERR_BADSESSION: | ||
4355 | case -NFS4ERR_BADSLOT: | ||
4356 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
4357 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
4358 | case -NFS4ERR_DEADSESSION: | ||
4175 | nfs4_schedule_state_recovery(server->nfs_client); | 4359 | nfs4_schedule_state_recovery(server->nfs_client); |
4176 | goto out; | 4360 | goto out; |
4177 | case -ERESTARTSYS: | 4361 | case -ERESTARTSYS: |
@@ -4191,6 +4375,7 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | |||
4191 | err = 0; | 4375 | err = 0; |
4192 | goto out; | 4376 | goto out; |
4193 | case -NFS4ERR_DELAY: | 4377 | case -NFS4ERR_DELAY: |
4378 | case -EKEYEXPIRED: | ||
4194 | break; | 4379 | break; |
4195 | } | 4380 | } |
4196 | err = nfs4_handle_exception(server, err, &exception); | 4381 | err = nfs4_handle_exception(server, err, &exception); |
@@ -4296,7 +4481,7 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
4296 | * NFS4ERR_BADSESSION in the sequence operation, and will therefore | 4481 | * NFS4ERR_BADSESSION in the sequence operation, and will therefore |
4297 | * be in some phase of session reset. | 4482 | * be in some phase of session reset. |
4298 | */ | 4483 | */ |
4299 | static int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | 4484 | int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) |
4300 | { | 4485 | { |
4301 | nfs4_verifier verifier; | 4486 | nfs4_verifier verifier; |
4302 | struct nfs41_exchange_id_args args = { | 4487 | struct nfs41_exchange_id_args args = { |
@@ -4318,6 +4503,9 @@ static int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
4318 | dprintk("--> %s\n", __func__); | 4503 | dprintk("--> %s\n", __func__); |
4319 | BUG_ON(clp == NULL); | 4504 | BUG_ON(clp == NULL); |
4320 | 4505 | ||
4506 | /* Remove server-only flags */ | ||
4507 | args.flags &= ~EXCHGID4_FLAG_CONFIRMED_R; | ||
4508 | |||
4321 | p = (u32 *)verifier.data; | 4509 | p = (u32 *)verifier.data; |
4322 | *p++ = htonl((u32)clp->cl_boot_time.tv_sec); | 4510 | *p++ = htonl((u32)clp->cl_boot_time.tv_sec); |
4323 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); | 4511 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); |
@@ -4333,7 +4521,7 @@ static int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
4333 | 4521 | ||
4334 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | 4522 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); |
4335 | 4523 | ||
4336 | if (status != NFS4ERR_CLID_INUSE) | 4524 | if (status != -NFS4ERR_CLID_INUSE) |
4337 | break; | 4525 | break; |
4338 | 4526 | ||
4339 | if (signalled()) | 4527 | if (signalled()) |
@@ -4361,11 +4549,12 @@ static void nfs4_get_lease_time_prepare(struct rpc_task *task, | |||
4361 | (struct nfs4_get_lease_time_data *)calldata; | 4549 | (struct nfs4_get_lease_time_data *)calldata; |
4362 | 4550 | ||
4363 | dprintk("--> %s\n", __func__); | 4551 | dprintk("--> %s\n", __func__); |
4552 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
4364 | /* just setup sequence, do not trigger session recovery | 4553 | /* just setup sequence, do not trigger session recovery |
4365 | since we're invoked within one */ | 4554 | since we're invoked within one */ |
4366 | ret = nfs41_setup_sequence(data->clp->cl_session, | 4555 | ret = nfs41_setup_sequence(data->clp->cl_session, |
4367 | &data->args->la_seq_args, | 4556 | &data->args->la_seq_args, |
4368 | &data->res->lr_seq_res, 0, task); | 4557 | &data->res->lr_seq_res, 0, task); |
4369 | 4558 | ||
4370 | BUG_ON(ret == -EAGAIN); | 4559 | BUG_ON(ret == -EAGAIN); |
4371 | rpc_call_start(task); | 4560 | rpc_call_start(task); |
@@ -4386,13 +4575,13 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata) | |||
4386 | switch (task->tk_status) { | 4575 | switch (task->tk_status) { |
4387 | case -NFS4ERR_DELAY: | 4576 | case -NFS4ERR_DELAY: |
4388 | case -NFS4ERR_GRACE: | 4577 | case -NFS4ERR_GRACE: |
4578 | case -EKEYEXPIRED: | ||
4389 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); | 4579 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); |
4390 | rpc_delay(task, NFS4_POLL_RETRY_MIN); | 4580 | rpc_delay(task, NFS4_POLL_RETRY_MIN); |
4391 | task->tk_status = 0; | 4581 | task->tk_status = 0; |
4392 | nfs4_restart_rpc(task, data->clp); | 4582 | nfs_restart_rpc(task, data->clp); |
4393 | return; | 4583 | return; |
4394 | } | 4584 | } |
4395 | nfs41_sequence_free_slot(data->clp, &data->res->lr_seq_res); | ||
4396 | dprintk("<-- %s\n", __func__); | 4585 | dprintk("<-- %s\n", __func__); |
4397 | } | 4586 | } |
4398 | 4587 | ||
@@ -4444,28 +4633,33 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) | |||
4444 | /* | 4633 | /* |
4445 | * Reset a slot table | 4634 | * Reset a slot table |
4446 | */ | 4635 | */ |
4447 | static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, int max_slots, | 4636 | static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs, |
4448 | int old_max_slots, int ivalue) | 4637 | int ivalue) |
4449 | { | 4638 | { |
4639 | struct nfs4_slot *new = NULL; | ||
4450 | int i; | 4640 | int i; |
4451 | int ret = 0; | 4641 | int ret = 0; |
4452 | 4642 | ||
4453 | dprintk("--> %s: max_reqs=%u, tbl %p\n", __func__, max_slots, tbl); | 4643 | dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__, |
4644 | max_reqs, tbl->max_slots); | ||
4454 | 4645 | ||
4455 | /* | 4646 | /* Does the newly negotiated max_reqs match the existing slot table? */ |
4456 | * Until we have dynamic slot table adjustment, insist | 4647 | if (max_reqs != tbl->max_slots) { |
4457 | * upon the same slot table size | 4648 | ret = -ENOMEM; |
4458 | */ | 4649 | new = kmalloc(max_reqs * sizeof(struct nfs4_slot), |
4459 | if (max_slots != old_max_slots) { | 4650 | GFP_KERNEL); |
4460 | dprintk("%s reset slot table does't match old\n", | 4651 | if (!new) |
4461 | __func__); | 4652 | goto out; |
4462 | ret = -EINVAL; /*XXX NFS4ERR_REQ_TOO_BIG ? */ | 4653 | ret = 0; |
4463 | goto out; | 4654 | kfree(tbl->slots); |
4464 | } | 4655 | } |
4465 | spin_lock(&tbl->slot_tbl_lock); | 4656 | spin_lock(&tbl->slot_tbl_lock); |
4466 | for (i = 0; i < max_slots; ++i) | 4657 | if (new) { |
4658 | tbl->slots = new; | ||
4659 | tbl->max_slots = max_reqs; | ||
4660 | } | ||
4661 | for (i = 0; i < tbl->max_slots; ++i) | ||
4467 | tbl->slots[i].seq_nr = ivalue; | 4662 | tbl->slots[i].seq_nr = ivalue; |
4468 | tbl->highest_used_slotid = -1; | ||
4469 | spin_unlock(&tbl->slot_tbl_lock); | 4663 | spin_unlock(&tbl->slot_tbl_lock); |
4470 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | 4664 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, |
4471 | tbl, tbl->slots, tbl->max_slots); | 4665 | tbl, tbl->slots, tbl->max_slots); |
@@ -4482,16 +4676,12 @@ static int nfs4_reset_slot_tables(struct nfs4_session *session) | |||
4482 | int status; | 4676 | int status; |
4483 | 4677 | ||
4484 | status = nfs4_reset_slot_table(&session->fc_slot_table, | 4678 | status = nfs4_reset_slot_table(&session->fc_slot_table, |
4485 | session->fc_attrs.max_reqs, | 4679 | session->fc_attrs.max_reqs, 1); |
4486 | session->fc_slot_table.max_slots, | ||
4487 | 1); | ||
4488 | if (status) | 4680 | if (status) |
4489 | return status; | 4681 | return status; |
4490 | 4682 | ||
4491 | status = nfs4_reset_slot_table(&session->bc_slot_table, | 4683 | status = nfs4_reset_slot_table(&session->bc_slot_table, |
4492 | session->bc_attrs.max_reqs, | 4684 | session->bc_attrs.max_reqs, 0); |
4493 | session->bc_slot_table.max_slots, | ||
4494 | 0); | ||
4495 | return status; | 4685 | return status; |
4496 | } | 4686 | } |
4497 | 4687 | ||
@@ -4515,7 +4705,6 @@ static void nfs4_destroy_slot_tables(struct nfs4_session *session) | |||
4515 | static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | 4705 | static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, |
4516 | int max_slots, int ivalue) | 4706 | int max_slots, int ivalue) |
4517 | { | 4707 | { |
4518 | int i; | ||
4519 | struct nfs4_slot *slot; | 4708 | struct nfs4_slot *slot; |
4520 | int ret = -ENOMEM; | 4709 | int ret = -ENOMEM; |
4521 | 4710 | ||
@@ -4526,18 +4715,9 @@ static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | |||
4526 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_KERNEL); | 4715 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_KERNEL); |
4527 | if (!slot) | 4716 | if (!slot) |
4528 | goto out; | 4717 | goto out; |
4529 | for (i = 0; i < max_slots; ++i) | ||
4530 | slot[i].seq_nr = ivalue; | ||
4531 | ret = 0; | 4718 | ret = 0; |
4532 | 4719 | ||
4533 | spin_lock(&tbl->slot_tbl_lock); | 4720 | spin_lock(&tbl->slot_tbl_lock); |
4534 | if (tbl->slots != NULL) { | ||
4535 | spin_unlock(&tbl->slot_tbl_lock); | ||
4536 | dprintk("%s: slot table already initialized. tbl=%p slots=%p\n", | ||
4537 | __func__, tbl, tbl->slots); | ||
4538 | WARN_ON(1); | ||
4539 | goto out_free; | ||
4540 | } | ||
4541 | tbl->max_slots = max_slots; | 4721 | tbl->max_slots = max_slots; |
4542 | tbl->slots = slot; | 4722 | tbl->slots = slot; |
4543 | tbl->highest_used_slotid = -1; /* no slot is currently used */ | 4723 | tbl->highest_used_slotid = -1; /* no slot is currently used */ |
@@ -4547,10 +4727,6 @@ static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | |||
4547 | out: | 4727 | out: |
4548 | dprintk("<-- %s: return %d\n", __func__, ret); | 4728 | dprintk("<-- %s: return %d\n", __func__, ret); |
4549 | return ret; | 4729 | return ret; |
4550 | |||
4551 | out_free: | ||
4552 | kfree(slot); | ||
4553 | goto out; | ||
4554 | } | 4730 | } |
4555 | 4731 | ||
4556 | /* | 4732 | /* |
@@ -4558,17 +4734,24 @@ out_free: | |||
4558 | */ | 4734 | */ |
4559 | static int nfs4_init_slot_tables(struct nfs4_session *session) | 4735 | static int nfs4_init_slot_tables(struct nfs4_session *session) |
4560 | { | 4736 | { |
4561 | int status; | 4737 | struct nfs4_slot_table *tbl; |
4738 | int status = 0; | ||
4562 | 4739 | ||
4563 | status = nfs4_init_slot_table(&session->fc_slot_table, | 4740 | tbl = &session->fc_slot_table; |
4564 | session->fc_attrs.max_reqs, 1); | 4741 | if (tbl->slots == NULL) { |
4565 | if (status) | 4742 | status = nfs4_init_slot_table(tbl, |
4566 | return status; | 4743 | session->fc_attrs.max_reqs, 1); |
4744 | if (status) | ||
4745 | return status; | ||
4746 | } | ||
4567 | 4747 | ||
4568 | status = nfs4_init_slot_table(&session->bc_slot_table, | 4748 | tbl = &session->bc_slot_table; |
4569 | session->bc_attrs.max_reqs, 0); | 4749 | if (tbl->slots == NULL) { |
4570 | if (status) | 4750 | status = nfs4_init_slot_table(tbl, |
4571 | nfs4_destroy_slot_tables(session); | 4751 | session->bc_attrs.max_reqs, 0); |
4752 | if (status) | ||
4753 | nfs4_destroy_slot_tables(session); | ||
4754 | } | ||
4572 | 4755 | ||
4573 | return status; | 4756 | return status; |
4574 | } | 4757 | } |
@@ -4582,7 +4765,6 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | |||
4582 | if (!session) | 4765 | if (!session) |
4583 | return NULL; | 4766 | return NULL; |
4584 | 4767 | ||
4585 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
4586 | /* | 4768 | /* |
4587 | * The create session reply races with the server back | 4769 | * The create session reply races with the server back |
4588 | * channel probe. Mark the client NFS_CS_SESSION_INITING | 4770 | * channel probe. Mark the client NFS_CS_SESSION_INITING |
@@ -4590,12 +4772,15 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | |||
4590 | * nfs_client struct | 4772 | * nfs_client struct |
4591 | */ | 4773 | */ |
4592 | clp->cl_cons_state = NFS_CS_SESSION_INITING; | 4774 | clp->cl_cons_state = NFS_CS_SESSION_INITING; |
4775 | init_completion(&session->complete); | ||
4593 | 4776 | ||
4594 | tbl = &session->fc_slot_table; | 4777 | tbl = &session->fc_slot_table; |
4778 | tbl->highest_used_slotid = -1; | ||
4595 | spin_lock_init(&tbl->slot_tbl_lock); | 4779 | spin_lock_init(&tbl->slot_tbl_lock); |
4596 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); | 4780 | rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); |
4597 | 4781 | ||
4598 | tbl = &session->bc_slot_table; | 4782 | tbl = &session->bc_slot_table; |
4783 | tbl->highest_used_slotid = -1; | ||
4599 | spin_lock_init(&tbl->slot_tbl_lock); | 4784 | spin_lock_init(&tbl->slot_tbl_lock); |
4600 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); | 4785 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); |
4601 | 4786 | ||
@@ -4637,16 +4822,14 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) | |||
4637 | args->fc_attrs.headerpadsz = 0; | 4822 | args->fc_attrs.headerpadsz = 0; |
4638 | args->fc_attrs.max_rqst_sz = mxrqst_sz; | 4823 | args->fc_attrs.max_rqst_sz = mxrqst_sz; |
4639 | args->fc_attrs.max_resp_sz = mxresp_sz; | 4824 | args->fc_attrs.max_resp_sz = mxresp_sz; |
4640 | args->fc_attrs.max_resp_sz_cached = mxresp_sz; | ||
4641 | args->fc_attrs.max_ops = NFS4_MAX_OPS; | 4825 | args->fc_attrs.max_ops = NFS4_MAX_OPS; |
4642 | args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs; | 4826 | args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs; |
4643 | 4827 | ||
4644 | dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u " | 4828 | dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u " |
4645 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", | 4829 | "max_ops=%u max_reqs=%u\n", |
4646 | __func__, | 4830 | __func__, |
4647 | args->fc_attrs.max_rqst_sz, args->fc_attrs.max_resp_sz, | 4831 | args->fc_attrs.max_rqst_sz, args->fc_attrs.max_resp_sz, |
4648 | args->fc_attrs.max_resp_sz_cached, args->fc_attrs.max_ops, | 4832 | args->fc_attrs.max_ops, args->fc_attrs.max_reqs); |
4649 | args->fc_attrs.max_reqs); | ||
4650 | 4833 | ||
4651 | /* Back channel attributes */ | 4834 | /* Back channel attributes */ |
4652 | args->bc_attrs.headerpadsz = 0; | 4835 | args->bc_attrs.headerpadsz = 0; |
@@ -4747,11 +4930,10 @@ static int _nfs4_proc_create_session(struct nfs_client *clp) | |||
4747 | * It is the responsibility of the caller to verify the session is | 4930 | * It is the responsibility of the caller to verify the session is |
4748 | * expired before calling this routine. | 4931 | * expired before calling this routine. |
4749 | */ | 4932 | */ |
4750 | int nfs4_proc_create_session(struct nfs_client *clp, int reset) | 4933 | int nfs4_proc_create_session(struct nfs_client *clp) |
4751 | { | 4934 | { |
4752 | int status; | 4935 | int status; |
4753 | unsigned *ptr; | 4936 | unsigned *ptr; |
4754 | struct nfs_fsinfo fsinfo; | ||
4755 | struct nfs4_session *session = clp->cl_session; | 4937 | struct nfs4_session *session = clp->cl_session; |
4756 | 4938 | ||
4757 | dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); | 4939 | dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); |
@@ -4760,35 +4942,19 @@ int nfs4_proc_create_session(struct nfs_client *clp, int reset) | |||
4760 | if (status) | 4942 | if (status) |
4761 | goto out; | 4943 | goto out; |
4762 | 4944 | ||
4763 | /* Init or reset the fore channel */ | 4945 | /* Init and reset the fore channel */ |
4764 | if (reset) | 4946 | status = nfs4_init_slot_tables(session); |
4765 | status = nfs4_reset_slot_tables(session); | 4947 | dprintk("slot table initialization returned %d\n", status); |
4766 | else | 4948 | if (status) |
4767 | status = nfs4_init_slot_tables(session); | 4949 | goto out; |
4768 | dprintk("fore channel slot table initialization returned %d\n", status); | 4950 | status = nfs4_reset_slot_tables(session); |
4951 | dprintk("slot table reset returned %d\n", status); | ||
4769 | if (status) | 4952 | if (status) |
4770 | goto out; | 4953 | goto out; |
4771 | 4954 | ||
4772 | ptr = (unsigned *)&session->sess_id.data[0]; | 4955 | ptr = (unsigned *)&session->sess_id.data[0]; |
4773 | dprintk("%s client>seqid %d sessionid %u:%u:%u:%u\n", __func__, | 4956 | dprintk("%s client>seqid %d sessionid %u:%u:%u:%u\n", __func__, |
4774 | clp->cl_seqid, ptr[0], ptr[1], ptr[2], ptr[3]); | 4957 | clp->cl_seqid, ptr[0], ptr[1], ptr[2], ptr[3]); |
4775 | |||
4776 | if (reset) | ||
4777 | /* Lease time is aleady set */ | ||
4778 | goto out; | ||
4779 | |||
4780 | /* Get the lease time */ | ||
4781 | status = nfs4_proc_get_lease_time(clp, &fsinfo); | ||
4782 | if (status == 0) { | ||
4783 | /* Update lease time and schedule renewal */ | ||
4784 | spin_lock(&clp->cl_lock); | ||
4785 | clp->cl_lease_time = fsinfo.lease_time * HZ; | ||
4786 | clp->cl_last_renewal = jiffies; | ||
4787 | clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
4788 | spin_unlock(&clp->cl_lock); | ||
4789 | |||
4790 | nfs4_schedule_state_renewal(clp); | ||
4791 | } | ||
4792 | out: | 4958 | out: |
4793 | dprintk("<-- %s\n", __func__); | 4959 | dprintk("<-- %s\n", __func__); |
4794 | return status; | 4960 | return status; |
@@ -4827,13 +4993,24 @@ int nfs4_proc_destroy_session(struct nfs4_session *session) | |||
4827 | int nfs4_init_session(struct nfs_server *server) | 4993 | int nfs4_init_session(struct nfs_server *server) |
4828 | { | 4994 | { |
4829 | struct nfs_client *clp = server->nfs_client; | 4995 | struct nfs_client *clp = server->nfs_client; |
4996 | struct nfs4_session *session; | ||
4997 | unsigned int rsize, wsize; | ||
4830 | int ret; | 4998 | int ret; |
4831 | 4999 | ||
4832 | if (!nfs4_has_session(clp)) | 5000 | if (!nfs4_has_session(clp)) |
4833 | return 0; | 5001 | return 0; |
4834 | 5002 | ||
4835 | clp->cl_session->fc_attrs.max_rqst_sz = server->wsize; | 5003 | rsize = server->rsize; |
4836 | clp->cl_session->fc_attrs.max_resp_sz = server->rsize; | 5004 | if (rsize == 0) |
5005 | rsize = NFS_MAX_FILE_IO_SIZE; | ||
5006 | wsize = server->wsize; | ||
5007 | if (wsize == 0) | ||
5008 | wsize = NFS_MAX_FILE_IO_SIZE; | ||
5009 | |||
5010 | session = clp->cl_session; | ||
5011 | session->fc_attrs.max_rqst_sz = wsize + nfs41_maxwrite_overhead; | ||
5012 | session->fc_attrs.max_resp_sz = rsize + nfs41_maxread_overhead; | ||
5013 | |||
4837 | ret = nfs4_recover_expired_lease(server); | 5014 | ret = nfs4_recover_expired_lease(server); |
4838 | if (!ret) | 5015 | if (!ret) |
4839 | ret = nfs4_check_client_ready(clp); | 5016 | ret = nfs4_check_client_ready(clp); |
@@ -4858,10 +5035,19 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | |||
4858 | args.sa_cache_this = 0; | 5035 | args.sa_cache_this = 0; |
4859 | 5036 | ||
4860 | return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args, | 5037 | return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args, |
4861 | &res, 0); | 5038 | &res, args.sa_cache_this, 1); |
5039 | } | ||
5040 | |||
5041 | static void nfs41_sequence_release(void *data) | ||
5042 | { | ||
5043 | struct nfs_client *clp = (struct nfs_client *)data; | ||
5044 | |||
5045 | if (atomic_read(&clp->cl_count) > 1) | ||
5046 | nfs4_schedule_state_renewal(clp); | ||
5047 | nfs_put_client(clp); | ||
4862 | } | 5048 | } |
4863 | 5049 | ||
4864 | void nfs41_sequence_call_done(struct rpc_task *task, void *data) | 5050 | static void nfs41_sequence_call_done(struct rpc_task *task, void *data) |
4865 | { | 5051 | { |
4866 | struct nfs_client *clp = (struct nfs_client *)data; | 5052 | struct nfs_client *clp = (struct nfs_client *)data; |
4867 | 5053 | ||
@@ -4869,16 +5055,17 @@ void nfs41_sequence_call_done(struct rpc_task *task, void *data) | |||
4869 | 5055 | ||
4870 | if (task->tk_status < 0) { | 5056 | if (task->tk_status < 0) { |
4871 | dprintk("%s ERROR %d\n", __func__, task->tk_status); | 5057 | dprintk("%s ERROR %d\n", __func__, task->tk_status); |
5058 | if (atomic_read(&clp->cl_count) == 1) | ||
5059 | goto out; | ||
4872 | 5060 | ||
4873 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) | 5061 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) |
4874 | == -EAGAIN) { | 5062 | == -EAGAIN) { |
4875 | nfs4_restart_rpc(task, clp); | 5063 | nfs_restart_rpc(task, clp); |
4876 | return; | 5064 | return; |
4877 | } | 5065 | } |
4878 | } | 5066 | } |
4879 | nfs41_sequence_free_slot(clp, task->tk_msg.rpc_resp); | ||
4880 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); | 5067 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); |
4881 | 5068 | out: | |
4882 | kfree(task->tk_msg.rpc_argp); | 5069 | kfree(task->tk_msg.rpc_argp); |
4883 | kfree(task->tk_msg.rpc_resp); | 5070 | kfree(task->tk_msg.rpc_resp); |
4884 | 5071 | ||
@@ -4903,6 +5090,7 @@ static void nfs41_sequence_prepare(struct rpc_task *task, void *data) | |||
4903 | static const struct rpc_call_ops nfs41_sequence_ops = { | 5090 | static const struct rpc_call_ops nfs41_sequence_ops = { |
4904 | .rpc_call_done = nfs41_sequence_call_done, | 5091 | .rpc_call_done = nfs41_sequence_call_done, |
4905 | .rpc_call_prepare = nfs41_sequence_prepare, | 5092 | .rpc_call_prepare = nfs41_sequence_prepare, |
5093 | .rpc_release = nfs41_sequence_release, | ||
4906 | }; | 5094 | }; |
4907 | 5095 | ||
4908 | static int nfs41_proc_async_sequence(struct nfs_client *clp, | 5096 | static int nfs41_proc_async_sequence(struct nfs_client *clp, |
@@ -4915,12 +5103,14 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, | |||
4915 | .rpc_cred = cred, | 5103 | .rpc_cred = cred, |
4916 | }; | 5104 | }; |
4917 | 5105 | ||
5106 | if (!atomic_inc_not_zero(&clp->cl_count)) | ||
5107 | return -EIO; | ||
4918 | args = kzalloc(sizeof(*args), GFP_KERNEL); | 5108 | args = kzalloc(sizeof(*args), GFP_KERNEL); |
4919 | if (!args) | ||
4920 | return -ENOMEM; | ||
4921 | res = kzalloc(sizeof(*res), GFP_KERNEL); | 5109 | res = kzalloc(sizeof(*res), GFP_KERNEL); |
4922 | if (!res) { | 5110 | if (!args || !res) { |
4923 | kfree(args); | 5111 | kfree(args); |
5112 | kfree(res); | ||
5113 | nfs_put_client(clp); | ||
4924 | return -ENOMEM; | 5114 | return -ENOMEM; |
4925 | } | 5115 | } |
4926 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 5116 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; |
@@ -4931,6 +5121,113 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, | |||
4931 | &nfs41_sequence_ops, (void *)clp); | 5121 | &nfs41_sequence_ops, (void *)clp); |
4932 | } | 5122 | } |
4933 | 5123 | ||
5124 | struct nfs4_reclaim_complete_data { | ||
5125 | struct nfs_client *clp; | ||
5126 | struct nfs41_reclaim_complete_args arg; | ||
5127 | struct nfs41_reclaim_complete_res res; | ||
5128 | }; | ||
5129 | |||
5130 | static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data) | ||
5131 | { | ||
5132 | struct nfs4_reclaim_complete_data *calldata = data; | ||
5133 | |||
5134 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
5135 | if (nfs4_setup_sequence(calldata->clp, &calldata->arg.seq_args, | ||
5136 | &calldata->res.seq_res, 0, task)) | ||
5137 | return; | ||
5138 | |||
5139 | rpc_call_start(task); | ||
5140 | } | ||
5141 | |||
5142 | static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data) | ||
5143 | { | ||
5144 | struct nfs4_reclaim_complete_data *calldata = data; | ||
5145 | struct nfs_client *clp = calldata->clp; | ||
5146 | struct nfs4_sequence_res *res = &calldata->res.seq_res; | ||
5147 | |||
5148 | dprintk("--> %s\n", __func__); | ||
5149 | nfs41_sequence_done(clp, res, task->tk_status); | ||
5150 | switch (task->tk_status) { | ||
5151 | case 0: | ||
5152 | case -NFS4ERR_COMPLETE_ALREADY: | ||
5153 | break; | ||
5154 | case -NFS4ERR_BADSESSION: | ||
5155 | case -NFS4ERR_DEADSESSION: | ||
5156 | /* | ||
5157 | * Handle the session error, but do not retry the operation, as | ||
5158 | * we have no way of telling whether the clientid had to be | ||
5159 | * reset before we got our reply. If reset, a new wave of | ||
5160 | * reclaim operations will follow, containing their own reclaim | ||
5161 | * complete. We don't want our retry to get on the way of | ||
5162 | * recovery by incorrectly indicating to the server that we're | ||
5163 | * done reclaiming state since the process had to be restarted. | ||
5164 | */ | ||
5165 | _nfs4_async_handle_error(task, NULL, clp, NULL); | ||
5166 | break; | ||
5167 | default: | ||
5168 | if (_nfs4_async_handle_error( | ||
5169 | task, NULL, clp, NULL) == -EAGAIN) { | ||
5170 | rpc_restart_call_prepare(task); | ||
5171 | return; | ||
5172 | } | ||
5173 | } | ||
5174 | |||
5175 | dprintk("<-- %s\n", __func__); | ||
5176 | } | ||
5177 | |||
5178 | static void nfs4_free_reclaim_complete_data(void *data) | ||
5179 | { | ||
5180 | struct nfs4_reclaim_complete_data *calldata = data; | ||
5181 | |||
5182 | kfree(calldata); | ||
5183 | } | ||
5184 | |||
5185 | static const struct rpc_call_ops nfs4_reclaim_complete_call_ops = { | ||
5186 | .rpc_call_prepare = nfs4_reclaim_complete_prepare, | ||
5187 | .rpc_call_done = nfs4_reclaim_complete_done, | ||
5188 | .rpc_release = nfs4_free_reclaim_complete_data, | ||
5189 | }; | ||
5190 | |||
5191 | /* | ||
5192 | * Issue a global reclaim complete. | ||
5193 | */ | ||
5194 | static int nfs41_proc_reclaim_complete(struct nfs_client *clp) | ||
5195 | { | ||
5196 | struct nfs4_reclaim_complete_data *calldata; | ||
5197 | struct rpc_task *task; | ||
5198 | struct rpc_message msg = { | ||
5199 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RECLAIM_COMPLETE], | ||
5200 | }; | ||
5201 | struct rpc_task_setup task_setup_data = { | ||
5202 | .rpc_client = clp->cl_rpcclient, | ||
5203 | .rpc_message = &msg, | ||
5204 | .callback_ops = &nfs4_reclaim_complete_call_ops, | ||
5205 | .flags = RPC_TASK_ASYNC, | ||
5206 | }; | ||
5207 | int status = -ENOMEM; | ||
5208 | |||
5209 | dprintk("--> %s\n", __func__); | ||
5210 | calldata = kzalloc(sizeof(*calldata), GFP_KERNEL); | ||
5211 | if (calldata == NULL) | ||
5212 | goto out; | ||
5213 | calldata->clp = clp; | ||
5214 | calldata->arg.one_fs = 0; | ||
5215 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
5216 | |||
5217 | msg.rpc_argp = &calldata->arg; | ||
5218 | msg.rpc_resp = &calldata->res; | ||
5219 | task_setup_data.callback_data = calldata; | ||
5220 | task = rpc_run_task(&task_setup_data); | ||
5221 | if (IS_ERR(task)) { | ||
5222 | status = PTR_ERR(task); | ||
5223 | goto out; | ||
5224 | } | ||
5225 | rpc_put_task(task); | ||
5226 | return 0; | ||
5227 | out: | ||
5228 | dprintk("<-- %s status=%d\n", __func__, status); | ||
5229 | return status; | ||
5230 | } | ||
4934 | #endif /* CONFIG_NFS_V4_1 */ | 5231 | #endif /* CONFIG_NFS_V4_1 */ |
4935 | 5232 | ||
4936 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { | 5233 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { |
@@ -4948,8 +5245,9 @@ struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = { | |||
4948 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, | 5245 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, |
4949 | .recover_open = nfs4_open_reclaim, | 5246 | .recover_open = nfs4_open_reclaim, |
4950 | .recover_lock = nfs4_lock_reclaim, | 5247 | .recover_lock = nfs4_lock_reclaim, |
4951 | .establish_clid = nfs4_proc_exchange_id, | 5248 | .establish_clid = nfs41_init_clientid, |
4952 | .get_clid_cred = nfs4_get_exchange_id_cred, | 5249 | .get_clid_cred = nfs4_get_exchange_id_cred, |
5250 | .reclaim_complete = nfs41_proc_reclaim_complete, | ||
4953 | }; | 5251 | }; |
4954 | #endif /* CONFIG_NFS_V4_1 */ | 5252 | #endif /* CONFIG_NFS_V4_1 */ |
4955 | 5253 | ||
@@ -4968,7 +5266,7 @@ struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = { | |||
4968 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | 5266 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, |
4969 | .recover_open = nfs4_open_expired, | 5267 | .recover_open = nfs4_open_expired, |
4970 | .recover_lock = nfs4_lock_expired, | 5268 | .recover_lock = nfs4_lock_expired, |
4971 | .establish_clid = nfs4_proc_exchange_id, | 5269 | .establish_clid = nfs41_init_clientid, |
4972 | .get_clid_cred = nfs4_get_exchange_id_cred, | 5270 | .get_clid_cred = nfs4_get_exchange_id_cred, |
4973 | }; | 5271 | }; |
4974 | #endif /* CONFIG_NFS_V4_1 */ | 5272 | #endif /* CONFIG_NFS_V4_1 */ |