From: Jeff Layton <jlayton@kernel.org>
To: Christoph Hellwig <hch@lst.de>, Trond Myklebust <trondmy@kernel.org>
Cc: Anna Schumaker <anna@kernel.org>, linux-nfs@vger.kernel.org
Subject: Re: [PATCH 4/4] NFS: use a hash table for delegation lookup
Date: Mon, 14 Jul 2025 09:14:27 -0400 [thread overview]
Message-ID: <fe1eccd60b2eff90f763aca232875d13643083fd.camel@kernel.org> (raw)
In-Reply-To: <20250714111651.1565055-5-hch@lst.de>
On Mon, 2025-07-14 at 13:16 +0200, Christoph Hellwig wrote:
> nfs_delegation_find_inode currently has to walk the entire list of
> delegations per inode, which can become pretty large, and can become even
> larger when increasing the delegation watermark.
>
> Add a hash table to speed up the delegation lookup, sized as a fraction
> of the delegation watermark.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
> fs/nfs/client.c | 23 +++++++++++++++++++----
> fs/nfs/delegation.c | 15 +++++++++++++--
> fs/nfs/delegation.h | 3 +++
> include/linux/nfs_fs_sb.h | 2 ++
> 4 files changed, 37 insertions(+), 6 deletions(-)
>
> diff --git a/fs/nfs/client.c b/fs/nfs/client.c
> index f55188928f67..94684a476dd8 100644
> --- a/fs/nfs/client.c
> +++ b/fs/nfs/client.c
> @@ -994,6 +994,7 @@ static DEFINE_IDA(s_sysfs_ids);
> struct nfs_server *nfs_alloc_server(void)
> {
> struct nfs_server *server;
> + int delegation_buckets, i;
>
> server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
> if (!server)
> @@ -1019,11 +1020,18 @@ struct nfs_server *nfs_alloc_server(void)
> atomic_set(&server->active, 0);
> atomic_long_set(&server->nr_active_delegations, 0);
>
> + delegation_buckets = roundup_pow_of_two(nfs_delegation_watermark / 16);
> + server->delegation_hash_mask = delegation_buckets - 1;
> + server->delegation_hash_table = kmalloc_array(delegation_buckets,
> + sizeof(*server->delegation_hash_table), GFP_KERNEL);
> + if (!server->delegation_hash_table)
> + goto out_free_server;
> + for (i = 0; i < delegation_buckets; i++)
> + INIT_HLIST_HEAD(&server->delegation_hash_table[i]);
> +
This is going to get created for any mount, even v3 ones. It might be
better to only bother with this for v4 mounts. Maybe do this in
nfs4_server_common_setup() instead?
Also, I wonder if you'd be better off using the rhashtable
infrastructure instead of adding a fixed-size one? The number of
delegations in flight is very workload-dependent, so a resizeable
hashtable may be a better option.
> server->io_stats = nfs_alloc_iostats();
> - if (!server->io_stats) {
> - kfree(server);
> - return NULL;
> - }
> + if (!server->io_stats)
> + goto out_free_delegation_hash;
>
> server->change_attr_type = NFS4_CHANGE_TYPE_IS_UNDEFINED;
>
> @@ -1036,6 +1044,12 @@ struct nfs_server *nfs_alloc_server(void)
> rpc_init_wait_queue(&server->uoc_rpcwaitq, "NFS UOC");
>
> return server;
> +
> +out_free_delegation_hash:
> + kfree(server->delegation_hash_table);
> +out_free_server:
> + kfree(server);
> + return NULL;
> }
> EXPORT_SYMBOL_GPL(nfs_alloc_server);
>
> @@ -1044,6 +1058,7 @@ static void delayed_free(struct rcu_head *p)
> struct nfs_server *server = container_of(p, struct nfs_server, rcu);
>
> nfs_free_iostats(server->io_stats);
> + kfree(server->delegation_hash_table);
> kfree(server);
> }
>
> diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
> index 621b635d1c56..ca830ceb466e 100644
> --- a/fs/nfs/delegation.c
> +++ b/fs/nfs/delegation.c
> @@ -27,9 +27,16 @@
>
> #define NFS_DEFAULT_DELEGATION_WATERMARK (15000U)
>
> -static unsigned nfs_delegation_watermark = NFS_DEFAULT_DELEGATION_WATERMARK;
> +unsigned nfs_delegation_watermark = NFS_DEFAULT_DELEGATION_WATERMARK;
> module_param_named(delegation_watermark, nfs_delegation_watermark, uint, 0644);
>
> +static struct hlist_head *nfs_delegation_hash(struct nfs_server *server,
> + const struct nfs_fh *fhandle)
> +{
> + return server->delegation_hash_table +
> + (nfs_fhandle_hash(fhandle) & server->delegation_hash_mask);
> +}
> +
> static void __nfs_free_delegation(struct nfs_delegation *delegation)
> {
> put_cred(delegation->cred);
> @@ -367,6 +374,7 @@ nfs_detach_delegation_locked(struct nfs_inode *nfsi,
> spin_unlock(&delegation->lock);
> return NULL;
> }
> + hlist_del_init_rcu(&delegation->hash);
> list_del_rcu(&delegation->super_list);
> delegation->inode = NULL;
> rcu_assign_pointer(nfsi->delegation, NULL);
> @@ -529,6 +537,8 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
> spin_unlock(&inode->i_lock);
>
> list_add_tail_rcu(&delegation->super_list, &server->delegations);
> + hlist_add_head_rcu(&delegation->hash,
> + nfs_delegation_hash(server, &NFS_I(inode)->fh));
> rcu_assign_pointer(nfsi->delegation, delegation);
> delegation = NULL;
>
> @@ -1166,11 +1176,12 @@ static struct inode *
> nfs_delegation_find_inode_server(struct nfs_server *server,
> const struct nfs_fh *fhandle)
> {
> + struct hlist_head *head = nfs_delegation_hash(server, fhandle);
> struct nfs_delegation *delegation;
> struct super_block *freeme = NULL;
> struct inode *res = NULL;
>
> - list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
> + hlist_for_each_entry_rcu(delegation, head, hash) {
> spin_lock(&delegation->lock);
> if (delegation->inode != NULL &&
> !test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) &&
> diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h
> index 8ff5ab9c5c25..9f1fb9b39c43 100644
> --- a/fs/nfs/delegation.h
> +++ b/fs/nfs/delegation.h
> @@ -14,6 +14,7 @@
> * NFSv4 delegation
> */
> struct nfs_delegation {
> + struct hlist_node hash;
> struct list_head super_list;
> const struct cred *cred;
> struct inode *inode;
> @@ -123,4 +124,6 @@ static inline int nfs_have_delegated_mtime(struct inode *inode)
> NFS_DELEGATION_FLAG_TIME);
> }
>
> +extern unsigned nfs_delegation_watermark;
> +
> #endif
> diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
> index fe930d685780..88212306fd87 100644
> --- a/include/linux/nfs_fs_sb.h
> +++ b/include/linux/nfs_fs_sb.h
> @@ -256,6 +256,8 @@ struct nfs_server {
> struct list_head layouts;
> struct list_head delegations;
> atomic_long_t nr_active_delegations;
> + unsigned int delegation_hash_mask;
> + struct hlist_head *delegation_hash_table;
> struct list_head ss_copies;
> struct list_head ss_src_copies;
>
--
Jeff Layton <jlayton@kernel.org>
next prev parent reply other threads:[~2025-07-14 13:14 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-14 11:16 use a hash for looking up delegation Christoph Hellwig
2025-07-14 11:16 ` [PATCH 1/4] NFS: cleanup nfs_inode_reclaim_delegation Christoph Hellwig
2025-07-14 13:06 ` Jeff Layton
2025-07-14 11:16 ` [PATCH 2/4] NFS: move the delegation_watermark module parameter Christoph Hellwig
2025-07-14 13:06 ` Jeff Layton
2025-07-15 8:03 ` Christoph Hellwig
2025-07-15 11:15 ` Jeff Layton
2025-07-14 11:16 ` [PATCH 3/4] NFS: track active delegations per-server Christoph Hellwig
2025-07-14 13:07 ` Jeff Layton
2025-07-14 11:16 ` [PATCH 4/4] NFS: use a hash table for delegation lookup Christoph Hellwig
2025-07-14 13:14 ` Jeff Layton [this message]
2025-07-14 13:18 ` Christoph Hellwig
2025-07-15 8:58 ` Christoph Hellwig
2025-07-15 11:19 ` Jeff Layton
-- strict thread matches above, loose matches on Subject: below --
2025-07-16 13:26 use a hash for looking up delegation v2 Christoph Hellwig
2025-07-16 13:26 ` [PATCH 4/4] NFS: use a hash table for delegation lookup Christoph Hellwig
2025-07-17 4:35 ` kernel test robot
2025-07-17 5:13 ` Christoph Hellwig
2025-07-17 16:00 ` Trond Myklebust
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=fe1eccd60b2eff90f763aca232875d13643083fd.camel@kernel.org \
--to=jlayton@kernel.org \
--cc=anna@kernel.org \
--cc=hch@lst.de \
--cc=linux-nfs@vger.kernel.org \
--cc=trondmy@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox