aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2016-08-27 23:44:04 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2016-08-28 14:23:22 -0400
commite09c978aae5bedfdb379be80363b024b7d82638b (patch)
treed218fe2842cef66c0d33648f1f12163a61f70a62
parent16590a228109e2f318d2cc6466221134cfab723a (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.c5
-rw-r--r--fs/nfs/nfs4session.c33
-rw-r--r--fs/nfs/nfs4session.h1
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
175static 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 */
195bool 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,
78extern void nfs4_shutdown_slot_table(struct nfs4_slot_table *tbl); 78extern void nfs4_shutdown_slot_table(struct nfs4_slot_table *tbl);
79extern struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl); 79extern struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl);
80extern struct nfs4_slot *nfs4_lookup_slot(struct nfs4_slot_table *tbl, u32 slotid); 80extern struct nfs4_slot *nfs4_lookup_slot(struct nfs4_slot_table *tbl, u32 slotid);
81extern bool nfs4_slot_seqid_in_use(struct nfs4_slot_table *tbl, u32 slotid, u32 seq_nr);
81extern bool nfs4_try_to_lock_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot); 82extern bool nfs4_try_to_lock_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot);
82extern void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot); 83extern void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot);
83extern void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl); 84extern void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl);