filecache.c (bb13f35b96f4c83dc4015d71fa2b543c665fbdae) filecache.c (5e113224c17e2fb156b785ddbbc48a0209fddb0c)
1/*
2 * Open file cache.
3 *
4 * (c) 2015 - Jeff Layton <jeff.layton@primarydata.com>
5 */
6
7#include <linux/hash.h>
8#include <linux/slab.h>
9#include <linux/file.h>
10#include <linux/sched.h>
11#include <linux/list_lru.h>
12#include <linux/fsnotify_backend.h>
13#include <linux/fsnotify.h>
14#include <linux/seq_file.h>
15
16#include "vfs.h"
17#include "nfsd.h"
18#include "nfsfh.h"
1/*
2 * Open file cache.
3 *
4 * (c) 2015 - Jeff Layton <jeff.layton@primarydata.com>
5 */
6
7#include <linux/hash.h>
8#include <linux/slab.h>
9#include <linux/file.h>
10#include <linux/sched.h>
11#include <linux/list_lru.h>
12#include <linux/fsnotify_backend.h>
13#include <linux/fsnotify.h>
14#include <linux/seq_file.h>
15
16#include "vfs.h"
17#include "nfsd.h"
18#include "nfsfh.h"
19#include "netns.h"
19#include "filecache.h"
20#include "trace.h"
21
22#define NFSDDBG_FACILITY NFSDDBG_FH
23
24/* FIXME: dynamically size this for the machine somehow? */
25#define NFSD_FILE_HASH_BITS 12
26#define NFSD_FILE_HASH_SIZE (1 << NFSD_FILE_HASH_BITS)

--- 135 unchanged lines hidden (view full) ---

162 else
163 fsnotify_put_mark(&new->nfm_mark);
164 } while (unlikely(err == -EEXIST));
165
166 return nfm;
167}
168
169static struct nfsd_file *
20#include "filecache.h"
21#include "trace.h"
22
23#define NFSDDBG_FACILITY NFSDDBG_FH
24
25/* FIXME: dynamically size this for the machine somehow? */
26#define NFSD_FILE_HASH_BITS 12
27#define NFSD_FILE_HASH_SIZE (1 << NFSD_FILE_HASH_BITS)

--- 135 unchanged lines hidden (view full) ---

