diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-08-27 23:44:04 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-08-28 14:23:22 -0400 |
commit | e09c978aae5bedfdb379be80363b024b7d82638b (patch) | |
tree | d218fe2842cef66c0d33648f1f12163a61f70a62 | |
parent | 16590a228109e2f318d2cc6466221134cfab723a (diff) |
NFSv4.1: Fix Oopsable condition in server callback races
The slot table hasn't been an array since v3.7. Ensure that we
use nfs4_lookup_slot() to access the slot correctly.
Fixes: 87dda67e7386 ("NFSv4.1: Allow SEQUENCE to resize the slot table...")
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Cc: stable@vger.kernel.org # v3.8+
-rw-r--r-- | fs/nfs/callback_proc.c | 5 | ||||
-rw-r--r-- | fs/nfs/nfs4session.c | 33 | ||||
-rw-r--r-- | fs/nfs/nfs4session.h | 1 |
3 files changed, 35 insertions, 4 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index c92a75e066a6..a4cf6d2c14a4 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -454,11 +454,8 @@ static bool referring_call_exists(struct nfs_client *clp, | |||
454 | ((u32 *)&rclist->rcl_sessionid.data)[3], | 454 | ((u32 *)&rclist->rcl_sessionid.data)[3], |
455 | ref->rc_sequenceid, ref->rc_slotid); | 455 | ref->rc_sequenceid, ref->rc_slotid); |
456 | 456 | ||
457 | spin_lock(&tbl->slot_tbl_lock); | 457 | status = nfs4_slot_seqid_in_use(tbl, ref->rc_slotid, |
458 | status = (test_bit(ref->rc_slotid, tbl->used_slots) && | ||
459 | tbl->slots[ref->rc_slotid].seq_nr == | ||
460 | ref->rc_sequenceid); | 458 | ref->rc_sequenceid); |
461 | spin_unlock(&tbl->slot_tbl_lock); | ||
462 | if (status) | 459 | if (status) |
463 | goto out; | 460 | goto out; |
464 | } | 461 | } |
diff --git a/fs/nfs/nfs4session.c b/fs/nfs/nfs4session.c index 332d06e64fa9..c1f4c208f38a 100644 --- a/fs/nfs/nfs4session.c +++ b/fs/nfs/nfs4session.c | |||
@@ -172,6 +172,39 @@ struct nfs4_slot *nfs4_lookup_slot(struct nfs4_slot_table *tbl, u32 slotid) | |||
172 | return ERR_PTR(-E2BIG); | 172 | return ERR_PTR(-E2BIG); |
173 | } | 173 | } |
174 | 174 | ||
175 | static int nfs4_slot_get_seqid(struct nfs4_slot_table *tbl, u32 slotid, | ||
176 | u32 *seq_nr) | ||
177 | __must_hold(&tbl->slot_tbl_lock) | ||
178 | { | ||
179 | struct nfs4_slot *slot; | ||
180 | |||
181 | slot = nfs4_lookup_slot(tbl, slotid); | ||
182 | if (IS_ERR(slot)) | ||
183 | return PTR_ERR(slot); | ||
184 | *seq_nr = slot->seq_nr; | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | /* | ||
189 | * nfs4_slot_seqid_in_use - test if a slot sequence id is still in use | ||
190 | * | ||
191 | * Given a slot table, slot id and sequence number, determine if the | ||
192 | * RPC call in question is still in flight. This function is mainly | ||
193 | * intended for use by the callback channel. | ||
194 | */ | ||
195 | bool nfs4_slot_seqid_in_use(struct nfs4_slot_table *tbl, u32 slotid, u32 seq_nr) | ||
196 | { | ||
197 | u32 cur_seq; | ||
198 | bool ret = false; | ||
199 | |||
200 | spin_lock(&tbl->slot_tbl_lock); | ||
201 | if (nfs4_slot_get_seqid(tbl, slotid, &cur_seq) == 0 && | ||
202 | cur_seq == seq_nr && test_bit(slotid, tbl->used_slots)) | ||
203 | ret = true; | ||
204 | spin_unlock(&tbl->slot_tbl_lock); | ||
205 | return ret; | ||
206 | } | ||
207 | |||
175 | /* | 208 | /* |
176 | * nfs4_alloc_slot - efficiently look for a free slot | 209 | * nfs4_alloc_slot - efficiently look for a free slot |
177 | * | 210 | * |
diff --git a/fs/nfs/nfs4session.h b/fs/nfs/nfs4session.h index 5b51298d1d03..33cace62b50b 100644 --- a/fs/nfs/nfs4session.h +++ b/fs/nfs/nfs4session.h | |||
@@ -78,6 +78,7 @@ extern int nfs4_setup_slot_table(struct nfs4_slot_table *tbl, | |||
78 | extern void nfs4_shutdown_slot_table(struct nfs4_slot_table *tbl); | 78 | extern void nfs4_shutdown_slot_table(struct nfs4_slot_table *tbl); |
79 | extern struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl); | 79 | extern struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl); |
80 | extern struct nfs4_slot *nfs4_lookup_slot(struct nfs4_slot_table *tbl, u32 slotid); | 80 | extern struct nfs4_slot *nfs4_lookup_slot(struct nfs4_slot_table *tbl, u32 slotid); |
81 | extern bool nfs4_slot_seqid_in_use(struct nfs4_slot_table *tbl, u32 slotid, u32 seq_nr); | ||
81 | extern bool nfs4_try_to_lock_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot); | 82 | extern bool nfs4_try_to_lock_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot); |
82 | extern void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot); | 83 | extern void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot); |
83 | extern void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl); | 84 | extern void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl); |