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 <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
Родитель
c7b824c3d0
Коммит
fc22945ecc
|
@ -13,6 +13,7 @@
|
|||
#include <linux/fsnotify_backend.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/rhashtable.h>
|
||||
|
||||
#include "vfs.h"
|
||||
#include "nfsd.h"
|
||||
|
@ -63,6 +64,136 @@ static unsigned long nfsd_file_flags;
|
|||
static struct fsnotify_group *nfsd_file_fsnotify_group;
|
||||
static atomic_long_t nfsd_filecache_count;
|
||||
static struct delayed_work nfsd_filecache_laundrette;
|
||||
static struct rhashtable nfsd_file_rhash_tbl
|
||||
____cacheline_aligned_in_smp;
|
||||
|
||||
enum nfsd_file_lookup_type {
|
||||
NFSD_FILE_KEY_INODE,
|
||||
NFSD_FILE_KEY_FULL,
|
||||
};
|
||||
|
||||
struct nfsd_file_lookup_key {
|
||||
struct inode *inode;
|
||||
struct net *net;
|
||||
const struct cred *cred;
|
||||
unsigned char need;
|
||||
enum nfsd_file_lookup_type type;
|
||||
};
|
||||
|
||||
/*
|
||||
* The returned hash value is based solely on the address of an in-code
|
||||
* inode, a pointer to a slab-allocated object. The entropy in such a
|
||||
* pointer is concentrated in its middle bits.
|
||||
*/
|
||||
static u32 nfsd_file_inode_hash(const struct inode *inode, u32 seed)
|
||||
{
|
||||
unsigned long ptr = (unsigned long)inode;
|
||||
u32 k;
|
||||
|
||||
k = ptr >> L1_CACHE_SHIFT;
|
||||
k &= 0x00ffffff;
|
||||
return jhash2(&k, 1, seed);
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_file_key_hashfn - Compute the hash value of a lookup key
|
||||
* @data: key on which to compute the hash value
|
||||
* @len: rhash table's key_len parameter (unused)
|
||||
* @seed: rhash table's random seed of the day
|
||||
*
|
||||
* Return value:
|
||||
* Computed 32-bit hash value
|
||||
*/
|
||||
static u32 nfsd_file_key_hashfn(const void *data, u32 len, u32 seed)
|
||||
{
|
||||
const struct nfsd_file_lookup_key *key = data;
|
||||
|
||||
return nfsd_file_inode_hash(key->inode, seed);
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_file_obj_hashfn - Compute the hash value of an nfsd_file
|
||||
* @data: object on which to compute the hash value
|
||||
* @len: rhash table's key_len parameter (unused)
|
||||
* @seed: rhash table's random seed of the day
|
||||
*
|
||||
* Return value:
|
||||
* Computed 32-bit hash value
|
||||
*/
|
||||
static u32 nfsd_file_obj_hashfn(const void *data, u32 len, u32 seed)
|
||||
{
|
||||
const struct nfsd_file *nf = data;
|
||||
|
||||
return nfsd_file_inode_hash(nf->nf_inode, seed);
|
||||
}
|
||||
|
||||
static bool
|
||||
nfsd_match_cred(const struct cred *c1, const struct cred *c2)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!uid_eq(c1->fsuid, c2->fsuid))
|
||||
return false;
|
||||
if (!gid_eq(c1->fsgid, c2->fsgid))
|
||||
return false;
|
||||
if (c1->group_info == NULL || c2->group_info == NULL)
|
||||
return c1->group_info == c2->group_info;
|
||||
if (c1->group_info->ngroups != c2->group_info->ngroups)
|
||||
return false;
|
||||
for (i = 0; i < c1->group_info->ngroups; i++) {
|
||||
if (!gid_eq(c1->group_info->gid[i], c2->group_info->gid[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_file_obj_cmpfn - Match a cache item against search criteria
|
||||
* @arg: search criteria
|
||||
* @ptr: cache item to check
|
||||
*
|
||||
* Return values:
|
||||
* %0 - Item matches search criteria
|
||||
* %1 - Item does not match search criteria
|
||||
*/
|
||||
static int nfsd_file_obj_cmpfn(struct rhashtable_compare_arg *arg,
|
||||
const void *ptr)
|
||||
{
|
||||
const struct nfsd_file_lookup_key *key = arg->key;
|
||||
const struct nfsd_file *nf = ptr;
|
||||
|
||||
switch (key->type) {
|
||||
case NFSD_FILE_KEY_INODE:
|
||||
if (nf->nf_inode != key->inode)
|
||||
return 1;
|
||||
break;
|
||||
case NFSD_FILE_KEY_FULL:
|
||||
if (nf->nf_inode != key->inode)
|
||||
return 1;
|
||||
if (nf->nf_may != key->need)
|
||||
return 1;
|
||||
if (nf->nf_net != key->net)
|
||||
return 1;
|
||||
if (!nfsd_match_cred(nf->nf_cred, key->cred))
|
||||
return 1;
|
||||
if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0)
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rhashtable_params nfsd_file_rhash_params = {
|
||||
.key_len = sizeof_field(struct nfsd_file, nf_inode),
|
||||
.key_offset = offsetof(struct nfsd_file, nf_inode),
|
||||
.head_offset = offsetof(struct nfsd_file, nf_rhash),
|
||||
.hashfn = nfsd_file_key_hashfn,
|
||||
.obj_hashfn = nfsd_file_obj_hashfn,
|
||||
.obj_cmpfn = nfsd_file_obj_cmpfn,
|
||||
/* Reduce resizing churn on light workloads */
|
||||
.min_size = 512, /* buckets */
|
||||
.automatic_shrinking = true,
|
||||
};
|
||||
|
||||
static void
|
||||
nfsd_file_schedule_laundrette(void)
|
||||
|
@ -694,13 +825,18 @@ static const struct fsnotify_ops nfsd_file_fsnotify_ops = {
|
|||
int
|
||||
nfsd_file_cache_init(void)
|
||||
{
|
||||
int ret = -ENOMEM;
|
||||
int ret;
|
||||
unsigned int i;
|
||||
|
||||
lockdep_assert_held(&nfsd_mutex);
|
||||
if (test_and_set_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 1)
|
||||
return 0;
|
||||
|
||||
ret = rhashtable_init(&nfsd_file_rhash_tbl, &nfsd_file_rhash_params);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = -ENOMEM;
|
||||
nfsd_filecache_wq = alloc_workqueue("nfsd_filecache", 0, 0);
|
||||
if (!nfsd_filecache_wq)
|
||||
goto out;
|
||||
|
@ -778,6 +914,7 @@ out_err:
|
|||
nfsd_file_hashtbl = NULL;
|
||||
destroy_workqueue(nfsd_filecache_wq);
|
||||
nfsd_filecache_wq = NULL;
|
||||
rhashtable_destroy(&nfsd_file_rhash_tbl);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -903,6 +1040,7 @@ nfsd_file_cache_shutdown(void)
|
|||
nfsd_file_hashtbl = NULL;
|
||||
destroy_workqueue(nfsd_filecache_wq);
|
||||
nfsd_filecache_wq = NULL;
|
||||
rhashtable_destroy(&nfsd_file_rhash_tbl);
|
||||
|
||||
for_each_possible_cpu(i) {
|
||||
per_cpu(nfsd_file_cache_hits, i) = 0;
|
||||
|
@ -914,26 +1052,6 @@ nfsd_file_cache_shutdown(void)
|
|||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
nfsd_match_cred(const struct cred *c1, const struct cred *c2)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!uid_eq(c1->fsuid, c2->fsuid))
|
||||
return false;
|
||||
if (!gid_eq(c1->fsgid, c2->fsgid))
|
||||
return false;
|
||||
if (c1->group_info == NULL || c2->group_info == NULL)
|
||||
return c1->group_info == c2->group_info;
|
||||
if (c1->group_info->ngroups != c2->group_info->ngroups)
|
||||
return false;
|
||||
for (i = 0; i < c1->group_info->ngroups; i++) {
|
||||
if (!gid_eq(c1->group_info->gid[i], c2->group_info->gid[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct nfsd_file *
|
||||
nfsd_file_find_locked(struct inode *inode, unsigned int may_flags,
|
||||
unsigned int hashval, struct net *net)
|
||||
|
|
|
@ -29,6 +29,7 @@ struct nfsd_file_mark {
|
|||
* never be dereferenced, only used for comparison.
|
||||
*/
|
||||
struct nfsd_file {
|
||||
struct rhash_head nf_rhash;
|
||||
struct hlist_node nf_node;
|
||||
struct list_head nf_lru;
|
||||
struct rcu_head nf_rcu;
|
||||
|
|
Загрузка…
Ссылка в новой задаче