163 else
164 fsnotify_put_mark(&new->nfm_mark);
165 } while (unlikely(err == -EEXIST));
166
167 return nfm;
168}
169
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{
172 struct nfsd_file *nf;
173
174 nf = kmem_cache_alloc(nfsd_file_slab, GFP_KERNEL);
175 if (nf) {
176 INIT_HLIST_NODE(&nf->nf_node);
177 INIT_LIST_HEAD(&nf->nf_lru);
178 nf->nf_file = NULL;
179 nf->nf_cred = get_current_cred();
173{
174 struct nfsd_file *nf;
175
176 nf = kmem_cache_alloc(nfsd_file_slab, GFP_KERNEL);
177 if (nf) {
178 INIT_HLIST_NODE(&nf->nf_node);
179 INIT_LIST_HEAD(&nf->nf_lru);
180 nf->nf_file = NULL;
181 nf->nf_cred = get_current_cred();
182 nf->nf_net = net;
180 nf->nf_flags = 0;
181 nf->nf_inode = inode;
182 nf->nf_hashval = hashval;
183 atomic_set(&nf->nf_ref, 1);
184 nf->nf_may = may & NFSD_FILE_MAY_MASK;
185 if (may & NFSD_MAY_NOT_BREAK_LEASE) {
186 if (may & NFSD_MAY_WRITE)
187 __set_bit(NFSD_FILE_BREAK_WRITE, &nf->nf_flags);

--- 414 unchanged lines hidden (view full) ---

602 nfsd_file_hashtbl = NULL;
603 goto out;
604}
605
606/*
607 * Note this can deadlock with nfsd_file_lru_cb.
608 */
609void
183 nf->nf_flags = 0;
184 nf->nf_inode = inode;
185 nf->nf_hashval = hashval;
186 atomic_set(&nf->nf_ref, 1);
187 nf->nf_may = may & NFSD_FILE_MAY_MASK;
188 if (may & NFSD_MAY_NOT_BREAK_LEASE) {
189 if (may & NFSD_MAY_WRITE)
190 __set_bit(NFSD_FILE_BREAK_WRITE, &nf->nf_flags);

--- 414 unchanged lines hidden (view full) ---

605 nfsd_file_hashtbl = NULL;
606 goto out;
607}
608
609/*
610 * Note this can deadlock with nfsd_file_lru_cb.
611 */
612void
610nfsd_file_cache_purge(void)
613nfsd_file_cache_purge(struct net *net)
611{
612 unsigned int i;
613 struct nfsd_file *nf;
614{
615 unsigned int i;
616 struct nfsd_file *nf;
617 struct hlist_node *next;
614 LIST_HEAD(dispose);
615 bool del;
616
617 if (!nfsd_file_hashtbl)
618 return;
619
620 for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) {
618 LIST_HEAD(dispose);
619 bool del;
620
621 if (!nfsd_file_hashtbl)
622 return;
623
624 for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) {
621 spin_lock(&nfsd_file_hashtbl[i].nfb_lock);
622 while(!hlist_empty(&nfsd_file_hashtbl[i].nfb_head)) {
623 nf = hlist_entry(nfsd_file_hashtbl[i].nfb_head.first,
624 struct nfsd_file, nf_node);
625 struct nfsd_fcache_bucket *nfb = &nfsd_file_hashtbl[i];
626
627 spin_lock(&nfb->nfb_lock);
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);
626
627 /*
628 * Deadlock detected! Something marked this entry as
629 * unhased, but hasn't removed it from the hash list.
630 */
631 WARN_ON_ONCE(!del);
632 }
631 del = nfsd_file_unhash_and_release_locked(nf, &dispose);
632
633 /*
634 * Deadlock detected! Something marked this entry as
635 * unhased, but hasn't removed it from the hash list.
636 */
637 WARN_ON_ONCE(!del);
638 }
633 spin_unlock(&nfsd_file_hashtbl[i].nfb_lock);
639 spin_unlock(&nfb->nfb_lock);
634 nfsd_file_dispose_list(&dispose);
635 }
636}
637
638void
639nfsd_file_cache_shutdown(void)
640{
641 LIST_HEAD(dispose);
642
643 set_bit(NFSD_FILE_SHUTDOWN, &nfsd_file_lru_flags);
644
645 lease_unregister_notifier(&nfsd_file_lease_notifier);
646 unregister_shrinker(&nfsd_file_shrinker);
647 /*
648 * make sure all callers of nfsd_file_lru_cb are done before
649 * calling nfsd_file_cache_purge
650 */
651 cancel_delayed_work_sync(&nfsd_filecache_laundrette);
640 nfsd_file_dispose_list(&dispose);
641 }
642}
643
644void
645nfsd_file_cache_shutdown(void)
646{
647 LIST_HEAD(dispose);
648
649 set_bit(NFSD_FILE_SHUTDOWN, &nfsd_file_lru_flags);
650
651 lease_unregister_notifier(&nfsd_file_lease_notifier);
652 unregister_shrinker(&nfsd_file_shrinker);
653 /*
654 * make sure all callers of nfsd_file_lru_cb are done before
655 * calling nfsd_file_cache_purge
656 */
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);
654 rcu_barrier();
655 fsnotify_put_group(nfsd_file_fsnotify_group);
656 nfsd_file_fsnotify_group = NULL;
657 kmem_cache_destroy(nfsd_file_slab);
658 nfsd_file_slab = NULL;
659 fsnotify_wait_marks_destroyed();
660 kmem_cache_destroy(nfsd_file_mark_slab);

--- 19 unchanged lines hidden (view full) ---

680 if (!gid_eq(c1->group_info->gid[i], c2->group_info->gid[i]))
681 return false;
682 }
683 return true;
684}
685
686static struct nfsd_file *
687nfsd_file_find_locked(struct inode *inode, unsigned int may_flags,
659 list_lru_destroy(&nfsd_file_lru);
660 rcu_barrier();
661 fsnotify_put_group(nfsd_file_fsnotify_group);
662 nfsd_file_fsnotify_group = NULL;
663 kmem_cache_destroy(nfsd_file_slab);
664 nfsd_file_slab = NULL;
665 fsnotify_wait_marks_destroyed();
666 kmem_cache_destroy(nfsd_file_mark_slab);

--- 19 unchanged lines hidden (view full) ---

686 if (!gid_eq(c1->group_info->gid[i], c2->group_info->gid[i]))
687 return false;
688 }
689 return true;
690}
691
692static struct nfsd_file *
693nfsd_file_find_locked(struct inode *inode, unsigned int may_flags,
688 unsigned int hashval)
694 unsigned int hashval, struct net *net)
689{
690 struct nfsd_file *nf;
691 unsigned char need = may_flags & NFSD_FILE_MAY_MASK;
692
693 hlist_for_each_entry_rcu(nf, &nfsd_file_hashtbl[hashval].nfb_head,
694 nf_node) {
695 if ((need & nf->nf_may) != need)
696 continue;
697 if (nf->nf_inode != inode)
698 continue;
695{
696 struct nfsd_file *nf;
697 unsigned char need = may_flags & NFSD_FILE_MAY_MASK;
698
699 hlist_for_each_entry_rcu(nf, &nfsd_file_hashtbl[hashval].nfb_head,
700 nf_node) {
701 if ((need & nf->nf_may) != need)
702 continue;
703 if (nf->nf_inode != inode)
704 continue;
705 if (nf->nf_net != net)
706 continue;
699 if (!nfsd_match_cred(nf->nf_cred, current_cred()))
700 continue;
701 if (nfsd_file_get(nf) != NULL)
702 return nf;
703 }
704 return NULL;
705}
706

--- 26 unchanged lines hidden (view full) ---

733 return ret;
734}
735
736__be32
737nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
738 unsigned int may_flags, struct nfsd_file **pnf)
739{
740 __be32 status;
707 if (!nfsd_match_cred(nf->nf_cred, current_cred()))
708 continue;
709 if (nfsd_file_get(nf) != NULL)
710 return nf;
711 }
712 return NULL;
713}
714

