Skip to content

Commit fc22945

Browse files
committed
NFSD: Set up an rhashtable for the filecache
Add code to initialize and tear down an rhashtable. The rhashtable is not used yet. Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: Chuck Lever <[email protected]>
1 parent c7b824c commit fc22945

File tree

2 files changed

+140
-21
lines changed

2 files changed

+140
-21
lines changed

fs/nfsd/filecache.c

Lines changed: 139 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
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;
6364
static struct fsnotify_group *nfsd_file_fsnotify_group;
6465
static atomic_long_t nfsd_filecache_count;
6566
static 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

67198
static void
68199
nfsd_file_schedule_laundrette(void)
@@ -694,13 +825,18 @@ static const struct fsnotify_ops nfsd_file_fsnotify_ops = {
694825
int
695826
nfsd_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-
9371055
static struct nfsd_file *
9381056
nfsd_file_find_locked(struct inode *inode, unsigned int may_flags,
9391057
unsigned int hashval, struct net *net)

fs/nfsd/filecache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ struct nfsd_file_mark {
2929
* never be dereferenced, only used for comparison.
3030
*/
3131
struct nfsd_file {
32+
struct rhash_head nf_rhash;
3233
struct hlist_node nf_node;
3334
struct list_head nf_lru;
3435
struct rcu_head nf_rcu;

0 commit comments

Comments
 (0)