diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-11-26 12:49:34 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-12-05 18:30:45 -0500 |
commit | 73e39aaa8366694450cd6034050f542f965e277d (patch) | |
tree | df731a81afdd826a401f611dd85c9cf08a9cd0c1 /fs | |
parent | 330212796756ca2752b2a70a83860e145b77487c (diff) |
NFSv4.1: Cleanup move session slot management to fs/nfs/nfs4session.c
NFSv4.1 session management is getting complex enough to deserve
a separate file.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/Makefile | 2 | ||||
-rw-r--r-- | fs/nfs/callback_proc.c | 1 | ||||
-rw-r--r-- | fs/nfs/internal.h | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 11 | ||||
-rw-r--r-- | fs/nfs/nfs4client.c | 1 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayoutdev.c | 1 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 415 | ||||
-rw-r--r-- | fs/nfs/nfs4session.c | 436 | ||||
-rw-r--r-- | fs/nfs/nfs4session.h | 35 |
9 files changed, 477 insertions, 427 deletions
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index b7db60897f91..cce2c057bd2d 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile | |||
@@ -24,7 +24,7 @@ nfsv4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o | |||
24 | delegation.o idmap.o callback.o callback_xdr.o callback_proc.o \ | 24 | delegation.o idmap.o callback.o callback_xdr.o callback_proc.o \ |
25 | nfs4namespace.o nfs4getroot.o nfs4client.o | 25 | nfs4namespace.o nfs4getroot.o nfs4client.o |
26 | nfsv4-$(CONFIG_SYSCTL) += nfs4sysctl.o | 26 | nfsv4-$(CONFIG_SYSCTL) += nfs4sysctl.o |
27 | nfsv4-$(CONFIG_NFS_V4_1) += pnfs.o pnfs_dev.o | 27 | nfsv4-$(CONFIG_NFS_V4_1) += nfs4session.o pnfs.o pnfs_dev.o |
28 | 28 | ||
29 | obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o | 29 | obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o |
30 | nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o | 30 | nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index f99faad78c72..c89b26bc9759 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include "delegation.h" | 14 | #include "delegation.h" |
15 | #include "internal.h" | 15 | #include "internal.h" |
16 | #include "pnfs.h" | 16 | #include "pnfs.h" |
17 | #include "nfs4session.h" | ||
17 | 18 | ||
18 | #ifdef NFS_DEBUG | 19 | #ifdef NFS_DEBUG |
19 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 20 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 05521cadac2e..8965a998b306 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -276,8 +276,6 @@ extern const u32 nfs41_maxwrite_overhead; | |||
276 | extern struct rpc_procinfo nfs4_procedures[]; | 276 | extern struct rpc_procinfo nfs4_procedures[]; |
277 | #endif | 277 | #endif |
278 | 278 | ||
279 | extern int nfs4_init_ds_session(struct nfs_client *, unsigned long); | ||
280 | |||
281 | /* proc.c */ | 279 | /* proc.c */ |
282 | void nfs_close_context(struct nfs_open_context *ctx, int is_sync); | 280 | void nfs_close_context(struct nfs_open_context *ctx, int is_sync); |
283 | extern struct nfs_client *nfs_init_client(struct nfs_client *clp, | 281 | extern struct nfs_client *nfs_init_client(struct nfs_client *clp, |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 2f6a9f9d9299..cd3e3096b60a 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -249,19 +249,13 @@ extern int nfs4_setup_sequence(const struct nfs_server *server, | |||
249 | extern int nfs41_setup_sequence(struct nfs4_session *session, | 249 | extern int nfs41_setup_sequence(struct nfs4_session *session, |
250 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | 250 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, |
251 | struct rpc_task *task); | 251 | struct rpc_task *task); |
252 | extern void nfs4_destroy_session(struct nfs4_session *session); | ||
253 | extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp); | ||
254 | extern int nfs4_proc_create_session(struct nfs_client *, struct rpc_cred *); | 252 | extern int nfs4_proc_create_session(struct nfs_client *, struct rpc_cred *); |
255 | extern int nfs4_proc_destroy_session(struct nfs4_session *, struct rpc_cred *); | 253 | extern int nfs4_proc_destroy_session(struct nfs4_session *, struct rpc_cred *); |
256 | extern int nfs4_init_session(struct nfs_server *server); | ||
257 | extern int nfs4_proc_get_lease_time(struct nfs_client *clp, | 254 | extern int nfs4_proc_get_lease_time(struct nfs_client *clp, |
258 | struct nfs_fsinfo *fsinfo); | 255 | struct nfs_fsinfo *fsinfo); |
259 | extern int nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, | 256 | extern int nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, |
260 | bool sync); | 257 | bool sync); |
261 | 258 | ||
262 | extern void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, | ||
263 | u32 target_highest_slotid); | ||
264 | |||
265 | static inline bool | 259 | static inline bool |
266 | is_ds_only_client(struct nfs_client *clp) | 260 | is_ds_only_client(struct nfs_client *clp) |
267 | { | 261 | { |
@@ -287,11 +281,6 @@ static inline int nfs4_setup_sequence(const struct nfs_server *server, | |||
287 | return 0; | 281 | return 0; |
288 | } | 282 | } |
289 | 283 | ||
290 | static inline int nfs4_init_session(struct nfs_server *server) | ||
291 | { | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static inline bool | 284 | static inline bool |
296 | is_ds_only_client(struct nfs_client *clp) | 285 | is_ds_only_client(struct nfs_client *clp) |
297 | { | 286 | { |
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 72717e67b34e..acc347268124 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include "internal.h" | 12 | #include "internal.h" |
13 | #include "callback.h" | 13 | #include "callback.h" |
14 | #include "delegation.h" | 14 | #include "delegation.h" |
15 | #include "nfs4session.h" | ||
15 | #include "pnfs.h" | 16 | #include "pnfs.h" |
16 | #include "netns.h" | 17 | #include "netns.h" |
17 | 18 | ||
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index 93e2530d7098..b720064bcd7f 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
34 | 34 | ||
35 | #include "internal.h" | 35 | #include "internal.h" |
36 | #include "nfs4session.h" | ||
36 | #include "nfs4filelayout.h" | 37 | #include "nfs4filelayout.h" |
37 | 38 | ||
38 | #define NFSDBG_FACILITY NFSDBG_PNFS_LD | 39 | #define NFSDBG_FACILITY NFSDBG_PNFS_LD |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d75e2a2576eb..a0c35ab12a6b 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -52,7 +52,6 @@ | |||
52 | #include <linux/mount.h> | 52 | #include <linux/mount.h> |
53 | #include <linux/module.h> | 53 | #include <linux/module.h> |
54 | #include <linux/nfs_idmap.h> | 54 | #include <linux/nfs_idmap.h> |
55 | #include <linux/sunrpc/bc_xprt.h> | ||
56 | #include <linux/xattr.h> | 55 | #include <linux/xattr.h> |
57 | #include <linux/utsname.h> | 56 | #include <linux/utsname.h> |
58 | #include <linux/freezer.h> | 57 | #include <linux/freezer.h> |
@@ -64,6 +63,8 @@ | |||
64 | #include "callback.h" | 63 | #include "callback.h" |
65 | #include "pnfs.h" | 64 | #include "pnfs.h" |
66 | #include "netns.h" | 65 | #include "netns.h" |
66 | #include "nfs4session.h" | ||
67 | |||
67 | 68 | ||
68 | #define NFSDBG_FACILITY NFSDBG_PROC | 69 | #define NFSDBG_FACILITY NFSDBG_PROC |
69 | 70 | ||
@@ -378,64 +379,6 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp | |||
378 | 379 | ||
379 | #if defined(CONFIG_NFS_V4_1) | 380 | #if defined(CONFIG_NFS_V4_1) |
380 | 381 | ||
381 | /* | ||
382 | * nfs4_shrink_slot_table - free retired slots from the slot table | ||
383 | */ | ||
384 | static void nfs4_shrink_slot_table(struct nfs4_slot_table *tbl, u32 newsize) | ||
385 | { | ||
386 | struct nfs4_slot **p; | ||
387 | if (newsize >= tbl->max_slots) | ||
388 | return; | ||
389 | |||
390 | p = &tbl->slots; | ||
391 | while (newsize--) | ||
392 | p = &(*p)->next; | ||
393 | while (*p) { | ||
394 | struct nfs4_slot *slot = *p; | ||
395 | |||
396 | *p = slot->next; | ||
397 | kfree(slot); | ||
398 | tbl->max_slots--; | ||
399 | } | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * nfs4_free_slot - free a slot and efficiently update slot table. | ||
404 | * | ||
405 | * freeing a slot is trivially done by clearing its respective bit | ||
406 | * in the bitmap. | ||
407 | * If the freed slotid equals highest_used_slotid we want to update it | ||
408 | * so that the server would be able to size down the slot table if needed, | ||
409 | * otherwise we know that the highest_used_slotid is still in use. | ||
410 | * When updating highest_used_slotid there may be "holes" in the bitmap | ||
411 | * so we need to scan down from highest_used_slotid to 0 looking for the now | ||
412 | * highest slotid in use. | ||
413 | * If none found, highest_used_slotid is set to NFS4_NO_SLOT. | ||
414 | * | ||
415 | * Must be called while holding tbl->slot_tbl_lock | ||
416 | */ | ||
417 | static void | ||
418 | nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot) | ||
419 | { | ||
420 | u32 slotid = slot->slot_nr; | ||
421 | |||
422 | /* clear used bit in bitmap */ | ||
423 | __clear_bit(slotid, tbl->used_slots); | ||
424 | |||
425 | /* update highest_used_slotid when it is freed */ | ||
426 | if (slotid == tbl->highest_used_slotid) { | ||
427 | u32 new_max = find_last_bit(tbl->used_slots, slotid); | ||
428 | if (new_max < slotid) | ||
429 | tbl->highest_used_slotid = new_max; | ||
430 | else { | ||
431 | tbl->highest_used_slotid = NFS4_NO_SLOT; | ||
432 | nfs4_session_drain_complete(tbl->session, tbl); | ||
433 | } | ||
434 | } | ||
435 | dprintk("%s: slotid %u highest_used_slotid %d\n", __func__, | ||
436 | slotid, tbl->highest_used_slotid); | ||
437 | } | ||
438 | |||
439 | bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy) | 382 | bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy) |
440 | { | 383 | { |
441 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | 384 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); |
@@ -465,56 +408,6 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) | |||
465 | res->sr_slot = NULL; | 408 | res->sr_slot = NULL; |
466 | } | 409 | } |
467 | 410 | ||
468 | /* Update the client's idea of target_highest_slotid */ | ||
469 | static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl, | ||
470 | u32 target_highest_slotid) | ||
471 | { | ||
472 | unsigned int max_slotid, i; | ||
473 | |||
474 | if (tbl->target_highest_slotid == target_highest_slotid) | ||
475 | return; | ||
476 | tbl->target_highest_slotid = target_highest_slotid; | ||
477 | tbl->generation++; | ||
478 | |||
479 | max_slotid = min(NFS4_MAX_SLOT_TABLE - 1, tbl->target_highest_slotid); | ||
480 | for (i = tbl->max_slotid + 1; i <= max_slotid; i++) | ||
481 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | ||
482 | tbl->max_slotid = max_slotid; | ||
483 | } | ||
484 | |||
485 | void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, | ||
486 | u32 target_highest_slotid) | ||
487 | { | ||
488 | spin_lock(&tbl->slot_tbl_lock); | ||
489 | nfs41_set_target_slotid_locked(tbl, target_highest_slotid); | ||
490 | spin_unlock(&tbl->slot_tbl_lock); | ||
491 | } | ||
492 | |||
493 | static void nfs41_set_server_slotid_locked(struct nfs4_slot_table *tbl, | ||
494 | u32 highest_slotid) | ||
495 | { | ||
496 | if (tbl->server_highest_slotid == highest_slotid) | ||
497 | return; | ||
498 | if (tbl->highest_used_slotid > highest_slotid) | ||
499 | return; | ||
500 | /* Deallocate slots */ | ||
501 | nfs4_shrink_slot_table(tbl, highest_slotid + 1); | ||
502 | tbl->server_highest_slotid = highest_slotid; | ||
503 | } | ||
504 | |||
505 | static void nfs41_update_target_slotid(struct nfs4_slot_table *tbl, | ||
506 | struct nfs4_slot *slot, | ||
507 | struct nfs4_sequence_res *res) | ||
508 | { | ||
509 | spin_lock(&tbl->slot_tbl_lock); | ||
510 | if (tbl->generation != slot->generation) | ||
511 | goto out; | ||
512 | nfs41_set_server_slotid_locked(tbl, res->sr_highest_slotid); | ||
513 | nfs41_set_target_slotid_locked(tbl, res->sr_target_highest_slotid); | ||
514 | out: | ||
515 | spin_unlock(&tbl->slot_tbl_lock); | ||
516 | } | ||
517 | |||
518 | static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) | 411 | static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) |
519 | { | 412 | { |
520 | struct nfs4_session *session; | 413 | struct nfs4_session *session; |
@@ -585,79 +478,6 @@ static int nfs4_sequence_done(struct rpc_task *task, | |||
585 | return nfs41_sequence_done(task, res); | 478 | return nfs41_sequence_done(task, res); |
586 | } | 479 | } |
587 | 480 | ||
588 | static struct nfs4_slot *nfs4_new_slot(struct nfs4_slot_table *tbl, | ||
589 | u32 slotid, u32 seq_init, gfp_t gfp_mask) | ||
590 | { | ||
591 | struct nfs4_slot *slot; | ||
592 | |||
593 | slot = kzalloc(sizeof(*slot), gfp_mask); | ||
594 | if (slot) { | ||
595 | slot->table = tbl; | ||
596 | slot->slot_nr = slotid; | ||
597 | slot->seq_nr = seq_init; | ||
598 | } | ||
599 | return slot; | ||
600 | } | ||
601 | |||
602 | static struct nfs4_slot *nfs4_find_or_create_slot(struct nfs4_slot_table *tbl, | ||
603 | u32 slotid, u32 seq_init, gfp_t gfp_mask) | ||
604 | { | ||
605 | struct nfs4_slot **p, *slot; | ||
606 | |||
607 | p = &tbl->slots; | ||
608 | for (;;) { | ||
609 | if (*p == NULL) { | ||
610 | *p = nfs4_new_slot(tbl, tbl->max_slots, | ||
611 | seq_init, gfp_mask); | ||
612 | if (*p == NULL) | ||
613 | break; | ||
614 | tbl->max_slots++; | ||
615 | } | ||
616 | slot = *p; | ||
617 | if (slot->slot_nr == slotid) | ||
618 | return slot; | ||
619 | p = &slot->next; | ||
620 | } | ||
621 | return ERR_PTR(-ENOMEM); | ||
622 | } | ||
623 | |||
624 | /* | ||
625 | * nfs4_alloc_slot - efficiently look for a free slot | ||
626 | * | ||
627 | * nfs4_alloc_slot looks for an unset bit in the used_slots bitmap. | ||
628 | * If found, we mark the slot as used, update the highest_used_slotid, | ||
629 | * and respectively set up the sequence operation args. | ||
630 | * | ||
631 | * Note: must be called with under the slot_tbl_lock. | ||
632 | */ | ||
633 | static struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl) | ||
634 | { | ||
635 | struct nfs4_slot *ret = ERR_PTR(-EBUSY); | ||
636 | u32 slotid; | ||
637 | |||
638 | dprintk("--> %s used_slots=%04lx highest_used=%u max_slots=%u\n", | ||
639 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, | ||
640 | tbl->max_slotid + 1); | ||
641 | slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slotid + 1); | ||
642 | if (slotid > tbl->max_slotid) | ||
643 | goto out; | ||
644 | ret = nfs4_find_or_create_slot(tbl, slotid, 1, GFP_NOWAIT); | ||
645 | if (IS_ERR(ret)) | ||
646 | goto out; | ||
647 | __set_bit(slotid, tbl->used_slots); | ||
648 | if (slotid > tbl->highest_used_slotid || | ||
649 | tbl->highest_used_slotid == NFS4_NO_SLOT) | ||
650 | tbl->highest_used_slotid = slotid; | ||
651 | ret->renewal_time = jiffies; | ||
652 | ret->generation = tbl->generation; | ||
653 | |||
654 | out: | ||
655 | dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d \n", | ||
656 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, | ||
657 | !IS_ERR(ret) ? ret->slot_nr : -1); | ||
658 | return ret; | ||
659 | } | ||
660 | |||
661 | static void nfs41_init_sequence(struct nfs4_sequence_args *args, | 481 | static void nfs41_init_sequence(struct nfs4_sequence_args *args, |
662 | struct nfs4_sequence_res *res, int cache_reply) | 482 | struct nfs4_sequence_res *res, int cache_reply) |
663 | { | 483 | { |
@@ -5716,143 +5536,6 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) | |||
5716 | return status; | 5536 | return status; |
5717 | } | 5537 | } |
5718 | 5538 | ||
5719 | static int nfs4_grow_slot_table(struct nfs4_slot_table *tbl, | ||
5720 | u32 max_reqs, u32 ivalue) | ||
5721 | { | ||
5722 | if (max_reqs <= tbl->max_slots) | ||
5723 | return 0; | ||
5724 | if (!IS_ERR(nfs4_find_or_create_slot(tbl, max_reqs - 1, ivalue, GFP_NOFS))) | ||
5725 | return 0; | ||
5726 | return -ENOMEM; | ||
5727 | } | ||
5728 | |||
5729 | static void nfs4_reset_slot_table(struct nfs4_slot_table *tbl, | ||
5730 | u32 server_highest_slotid, | ||
5731 | u32 ivalue) | ||
5732 | { | ||
5733 | struct nfs4_slot **p; | ||
5734 | |||
5735 | nfs4_shrink_slot_table(tbl, server_highest_slotid + 1); | ||
5736 | p = &tbl->slots; | ||
5737 | while (*p) { | ||
5738 | (*p)->seq_nr = ivalue; | ||
5739 | p = &(*p)->next; | ||
5740 | } | ||
5741 | tbl->highest_used_slotid = NFS4_NO_SLOT; | ||
5742 | tbl->target_highest_slotid = server_highest_slotid; | ||
5743 | tbl->server_highest_slotid = server_highest_slotid; | ||
5744 | tbl->max_slotid = server_highest_slotid; | ||
5745 | } | ||
5746 | |||
5747 | /* | ||
5748 | * (re)Initialise a slot table | ||
5749 | */ | ||
5750 | static int nfs4_realloc_slot_table(struct nfs4_slot_table *tbl, | ||
5751 | u32 max_reqs, u32 ivalue) | ||
5752 | { | ||
5753 | int ret; | ||
5754 | |||
5755 | dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__, | ||
5756 | max_reqs, tbl->max_slots); | ||
5757 | |||
5758 | if (max_reqs > NFS4_MAX_SLOT_TABLE) | ||
5759 | max_reqs = NFS4_MAX_SLOT_TABLE; | ||
5760 | |||
5761 | ret = nfs4_grow_slot_table(tbl, max_reqs, ivalue); | ||
5762 | if (ret) | ||
5763 | goto out; | ||
5764 | |||
5765 | spin_lock(&tbl->slot_tbl_lock); | ||
5766 | nfs4_reset_slot_table(tbl, max_reqs - 1, ivalue); | ||
5767 | spin_unlock(&tbl->slot_tbl_lock); | ||
5768 | |||
5769 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | ||
5770 | tbl, tbl->slots, tbl->max_slots); | ||
5771 | out: | ||
5772 | dprintk("<-- %s: return %d\n", __func__, ret); | ||
5773 | return ret; | ||
5774 | } | ||
5775 | |||
5776 | /* Destroy the slot table */ | ||
5777 | static void nfs4_destroy_slot_tables(struct nfs4_session *session) | ||
5778 | { | ||
5779 | nfs4_shrink_slot_table(&session->fc_slot_table, 0); | ||
5780 | nfs4_shrink_slot_table(&session->bc_slot_table, 0); | ||
5781 | } | ||
5782 | |||
5783 | /* | ||
5784 | * Initialize or reset the forechannel and backchannel tables | ||
5785 | */ | ||
5786 | static int nfs4_setup_session_slot_tables(struct nfs4_session *ses) | ||
5787 | { | ||
5788 | struct nfs4_slot_table *tbl; | ||
5789 | int status; | ||
5790 | |||
5791 | dprintk("--> %s\n", __func__); | ||
5792 | /* Fore channel */ | ||
5793 | tbl = &ses->fc_slot_table; | ||
5794 | tbl->session = ses; | ||
5795 | status = nfs4_realloc_slot_table(tbl, ses->fc_attrs.max_reqs, 1); | ||
5796 | if (status) /* -ENOMEM */ | ||
5797 | return status; | ||
5798 | /* Back channel */ | ||
5799 | tbl = &ses->bc_slot_table; | ||
5800 | tbl->session = ses; | ||
5801 | status = nfs4_realloc_slot_table(tbl, ses->bc_attrs.max_reqs, 0); | ||
5802 | if (status && tbl->slots == NULL) | ||
5803 | /* Fore and back channel share a connection so get | ||
5804 | * both slot tables or neither */ | ||
5805 | nfs4_destroy_slot_tables(ses); | ||
5806 | return status; | ||
5807 | } | ||
5808 | |||
5809 | struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | ||
5810 | { | ||
5811 | struct nfs4_session *session; | ||
5812 | struct nfs4_slot_table *tbl; | ||
5813 | |||
5814 | session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS); | ||
5815 | if (!session) | ||
5816 | return NULL; | ||
5817 | |||
5818 | tbl = &session->fc_slot_table; | ||
5819 | tbl->highest_used_slotid = NFS4_NO_SLOT; | ||
5820 | spin_lock_init(&tbl->slot_tbl_lock); | ||
5821 | rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); | ||
5822 | init_completion(&tbl->complete); | ||
5823 | |||
5824 | tbl = &session->bc_slot_table; | ||
5825 | tbl->highest_used_slotid = NFS4_NO_SLOT; | ||
5826 | spin_lock_init(&tbl->slot_tbl_lock); | ||
5827 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); | ||
5828 | init_completion(&tbl->complete); | ||
5829 | |||
5830 | session->session_state = 1<<NFS4_SESSION_INITING; | ||
5831 | |||
5832 | session->clp = clp; | ||
5833 | return session; | ||
5834 | } | ||
5835 | |||
5836 | void nfs4_destroy_session(struct nfs4_session *session) | ||
5837 | { | ||
5838 | struct rpc_xprt *xprt; | ||
5839 | struct rpc_cred *cred; | ||
5840 | |||
5841 | cred = nfs4_get_exchange_id_cred(session->clp); | ||
5842 | nfs4_proc_destroy_session(session, cred); | ||
5843 | if (cred) | ||
5844 | put_rpccred(cred); | ||
5845 | |||
5846 | rcu_read_lock(); | ||
5847 | xprt = rcu_dereference(session->clp->cl_rpcclient->cl_xprt); | ||
5848 | rcu_read_unlock(); | ||
5849 | dprintk("%s Destroy backchannel for xprt %p\n", | ||
5850 | __func__, xprt); | ||
5851 | xprt_destroy_backchannel(xprt, NFS41_BC_MIN_CALLBACKS); | ||
5852 | nfs4_destroy_slot_tables(session); | ||
5853 | kfree(session); | ||
5854 | } | ||
5855 | |||
5856 | /* | 5539 | /* |
5857 | * Initialize the values to be used by the client in CREATE_SESSION | 5540 | * Initialize the values to be used by the client in CREATE_SESSION |
5858 | * If nfs4_init_session set the fore channel request and response sizes, | 5541 | * If nfs4_init_session set the fore channel request and response sizes, |
@@ -6047,100 +5730,6 @@ int nfs4_proc_destroy_session(struct nfs4_session *session, | |||
6047 | } | 5730 | } |
6048 | 5731 | ||
6049 | /* | 5732 | /* |
6050 | * With sessions, the client is not marked ready until after a | ||
6051 | * successful EXCHANGE_ID and CREATE_SESSION. | ||
6052 | * | ||
6053 | * Map errors cl_cons_state errors to EPROTONOSUPPORT to indicate | ||
6054 | * other versions of NFS can be tried. | ||
6055 | */ | ||
6056 | static int nfs41_check_session_ready(struct nfs_client *clp) | ||
6057 | { | ||
6058 | int ret; | ||
6059 | |||
6060 | if (clp->cl_cons_state == NFS_CS_SESSION_INITING) { | ||
6061 | ret = nfs4_client_recover_expired_lease(clp); | ||
6062 | if (ret) | ||
6063 | return ret; | ||
6064 | } | ||
6065 | if (clp->cl_cons_state < NFS_CS_READY) | ||
6066 | return -EPROTONOSUPPORT; | ||
6067 | smp_rmb(); | ||
6068 | return 0; | ||
6069 | } | ||
6070 | |||
6071 | int nfs4_init_session(struct nfs_server *server) | ||
6072 | { | ||
6073 | struct nfs_client *clp = server->nfs_client; | ||
6074 | struct nfs4_session *session; | ||
6075 | unsigned int target_max_rqst_sz = NFS_MAX_FILE_IO_SIZE; | ||
6076 | unsigned int target_max_resp_sz = NFS_MAX_FILE_IO_SIZE; | ||
6077 | |||
6078 | if (!nfs4_has_session(clp)) | ||
6079 | return 0; | ||
6080 | |||
6081 | if (server->rsize != 0) | ||
6082 | target_max_resp_sz = server->rsize; | ||
6083 | target_max_resp_sz += nfs41_maxread_overhead; | ||
6084 | |||
6085 | if (server->wsize != 0) | ||
6086 | target_max_rqst_sz = server->wsize; | ||
6087 | target_max_rqst_sz += nfs41_maxwrite_overhead; | ||
6088 | |||
6089 | session = clp->cl_session; | ||
6090 | spin_lock(&clp->cl_lock); | ||
6091 | if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) { | ||
6092 | /* Initialise targets and channel attributes */ | ||
6093 | session->fc_target_max_rqst_sz = target_max_rqst_sz; | ||
6094 | session->fc_attrs.max_rqst_sz = target_max_rqst_sz; | ||
6095 | session->fc_target_max_resp_sz = target_max_resp_sz; | ||
6096 | session->fc_attrs.max_resp_sz = target_max_resp_sz; | ||
6097 | } else { | ||
6098 | /* Just adjust the targets */ | ||
6099 | if (target_max_rqst_sz > session->fc_target_max_rqst_sz) { | ||
6100 | session->fc_target_max_rqst_sz = target_max_rqst_sz; | ||
6101 | set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); | ||
6102 | } | ||
6103 | if (target_max_resp_sz > session->fc_target_max_resp_sz) { | ||
6104 | session->fc_target_max_resp_sz = target_max_resp_sz; | ||
6105 | set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); | ||
6106 | } | ||
6107 | } | ||
6108 | spin_unlock(&clp->cl_lock); | ||
6109 | |||
6110 | if (test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) | ||
6111 | nfs4_schedule_lease_recovery(clp); | ||
6112 | |||
6113 | return nfs41_check_session_ready(clp); | ||
6114 | } | ||
6115 | |||
6116 | int nfs4_init_ds_session(struct nfs_client *clp, unsigned long lease_time) | ||
6117 | { | ||
6118 | struct nfs4_session *session = clp->cl_session; | ||
6119 | int ret; | ||
6120 | |||
6121 | spin_lock(&clp->cl_lock); | ||
6122 | if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) { | ||
6123 | /* | ||
6124 | * Do not set NFS_CS_CHECK_LEASE_TIME instead set the | ||
6125 | * DS lease to be equal to the MDS lease. | ||
6126 | */ | ||
6127 | clp->cl_lease_time = lease_time; | ||
6128 | clp->cl_last_renewal = jiffies; | ||
6129 | } | ||
6130 | spin_unlock(&clp->cl_lock); | ||
6131 | |||
6132 | ret = nfs41_check_session_ready(clp); | ||
6133 | if (ret) | ||
6134 | return ret; | ||
6135 | /* Test for the DS role */ | ||
6136 | if (!is_ds_client(clp)) | ||
6137 | return -ENODEV; | ||
6138 | return 0; | ||
6139 | } | ||
6140 | EXPORT_SYMBOL_GPL(nfs4_init_ds_session); | ||
6141 | |||
6142 | |||
6143 | /* | ||
6144 | * Renew the cl_session lease. | 5733 | * Renew the cl_session lease. |
6145 | */ | 5734 | */ |
6146 | struct nfs4_sequence_data { | 5735 | struct nfs4_sequence_data { |
diff --git a/fs/nfs/nfs4session.c b/fs/nfs/nfs4session.c new file mode 100644 index 000000000000..701170293ceb --- /dev/null +++ b/fs/nfs/nfs4session.c | |||
@@ -0,0 +1,436 @@ | |||
1 | /* | ||
2 | * fs/nfs/nfs4session.c | ||
3 | * | ||
4 | * Copyright (c) 2012 Trond Myklebust <Trond.Myklebust@netapp.com> | ||
5 | * | ||
6 | */ | ||
7 | #include <linux/kernel.h> | ||
8 | #include <linux/errno.h> | ||
9 | #include <linux/string.h> | ||
10 | #include <linux/printk.h> | ||
11 | #include <linux/slab.h> | ||
12 | #include <linux/sunrpc/sched.h> | ||
13 | #include <linux/sunrpc/bc_xprt.h> | ||
14 | #include <linux/nfs.h> | ||
15 | #include <linux/nfs4.h> | ||
16 | #include <linux/nfs_fs.h> | ||
17 | #include <linux/module.h> | ||
18 | |||
19 | #include "nfs4_fs.h" | ||
20 | #include "internal.h" | ||
21 | #include "nfs4session.h" | ||
22 | #include "callback.h" | ||
23 | |||
24 | #define NFSDBG_FACILITY NFSDBG_STATE | ||
25 | |||
26 | /* | ||
27 | * nfs4_shrink_slot_table - free retired slots from the slot table | ||
28 | */ | ||
29 | static void nfs4_shrink_slot_table(struct nfs4_slot_table *tbl, u32 newsize) | ||
30 | { | ||
31 | struct nfs4_slot **p; | ||
32 | if (newsize >= tbl->max_slots) | ||
33 | return; | ||
34 | |||
35 | p = &tbl->slots; | ||
36 | while (newsize--) | ||
37 | p = &(*p)->next; | ||
38 | while (*p) { | ||
39 | struct nfs4_slot *slot = *p; | ||
40 | |||
41 | *p = slot->next; | ||
42 | kfree(slot); | ||
43 | tbl->max_slots--; | ||
44 | } | ||
45 | } | ||
46 | |||
47 | /* | ||
48 | * nfs4_free_slot - free a slot and efficiently update slot table. | ||
49 | * | ||
50 | * freeing a slot is trivially done by clearing its respective bit | ||
51 | * in the bitmap. | ||
52 | * If the freed slotid equals highest_used_slotid we want to update it | ||
53 | * so that the server would be able to size down the slot table if needed, | ||
54 | * otherwise we know that the highest_used_slotid is still in use. | ||
55 | * When updating highest_used_slotid there may be "holes" in the bitmap | ||
56 | * so we need to scan down from highest_used_slotid to 0 looking for the now | ||
57 | * highest slotid in use. | ||
58 | * If none found, highest_used_slotid is set to NFS4_NO_SLOT. | ||
59 | * | ||
60 | * Must be called while holding tbl->slot_tbl_lock | ||
61 | */ | ||
62 | void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot) | ||
63 | { | ||
64 | u32 slotid = slot->slot_nr; | ||
65 | |||
66 | /* clear used bit in bitmap */ | ||
67 | __clear_bit(slotid, tbl->used_slots); | ||
68 | |||
69 | /* update highest_used_slotid when it is freed */ | ||
70 | if (slotid == tbl->highest_used_slotid) { | ||
71 | u32 new_max = find_last_bit(tbl->used_slots, slotid); | ||
72 | if (new_max < slotid) | ||
73 | tbl->highest_used_slotid = new_max; | ||
74 | else { | ||
75 | tbl->highest_used_slotid = NFS4_NO_SLOT; | ||
76 | nfs4_session_drain_complete(tbl->session, tbl); | ||
77 | } | ||
78 | } | ||
79 | dprintk("%s: slotid %u highest_used_slotid %d\n", __func__, | ||
80 | slotid, tbl->highest_used_slotid); | ||
81 | } | ||
82 | |||
83 | static struct nfs4_slot *nfs4_new_slot(struct nfs4_slot_table *tbl, | ||
84 | u32 slotid, u32 seq_init, gfp_t gfp_mask) | ||
85 | { | ||
86 | struct nfs4_slot *slot; | ||
87 | |||
88 | slot = kzalloc(sizeof(*slot), gfp_mask); | ||
89 | if (slot) { | ||
90 | slot->table = tbl; | ||
91 | slot->slot_nr = slotid; | ||
92 | slot->seq_nr = seq_init; | ||
93 | } | ||
94 | return slot; | ||
95 | } | ||
96 | |||
97 | static struct nfs4_slot *nfs4_find_or_create_slot(struct nfs4_slot_table *tbl, | ||
98 | u32 slotid, u32 seq_init, gfp_t gfp_mask) | ||
99 | { | ||
100 | struct nfs4_slot **p, *slot; | ||
101 | |||
102 | p = &tbl->slots; | ||
103 | for (;;) { | ||
104 | if (*p == NULL) { | ||
105 | *p = nfs4_new_slot(tbl, tbl->max_slots, | ||
106 | seq_init, gfp_mask); | ||
107 | if (*p == NULL) | ||
108 | break; | ||
109 | tbl->max_slots++; | ||
110 | } | ||
111 | slot = *p; | ||
112 | if (slot->slot_nr == slotid) | ||
113 | return slot; | ||
114 | p = &slot->next; | ||
115 | } | ||
116 | return ERR_PTR(-ENOMEM); | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * nfs4_alloc_slot - efficiently look for a free slot | ||
121 | * | ||
122 | * nfs4_alloc_slot looks for an unset bit in the used_slots bitmap. | ||
123 | * If found, we mark the slot as used, update the highest_used_slotid, | ||
124 | * and respectively set up the sequence operation args. | ||
125 | * | ||
126 | * Note: must be called with under the slot_tbl_lock. | ||
127 | */ | ||
128 | struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl) | ||
129 | { | ||
130 | struct nfs4_slot *ret = ERR_PTR(-EBUSY); | ||
131 | u32 slotid; | ||
132 | |||
133 | dprintk("--> %s used_slots=%04lx highest_used=%u max_slots=%u\n", | ||
134 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, | ||
135 | tbl->max_slotid + 1); | ||
136 | slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slotid + 1); | ||
137 | if (slotid > tbl->max_slotid) | ||
138 | goto out; | ||
139 | ret = nfs4_find_or_create_slot(tbl, slotid, 1, GFP_NOWAIT); | ||
140 | if (IS_ERR(ret)) | ||
141 | goto out; | ||
142 | __set_bit(slotid, tbl->used_slots); | ||
143 | if (slotid > tbl->highest_used_slotid || | ||
144 | tbl->highest_used_slotid == NFS4_NO_SLOT) | ||
145 | tbl->highest_used_slotid = slotid; | ||
146 | ret->renewal_time = jiffies; | ||
147 | ret->generation = tbl->generation; | ||
148 | |||
149 | out: | ||
150 | dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d \n", | ||
151 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, | ||
152 | !IS_ERR(ret) ? ret->slot_nr : -1); | ||
153 | return ret; | ||
154 | } | ||
155 | |||
156 | static int nfs4_grow_slot_table(struct nfs4_slot_table *tbl, | ||
157 | u32 max_reqs, u32 ivalue) | ||
158 | { | ||
159 | if (max_reqs <= tbl->max_slots) | ||
160 | return 0; | ||
161 | if (!IS_ERR(nfs4_find_or_create_slot(tbl, max_reqs - 1, ivalue, GFP_NOFS))) | ||
162 | return 0; | ||
163 | return -ENOMEM; | ||
164 | } | ||
165 | |||
166 | static void nfs4_reset_slot_table(struct nfs4_slot_table *tbl, | ||
167 | u32 server_highest_slotid, | ||
168 | u32 ivalue) | ||
169 | { | ||
170 | struct nfs4_slot **p; | ||
171 | |||
172 | nfs4_shrink_slot_table(tbl, server_highest_slotid + 1); | ||
173 | p = &tbl->slots; | ||
174 | while (*p) { | ||
175 | (*p)->seq_nr = ivalue; | ||
176 | p = &(*p)->next; | ||
177 | } | ||
178 | tbl->highest_used_slotid = NFS4_NO_SLOT; | ||
179 | tbl->target_highest_slotid = server_highest_slotid; | ||
180 | tbl->server_highest_slotid = server_highest_slotid; | ||
181 | tbl->max_slotid = server_highest_slotid; | ||
182 | } | ||
183 | |||
184 | /* | ||
185 | * (re)Initialise a slot table | ||
186 | */ | ||
187 | static int nfs4_realloc_slot_table(struct nfs4_slot_table *tbl, | ||
188 | u32 max_reqs, u32 ivalue) | ||
189 | { | ||
190 | int ret; | ||
191 | |||
192 | dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__, | ||
193 | max_reqs, tbl->max_slots); | ||
194 | |||
195 | if (max_reqs > NFS4_MAX_SLOT_TABLE) | ||
196 | max_reqs = NFS4_MAX_SLOT_TABLE; | ||
197 | |||
198 | ret = nfs4_grow_slot_table(tbl, max_reqs, ivalue); | ||
199 | if (ret) | ||
200 | goto out; | ||
201 | |||
202 | spin_lock(&tbl->slot_tbl_lock); | ||
203 | nfs4_reset_slot_table(tbl, max_reqs - 1, ivalue); | ||
204 | spin_unlock(&tbl->slot_tbl_lock); | ||
205 | |||
206 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | ||
207 | tbl, tbl->slots, tbl->max_slots); | ||
208 | out: | ||
209 | dprintk("<-- %s: return %d\n", __func__, ret); | ||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | /* Destroy the slot table */ | ||
214 | static void nfs4_destroy_slot_tables(struct nfs4_session *session) | ||
215 | { | ||
216 | nfs4_shrink_slot_table(&session->fc_slot_table, 0); | ||
217 | nfs4_shrink_slot_table(&session->bc_slot_table, 0); | ||
218 | } | ||
219 | |||
220 | /* Update the client's idea of target_highest_slotid */ | ||
221 | static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl, | ||
222 | u32 target_highest_slotid) | ||
223 | { | ||
224 | unsigned int max_slotid, i; | ||
225 | |||
226 | if (tbl->target_highest_slotid == target_highest_slotid) | ||
227 | return; | ||
228 | tbl->target_highest_slotid = target_highest_slotid; | ||
229 | tbl->generation++; | ||
230 | |||
231 | max_slotid = min(NFS4_MAX_SLOT_TABLE - 1, tbl->target_highest_slotid); | ||
232 | for (i = tbl->max_slotid + 1; i <= max_slotid; i++) | ||
233 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | ||
234 | tbl->max_slotid = max_slotid; | ||
235 | } | ||
236 | |||
237 | void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, | ||
238 | u32 target_highest_slotid) | ||
239 | { | ||
240 | spin_lock(&tbl->slot_tbl_lock); | ||
241 | nfs41_set_target_slotid_locked(tbl, target_highest_slotid); | ||
242 | spin_unlock(&tbl->slot_tbl_lock); | ||
243 | } | ||
244 | |||
245 | static void nfs41_set_server_slotid_locked(struct nfs4_slot_table *tbl, | ||
246 | u32 highest_slotid) | ||
247 | { | ||
248 | if (tbl->server_highest_slotid == highest_slotid) | ||
249 | return; | ||
250 | if (tbl->highest_used_slotid > highest_slotid) | ||
251 | return; | ||
252 | /* Deallocate slots */ | ||
253 | nfs4_shrink_slot_table(tbl, highest_slotid + 1); | ||
254 | tbl->server_highest_slotid = highest_slotid; | ||
255 | } | ||
256 | |||
257 | void nfs41_update_target_slotid(struct nfs4_slot_table *tbl, | ||
258 | struct nfs4_slot *slot, | ||
259 | struct nfs4_sequence_res *res) | ||
260 | { | ||
261 | spin_lock(&tbl->slot_tbl_lock); | ||
262 | if (tbl->generation != slot->generation) | ||
263 | goto out; | ||
264 | nfs41_set_server_slotid_locked(tbl, res->sr_highest_slotid); | ||
265 | nfs41_set_target_slotid_locked(tbl, res->sr_target_highest_slotid); | ||
266 | out: | ||
267 | spin_unlock(&tbl->slot_tbl_lock); | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * Initialize or reset the forechannel and backchannel tables | ||
272 | */ | ||
273 | int nfs4_setup_session_slot_tables(struct nfs4_session *ses) | ||
274 | { | ||
275 | struct nfs4_slot_table *tbl; | ||
276 | int status; | ||
277 | |||
278 | dprintk("--> %s\n", __func__); | ||
279 | /* Fore channel */ | ||
280 | tbl = &ses->fc_slot_table; | ||
281 | tbl->session = ses; | ||
282 | status = nfs4_realloc_slot_table(tbl, ses->fc_attrs.max_reqs, 1); | ||
283 | if (status) /* -ENOMEM */ | ||
284 | return status; | ||
285 | /* Back channel */ | ||
286 | tbl = &ses->bc_slot_table; | ||
287 | tbl->session = ses; | ||
288 | status = nfs4_realloc_slot_table(tbl, ses->bc_attrs.max_reqs, 0); | ||
289 | if (status && tbl->slots == NULL) | ||
290 | /* Fore and back channel share a connection so get | ||
291 | * both slot tables or neither */ | ||
292 | nfs4_destroy_slot_tables(ses); | ||
293 | return status; | ||
294 | } | ||
295 | |||
296 | struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | ||
297 | { | ||
298 | struct nfs4_session *session; | ||
299 | struct nfs4_slot_table *tbl; | ||
300 | |||
301 | session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS); | ||
302 | if (!session) | ||
303 | return NULL; | ||
304 | |||
305 | tbl = &session->fc_slot_table; | ||
306 | tbl->highest_used_slotid = NFS4_NO_SLOT; | ||
307 | spin_lock_init(&tbl->slot_tbl_lock); | ||
308 | rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); | ||
309 | init_completion(&tbl->complete); | ||
310 | |||
311 | tbl = &session->bc_slot_table; | ||
312 | tbl->highest_used_slotid = NFS4_NO_SLOT; | ||
313 | spin_lock_init(&tbl->slot_tbl_lock); | ||
314 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); | ||
315 | init_completion(&tbl->complete); | ||
316 | |||
317 | session->session_state = 1<<NFS4_SESSION_INITING; | ||
318 | |||
319 | session->clp = clp; | ||
320 | return session; | ||
321 | } | ||
322 | |||
323 | void nfs4_destroy_session(struct nfs4_session *session) | ||
324 | { | ||
325 | struct rpc_xprt *xprt; | ||
326 | struct rpc_cred *cred; | ||
327 | |||
328 | cred = nfs4_get_exchange_id_cred(session->clp); | ||
329 | nfs4_proc_destroy_session(session, cred); | ||
330 | if (cred) | ||
331 | put_rpccred(cred); | ||
332 | |||
333 | rcu_read_lock(); | ||
334 | xprt = rcu_dereference(session->clp->cl_rpcclient->cl_xprt); | ||
335 | rcu_read_unlock(); | ||
336 | dprintk("%s Destroy backchannel for xprt %p\n", | ||
337 | __func__, xprt); | ||
338 | xprt_destroy_backchannel(xprt, NFS41_BC_MIN_CALLBACKS); | ||
339 | nfs4_destroy_slot_tables(session); | ||
340 | kfree(session); | ||
341 | } | ||
342 | |||
343 | /* | ||
344 | * With sessions, the client is not marked ready until after a | ||
345 | * successful EXCHANGE_ID and CREATE_SESSION. | ||
346 | * | ||
347 | * Map errors cl_cons_state errors to EPROTONOSUPPORT to indicate | ||
348 | * other versions of NFS can be tried. | ||
349 | */ | ||
350 | static int nfs41_check_session_ready(struct nfs_client *clp) | ||
351 | { | ||
352 | int ret; | ||
353 | |||
354 | if (clp->cl_cons_state == NFS_CS_SESSION_INITING) { | ||
355 | ret = nfs4_client_recover_expired_lease(clp); | ||
356 | if (ret) | ||
357 | return ret; | ||
358 | } | ||
359 | if (clp->cl_cons_state < NFS_CS_READY) | ||
360 | return -EPROTONOSUPPORT; | ||
361 | smp_rmb(); | ||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | int nfs4_init_session(struct nfs_server *server) | ||
366 | { | ||
367 | struct nfs_client *clp = server->nfs_client; | ||
368 | struct nfs4_session *session; | ||
369 | unsigned int target_max_rqst_sz = NFS_MAX_FILE_IO_SIZE; | ||
370 | unsigned int target_max_resp_sz = NFS_MAX_FILE_IO_SIZE; | ||
371 | |||
372 | if (!nfs4_has_session(clp)) | ||
373 | return 0; | ||
374 | |||
375 | if (server->rsize != 0) | ||
376 | target_max_resp_sz = server->rsize; | ||
377 | target_max_resp_sz += nfs41_maxread_overhead; | ||
378 | |||
379 | if (server->wsize != 0) | ||
380 | target_max_rqst_sz = server->wsize; | ||
381 | target_max_rqst_sz += nfs41_maxwrite_overhead; | ||
382 | |||
383 | session = clp->cl_session; | ||
384 | spin_lock(&clp->cl_lock); | ||
385 | if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) { | ||
386 | /* Initialise targets and channel attributes */ | ||
387 | session->fc_target_max_rqst_sz = target_max_rqst_sz; | ||
388 | session->fc_attrs.max_rqst_sz = target_max_rqst_sz; | ||
389 | session->fc_target_max_resp_sz = target_max_resp_sz; | ||
390 | session->fc_attrs.max_resp_sz = target_max_resp_sz; | ||
391 | } else { | ||
392 | /* Just adjust the targets */ | ||
393 | if (target_max_rqst_sz > session->fc_target_max_rqst_sz) { | ||
394 | session->fc_target_max_rqst_sz = target_max_rqst_sz; | ||
395 | set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); | ||
396 | } | ||
397 | if (target_max_resp_sz > session->fc_target_max_resp_sz) { | ||
398 | session->fc_target_max_resp_sz = target_max_resp_sz; | ||
399 | set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); | ||
400 | } | ||
401 | } | ||
402 | spin_unlock(&clp->cl_lock); | ||
403 | |||
404 | if (test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) | ||
405 | nfs4_schedule_lease_recovery(clp); | ||
406 | |||
407 | return nfs41_check_session_ready(clp); | ||
408 | } | ||
409 | |||
410 | int nfs4_init_ds_session(struct nfs_client *clp, unsigned long lease_time) | ||
411 | { | ||
412 | struct nfs4_session *session = clp->cl_session; | ||
413 | int ret; | ||
414 | |||
415 | spin_lock(&clp->cl_lock); | ||
416 | if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) { | ||
417 | /* | ||
418 | * Do not set NFS_CS_CHECK_LEASE_TIME instead set the | ||
419 | * DS lease to be equal to the MDS lease. | ||
420 | */ | ||
421 | clp->cl_lease_time = lease_time; | ||
422 | clp->cl_last_renewal = jiffies; | ||
423 | } | ||
424 | spin_unlock(&clp->cl_lock); | ||
425 | |||
426 | ret = nfs41_check_session_ready(clp); | ||
427 | if (ret) | ||
428 | return ret; | ||
429 | /* Test for the DS role */ | ||
430 | if (!is_ds_client(clp)) | ||
431 | return -ENODEV; | ||
432 | return 0; | ||
433 | } | ||
434 | EXPORT_SYMBOL_GPL(nfs4_init_ds_session); | ||
435 | |||
436 | |||
diff --git a/fs/nfs/nfs4session.h b/fs/nfs/nfs4session.h new file mode 100644 index 000000000000..cb47b1eb0886 --- /dev/null +++ b/fs/nfs/nfs4session.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * fs/nfs/nfs4session.h | ||
3 | * | ||
4 | * Copyright (c) 2012 Trond Myklebust <Trond.Myklebust@netapp.com> | ||
5 | * | ||
6 | */ | ||
7 | #ifndef __LINUX_FS_NFS_NFS4SESSION_H | ||
8 | #define __LINUX_FS_NFS_NFS4SESSION_H | ||
9 | |||
10 | #if defined(CONFIG_NFS_V4_1) | ||
11 | extern struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl); | ||
12 | extern void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot); | ||
13 | |||
14 | extern void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, | ||
15 | u32 target_highest_slotid); | ||
16 | extern void nfs41_update_target_slotid(struct nfs4_slot_table *tbl, | ||
17 | struct nfs4_slot *slot, | ||
18 | struct nfs4_sequence_res *res); | ||
19 | |||
20 | extern int nfs4_setup_session_slot_tables(struct nfs4_session *ses); | ||
21 | |||
22 | extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp); | ||
23 | extern void nfs4_destroy_session(struct nfs4_session *session); | ||
24 | extern int nfs4_init_session(struct nfs_server *server); | ||
25 | extern int nfs4_init_ds_session(struct nfs_client *, unsigned long); | ||
26 | |||
27 | #else /* defined(CONFIG_NFS_V4_1) */ | ||
28 | |||
29 | static inline int nfs4_init_session(struct nfs_server *server) | ||
30 | { | ||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | #endif /* defined(CONFIG_NFS_V4_1) */ | ||
35 | #endif /* __LINUX_FS_NFS_NFS4SESSION_H */ | ||