diff mbox

[8/9] nfsd: add a ->flush routine to svc_export_cache

Message ID 1438264341-18048-10-git-send-email-jeff.layton@primarydata.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jeff Layton July 30, 2015, 1:52 p.m. UTC
...to purge the nfsd_file table. This should help ensure that
filesystems are unmountable very soon after unexporting them.

Note that we take the nfsd_mutex in this code to ensure that we can't
race with a concurrent shutdown of nfsd that might destroy the cache.

Signed-off-by: Jeff Layton <jeff.layton@primarydata.com>
---
 fs/nfsd/export.c    | 14 ++++++++++++++
 fs/nfsd/filecache.c | 39 +++++++++++++++++++++++++--------------
 fs/nfsd/filecache.h |  1 +
 3 files changed, 40 insertions(+), 14 deletions(-)
diff mbox

Patch

diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index f79521a59747..be80ff370072 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -21,6 +21,7 @@ 
 #include "nfsfh.h"
 #include "netns.h"
 #include "pnfs.h"
+#include "filecache.h"
 
 #define NFSDDBG_FACILITY	NFSDDBG_EXPORT
 
@@ -231,6 +232,18 @@  static struct cache_head *expkey_alloc(void)
 		return NULL;
 }
 
+static void
+expkey_flush(void)
+{
+	/*
+	 * Take the nfsd_mutex here to ensure that the file cache is not
+	 * destroyed while we're in the middle of flushing.
+	 */
+	mutex_lock(&nfsd_mutex);
+	nfsd_file_cache_purge();
+	mutex_unlock(&nfsd_mutex);
+}
+
 static struct cache_detail svc_expkey_cache_template = {
 	.owner		= THIS_MODULE,
 	.hash_size	= EXPKEY_HASHMAX,
@@ -243,6 +256,7 @@  static struct cache_detail svc_expkey_cache_template = {
 	.init		= expkey_init,
 	.update       	= expkey_update,
 	.alloc		= expkey_alloc,
+	.flush		= expkey_flush,
 };
 
 static int
diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c
index 564b4eec0350..55930995a1ec 100644
--- a/fs/nfsd/filecache.c
+++ b/fs/nfsd/filecache.c
@@ -124,6 +124,30 @@  nfsd_file_dispose_list(struct list_head *dispose)
 	}
 }
 
+void
+nfsd_file_cache_purge(void)
+{
+	unsigned int		i;
+	struct nfsd_file	*nf;
+	LIST_HEAD(dispose);
+
+	if (!atomic_read(&nfsd_file_count))
+		return;
+
+	for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) {
+		spin_lock(&nfsd_file_hashtbl[i].nfb_lock);
+		while(!hlist_empty(&nfsd_file_hashtbl[i].nfb_head)) {
+			nf = hlist_entry(nfsd_file_hashtbl[i].nfb_head.first,
+					 struct nfsd_file, nf_node);
+			nfsd_file_unhash(nf);
+			/* put the hash reference */
+			nfsd_file_put_locked(nf, &dispose);
+		}
+		spin_unlock(&nfsd_file_hashtbl[i].nfb_lock);
+		nfsd_file_dispose_list(&dispose);
+	}
+}
+
 static void
 nfsd_file_cache_prune(void)
 {
@@ -200,23 +224,10 @@  out_nomem:
 void
 nfsd_file_cache_shutdown(void)
 {
-	unsigned int		i;
-	struct nfsd_file	*nf;
 	LIST_HEAD(dispose);
 
 	cancel_delayed_work_sync(&nfsd_file_cache_clean_work);
-	for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) {
-		spin_lock(&nfsd_file_hashtbl[i].nfb_lock);
-		while(!hlist_empty(&nfsd_file_hashtbl[i].nfb_head)) {
-			nf = hlist_entry(nfsd_file_hashtbl[i].nfb_head.first,
-					 struct nfsd_file, nf_node);
-			nfsd_file_unhash(nf);
-			/* put the hash reference */
-			nfsd_file_put_locked(nf, &dispose);
-		}
-		spin_unlock(&nfsd_file_hashtbl[i].nfb_lock);
-		nfsd_file_dispose_list(&dispose);
-	}
+	nfsd_file_cache_purge();
 	kfree(nfsd_file_hashtbl);
 	nfsd_file_hashtbl = NULL;
 }
diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h
index adf7e78b8e43..98976f71caa8 100644
--- a/fs/nfsd/filecache.h
+++ b/fs/nfsd/filecache.h
@@ -39,6 +39,7 @@  struct nfsd_file {
 };
 
 int nfsd_file_cache_init(void);
+void nfsd_file_cache_purge(void);
 void nfsd_file_cache_shutdown(void);
 void nfsd_file_put(struct nfsd_file *nf);
 __be32 nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,