Skip to content

Commit

Permalink
NFSv4.1: Fix Oopsable condition in server callback races
Browse files Browse the repository at this point in the history
The slot table hasn't been an array since v3.7. Ensure that we
use nfs4_lookup_slot() to access the slot correctly.

Fixes: 87dda67 ("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+
  • Loading branch information
Trond Myklebust committed Aug 28, 2016
1 parent 16590a2 commit e09c978
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 4 deletions.
5 changes: 1 addition & 4 deletions fs/nfs/callback_proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -454,11 +454,8 @@ static bool referring_call_exists(struct nfs_client *clp,
((u32 *)&rclist->rcl_sessionid.data)[3],
ref->rc_sequenceid, ref->rc_slotid);

spin_lock(&tbl->slot_tbl_lock);
status = (test_bit(ref->rc_slotid, tbl->used_slots) &&
tbl->slots[ref->rc_slotid].seq_nr ==
status = nfs4_slot_seqid_in_use(tbl, ref->rc_slotid,
ref->rc_sequenceid);
spin_unlock(&tbl->slot_tbl_lock);
if (status)
goto out;
}
Expand Down
33 changes: 33 additions & 0 deletions fs/nfs/nfs4session.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,39 @@ struct nfs4_slot *nfs4_lookup_slot(struct nfs4_slot_table *tbl, u32 slotid)
return ERR_PTR(-E2BIG);
}

static int nfs4_slot_get_seqid(struct nfs4_slot_table *tbl, u32 slotid,
u32 *seq_nr)
__must_hold(&tbl->slot_tbl_lock)
{
struct nfs4_slot *slot;

slot = nfs4_lookup_slot(tbl, slotid);
if (IS_ERR(slot))
return PTR_ERR(slot);
*seq_nr = slot->seq_nr;
return 0;
}

/*
* nfs4_slot_seqid_in_use - test if a slot sequence id is still in use
*
* Given a slot table, slot id and sequence number, determine if the
* RPC call in question is still in flight. This function is mainly
* intended for use by the callback channel.
*/
bool nfs4_slot_seqid_in_use(struct nfs4_slot_table *tbl, u32 slotid, u32 seq_nr)
{
u32 cur_seq;
bool ret = false;

spin_lock(&tbl->slot_tbl_lock);
if (nfs4_slot_get_seqid(tbl, slotid, &cur_seq) == 0 &&
cur_seq == seq_nr && test_bit(slotid, tbl->used_slots))
ret = true;
spin_unlock(&tbl->slot_tbl_lock);
return ret;
}

/*
* nfs4_alloc_slot - efficiently look for a free slot
*
Expand Down
1 change: 1 addition & 0 deletions fs/nfs/nfs4session.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ extern int nfs4_setup_slot_table(struct nfs4_slot_table *tbl,
extern void nfs4_shutdown_slot_table(struct nfs4_slot_table *tbl);
extern struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl);
extern struct nfs4_slot *nfs4_lookup_slot(struct nfs4_slot_table *tbl, u32 slotid);
extern bool nfs4_slot_seqid_in_use(struct nfs4_slot_table *tbl, u32 slotid, u32 seq_nr);
extern bool nfs4_try_to_lock_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot);
extern void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot);
extern void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl);
Expand Down

0 comments on commit e09c978

Please sign in to comment.