summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <trondmy@gmail.com>2019-09-02 13:02:55 -0400
committerJ. Bruce Fields <bfields@redhat.com>2019-09-10 09:23:41 -0400
commit5e113224c17e2fb156b785ddbbc48a0209fddb0c (patch)
treedd3f0e389afb149e37ab9a96306f4f8445398169
parent2b86e3aaf993a3ea6c73dfcf86143061a40c62e6 (diff)
nfsd: nfsd_file cache entries should be per net namespace
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>
-rw-r--r--fs/nfsd/export.c2
-rw-r--r--fs/nfsd/filecache.c33
-rw-r--r--fs/nfsd/filecache.h3
-rw-r--r--fs/nfsd/nfssvc.c1
4 files changed, 25 insertions, 14 deletions
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 052fac64b578..15422c951fd1 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -240,7 +240,7 @@ static void expkey_flush(void)
240 * destroyed while we're in the middle of flushing. 240 * destroyed while we're in the middle of flushing.
241 */ 241 */
242 mutex_lock(&nfsd_mutex); 242 mutex_lock(&nfsd_mutex);
243 nfsd_file_cache_purge(); 243 nfsd_file_cache_purge(current->nsproxy->net_ns);
244 mutex_unlock(&nfsd_mutex); 244 mutex_unlock(&nfsd_mutex);
245} 245}
246 246
diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c
index 2e1a972231e5..da9e790a055e 100644
--- a/fs/nfsd/filecache.c
+++ b/fs/nfsd/filecache.c
@@ -16,6 +16,7 @@
16#include "vfs.h" 16#include "vfs.h"
17#include "nfsd.h" 17#include "nfsd.h"
18#include "nfsfh.h" 18#include "nfsfh.h"
19#include "netns.h"
19#include "filecache.h" 20#include "filecache.h"
20#include "trace.h" 21#include "trace.h"
21 22
@@ -167,7 +168,8 @@ nfsd_file_mark_find_or_create(struct nfsd_file *nf)
167} 168}
168 169
169static struct nfsd_file * 170static struct nfsd_file *
170nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval) 171nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval,
172 struct net *net)
171{ 173{
172 struct nfsd_file *nf; 174 struct nfsd_file *nf;
173 175
@@ -177,6 +179,7 @@ nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval)
177 INIT_LIST_HEAD(&nf->nf_lru); 179 INIT_LIST_HEAD(&nf->nf_lru);
178 nf->nf_file = NULL; 180 nf->nf_file = NULL;
179 nf->nf_cred = get_current_cred(); 181 nf->nf_cred = get_current_cred();
182 nf->nf_net = net;
180 nf->nf_flags = 0; 183 nf->nf_flags = 0;
181 nf->nf_inode = inode; 184 nf->nf_inode = inode;
182 nf->nf_hashval = hashval; 185 nf->nf_hashval = hashval;
@@ -607,10 +610,11 @@ out_err:
607 * Note this can deadlock with nfsd_file_lru_cb. 610 * Note this can deadlock with nfsd_file_lru_cb.
608 */ 611 */
609void 612void
610nfsd_file_cache_purge(void) 613nfsd_file_cache_purge(struct net *net)
611{ 614{
612 unsigned int i; 615 unsigned int i;
613 struct nfsd_file *nf; 616 struct nfsd_file *nf;
617 struct hlist_node *next;
614 LIST_HEAD(dispose); 618 LIST_HEAD(dispose);
615 bool del; 619 bool del;
616 620
@@ -618,10 +622,12 @@ nfsd_file_cache_purge(void)
618 return; 622 return;
619 623
620 for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) { 624 for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) {
621 spin_lock(&nfsd_file_hashtbl[i].nfb_lock); 625 struct nfsd_fcache_bucket *nfb = &nfsd_file_hashtbl[i];
622 while(!hlist_empty(&nfsd_file_hashtbl[i].nfb_head)) { 626
623 nf = hlist_entry(nfsd_file_hashtbl[i].nfb_head.first, 627 spin_lock(&nfb->nfb_lock);
624 struct nfsd_file, nf_node); 628 hlist_for_each_entry_safe(nf, next, &nfb->nfb_head, nf_node) {
629 if (net && nf->nf_net != net)
630 continue;
625 del = nfsd_file_unhash_and_release_locked(nf, &dispose); 631 del = nfsd_file_unhash_and_release_locked(nf, &dispose);
626 632
627 /* 633 /*
@@ -630,7 +636,7 @@ nfsd_file_cache_purge(void)
630 */ 636 */
631 WARN_ON_ONCE(!del); 637 WARN_ON_ONCE(!del);
632 } 638 }
633 spin_unlock(&nfsd_file_hashtbl[i].nfb_lock); 639 spin_unlock(&nfb->nfb_lock);
634 nfsd_file_dispose_list(&dispose); 640 nfsd_file_dispose_list(&dispose);
635 } 641 }
636} 642}
@@ -649,7 +655,7 @@ nfsd_file_cache_shutdown(void)
649 * calling nfsd_file_cache_purge 655 * calling nfsd_file_cache_purge
650 */ 656 */
651 cancel_delayed_work_sync(&nfsd_filecache_laundrette); 657 cancel_delayed_work_sync(&nfsd_filecache_laundrette);
652 nfsd_file_cache_purge(); 658 nfsd_file_cache_purge(NULL);
653 list_lru_destroy(&nfsd_file_lru); 659 list_lru_destroy(&nfsd_file_lru);
654 rcu_barrier(); 660 rcu_barrier();
655 fsnotify_put_group(nfsd_file_fsnotify_group); 661 fsnotify_put_group(nfsd_file_fsnotify_group);
@@ -685,7 +691,7 @@ nfsd_match_cred(const struct cred *c1, const struct cred *c2)
685 691
686static struct nfsd_file * 692static struct nfsd_file *
687nfsd_file_find_locked(struct inode *inode, unsigned int may_flags, 693nfsd_file_find_locked(struct inode *inode, unsigned int may_flags,
688 unsigned int hashval) 694 unsigned int hashval, struct net *net)
689{ 695{
690 struct nfsd_file *nf; 696 struct nfsd_file *nf;
691 unsigned char need = may_flags & NFSD_FILE_MAY_MASK; 697 unsigned char need = may_flags & NFSD_FILE_MAY_MASK;
@@ -696,6 +702,8 @@ nfsd_file_find_locked(struct inode *inode, unsigned int may_flags,
696 continue; 702 continue;
697 if (nf->nf_inode != inode) 703 if (nf->nf_inode != inode)
698 continue; 704 continue;
705 if (nf->nf_net != net)
706 continue;
699 if (!nfsd_match_cred(nf->nf_cred, current_cred())) 707 if (!nfsd_match_cred(nf->nf_cred, current_cred()))
700 continue; 708 continue;
701 if (nfsd_file_get(nf) != NULL) 709 if (nfsd_file_get(nf) != NULL)
@@ -738,6 +746,7 @@ nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
738 unsigned int may_flags, struct nfsd_file **pnf) 746 unsigned int may_flags, struct nfsd_file **pnf)
739{ 747{
740 __be32 status; 748 __be32 status;
749 struct net *net = SVC_NET(rqstp);
741 struct nfsd_file *nf, *new; 750 struct nfsd_file *nf, *new;
742 struct inode *inode; 751 struct inode *inode;
743 unsigned int hashval; 752 unsigned int hashval;
@@ -752,12 +761,12 @@ nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
752 hashval = (unsigned int)hash_long(inode->i_ino, NFSD_FILE_HASH_BITS); 761 hashval = (unsigned int)hash_long(inode->i_ino, NFSD_FILE_HASH_BITS);
753retry: 762retry:
754 rcu_read_lock(); 763 rcu_read_lock();
755 nf = nfsd_file_find_locked(inode, may_flags, hashval); 764 nf = nfsd_file_find_locked(inode, may_flags, hashval, net);
756 rcu_read_unlock(); 765 rcu_read_unlock();
757 if (nf) 766 if (nf)
758 goto wait_for_construction; 767 goto wait_for_construction;
759 768
760 new = nfsd_file_alloc(inode, may_flags, hashval); 769 new = nfsd_file_alloc(inode, may_flags, hashval, net);
761 if (!new) { 770 if (!new) {
762 trace_nfsd_file_acquire(rqstp, hashval, inode, may_flags, 771 trace_nfsd_file_acquire(rqstp, hashval, inode, may_flags,
763 NULL, nfserr_jukebox); 772 NULL, nfserr_jukebox);
@@ -765,7 +774,7 @@ retry:
765 } 774 }
766 775
767 spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock); 776 spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock);
768 nf = nfsd_file_find_locked(inode, may_flags, hashval); 777 nf = nfsd_file_find_locked(inode, may_flags, hashval, net);
769 if (nf == NULL) 778 if (nf == NULL)
770 goto open_file; 779 goto open_file;
771 spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock); 780 spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock);
diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h
index 0c0c67166b87..851d9abf54c2 100644
--- a/fs/nfsd/filecache.h
+++ b/fs/nfsd/filecache.h
@@ -34,6 +34,7 @@ struct nfsd_file {
34 struct rcu_head nf_rcu; 34 struct rcu_head nf_rcu;
35 struct file *nf_file; 35 struct file *nf_file;
36 const struct cred *nf_cred; 36 const struct cred *nf_cred;
37 struct net *nf_net;
37#define NFSD_FILE_HASHED (0) 38#define NFSD_FILE_HASHED (0)
38#define NFSD_FILE_PENDING (1) 39#define NFSD_FILE_PENDING (1)
39#define NFSD_FILE_BREAK_READ (2) 40#define NFSD_FILE_BREAK_READ (2)
@@ -48,7 +49,7 @@ struct nfsd_file {
48}; 49};
49 50
50int nfsd_file_cache_init(void); 51int nfsd_file_cache_init(void);
51void nfsd_file_cache_purge(void); 52void nfsd_file_cache_purge(struct net *);
52void nfsd_file_cache_shutdown(void); 53void nfsd_file_cache_shutdown(void);
53void nfsd_file_put(struct nfsd_file *nf); 54void nfsd_file_put(struct nfsd_file *nf);
54struct nfsd_file *nfsd_file_get(struct nfsd_file *nf); 55struct nfsd_file *nfsd_file_get(struct nfsd_file *nf);
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index d02712ca2685..b944553c6927 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -387,6 +387,7 @@ static void nfsd_shutdown_net(struct net *net)
387{ 387{
388 struct nfsd_net *nn = net_generic(net, nfsd_net_id); 388 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
389 389
390 nfsd_file_cache_purge(net);
390 nfs4_state_shutdown_net(net); 391 nfs4_state_shutdown_net(net);
391 if (nn->lockd_up) { 392 if (nn->lockd_up) {
392 lockd_down(net); 393 lockd_down(net);