diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-11-20 19:49:20 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-12-05 18:30:42 -0500 |
commit | 87dda67e7386ba7d2164391ea58b34e028d8157b (patch) | |
tree | 9f8740fa1631a5bb5d3163d86783a764d542cbc6 /fs/nfs | |
parent | 97e548a93de213b149eea025a97d88e28143b445 (diff) |
NFSv4.1: Allow SEQUENCE to resize the slot table on the fly
Instead of an array of slots, use a singly linked list of slots that
can be dynamically appended to or shrunk.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/nfs4_fs.h | 4 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 174 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 22 |
3 files changed, 120 insertions, 80 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 5d4e82b10c3c..856bc496a210 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -258,10 +258,10 @@ extern int nfs4_proc_get_lease_time(struct nfs_client *clp, | |||
258 | extern int nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, | 258 | extern int nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, |
259 | bool sync); | 259 | bool sync); |
260 | 260 | ||
261 | extern struct nfs4_slot *nfs4_alloc_slots(struct nfs4_slot_table *table, | ||
262 | u32 max_slots, gfp_t gfp_flags); | ||
263 | extern void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, | 261 | extern void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, |
264 | u32 target_highest_slotid); | 262 | u32 target_highest_slotid); |
263 | extern int nfs4_resize_slot_table(struct nfs4_slot_table *tbl, | ||
264 | u32 max_reqs, u32 ivalue); | ||
265 | 265 | ||
266 | static inline bool | 266 | static inline bool |
267 | is_ds_only_client(struct nfs_client *clp) | 267 | is_ds_only_client(struct nfs_client *clp) |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 1792ece8b53c..fc65300172e1 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -397,6 +397,27 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp | |||
397 | #if defined(CONFIG_NFS_V4_1) | 397 | #if defined(CONFIG_NFS_V4_1) |
398 | 398 | ||
399 | /* | 399 | /* |
400 | * nfs4_shrink_slot_table - free retired slots from the slot table | ||
401 | */ | ||
402 | static void nfs4_shrink_slot_table(struct nfs4_slot_table *tbl, u32 newsize) | ||
403 | { | ||
404 | struct nfs4_slot **p; | ||
405 | if (newsize >= tbl->max_slots) | ||
406 | return; | ||
407 | |||
408 | p = &tbl->slots; | ||
409 | while (newsize--) | ||
410 | p = &(*p)->next; | ||
411 | while (*p) { | ||
412 | struct nfs4_slot *slot = *p; | ||
413 | |||
414 | *p = slot->next; | ||
415 | kfree(slot); | ||
416 | tbl->max_slots--; | ||
417 | } | ||
418 | } | ||
419 | |||
420 | /* | ||
400 | * nfs4_free_slot - free a slot and efficiently update slot table. | 421 | * nfs4_free_slot - free a slot and efficiently update slot table. |
401 | * | 422 | * |
402 | * freeing a slot is trivially done by clearing its respective bit | 423 | * freeing a slot is trivially done by clearing its respective bit |
@@ -499,7 +520,7 @@ static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl, | |||
499 | tbl->target_highest_slotid = target_highest_slotid; | 520 | tbl->target_highest_slotid = target_highest_slotid; |
500 | tbl->generation++; | 521 | tbl->generation++; |
501 | 522 | ||
502 | max_slotid = min(tbl->max_slots - 1, tbl->target_highest_slotid); | 523 | max_slotid = min(NFS4_MAX_SLOT_TABLE - 1, tbl->target_highest_slotid); |
503 | for (i = tbl->max_slotid + 1; i <= max_slotid; i++) | 524 | for (i = tbl->max_slotid + 1; i <= max_slotid; i++) |
504 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | 525 | rpc_wake_up_next(&tbl->slot_tbl_waitq); |
505 | tbl->max_slotid = max_slotid; | 526 | tbl->max_slotid = max_slotid; |
@@ -516,16 +537,12 @@ void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, | |||
516 | static void nfs41_set_server_slotid_locked(struct nfs4_slot_table *tbl, | 537 | static void nfs41_set_server_slotid_locked(struct nfs4_slot_table *tbl, |
517 | u32 highest_slotid) | 538 | u32 highest_slotid) |
518 | { | 539 | { |
519 | unsigned int max_slotid, i; | ||
520 | |||
521 | if (tbl->server_highest_slotid == highest_slotid) | 540 | if (tbl->server_highest_slotid == highest_slotid) |
522 | return; | 541 | return; |
523 | if (tbl->highest_used_slotid > highest_slotid) | 542 | if (tbl->highest_used_slotid > highest_slotid) |
524 | return; | 543 | return; |
525 | max_slotid = min(tbl->max_slots - 1, highest_slotid); | 544 | /* Deallocate slots */ |
526 | /* Reset the seq_nr for deallocated slots */ | 545 | nfs4_shrink_slot_table(tbl, highest_slotid + 1); |
527 | for (i = tbl->server_highest_slotid + 1; i <= max_slotid; i++) | ||
528 | tbl->slots[i].seq_nr = 1; | ||
529 | tbl->server_highest_slotid = highest_slotid; | 546 | tbl->server_highest_slotid = highest_slotid; |
530 | } | 547 | } |
531 | 548 | ||
@@ -612,6 +629,42 @@ static int nfs4_sequence_done(struct rpc_task *task, | |||
612 | return nfs41_sequence_done(task, res); | 629 | return nfs41_sequence_done(task, res); |
613 | } | 630 | } |
614 | 631 | ||
632 | static struct nfs4_slot *nfs4_new_slot(struct nfs4_slot_table *tbl, | ||
633 | u32 slotid, u32 seq_init, gfp_t gfp_mask) | ||
634 | { | ||
635 | struct nfs4_slot *slot; | ||
636 | |||
637 | slot = kzalloc(sizeof(*slot), gfp_mask); | ||
638 | if (slot) { | ||
639 | slot->table = tbl; | ||
640 | slot->slot_nr = slotid; | ||
641 | slot->seq_nr = seq_init; | ||
642 | } | ||
643 | return slot; | ||
644 | } | ||
645 | |||
646 | static struct nfs4_slot *nfs4_find_or_create_slot(struct nfs4_slot_table *tbl, | ||
647 | u32 slotid, u32 seq_init, gfp_t gfp_mask) | ||
648 | { | ||
649 | struct nfs4_slot **p, *slot; | ||
650 | |||
651 | p = &tbl->slots; | ||
652 | for (;;) { | ||
653 | if (*p == NULL) { | ||
654 | *p = nfs4_new_slot(tbl, tbl->max_slots, | ||
655 | seq_init, gfp_mask); | ||
656 | if (*p == NULL) | ||
657 | break; | ||
658 | tbl->max_slots++; | ||
659 | } | ||
660 | slot = *p; | ||
661 | if (slot->slot_nr == slotid) | ||
662 | return slot; | ||
663 | p = &slot->next; | ||
664 | } | ||
665 | return NULL; | ||
666 | } | ||
667 | |||
615 | /* | 668 | /* |
616 | * nfs4_alloc_slot - efficiently look for a free slot | 669 | * nfs4_alloc_slot - efficiently look for a free slot |
617 | * | 670 | * |
@@ -628,15 +681,17 @@ static struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl) | |||
628 | 681 | ||
629 | dprintk("--> %s used_slots=%04lx highest_used=%u max_slots=%u\n", | 682 | dprintk("--> %s used_slots=%04lx highest_used=%u max_slots=%u\n", |
630 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, | 683 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, |
631 | tbl->max_slots); | 684 | tbl->max_slotid + 1); |
632 | slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slotid + 1); | 685 | slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slotid + 1); |
633 | if (slotid > tbl->max_slotid) | 686 | if (slotid > tbl->max_slotid) |
634 | goto out; | 687 | goto out; |
688 | ret = nfs4_find_or_create_slot(tbl, slotid, 1, GFP_NOWAIT); | ||
689 | if (ret == NULL) | ||
690 | goto out; | ||
635 | __set_bit(slotid, tbl->used_slots); | 691 | __set_bit(slotid, tbl->used_slots); |
636 | if (slotid > tbl->highest_used_slotid || | 692 | if (slotid > tbl->highest_used_slotid || |
637 | tbl->highest_used_slotid == NFS4_NO_SLOT) | 693 | tbl->highest_used_slotid == NFS4_NO_SLOT) |
638 | tbl->highest_used_slotid = slotid; | 694 | tbl->highest_used_slotid = slotid; |
639 | ret = &tbl->slots[slotid]; | ||
640 | ret->renewal_time = jiffies; | 695 | ret->renewal_time = jiffies; |
641 | ret->generation = tbl->generation; | 696 | ret->generation = tbl->generation; |
642 | 697 | ||
@@ -5718,67 +5773,56 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) | |||
5718 | return status; | 5773 | return status; |
5719 | } | 5774 | } |
5720 | 5775 | ||
5721 | struct nfs4_slot *nfs4_alloc_slots(struct nfs4_slot_table *table, | 5776 | static int nfs4_grow_slot_table(struct nfs4_slot_table *tbl, |
5722 | u32 max_slots, gfp_t gfp_flags) | 5777 | u32 max_reqs, u32 ivalue) |
5723 | { | 5778 | { |
5724 | struct nfs4_slot *tbl; | 5779 | if (max_reqs <= tbl->max_slots) |
5725 | u32 i; | 5780 | return 0; |
5726 | 5781 | if (nfs4_find_or_create_slot(tbl, max_reqs - 1, ivalue, GFP_NOFS)) | |
5727 | tbl = kmalloc_array(max_slots, sizeof(*tbl), gfp_flags); | 5782 | return 0; |
5728 | if (tbl != NULL) { | 5783 | return -ENOMEM; |
5729 | for (i = 0; i < max_slots; i++) { | ||
5730 | tbl[i].table = table; | ||
5731 | tbl[i].slot_nr = i; | ||
5732 | } | ||
5733 | } | ||
5734 | return tbl; | ||
5735 | } | 5784 | } |
5736 | 5785 | ||
5737 | static void nfs4_add_and_init_slots(struct nfs4_slot_table *tbl, | 5786 | static void nfs4_reset_slot_table(struct nfs4_slot_table *tbl, |
5738 | struct nfs4_slot *new, | 5787 | u32 server_highest_slotid, |
5739 | u32 max_slots, | ||
5740 | u32 ivalue) | 5788 | u32 ivalue) |
5741 | { | 5789 | { |
5742 | struct nfs4_slot *old = NULL; | 5790 | struct nfs4_slot **p; |
5743 | u32 i; | ||
5744 | 5791 | ||
5745 | spin_lock(&tbl->slot_tbl_lock); | 5792 | nfs4_shrink_slot_table(tbl, server_highest_slotid + 1); |
5746 | if (new) { | 5793 | p = &tbl->slots; |
5747 | old = tbl->slots; | 5794 | while (*p) { |
5748 | tbl->slots = new; | 5795 | (*p)->seq_nr = ivalue; |
5749 | tbl->max_slots = max_slots; | 5796 | p = &(*p)->next; |
5750 | } | 5797 | } |
5751 | tbl->highest_used_slotid = NFS4_NO_SLOT; | 5798 | tbl->highest_used_slotid = NFS4_NO_SLOT; |
5752 | tbl->target_highest_slotid = max_slots - 1; | 5799 | tbl->target_highest_slotid = server_highest_slotid; |
5753 | tbl->server_highest_slotid = max_slots - 1; | 5800 | tbl->server_highest_slotid = server_highest_slotid; |
5754 | tbl->max_slotid = max_slots - 1; | 5801 | tbl->max_slotid = server_highest_slotid; |
5755 | for (i = 0; i < tbl->max_slots; i++) | ||
5756 | tbl->slots[i].seq_nr = ivalue; | ||
5757 | spin_unlock(&tbl->slot_tbl_lock); | ||
5758 | kfree(old); | ||
5759 | } | 5802 | } |
5760 | 5803 | ||
5761 | /* | 5804 | /* |
5762 | * (re)Initialise a slot table | 5805 | * (re)Initialise a slot table |
5763 | */ | 5806 | */ |
5764 | static int nfs4_realloc_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs, | 5807 | static int nfs4_realloc_slot_table(struct nfs4_slot_table *tbl, |
5765 | u32 ivalue) | 5808 | u32 max_reqs, u32 ivalue) |
5766 | { | 5809 | { |
5767 | struct nfs4_slot *new = NULL; | 5810 | int ret; |
5768 | int ret = -ENOMEM; | ||
5769 | 5811 | ||
5770 | dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__, | 5812 | dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__, |
5771 | max_reqs, tbl->max_slots); | 5813 | max_reqs, tbl->max_slots); |
5772 | 5814 | ||
5773 | /* Does the newly negotiated max_reqs match the existing slot table? */ | 5815 | if (max_reqs > NFS4_MAX_SLOT_TABLE) |
5774 | if (max_reqs != tbl->max_slots) { | 5816 | max_reqs = NFS4_MAX_SLOT_TABLE; |
5775 | new = nfs4_alloc_slots(tbl, max_reqs, GFP_NOFS); | 5817 | |
5776 | if (!new) | 5818 | ret = nfs4_grow_slot_table(tbl, max_reqs, ivalue); |
5777 | goto out; | 5819 | if (ret) |
5778 | } | 5820 | goto out; |
5779 | ret = 0; | 5821 | |
5822 | spin_lock(&tbl->slot_tbl_lock); | ||
5823 | nfs4_reset_slot_table(tbl, max_reqs - 1, ivalue); | ||
5824 | spin_unlock(&tbl->slot_tbl_lock); | ||
5780 | 5825 | ||
5781 | nfs4_add_and_init_slots(tbl, new, max_reqs, ivalue); | ||
5782 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | 5826 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, |
5783 | tbl, tbl->slots, tbl->max_slots); | 5827 | tbl, tbl->slots, tbl->max_slots); |
5784 | out: | 5828 | out: |
@@ -5786,18 +5830,28 @@ out: | |||
5786 | return ret; | 5830 | return ret; |
5787 | } | 5831 | } |
5788 | 5832 | ||
5833 | int nfs4_resize_slot_table(struct nfs4_slot_table *tbl, | ||
5834 | u32 max_reqs, u32 ivalue) | ||
5835 | { | ||
5836 | int ret; | ||
5837 | |||
5838 | if (max_reqs > NFS4_MAX_SLOT_TABLE) | ||
5839 | max_reqs = NFS4_MAX_SLOT_TABLE; | ||
5840 | ret = nfs4_grow_slot_table(tbl, max_reqs, ivalue); | ||
5841 | if (ret) | ||
5842 | return ret; | ||
5843 | spin_lock(&tbl->slot_tbl_lock); | ||
5844 | nfs4_shrink_slot_table(tbl, max_reqs); | ||
5845 | tbl->max_slotid = max_reqs - 1; | ||
5846 | spin_unlock(&tbl->slot_tbl_lock); | ||
5847 | return 0; | ||
5848 | } | ||
5849 | |||
5789 | /* Destroy the slot table */ | 5850 | /* Destroy the slot table */ |
5790 | static void nfs4_destroy_slot_tables(struct nfs4_session *session) | 5851 | static void nfs4_destroy_slot_tables(struct nfs4_session *session) |
5791 | { | 5852 | { |
5792 | if (session->fc_slot_table.slots != NULL) { | 5853 | nfs4_shrink_slot_table(&session->fc_slot_table, 0); |
5793 | kfree(session->fc_slot_table.slots); | 5854 | nfs4_shrink_slot_table(&session->bc_slot_table, 0); |
5794 | session->fc_slot_table.slots = NULL; | ||
5795 | } | ||
5796 | if (session->bc_slot_table.slots != NULL) { | ||
5797 | kfree(session->bc_slot_table.slots); | ||
5798 | session->bc_slot_table.slots = NULL; | ||
5799 | } | ||
5800 | return; | ||
5801 | } | 5855 | } |
5802 | 5856 | ||
5803 | /* | 5857 | /* |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 1b7fa73c9436..c14b2c7ac8a7 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -2025,29 +2025,15 @@ out: | |||
2025 | static int nfs4_recall_slot(struct nfs_client *clp) | 2025 | static int nfs4_recall_slot(struct nfs_client *clp) |
2026 | { | 2026 | { |
2027 | struct nfs4_slot_table *fc_tbl; | 2027 | struct nfs4_slot_table *fc_tbl; |
2028 | struct nfs4_slot *new, *old; | 2028 | u32 new_size; |
2029 | int i; | ||
2030 | 2029 | ||
2031 | if (!nfs4_has_session(clp)) | 2030 | if (!nfs4_has_session(clp)) |
2032 | return 0; | 2031 | return 0; |
2033 | nfs4_begin_drain_session(clp); | 2032 | nfs4_begin_drain_session(clp); |
2034 | fc_tbl = &clp->cl_session->fc_slot_table; | ||
2035 | new = nfs4_alloc_slots(fc_tbl, fc_tbl->target_highest_slotid + 1, GFP_NOFS); | ||
2036 | if (!new) | ||
2037 | return -ENOMEM; | ||
2038 | 2033 | ||
2039 | spin_lock(&fc_tbl->slot_tbl_lock); | 2034 | fc_tbl = &clp->cl_session->fc_slot_table; |
2040 | for (i = 0; i <= fc_tbl->target_highest_slotid; i++) | 2035 | new_size = fc_tbl->server_highest_slotid + 1; |
2041 | new[i].seq_nr = fc_tbl->slots[i].seq_nr; | 2036 | return nfs4_resize_slot_table(fc_tbl, new_size, 1); |
2042 | old = fc_tbl->slots; | ||
2043 | fc_tbl->slots = new; | ||
2044 | fc_tbl->max_slots = fc_tbl->target_highest_slotid + 1; | ||
2045 | fc_tbl->max_slotid = fc_tbl->target_highest_slotid; | ||
2046 | clp->cl_session->fc_attrs.max_reqs = fc_tbl->max_slots; | ||
2047 | spin_unlock(&fc_tbl->slot_tbl_lock); | ||
2048 | |||
2049 | kfree(old); | ||
2050 | return 0; | ||
2051 | } | 2037 | } |
2052 | 2038 | ||
2053 | static int nfs4_bind_conn_to_session(struct nfs_client *clp) | 2039 | static int nfs4_bind_conn_to_session(struct nfs_client *clp) |