Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Trond Myklebust and committed by
J. Bruce Fields
5e113224 2b86e3aa

+25 -14
+1 -1
fs/nfsd/export.c
··· 240 240 * destroyed while we're in the middle of flushing. 241 241 */ 242 242 mutex_lock(&nfsd_mutex); 243 - nfsd_file_cache_purge(); 243 + nfsd_file_cache_purge(current->nsproxy->net_ns); 244 244 mutex_unlock(&nfsd_mutex); 245 245 } 246 246
+21 -12
fs/nfsd/filecache.c
··· 16 16 #include "vfs.h" 17 17 #include "nfsd.h" 18 18 #include "nfsfh.h" 19 + #include "netns.h" 19 20 #include "filecache.h" 20 21 #include "trace.h" 21 22 ··· 168 167 } 169 168 170 169 static struct nfsd_file * 171 - nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval) 170 + nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval, 171 + struct net *net) 172 172 { 173 173 struct nfsd_file *nf; 174 174 ··· 179 177 INIT_LIST_HEAD(&nf->nf_lru); 180 178 nf->nf_file = NULL; 181 179 nf->nf_cred = get_current_cred(); 180 + nf->nf_net = net; 182 181 nf->nf_flags = 0; 183 182 nf->nf_inode = inode; 184 183 nf->nf_hashval = hashval; ··· 610 607 * Note this can deadlock with nfsd_file_lru_cb. 611 608 */ 612 609 void 613 - nfsd_file_cache_purge(void) 610 + nfsd_file_cache_purge(struct net *net) 614 611 { 615 612 unsigned int i; 616 613 struct nfsd_file *nf; 614 + struct hlist_node *next; 617 615 LIST_HEAD(dispose); 618 616 bool del; 619 617 ··· 622 618 return; 623 619 624 620 for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) { 625 - spin_lock(&nfsd_file_hashtbl[i].nfb_lock); 626 - while(!hlist_empty(&nfsd_file_hashtbl[i].nfb_head)) { 627 - nf = hlist_entry(nfsd_file_hashtbl[i].nfb_head.first, 628 - struct nfsd_file, nf_node); 621 + struct nfsd_fcache_bucket *nfb = &nfsd_file_hashtbl[i]; 622 + 623 + spin_lock(&nfb->nfb_lock); 624 + hlist_for_each_entry_safe(nf, next, &nfb->nfb_head, nf_node) { 625 + if (net && nf->nf_net != net) 626 + continue; 629 627 del = nfsd_file_unhash_and_release_locked(nf, &dispose); 630 628 631 629 /* ··· 636 630 */ 637 631 WARN_ON_ONCE(!del); 638 632 } 639 - spin_unlock(&nfsd_file_hashtbl[i].nfb_lock); 633 + spin_unlock(&nfb->nfb_lock); 640 634 nfsd_file_dispose_list(&dispose); 641 635 } 642 636 } ··· 655 649 * calling nfsd_file_cache_purge 656 650 */ 657 651 cancel_delayed_work_sync(&nfsd_filecache_laundrette); 658 - nfsd_file_cache_purge(); 652 + nfsd_file_cache_purge(NULL); 659 653 list_lru_destroy(&nfsd_file_lru); 660 654 rcu_barrier(); 661 655 fsnotify_put_group(nfsd_file_fsnotify_group); ··· 691 685 692 686 static struct nfsd_file * 693 687 nfsd_file_find_locked(struct inode *inode, unsigned int may_flags, 694 - unsigned int hashval) 688 + unsigned int hashval, struct net *net) 695 689 { 696 690 struct nfsd_file *nf; 697 691 unsigned char need = may_flags & NFSD_FILE_MAY_MASK; ··· 701 695 if ((need & nf->nf_may) != need) 702 696 continue; 703 697 if (nf->nf_inode != inode) 698 + continue; 699 + if (nf->nf_net != net) 704 700 continue; 705 701 if (!nfsd_match_cred(nf->nf_cred, current_cred())) 706 702 continue; ··· 746 738 unsigned int may_flags, struct nfsd_file **pnf) 747 739 { 748 740 __be32 status; 741 + struct net *net = SVC_NET(rqstp); 749 742 struct nfsd_file *nf, *new; 750 743 struct inode *inode; 751 744 unsigned int hashval; ··· 761 752 hashval = (unsigned int)hash_long(inode->i_ino, NFSD_FILE_HASH_BITS); 762 753 retry: 763 754 rcu_read_lock(); 764 - nf = nfsd_file_find_locked(inode, may_flags, hashval); 755 + nf = nfsd_file_find_locked(inode, may_flags, hashval, net); 765 756 rcu_read_unlock(); 766 757 if (nf) 767 758 goto wait_for_construction; 768 759 769 - new = nfsd_file_alloc(inode, may_flags, hashval); 760 + new = nfsd_file_alloc(inode, may_flags, hashval, net); 770 761 if (!new) { 771 762 trace_nfsd_file_acquire(rqstp, hashval, inode, may_flags, 772 763 NULL, nfserr_jukebox); ··· 774 765 } 775 766 776 767 spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock); 777 - nf = nfsd_file_find_locked(inode, may_flags, hashval); 768 + nf = nfsd_file_find_locked(inode, may_flags, hashval, net); 778 769 if (nf == NULL) 779 770 goto open_file; 780 771 spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock);
+2 -1
fs/nfsd/filecache.h
··· 34 34 struct rcu_head nf_rcu; 35 35 struct file *nf_file; 36 36 const struct cred *nf_cred; 37 + struct net *nf_net; 37 38 #define NFSD_FILE_HASHED (0) 38 39 #define NFSD_FILE_PENDING (1) 39 40 #define NFSD_FILE_BREAK_READ (2) ··· 49 48 }; 50 49 51 50 int nfsd_file_cache_init(void); 52 - void nfsd_file_cache_purge(void); 51 + void nfsd_file_cache_purge(struct net *); 53 52 void nfsd_file_cache_shutdown(void); 54 53 void nfsd_file_put(struct nfsd_file *nf); 55 54 struct nfsd_file *nfsd_file_get(struct nfsd_file *nf);
+1
fs/nfsd/nfssvc.c
··· 387 387 { 388 388 struct nfsd_net *nn = net_generic(net, nfsd_net_id); 389 389 390 + nfsd_file_cache_purge(net); 390 391 nfs4_state_shutdown_net(net); 391 392 if (nn->lockd_up) { 392 393 lockd_down(net);