From 79e7ffd01482d90cd5f6e98b5a362bbf95ea9b2c Mon Sep 17 00:00:00 2001 From: Frank van der Linden Date: Thu, 16 Jul 2020 21:35:29 +0000 Subject: [PATCH 2/2] nfsd: change file_hashtbl to an rhashtable file_hashtbl can grow quite large, so use rhashtable, which has automatic growing (and shrinking). Signed-off-by: Frank van der Linden --- fs/nfsd/nfs4state.c | 112 +++++++++++++++++++++++++++++--------------- fs/nfsd/nfsctl.c | 7 ++- fs/nfsd/nfsd.h | 4 ++ fs/nfsd/state.h | 3 +- 4 files changed, 86 insertions(+), 40 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 451a1071daf4..ff81c0136224 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -417,13 +417,33 @@ static void nfsd4_free_file_rcu(struct rcu_head *rcu) kmem_cache_free(file_slab, fp); } +/* hash table for nfs4_file */ +#define FILE_HASH_SIZE 256 + +static u32 nfsd4_file_key_hash(const void *data, u32 len, u32 seed); +static u32 nfsd4_file_obj_hash(const void *data, u32 len, u32 seed); +static int nfsd4_file_obj_compare(struct rhashtable_compare_arg *arg, + const void *obj); + +static const struct rhashtable_params file_rhashparams = { + .head_offset = offsetof(struct nfs4_file, fi_hash), + .min_size = FILE_HASH_SIZE, + .automatic_shrinking = true, + .hashfn = nfsd4_file_key_hash, + .obj_hashfn = nfsd4_file_obj_hash, + .obj_cmpfn = nfsd4_file_obj_compare, +}; + +struct rhashtable file_hashtbl; + void put_nfs4_file(struct nfs4_file *fi) { might_lock(&state_lock); if (refcount_dec_and_lock(&fi->fi_ref, &state_lock)) { - hlist_del_rcu(&fi->fi_hash); + rhashtable_remove_fast(&file_hashtbl, &fi->fi_hash, + file_rhashparams); spin_unlock(&state_lock); WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate)); WARN_ON_ONCE(!list_empty(&fi->fi_delegations)); @@ -527,21 +547,33 @@ static unsigned int ownerstr_hashval(struct xdr_netobj *ownername) return ret & OWNER_HASH_MASK; } -/* hash table for nfs4_file */ -#define FILE_HASH_BITS 8 -#define FILE_HASH_SIZE (1 << FILE_HASH_BITS) - -static unsigned int nfsd_fh_hashval(struct knfsd_fh *fh) +static u32 nfsd4_file_key_hash(const void *data, u32 len, u32 seed) { - return jhash2(fh->fh_base.fh_pad, XDR_QUADLEN(fh->fh_size), 0); + struct knfsd_fh *fh = (struct knfsd_fh *)data; + + return jhash2(fh->fh_base.fh_pad, XDR_QUADLEN(fh->fh_size), seed); } -static unsigned int file_hashval(struct knfsd_fh *fh) +static u32 nfsd4_file_obj_hash(const void *data, u32 len, u32 seed) { - return nfsd_fh_hashval(fh) & (FILE_HASH_SIZE - 1); + struct nfs4_file *fp = (struct nfs4_file *)data; + struct knfsd_fh *fh; + + fh = &fp->fi_fhandle; + + return jhash2(fh->fh_base.fh_pad, XDR_QUADLEN(fh->fh_size), seed); } -static struct hlist_head file_hashtbl[FILE_HASH_SIZE]; +static int nfsd4_file_obj_compare(struct rhashtable_compare_arg *arg, + const void *obj) +{ + struct nfs4_file *fp = (struct nfs4_file *)obj; + + if (fh_match(&fp->fi_fhandle, (struct knfsd_fh *)arg->key)) + return 0; + + return 1; +} static void __nfs4_file_get_access(struct nfs4_file *fp, u32 access) @@ -4042,8 +4074,7 @@ static struct nfs4_file *nfsd4_alloc_file(void) } /* OPEN Share state helper functions */ -static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval, - struct nfs4_file *fp) +static void nfsd4_init_file(struct knfsd_fh *fh, struct nfs4_file *fp) { lockdep_assert_held(&state_lock); @@ -4062,7 +4093,6 @@ static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval, INIT_LIST_HEAD(&fp->fi_lo_states); atomic_set(&fp->fi_lo_recalls, 0); #endif - hlist_add_head_rcu(&fp->fi_hash, &file_hashtbl[hashval]); } void @@ -4126,6 +4156,18 @@ nfsd4_init_slabs(void) return -ENOMEM; } +int +nfsd4_init_hash(void) +{ + return rhashtable_init(&file_hashtbl, &file_rhashparams); +} + +void +nfsd4_free_hash(void) +{ + rhashtable_destroy(&file_hashtbl); +} + static void init_nfs4_replay(struct nfs4_replay *rp) { rp->rp_status = nfserr_serverfault; @@ -4395,30 +4437,19 @@ move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) } /* search file_hashtbl[] for file */ -static struct nfs4_file * -find_file_locked(struct knfsd_fh *fh, unsigned int hashval) -{ - struct nfs4_file *fp; - - hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash, - lockdep_is_held(&state_lock)) { - if (fh_match(&fp->fi_fhandle, fh)) { - if (refcount_inc_not_zero(&fp->fi_ref)) - return fp; - } - } - return NULL; -} - struct nfs4_file * find_file(struct knfsd_fh *fh) { struct nfs4_file *fp; - unsigned int hashval = file_hashval(fh); rcu_read_lock(); - fp = find_file_locked(fh, hashval); + fp = rhashtable_lookup(&file_hashtbl, fh, file_rhashparams); + if (fp) { + if (IS_ERR(fp) || refcount_inc_not_zero(&fp->fi_ref)) + fp = NULL; + } rcu_read_unlock(); + return fp; } @@ -4426,22 +4457,27 @@ static struct nfs4_file * find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh) { struct nfs4_file *fp; - unsigned int hashval = file_hashval(fh); - rcu_read_lock(); - fp = find_file_locked(fh, hashval); - rcu_read_unlock(); + fp = find_file(fh); if (fp) return fp; + nfsd4_init_file(fh, new); + spin_lock(&state_lock); - fp = find_file_locked(fh, hashval); - if (likely(fp == NULL)) { - nfsd4_init_file(fh, hashval, new); + + fp = rhashtable_lookup_get_insert_key(&file_hashtbl, &new->fi_fhandle, + &new->fi_hash, file_rhashparams); + if (likely(fp == NULL)) fp = new; - } + else if (IS_ERR(fp)) + fp = NULL; + else + refcount_inc(&fp->fi_ref); + spin_unlock(&state_lock); + return fp; } diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index b68e96681522..bac5d8cff1d3 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1528,9 +1528,12 @@ static int __init init_nfsd(void) retval = nfsd4_init_slabs(); if (retval) goto out_unregister_notifier; - retval = nfsd4_init_pnfs(); + retval = nfsd4_init_hash(); if (retval) goto out_free_slabs; + retval = nfsd4_init_pnfs(); + if (retval) + goto out_free_hash; nfsd_fault_inject_init(); /* nfsd fault injection controls */ nfsd_stat_init(); /* Statistics */ retval = nfsd_drc_slab_create(); @@ -1554,6 +1557,8 @@ static int __init init_nfsd(void) nfsd_stat_shutdown(); nfsd_fault_inject_cleanup(); nfsd4_exit_pnfs(); +out_free_hash: + nfsd4_free_hash(); out_free_slabs: nfsd4_free_slabs(); out_unregister_notifier: diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 5343c771da18..fb0349d16158 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -141,6 +141,8 @@ nfsd_user_namespace(const struct svc_rqst *rqstp) extern unsigned long max_delegations; int nfsd4_init_slabs(void); void nfsd4_free_slabs(void); +int nfsd4_init_hash(void); +void nfsd4_free_hash(void); int nfs4_state_start(void); int nfs4_state_start_net(struct net *net); void nfs4_state_shutdown(void); @@ -151,6 +153,8 @@ bool nfsd4_spo_must_allow(struct svc_rqst *rqstp); #else static inline int nfsd4_init_slabs(void) { return 0; } static inline void nfsd4_free_slabs(void) { } +static inline int nfsd4_init_hash(void) { return 0; } +static inline void nfsd4_free_hash(void) { } static inline int nfs4_state_start(void) { return 0; } static inline int nfs4_state_start_net(struct net *net) { return 0; } static inline void nfs4_state_shutdown(void) { } diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 3b408532a5dc..bf66244a7a2d 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -38,6 +38,7 @@ #include #include #include +#include #include "nfsfh.h" #include "nfsd.h" @@ -513,7 +514,7 @@ struct nfs4_clnt_odstate { struct nfs4_file { refcount_t fi_ref; spinlock_t fi_lock; - struct hlist_node fi_hash; /* hash on fi_fhandle */ + struct rhash_head fi_hash; /* hash on fi_fhandle */ struct list_head fi_stateids; union { struct list_head fi_delegations; -- 2.17.2