1313#include <linux/fsnotify_backend.h>
1414#include <linux/fsnotify.h>
1515#include <linux/seq_file.h>
16+ #include <linux/rhashtable.h>
1617
1718#include "vfs.h"
1819#include "nfsd.h"
@@ -63,6 +64,136 @@ static unsigned long nfsd_file_flags;
6364static struct fsnotify_group * nfsd_file_fsnotify_group ;
6465static atomic_long_t nfsd_filecache_count ;
6566static struct delayed_work nfsd_filecache_laundrette ;
67+ static struct rhashtable nfsd_file_rhash_tbl
68+ ____cacheline_aligned_in_smp ;
69+
70+ enum nfsd_file_lookup_type {
71+ NFSD_FILE_KEY_INODE ,
72+ NFSD_FILE_KEY_FULL ,
73+ };
74+
75+ struct nfsd_file_lookup_key {
76+ struct inode * inode ;
77+ struct net * net ;
78+ const struct cred * cred ;
79+ unsigned char need ;
80+ enum nfsd_file_lookup_type type ;
81+ };
82+
83+ /*
84+ * The returned hash value is based solely on the address of an in-code
85+ * inode, a pointer to a slab-allocated object. The entropy in such a
86+ * pointer is concentrated in its middle bits.
87+ */
88+ static u32 nfsd_file_inode_hash (const struct inode * inode , u32 seed )
89+ {
90+ unsigned long ptr = (unsigned long )inode ;
91+ u32 k ;
92+
93+ k = ptr >> L1_CACHE_SHIFT ;
94+ k &= 0x00ffffff ;
95+ return jhash2 (& k , 1 , seed );
96+ }
97+
98+ /**
99+ * nfsd_file_key_hashfn - Compute the hash value of a lookup key
100+ * @data: key on which to compute the hash value
101+ * @len: rhash table's key_len parameter (unused)
102+ * @seed: rhash table's random seed of the day
103+ *
104+ * Return value:
105+ * Computed 32-bit hash value
106+ */
107+ static u32 nfsd_file_key_hashfn (const void * data , u32 len , u32 seed )
108+ {
109+ const struct nfsd_file_lookup_key * key = data ;
110+
111+ return nfsd_file_inode_hash (key -> inode , seed );
112+ }
113+
114+ /**
115+ * nfsd_file_obj_hashfn - Compute the hash value of an nfsd_file
116+ * @data: object on which to compute the hash value
117+ * @len: rhash table's key_len parameter (unused)
118+ * @seed: rhash table's random seed of the day
119+ *
120+ * Return value:
121+ * Computed 32-bit hash value
122+ */
123+ static u32 nfsd_file_obj_hashfn (const void * data , u32 len , u32 seed )
124+ {
125+ const struct nfsd_file * nf = data ;
126+
127+ return nfsd_file_inode_hash (nf -> nf_inode , seed );
128+ }
129+
130+ static bool
131+ nfsd_match_cred (const struct cred * c1 , const struct cred * c2 )
132+ {
133+ int i ;
134+
135+ if (!uid_eq (c1 -> fsuid , c2 -> fsuid ))
136+ return false;
137+ if (!gid_eq (c1 -> fsgid , c2 -> fsgid ))
138+ return false;
139+ if (c1 -> group_info == NULL || c2 -> group_info == NULL )
140+ return c1 -> group_info == c2 -> group_info ;
141+ if (c1 -> group_info -> ngroups != c2 -> group_info -> ngroups )
142+ return false;
143+ for (i = 0 ; i < c1 -> group_info -> ngroups ; i ++ ) {
144+ if (!gid_eq (c1 -> group_info -> gid [i ], c2 -> group_info -> gid [i ]))
145+ return false;
146+ }
147+ return true;
148+ }
149+
150+ /**
151+ * nfsd_file_obj_cmpfn - Match a cache item against search criteria
152+ * @arg: search criteria
153+ * @ptr: cache item to check
154+ *
155+ * Return values:
156+ * %0 - Item matches search criteria
157+ * %1 - Item does not match search criteria
158+ */
159+ static int nfsd_file_obj_cmpfn (struct rhashtable_compare_arg * arg ,
160+ const void * ptr )
161+ {
162+ const struct nfsd_file_lookup_key * key = arg -> key ;
163+ const struct nfsd_file * nf = ptr ;
164+
165+ switch (key -> type ) {
166+ case NFSD_FILE_KEY_INODE :
167+ if (nf -> nf_inode != key -> inode )
168+ return 1 ;
169+ break ;
170+ case NFSD_FILE_KEY_FULL :
171+ if (nf -> nf_inode != key -> inode )
172+ return 1 ;
173+ if (nf -> nf_may != key -> need )
174+ return 1 ;
175+ if (nf -> nf_net != key -> net )
176+ return 1 ;
177+ if (!nfsd_match_cred (nf -> nf_cred , key -> cred ))
178+ return 1 ;
179+ if (test_bit (NFSD_FILE_HASHED , & nf -> nf_flags ) == 0 )
180+ return 1 ;
181+ break ;
182+ }
183+ return 0 ;
184+ }
185+
186+ static const struct rhashtable_params nfsd_file_rhash_params = {
187+ .key_len = sizeof_field (struct nfsd_file , nf_inode ),
188+ .key_offset = offsetof(struct nfsd_file , nf_inode ),
189+ .head_offset = offsetof(struct nfsd_file , nf_rhash ),
190+ .hashfn = nfsd_file_key_hashfn ,
191+ .obj_hashfn = nfsd_file_obj_hashfn ,
192+ .obj_cmpfn = nfsd_file_obj_cmpfn ,
193+ /* Reduce resizing churn on light workloads */
194+ .min_size = 512 , /* buckets */
195+ .automatic_shrinking = true,
196+ };
66197
67198static void
68199nfsd_file_schedule_laundrette (void )
@@ -694,13 +825,18 @@ static const struct fsnotify_ops nfsd_file_fsnotify_ops = {
694825int
695826nfsd_file_cache_init (void )
696827{
697- int ret = - ENOMEM ;
828+ int ret ;
698829 unsigned int i ;
699830
700831 lockdep_assert_held (& nfsd_mutex );
701832 if (test_and_set_bit (NFSD_FILE_CACHE_UP , & nfsd_file_flags ) == 1 )
702833 return 0 ;
703834
835+ ret = rhashtable_init (& nfsd_file_rhash_tbl , & nfsd_file_rhash_params );
836+ if (ret )
837+ return ret ;
838+
839+ ret = - ENOMEM ;
704840 nfsd_filecache_wq = alloc_workqueue ("nfsd_filecache" , 0 , 0 );
705841 if (!nfsd_filecache_wq )
706842 goto out ;
@@ -778,6 +914,7 @@ nfsd_file_cache_init(void)
778914 nfsd_file_hashtbl = NULL ;
779915 destroy_workqueue (nfsd_filecache_wq );
780916 nfsd_filecache_wq = NULL ;
917+ rhashtable_destroy (& nfsd_file_rhash_tbl );
781918 goto out ;
782919}
783920
@@ -903,6 +1040,7 @@ nfsd_file_cache_shutdown(void)
9031040 nfsd_file_hashtbl = NULL ;
9041041 destroy_workqueue (nfsd_filecache_wq );
9051042 nfsd_filecache_wq = NULL ;
1043+ rhashtable_destroy (& nfsd_file_rhash_tbl );
9061044
9071045 for_each_possible_cpu (i ) {
9081046 per_cpu (nfsd_file_cache_hits , i ) = 0 ;
@@ -914,26 +1052,6 @@ nfsd_file_cache_shutdown(void)
9141052 }
9151053}
9161054
917- static bool
918- nfsd_match_cred (const struct cred * c1 , const struct cred * c2 )
919- {
920- int i ;
921-
922- if (!uid_eq (c1 -> fsuid , c2 -> fsuid ))
923- return false;
924- if (!gid_eq (c1 -> fsgid , c2 -> fsgid ))
925- return false;
926- if (c1 -> group_info == NULL || c2 -> group_info == NULL )
927- return c1 -> group_info == c2 -> group_info ;
928- if (c1 -> group_info -> ngroups != c2 -> group_info -> ngroups )
929- return false;
930- for (i = 0 ; i < c1 -> group_info -> ngroups ; i ++ ) {
931- if (!gid_eq (c1 -> group_info -> gid [i ], c2 -> group_info -> gid [i ]))
932- return false;
933- }
934- return true;
935- }
936-
9371055static struct nfsd_file *
9381056nfsd_file_find_locked (struct inode * inode , unsigned int may_flags ,
9391057 unsigned int hashval , struct net * net )
0 commit comments