@@ -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
@@ -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;
}
@@ -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,
...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(-)