nfsd: serialize nfsdcltrack upcalls for a particular client
authorJeff Layton <jlayton@primarydata.com>
Fri, 12 Sep 2014 20:40:21 +0000 (16:40 -0400)
committerJ. Bruce Fields <bfields@redhat.com>
Wed, 17 Sep 2014 20:33:16 +0000 (16:33 -0400)
In a later patch, we want to add a flag that will allow us to reduce the
need for upcalls. In order to handle that correctly, we'll need to
ensure that racing upcalls for the same client can't occur. In practice
it should be rare for this to occur with a well-behaved client, but it
is possible.

Convert one of the bits in the cl_flags field to be an upcall bitlock,
and use it to ensure that upcalls for the same client are serialized.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
fs/nfsd/nfs4recover.c
fs/nfsd/state.h

index b4289060ebaf06c801438bc04972e6f37a3c515e..bf3a3575d060aeb67f5fc6305256332e30430abd 100644 (file)
@@ -1264,6 +1264,22 @@ nfsd4_umh_cltrack_init(struct net *net)
        return ret;
 }
 
+static void
+nfsd4_cltrack_upcall_lock(struct nfs4_client *clp)
+{
+       wait_on_bit_lock(&clp->cl_flags, NFSD4_CLIENT_UPCALL_LOCK,
+                        TASK_UNINTERRUPTIBLE);
+}
+
+static void
+nfsd4_cltrack_upcall_unlock(struct nfs4_client *clp)
+{
+       smp_mb__before_atomic();
+       clear_bit(NFSD4_CLIENT_UPCALL_LOCK, &clp->cl_flags);
+       smp_mb__after_atomic();
+       wake_up_bit(&clp->cl_flags, NFSD4_CLIENT_UPCALL_LOCK);
+}
+
 static void
 nfsd4_umh_cltrack_create(struct nfs4_client *clp)
 {
@@ -1275,9 +1291,14 @@ nfsd4_umh_cltrack_create(struct nfs4_client *clp)
                dprintk("%s: can't allocate memory for upcall!\n", __func__);
                return;
        }
+
        has_session = nfsd4_cltrack_client_has_session(clp);
        grace_start = nfsd4_cltrack_grace_start(nn->boot_time);
+
+       nfsd4_cltrack_upcall_lock(clp);
        nfsd4_umh_cltrack_upcall("create", hexid, has_session, grace_start);
+       nfsd4_cltrack_upcall_unlock(clp);
+
        kfree(has_session);
        kfree(grace_start);
        kfree(hexid);
@@ -1293,7 +1314,11 @@ nfsd4_umh_cltrack_remove(struct nfs4_client *clp)
                dprintk("%s: can't allocate memory for upcall!\n", __func__);
                return;
        }
+
+       nfsd4_cltrack_upcall_lock(clp);
        nfsd4_umh_cltrack_upcall("remove", hexid, NULL, NULL);
+       nfsd4_cltrack_upcall_unlock(clp);
+
        kfree(hexid);
 }
 
@@ -1311,7 +1336,11 @@ nfsd4_umh_cltrack_check(struct nfs4_client *clp)
 
        has_session = nfsd4_cltrack_client_has_session(clp);
        legacy = nfsd4_cltrack_legacy_recdir(&clp->cl_name);
+
+       nfsd4_cltrack_upcall_lock(clp);
        ret = nfsd4_umh_cltrack_upcall("check", hexid, has_session, legacy);
+       nfsd4_cltrack_upcall_unlock(clp);
+
        kfree(has_session);
        kfree(legacy);
        kfree(hexid);
index 854f0c574ccf887ad1259c03dd319883a5762b71..62a82ab06cf1bba3ee102dcaf25f9637cef608eb 100644 (file)
@@ -306,6 +306,7 @@ struct nfs4_client {
 #define NFSD4_CLIENT_STABLE            (2)     /* client on stable storage */
 #define NFSD4_CLIENT_RECLAIM_COMPLETE  (3)     /* reclaim_complete done */
 #define NFSD4_CLIENT_CONFIRMED         (4)     /* client is confirmed */
+#define NFSD4_CLIENT_UPCALL_LOCK       (5)     /* upcall serialization */
 #define NFSD4_CLIENT_CB_FLAG_MASK      (1 << NFSD4_CLIENT_CB_UPDATE | \
                                         1 << NFSD4_CLIENT_CB_KILL)
        unsigned long           cl_flags;