summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/callback_proc.c2
-rw-r--r--fs/nfs/nfs4proc.c25
-rw-r--r--fs/nfs/nfs4state.c7
-rw-r--r--fs/nfs/nfs4xdr.c4
-rw-r--r--include/linux/nfs_fs_sb.h5
-rw-r--r--include/linux/nfs_xdr.h2
6 files changed, 36 insertions, 9 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 0be08b964f38..0ef047b7d28d 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -576,7 +576,7 @@ __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy,
if (args->crsa_target_max_slots == fc_tbl->max_slots)
goto out;
- fc_tbl->target_max_slots = args->crsa_target_max_slots;
+ fc_tbl->target_highest_slotid = args->crsa_target_max_slots;
nfs41_handle_recall_slot(cps->clp);
out:
dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 197ef3e4e1f7..d91abaa522e8 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -488,6 +488,28 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
res->sr_slot = NULL;
}
+/* Update the client's idea of target_highest_slotid */
+static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl,
+ u32 target_highest_slotid)
+{
+ if (tbl->target_highest_slotid == target_highest_slotid)
+ return;
+ tbl->target_highest_slotid = target_highest_slotid;
+ tbl->generation++;
+}
+
+static void nfs41_update_target_slotid(struct nfs4_slot_table *tbl,
+ struct nfs4_slot *slot,
+ struct nfs4_sequence_res *res)
+{
+ spin_lock(&tbl->slot_tbl_lock);
+ if (tbl->generation != slot->generation)
+ goto out;
+ nfs41_set_target_slotid_locked(tbl, res->sr_target_highest_slotid);
+out:
+ spin_unlock(&tbl->slot_tbl_lock);
+}
+
static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
{
struct nfs4_session *session;
@@ -522,6 +544,7 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *
/* Check sequence flags */
if (res->sr_status_flags != 0)
nfs4_schedule_lease_recovery(clp);
+ nfs41_update_target_slotid(slot->table, slot, res);
break;
case -NFS4ERR_DELAY:
/* The server detected a resend of the RPC call and
@@ -583,6 +606,7 @@ static struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl)
tbl->highest_used_slotid = slotid;
ret = &tbl->slots[slotid];
ret->renewal_time = jiffies;
+ ret->generation = tbl->generation;
out:
dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d \n",
@@ -5693,6 +5717,7 @@ static void nfs4_add_and_init_slots(struct nfs4_slot_table *tbl,
tbl->max_slots = max_slots;
}
tbl->highest_used_slotid = NFS4_NO_SLOT;
+ tbl->target_highest_slotid = max_slots - 1;
for (i = 0; i < tbl->max_slots; i++)
tbl->slots[i].seq_nr = ivalue;
spin_unlock(&tbl->slot_tbl_lock);
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 9495789c425b..842cb8c2f65d 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -2033,17 +2033,16 @@ static int nfs4_recall_slot(struct nfs_client *clp)
return 0;
nfs4_begin_drain_session(clp);
fc_tbl = &clp->cl_session->fc_slot_table;
- new = nfs4_alloc_slots(fc_tbl, fc_tbl->target_max_slots, GFP_NOFS);
+ new = nfs4_alloc_slots(fc_tbl, fc_tbl->target_highest_slotid + 1, GFP_NOFS);
if (!new)
return -ENOMEM;
spin_lock(&fc_tbl->slot_tbl_lock);
- for (i = 0; i < fc_tbl->target_max_slots; i++)
+ for (i = 0; i <= fc_tbl->target_highest_slotid; i++)
new[i].seq_nr = fc_tbl->slots[i].seq_nr;
old = fc_tbl->slots;
fc_tbl->slots = new;
- fc_tbl->max_slots = fc_tbl->target_max_slots;
- fc_tbl->target_max_slots = 0;
+ fc_tbl->max_slots = fc_tbl->target_highest_slotid + 1;
clp->cl_session->fc_attrs.max_reqs = fc_tbl->max_slots;
spin_unlock(&fc_tbl->slot_tbl_lock);
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 27b0fec1a6b0..05d34f1fcc19 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -5552,8 +5552,8 @@ static int decode_sequence(struct xdr_stream *xdr,
}
/* highest slot id - currently not processed */
dummy = be32_to_cpup(p++);
- /* target highest slot id - currently not processed */
- dummy = be32_to_cpup(p++);
+ /* target highest slot id */
+ res->sr_target_highest_slotid = be32_to_cpup(p++);
/* result flags */
res->sr_status_flags = be32_to_cpup(p);
status = 0;
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index b0412873d29c..57d406997def 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -217,8 +217,9 @@ struct nfs4_slot_table {
u32 max_slots; /* # slots in table */
u32 highest_used_slotid; /* sent to server on each SEQ.
* op for dynamic resizing */
- u32 target_max_slots; /* Set by CB_RECALL_SLOT as
- * the new max_slots */
+ u32 target_highest_slotid; /* Server max_slot target */
+ unsigned long generation; /* Generation counter for
+ target_highest_slotid */
struct completion complete;
};
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index deb31bbbb857..08c47db7417f 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -188,6 +188,7 @@ struct nfs4_channel_attrs {
/* nfs41 sessions slot seqid */
struct nfs4_slot {
struct nfs4_slot_table *table;
+ unsigned long generation;
unsigned long renewal_time;
u32 slot_nr;
u32 seq_nr;
@@ -202,6 +203,7 @@ struct nfs4_sequence_res {
struct nfs4_slot *sr_slot; /* slot used to send request */
int sr_status; /* sequence operation status */
u32 sr_status_flags;
+ u32 sr_target_highest_slotid;
};
struct nfs4_get_lease_time_args {