summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jlayton@primarydata.com>2014-09-12 16:40:21 -0400
committerJ. Bruce Fields <bfields@redhat.com>2014-09-17 16:33:16 -0400
commitd682e750ce14cfb3be655e6d492c77511e637228 (patch)
treef862ca27fa345f0e08ca7683e9349a87cb88a1a0
parentd4318acd5d2d34d69a46537f057b20a8f0266e1e (diff)
downloadlinux-d682e750ce14cfb3be655e6d492c77511e637228.tar.bz2
nfsd: serialize nfsdcltrack upcalls for a particular client
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>
-rw-r--r--fs/nfsd/nfs4recover.c29
-rw-r--r--fs/nfsd/state.h1
2 files changed, 30 insertions, 0 deletions
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index b4289060ebaf..bf3a3575d060 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -1265,6 +1265,22 @@ nfsd4_umh_cltrack_init(struct net *net)
}
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)
{
char *hexid, *has_session, *grace_start;
@@ -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);
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 854f0c574ccf..62a82ab06cf1 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -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;