Skip to content

Commit

Permalink
nfsd: nfsd_file cache entries should be per net namespace
Browse files Browse the repository at this point in the history
Ensure that we can safely clear out the file cache entries when the
nfs server is shut down on a container. Otherwise, the file cache
may end up pinning the mounts.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
  • Loading branch information
Trond Myklebust authored and J. Bruce Fields committed Sep 10, 2019
1 parent 2b86e3a commit 5e11322
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 14 deletions.
2 changes: 1 addition & 1 deletion fs/nfsd/export.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ static void expkey_flush(void)
* destroyed while we're in the middle of flushing.
*/
mutex_lock(&nfsd_mutex);
nfsd_file_cache_purge();
nfsd_file_cache_purge(current->nsproxy->net_ns);
mutex_unlock(&nfsd_mutex);
}

Expand Down
33 changes: 21 additions & 12 deletions fs/nfsd/filecache.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "vfs.h"
#include "nfsd.h"
#include "nfsfh.h"
#include "netns.h"
#include "filecache.h"
#include "trace.h"

Expand Down Expand Up @@ -167,7 +168,8 @@ nfsd_file_mark_find_or_create(struct nfsd_file *nf)
}

static struct nfsd_file *
nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval)
nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval,
struct net *net)
{
struct nfsd_file *nf;

Expand All @@ -177,6 +179,7 @@ nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval)
INIT_LIST_HEAD(&nf->nf_lru);
nf->nf_file = NULL;
nf->nf_cred = get_current_cred();
nf->nf_net = net;
nf->nf_flags = 0;
nf->nf_inode = inode;
nf->nf_hashval = hashval;
Expand Down Expand Up @@ -607,21 +610,24 @@ nfsd_file_cache_init(void)
* Note this can deadlock with nfsd_file_lru_cb.
*/
void
nfsd_file_cache_purge(void)
nfsd_file_cache_purge(struct net *net)
{
unsigned int i;
struct nfsd_file *nf;
struct hlist_node *next;
LIST_HEAD(dispose);
bool del;

if (!nfsd_file_hashtbl)
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);
struct nfsd_fcache_bucket *nfb = &nfsd_file_hashtbl[i];

spin_lock(&nfb->nfb_lock);
hlist_for_each_entry_safe(nf, next, &nfb->nfb_head, nf_node) {
if (net && nf->nf_net != net)
continue;
del = nfsd_file_unhash_and_release_locked(nf, &dispose);

/*
Expand All @@ -630,7 +636,7 @@ nfsd_file_cache_purge(void)
*/
WARN_ON_ONCE(!del);
}
spin_unlock(&nfsd_file_hashtbl[i].nfb_lock);
spin_unlock(&nfb->nfb_lock);
nfsd_file_dispose_list(&dispose);
}
}
Expand All @@ -649,7 +655,7 @@ nfsd_file_cache_shutdown(void)
* calling nfsd_file_cache_purge
*/
cancel_delayed_work_sync(&nfsd_filecache_laundrette);
nfsd_file_cache_purge();
nfsd_file_cache_purge(NULL);
list_lru_destroy(&nfsd_file_lru);
rcu_barrier();
fsnotify_put_group(nfsd_file_fsnotify_group);
Expand Down Expand Up @@ -685,7 +691,7 @@ nfsd_match_cred(const struct cred *c1, const struct cred *c2)

static struct nfsd_file *
nfsd_file_find_locked(struct inode *inode, unsigned int may_flags,
unsigned int hashval)
unsigned int hashval, struct net *net)
{
struct nfsd_file *nf;
unsigned char need = may_flags & NFSD_FILE_MAY_MASK;
Expand All @@ -696,6 +702,8 @@ nfsd_file_find_locked(struct inode *inode, unsigned int may_flags,
continue;
if (nf->nf_inode != inode)
continue;
if (nf->nf_net != net)
continue;
if (!nfsd_match_cred(nf->nf_cred, current_cred()))
continue;
if (nfsd_file_get(nf) != NULL)
Expand Down Expand Up @@ -738,6 +746,7 @@ nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
unsigned int may_flags, struct nfsd_file **pnf)
{
__be32 status;
struct net *net = SVC_NET(rqstp);
struct nfsd_file *nf, *new;
struct inode *inode;
unsigned int hashval;
Expand All @@ -752,20 +761,20 @@ nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
hashval = (unsigned int)hash_long(inode->i_ino, NFSD_FILE_HASH_BITS);
retry:
rcu_read_lock();
nf = nfsd_file_find_locked(inode, may_flags, hashval);
nf = nfsd_file_find_locked(inode, may_flags, hashval, net);
rcu_read_unlock();
if (nf)
goto wait_for_construction;

new = nfsd_file_alloc(inode, may_flags, hashval);
new = nfsd_file_alloc(inode, may_flags, hashval, net);
if (!new) {
trace_nfsd_file_acquire(rqstp, hashval, inode, may_flags,
NULL, nfserr_jukebox);
return nfserr_jukebox;
}

spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock);
nf = nfsd_file_find_locked(inode, may_flags, hashval);
nf = nfsd_file_find_locked(inode, may_flags, hashval, net);
if (nf == NULL)
goto open_file;
spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock);
Expand Down
3 changes: 2 additions & 1 deletion fs/nfsd/filecache.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ struct nfsd_file {
struct rcu_head nf_rcu;
struct file *nf_file;
const struct cred *nf_cred;
struct net *nf_net;
#define NFSD_FILE_HASHED (0)
#define NFSD_FILE_PENDING (1)
#define NFSD_FILE_BREAK_READ (2)
Expand All @@ -48,7 +49,7 @@ struct nfsd_file {
};

int nfsd_file_cache_init(void);
void nfsd_file_cache_purge(void);
void nfsd_file_cache_purge(struct net *);
void nfsd_file_cache_shutdown(void);
void nfsd_file_put(struct nfsd_file *nf);
struct nfsd_file *nfsd_file_get(struct nfsd_file *nf);
Expand Down
1 change: 1 addition & 0 deletions fs/nfsd/nfssvc.c
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ static void nfsd_shutdown_net(struct net *net)
{
struct nfsd_net *nn = net_generic(net, nfsd_net_id);

nfsd_file_cache_purge(net);
nfs4_state_shutdown_net(net);
if (nn->lockd_up) {
lockd_down(net);
Expand Down

0 comments on commit 5e11322

Please sign in to comment.