NFSv4.1: Ensure that the client tracks the server target_highest_slotid
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 20 Nov 2012 17:49:27 +0000 (12:49 -0500)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Wed, 5 Dec 2012 23:29:47 +0000 (00:29 +0100)
Dynamic slot allocation in NFSv4.1 depends on the client being able to
track the server's target value for the highest slotid in the
slot table.  See the reference in Section 2.10.6.1 of RFC5661.

To avoid ordering problems in the case where 2 SEQUENCE replies contain
conflicting updates to this target value, we also introduce a generation
counter, to track whether or not an RPC containing a SEQUENCE operation
was launched before or after the last update.

Also rename the nfs4_slot_table target_max_slots field to
'target_highest_slotid' to avoid confusion with a slot
table size or number of slots.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/callback_proc.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
include/linux/nfs_fs_sb.h
include/linux/nfs_xdr.h

index 0be08b964f387e3ee7a093214969b54aa506dd02..0ef047b7d28dab76ed660720d928749c856e0d17 100644 (file)
@@ -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));
index 197ef3e4e1f7edd7098ee13cba12bce787463c8c..d91abaa522e85a3c9c2b0ae24d275d68ba8b5c10 100644 (file)
@@ -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);
index 9495789c425b3e8591b677a4b605cd064024d38f..842cb8c2f65deed6d3a04bb15d5c7fa5b5dc267b 100644 (file)
@@ -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);
 
index 27b0fec1a6b03125c0175e07f82b9bc1f46b4b32..05d34f1fcc19c65de88f6c880a540c760c617257 100644 (file)
@@ -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;
index b0412873d29c4f5bb35dc1dc32354106eb2eeca7..57d406997def7b736c7668b042526c0b399b6125 100644 (file)
@@ -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;
 };
 
index deb31bbbb85769397ea283927e67c574d66a36ad..08c47db7417fc61e31f289fbe19a561e24b464ae 100644 (file)
@@ -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 {