diff options
author | Trond Myklebust <trondmy@gmail.com> | 2019-09-02 13:02:55 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2019-09-10 09:23:41 -0400 |
commit | 5e113224c17e2fb156b785ddbbc48a0209fddb0c (patch) | |
tree | dd3f0e389afb149e37ab9a96306f4f8445398169 | |
parent | 2b86e3aaf993a3ea6c73dfcf86143061a40c62e6 (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.c | 2 | ||||
-rw-r--r-- | fs/nfsd/filecache.c | 33 | ||||
-rw-r--r-- | fs/nfsd/filecache.h | 3 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 1 |
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 | ||
169 | static struct nfsd_file * | 170 | static struct nfsd_file * |
170 | nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval) | 171 | nfsd_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 | */ |
609 | void | 612 | void |
610 | nfsd_file_cache_purge(void) | 613 | nfsd_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 | ||
686 | static struct nfsd_file * | 692 | static struct nfsd_file * |
687 | nfsd_file_find_locked(struct inode *inode, unsigned int may_flags, | 693 | nfsd_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); |
753 | retry: | 762 | retry: |
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 | ||
50 | int nfsd_file_cache_init(void); | 51 | int nfsd_file_cache_init(void); |
51 | void nfsd_file_cache_purge(void); | 52 | void nfsd_file_cache_purge(struct net *); |
52 | void nfsd_file_cache_shutdown(void); | 53 | void nfsd_file_cache_shutdown(void); |
53 | void nfsd_file_put(struct nfsd_file *nf); | 54 | void nfsd_file_put(struct nfsd_file *nf); |
54 | struct nfsd_file *nfsd_file_get(struct nfsd_file *nf); | 55 | struct 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); |