diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-02-14 20:33:19 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-02-17 17:33:39 -0500 |
commit | f86f36a6ae625eda87a13e1ea102a908e08f491b (patch) | |
tree | 4facbd3378390f4a571bbc169e197a3373f39159 /fs | |
parent | b9f9a03150969e4bd9967c20bce67c4de769058f (diff) |
NFSv4.1: Fix a NFSv4.1 session initialisation regression
Commit aacd553 (NFSv4.1: cleanup init and reset of session slot tables)
introduces a regression in the session initialisation code. New tables
now find their sequence ids initialised to 0, rather than the mandated
value of 1 (see RFC5661).
Fix the problem by merging nfs4_reset_slot_table() and nfs4_init_slot_table().
Since the tbl->max_slots is initialised to 0, the test in
nfs4_reset_slot_table for max_reqs != tbl->max_slots will automatically
pass for an empty table.
Reported-by: Vitaliy Gusev <gusev.vitaliy@nexenta.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/nfs4proc.c | 107 |
1 files changed, 42 insertions, 65 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d202e04aca94..b4d67feab90b 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -5008,37 +5008,53 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) | |||
5008 | return status; | 5008 | return status; |
5009 | } | 5009 | } |
5010 | 5010 | ||
5011 | static struct nfs4_slot *nfs4_alloc_slots(u32 max_slots, gfp_t gfp_flags) | ||
5012 | { | ||
5013 | return kcalloc(max_slots, sizeof(struct nfs4_slot), gfp_flags); | ||
5014 | } | ||
5015 | |||
5016 | static void nfs4_add_and_init_slots(struct nfs4_slot_table *tbl, | ||
5017 | struct nfs4_slot *new, | ||
5018 | u32 max_slots, | ||
5019 | u32 ivalue) | ||
5020 | { | ||
5021 | struct nfs4_slot *old = NULL; | ||
5022 | u32 i; | ||
5023 | |||
5024 | spin_lock(&tbl->slot_tbl_lock); | ||
5025 | if (new) { | ||
5026 | old = tbl->slots; | ||
5027 | tbl->slots = new; | ||
5028 | tbl->max_slots = max_slots; | ||
5029 | } | ||
5030 | tbl->highest_used_slotid = -1; /* no slot is currently used */ | ||
5031 | for (i = 0; i < tbl->max_slots; i++) | ||
5032 | tbl->slots[i].seq_nr = ivalue; | ||
5033 | spin_unlock(&tbl->slot_tbl_lock); | ||
5034 | kfree(old); | ||
5035 | } | ||
5036 | |||
5011 | /* | 5037 | /* |
5012 | * Reset a slot table | 5038 | * (re)Initialise a slot table |
5013 | */ | 5039 | */ |
5014 | static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs, | 5040 | static int nfs4_realloc_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs, |
5015 | int ivalue) | 5041 | u32 ivalue) |
5016 | { | 5042 | { |
5017 | struct nfs4_slot *new = NULL; | 5043 | struct nfs4_slot *new = NULL; |
5018 | int i; | 5044 | int ret = -ENOMEM; |
5019 | int ret = 0; | ||
5020 | 5045 | ||
5021 | dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__, | 5046 | dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__, |
5022 | max_reqs, tbl->max_slots); | 5047 | max_reqs, tbl->max_slots); |
5023 | 5048 | ||
5024 | /* Does the newly negotiated max_reqs match the existing slot table? */ | 5049 | /* Does the newly negotiated max_reqs match the existing slot table? */ |
5025 | if (max_reqs != tbl->max_slots) { | 5050 | if (max_reqs != tbl->max_slots) { |
5026 | ret = -ENOMEM; | 5051 | new = nfs4_alloc_slots(max_reqs, GFP_NOFS); |
5027 | new = kmalloc(max_reqs * sizeof(struct nfs4_slot), | ||
5028 | GFP_NOFS); | ||
5029 | if (!new) | 5052 | if (!new) |
5030 | goto out; | 5053 | goto out; |
5031 | ret = 0; | ||
5032 | kfree(tbl->slots); | ||
5033 | } | ||
5034 | spin_lock(&tbl->slot_tbl_lock); | ||
5035 | if (new) { | ||
5036 | tbl->slots = new; | ||
5037 | tbl->max_slots = max_reqs; | ||
5038 | } | 5054 | } |
5039 | for (i = 0; i < tbl->max_slots; ++i) | 5055 | ret = 0; |
5040 | tbl->slots[i].seq_nr = ivalue; | 5056 | |
5041 | spin_unlock(&tbl->slot_tbl_lock); | 5057 | nfs4_add_and_init_slots(tbl, new, max_reqs, ivalue); |
5042 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | 5058 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, |
5043 | tbl, tbl->slots, tbl->max_slots); | 5059 | tbl, tbl->slots, tbl->max_slots); |
5044 | out: | 5060 | out: |
@@ -5061,36 +5077,6 @@ static void nfs4_destroy_slot_tables(struct nfs4_session *session) | |||
5061 | } | 5077 | } |
5062 | 5078 | ||
5063 | /* | 5079 | /* |
5064 | * Initialize slot table | ||
5065 | */ | ||
5066 | static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | ||
5067 | int max_slots, int ivalue) | ||
5068 | { | ||
5069 | struct nfs4_slot *slot; | ||
5070 | int ret = -ENOMEM; | ||
5071 | |||
5072 | BUG_ON(max_slots > NFS4_MAX_SLOT_TABLE); | ||
5073 | |||
5074 | dprintk("--> %s: max_reqs=%u\n", __func__, max_slots); | ||
5075 | |||
5076 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_NOFS); | ||
5077 | if (!slot) | ||
5078 | goto out; | ||
5079 | ret = 0; | ||
5080 | |||
5081 | spin_lock(&tbl->slot_tbl_lock); | ||
5082 | tbl->max_slots = max_slots; | ||
5083 | tbl->slots = slot; | ||
5084 | tbl->highest_used_slotid = -1; /* no slot is currently used */ | ||
5085 | spin_unlock(&tbl->slot_tbl_lock); | ||
5086 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | ||
5087 | tbl, tbl->slots, tbl->max_slots); | ||
5088 | out: | ||
5089 | dprintk("<-- %s: return %d\n", __func__, ret); | ||
5090 | return ret; | ||
5091 | } | ||
5092 | |||
5093 | /* | ||
5094 | * Initialize or reset the forechannel and backchannel tables | 5080 | * Initialize or reset the forechannel and backchannel tables |
5095 | */ | 5081 | */ |
5096 | static int nfs4_setup_session_slot_tables(struct nfs4_session *ses) | 5082 | static int nfs4_setup_session_slot_tables(struct nfs4_session *ses) |
@@ -5101,25 +5087,16 @@ static int nfs4_setup_session_slot_tables(struct nfs4_session *ses) | |||
5101 | dprintk("--> %s\n", __func__); | 5087 | dprintk("--> %s\n", __func__); |
5102 | /* Fore channel */ | 5088 | /* Fore channel */ |
5103 | tbl = &ses->fc_slot_table; | 5089 | tbl = &ses->fc_slot_table; |
5104 | if (tbl->slots == NULL) { | 5090 | status = nfs4_realloc_slot_table(tbl, ses->fc_attrs.max_reqs, 1); |
5105 | status = nfs4_init_slot_table(tbl, ses->fc_attrs.max_reqs, 1); | 5091 | if (status) /* -ENOMEM */ |
5106 | if (status) /* -ENOMEM */ | 5092 | return status; |
5107 | return status; | ||
5108 | } else { | ||
5109 | status = nfs4_reset_slot_table(tbl, ses->fc_attrs.max_reqs, 1); | ||
5110 | if (status) | ||
5111 | return status; | ||
5112 | } | ||
5113 | /* Back channel */ | 5093 | /* Back channel */ |
5114 | tbl = &ses->bc_slot_table; | 5094 | tbl = &ses->bc_slot_table; |
5115 | if (tbl->slots == NULL) { | 5095 | status = nfs4_realloc_slot_table(tbl, ses->bc_attrs.max_reqs, 0); |
5116 | status = nfs4_init_slot_table(tbl, ses->bc_attrs.max_reqs, 0); | 5096 | if (status && tbl->slots == NULL) |
5117 | if (status) | 5097 | /* Fore and back channel share a connection so get |
5118 | /* Fore and back channel share a connection so get | 5098 | * both slot tables or neither */ |
5119 | * both slot tables or neither */ | 5099 | nfs4_destroy_slot_tables(ses); |
5120 | nfs4_destroy_slot_tables(ses); | ||
5121 | } else | ||
5122 | status = nfs4_reset_slot_table(tbl, ses->bc_attrs.max_reqs, 0); | ||
5123 | return status; | 5100 | return status; |
5124 | } | 5101 | } |
5125 | 5102 | ||