--- 26 unchanged lines hidden (view full) ---

741 return ret;
742}
743
744__be32
745nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
746 unsigned int may_flags, struct nfsd_file **pnf)
747{
748 __be32 status;
749 struct net *net = SVC_NET(rqstp);
741 struct nfsd_file *nf, *new;
742 struct inode *inode;
743 unsigned int hashval;
744
745 /* FIXME: skip this if fh_dentry is already set? */
746 status = fh_verify(rqstp, fhp, S_IFREG,
747 may_flags|NFSD_MAY_OWNER_OVERRIDE);
748 if (status != nfs_ok)
749 return status;
750
751 inode = d_inode(fhp->fh_dentry);
752 hashval = (unsigned int)hash_long(inode->i_ino, NFSD_FILE_HASH_BITS);
753retry:
754 rcu_read_lock();
750 struct nfsd_file *nf, *new;
751 struct inode *inode;
752 unsigned int hashval;
753
754 /* FIXME: skip this if fh_dentry is already set? */
755 status = fh_verify(rqstp, fhp, S_IFREG,
756 may_flags|NFSD_MAY_OWNER_OVERRIDE);
757 if (status != nfs_ok)
758 return status;
759
760 inode = d_inode(fhp->fh_dentry);
761 hashval = (unsigned int)hash_long(inode->i_ino, NFSD_FILE_HASH_BITS);
762retry:
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();
757 if (nf)
758 goto wait_for_construction;
759
765 rcu_read_unlock();
766 if (nf)
767 goto wait_for_construction;
768
760 new = nfsd_file_alloc(inode, may_flags, hashval);
769 new = nfsd_file_alloc(inode, may_flags, hashval, net);
761 if (!new) {
762 trace_nfsd_file_acquire(rqstp, hashval, inode, may_flags,
763 NULL, nfserr_jukebox);
764 return nfserr_jukebox;
765 }
766
767 spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock);
770 if (!new) {
771 trace_nfsd_file_acquire(rqstp, hashval, inode, may_flags,
772 NULL, nfserr_jukebox);
773 return nfserr_jukebox;
774 }
775
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)
770 goto open_file;
771 spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock);
772 nfsd_file_slab_free(&new->nf_rcu);
773
774wait_for_construction:
775 wait_on_bit(&nf->nf_flags, NFSD_FILE_PENDING, TASK_UNINTERRUPTIBLE);
776

--- 108 unchanged lines hidden ---
778 if (nf == NULL)
779 goto open_file;
780 spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock);
781 nfsd_file_slab_free(&new->nf_rcu);
782
783wait_for_construction:
784 wait_on_bit(&nf->nf_flags, NFSD_FILE_PENDING, TASK_UNINTERRUPTIBLE);
785

--- 108 unchanged lines hidden ---