Skip to content

Commit

Permalink
NFSv4.x: Allow multiple callbacks in flight
Browse files Browse the repository at this point in the history
Hook the callback channel into the same session management machinery
as we use for the forward channel.

Signed-off-by: Trond Myklebust <[email protected]>
  • Loading branch information
trondmypd committed Jan 25, 2016
1 parent 5f83d86 commit 810d82e
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 22 deletions.
3 changes: 2 additions & 1 deletion fs/nfs/callback.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ enum nfs4_callback_opnum {
OP_CB_ILLEGAL = 10044,
};

struct nfs4_slot;
struct cb_process_state {
__be32 drc_status;
struct nfs_client *clp;
u32 slotid;
struct nfs4_slot *slot;
u32 minorversion;
struct net *net;
};
Expand Down
14 changes: 10 additions & 4 deletions fs/nfs/callback_proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ validate_seqid(const struct nfs4_slot_table *tbl, const struct nfs4_slot *slot,
if (args->csa_sequenceid == slot->seq_nr) {
dprintk("%s seqid %u is a replay\n",
__func__, args->csa_sequenceid);
if (tbl->highest_used_slotid != NFS4_NO_SLOT)
if (nfs4_test_locked_slot(tbl, slot->slot_nr))
return htonl(NFS4ERR_DELAY);
/* Signal process_op to set this error on next op */
if (args->csa_cachethis == 0)
Expand Down Expand Up @@ -476,12 +476,18 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
goto out_unlock;
}

status = htonl(NFS4ERR_BADSLOT);
slot = nfs4_lookup_slot(tbl, args->csa_slotid);
if (IS_ERR(slot))
goto out_unlock;
status = validate_seqid(tbl, slot, args);
if (status)
goto out_unlock;

cps->slotid = args->csa_slotid;
tbl->highest_used_slotid = args->csa_slotid;
if (!nfs4_try_to_lock_slot(tbl, slot)) {
status = htonl(NFS4ERR_DELAY);
goto out_unlock;
}
cps->slot = slot;

memcpy(&res->csr_sessionid, &args->csa_sessionid,
sizeof(res->csr_sessionid));
Expand Down
12 changes: 7 additions & 5 deletions fs/nfs/callback_xdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,8 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
return htonl(NFS_OK);
}

static void nfs4_callback_free_slot(struct nfs4_session *session)
static void nfs4_callback_free_slot(struct nfs4_session *session,
struct nfs4_slot *slot)
{
struct nfs4_slot_table *tbl = &session->bc_slot_table;

Expand All @@ -761,15 +762,17 @@ static void nfs4_callback_free_slot(struct nfs4_session *session)
* Let the state manager know callback processing done.
* A single slot, so highest used slotid is either 0 or -1
*/
tbl->highest_used_slotid = NFS4_NO_SLOT;
nfs4_free_slot(tbl, slot);
nfs4_slot_tbl_drain_complete(tbl);
spin_unlock(&tbl->slot_tbl_lock);
}

static void nfs4_cb_free_slot(struct cb_process_state *cps)
{
if (cps->slotid != NFS4_NO_SLOT)
nfs4_callback_free_slot(cps->clp->cl_session);
if (cps->slot) {
nfs4_callback_free_slot(cps->clp->cl_session, cps->slot);
cps->slot = NULL;
}
}

#else /* CONFIG_NFS_V4_1 */
Expand Down Expand Up @@ -893,7 +896,6 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
struct cb_process_state cps = {
.drc_status = 0,
.clp = NULL,
.slotid = NFS4_NO_SLOT,
.net = SVC_NET(rqstp),
};
unsigned int nops = 0;
Expand Down
54 changes: 42 additions & 12 deletions fs/nfs/nfs4session.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,43 @@ static struct nfs4_slot *nfs4_find_or_create_slot(struct nfs4_slot_table *tbl,
return ERR_PTR(-ENOMEM);
}

static void nfs4_lock_slot(struct nfs4_slot_table *tbl,
struct nfs4_slot *slot)
{
u32 slotid = slot->slot_nr;

__set_bit(slotid, tbl->used_slots);
if (slotid > tbl->highest_used_slotid ||
tbl->highest_used_slotid == NFS4_NO_SLOT)
tbl->highest_used_slotid = slotid;
slot->generation = tbl->generation;
}

/*
* nfs4_try_to_lock_slot - Given a slot try to allocate it
*
* Note: must be called with the slot_tbl_lock held.
*/
bool nfs4_try_to_lock_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot)
{
if (nfs4_test_locked_slot(tbl, slot->slot_nr))
return false;
nfs4_lock_slot(tbl, slot);
return true;
}

/*
* nfs4_lookup_slot - Find a slot but don't allocate it
*
* Note: must be called with the slot_tbl_lock held.
*/
struct nfs4_slot *nfs4_lookup_slot(struct nfs4_slot_table *tbl, u32 slotid)
{
if (slotid <= tbl->max_slotid)
return nfs4_find_or_create_slot(tbl, slotid, 1, GFP_NOWAIT);
return ERR_PTR(-E2BIG);
}

/*
* nfs4_alloc_slot - efficiently look for a free slot
*
Expand All @@ -153,18 +190,11 @@ struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl)
__func__, tbl->used_slots[0], tbl->highest_used_slotid,
tbl->max_slotid + 1);
slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slotid + 1);
if (slotid > tbl->max_slotid)
goto out;
ret = nfs4_find_or_create_slot(tbl, slotid, 1, GFP_NOWAIT);
if (IS_ERR(ret))
goto out;
__set_bit(slotid, tbl->used_slots);
if (slotid > tbl->highest_used_slotid ||
tbl->highest_used_slotid == NFS4_NO_SLOT)
tbl->highest_used_slotid = slotid;
ret->generation = tbl->generation;

out:
if (slotid <= tbl->max_slotid) {
ret = nfs4_find_or_create_slot(tbl, slotid, 1, GFP_NOWAIT);
if (!IS_ERR(ret))
nfs4_lock_slot(tbl, ret);
}
dprintk("<-- %s used_slots=%04lx highest_used=%u slotid=%u\n",
__func__, tbl->used_slots[0], tbl->highest_used_slotid,
!IS_ERR(ret) ? ret->slot_nr : NFS4_NO_SLOT);
Expand Down
8 changes: 8 additions & 0 deletions fs/nfs/nfs4session.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ extern int nfs4_setup_slot_table(struct nfs4_slot_table *tbl,
unsigned int max_reqs, const char *queue);
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_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);
bool nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl,
Expand All @@ -88,6 +90,12 @@ static inline bool nfs4_slot_tbl_draining(struct nfs4_slot_table *tbl)
return !!test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state);
}

static inline bool nfs4_test_locked_slot(const struct nfs4_slot_table *tbl,
u32 slotid)
{
return !!test_bit(slotid, tbl->used_slots);
}

#if defined(CONFIG_NFS_V4_1)
extern void nfs41_set_target_slotid(struct nfs4_slot_table *tbl,
u32 target_highest_slotid);
Expand Down

0 comments on commit 810d82e

Please sign in to comment.