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