* use a hash for looking up delegation
@ 2025-07-14 11:16 Christoph Hellwig
2025-07-14 11:16 ` [PATCH 1/4] NFS: cleanup nfs_inode_reclaim_delegation Christoph Hellwig
` (3 more replies)
0 siblings, 4 replies; 15+ messages in thread
From: Christoph Hellwig @ 2025-07-14 11:16 UTC (permalink / raw)
To: Trond Myklebust; +Cc: Anna Schumaker, linux-nfs
Hi all,
currently recalling delegations has to walk the server->delegations
list, and then take the lock for each delegation. This can take a lot of
time and has adverse effects to the rest of the system due to the number
atomic operations, cache lines touched and a long RCU critical section.
This series first converts the delegation watermark to be per-server, as
all the state guarded by it is per-server and the commit message adding
it talks about server side overhead as well, and then adds a very simple
hash for finding the delegation for a given file handle in
nfs_delegation_find_inode_server.
With this hash sample microbenchmarks that cause delegation recalls in
reverse list order are sped up ~5 percent, although the time is still
very variable due to other factors.
Diffstat:
fs/nfs/client.c | 24 +++++++++--
fs/nfs/delegation.c | 99 ++++++++++++++++++++++++++--------------------
fs/nfs/delegation.h | 3 +
include/linux/nfs_fs_sb.h | 3 +
4 files changed, 82 insertions(+), 47 deletions(-)
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 1/4] NFS: cleanup nfs_inode_reclaim_delegation
2025-07-14 11:16 use a hash for looking up delegation Christoph Hellwig
@ 2025-07-14 11:16 ` 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
` (2 subsequent siblings)
3 siblings, 1 reply; 15+ messages in thread
From: Christoph Hellwig @ 2025-07-14 11:16 UTC (permalink / raw)
To: Trond Myklebust; +Cc: Anna Schumaker, linux-nfs
Reduce a level of indentation for most of the code in this function.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/nfs/delegation.c | 48 ++++++++++++++++++++++-----------------------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 519bdc91112c..56bb2a7e1793 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -237,34 +237,34 @@ void nfs_inode_reclaim_delegation(struct inode *inode, const struct cred *cred,
rcu_read_lock();
delegation = rcu_dereference(NFS_I(inode)->delegation);
- if (delegation != NULL) {
- spin_lock(&delegation->lock);
- nfs4_stateid_copy(&delegation->stateid, stateid);
- delegation->type = type;
- delegation->pagemod_limit = pagemod_limit;
- oldcred = delegation->cred;
- delegation->cred = get_cred(cred);
- switch (deleg_type) {
- case NFS4_OPEN_DELEGATE_READ_ATTRS_DELEG:
- case NFS4_OPEN_DELEGATE_WRITE_ATTRS_DELEG:
- set_bit(NFS_DELEGATION_DELEGTIME, &delegation->flags);
- break;
- default:
- clear_bit(NFS_DELEGATION_DELEGTIME, &delegation->flags);
- }
- clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
- if (test_and_clear_bit(NFS_DELEGATION_REVOKED,
- &delegation->flags))
- atomic_long_inc(&nfs_active_delegations);
- spin_unlock(&delegation->lock);
- rcu_read_unlock();
- put_cred(oldcred);
- trace_nfs4_reclaim_delegation(inode, type);
- } else {
+ if (!delegation) {
rcu_read_unlock();
nfs_inode_set_delegation(inode, cred, type, stateid,
pagemod_limit, deleg_type);
+ return;
+ }
+
+ spin_lock(&delegation->lock);
+ nfs4_stateid_copy(&delegation->stateid, stateid);
+ delegation->type = type;
+ delegation->pagemod_limit = pagemod_limit;
+ oldcred = delegation->cred;
+ delegation->cred = get_cred(cred);
+ switch (deleg_type) {
+ case NFS4_OPEN_DELEGATE_READ_ATTRS_DELEG:
+ case NFS4_OPEN_DELEGATE_WRITE_ATTRS_DELEG:
+ set_bit(NFS_DELEGATION_DELEGTIME, &delegation->flags);
+ break;
+ default:
+ clear_bit(NFS_DELEGATION_DELEGTIME, &delegation->flags);
}
+ clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
+ if (test_and_clear_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
+ atomic_long_inc(&nfs_active_delegations);
+ spin_unlock(&delegation->lock);
+ rcu_read_unlock();
+ put_cred(oldcred);
+ trace_nfs4_reclaim_delegation(inode, type);
}
static int nfs_do_return_delegation(struct inode *inode,
--
2.47.2
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 2/4] NFS: move the delegation_watermark module parameter
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 11:16 ` Christoph Hellwig
2025-07-14 13:06 ` Jeff Layton
2025-07-14 11:16 ` [PATCH 3/4] NFS: track active delegations per-server Christoph Hellwig
2025-07-14 11:16 ` [PATCH 4/4] NFS: use a hash table for delegation lookup Christoph Hellwig
3 siblings, 1 reply; 15+ messages in thread
From: Christoph Hellwig @ 2025-07-14 11:16 UTC (permalink / raw)
To: Trond Myklebust; +Cc: Anna Schumaker, linux-nfs
Keep the module_param_named next to the variable declaration instead of
somewhere unrelated, following the best practice in the rest of the
kernel.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/nfs/delegation.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 56bb2a7e1793..d036796dbe69 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -29,6 +29,7 @@
static atomic_long_t nfs_active_delegations;
static unsigned nfs_delegation_watermark = NFS_DEFAULT_DELEGATION_WATERMARK;
+module_param_named(delegation_watermark, nfs_delegation_watermark, uint, 0644);
static void __nfs_free_delegation(struct nfs_delegation *delegation)
{
@@ -1575,5 +1576,3 @@ bool nfs4_delegation_flush_on_close(const struct inode *inode)
rcu_read_unlock();
return ret;
}
-
-module_param_named(delegation_watermark, nfs_delegation_watermark, uint, 0644);
--
2.47.2
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 3/4] NFS: track active delegations per-server
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 11:16 ` [PATCH 2/4] NFS: move the delegation_watermark module parameter Christoph Hellwig
@ 2025-07-14 11:16 ` 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
3 siblings, 1 reply; 15+ messages in thread
From: Christoph Hellwig @ 2025-07-14 11:16 UTC (permalink / raw)
To: Trond Myklebust; +Cc: Anna Schumaker, linux-nfs
The active delegation watermark was added to avoid overloading servers.
Track the active delegation per-server instead of globally so that clients
talking to multiple servers aren't limited by the global limit.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/nfs/client.c | 1 +
fs/nfs/delegation.c | 35 +++++++++++++++++++----------------
include/linux/nfs_fs_sb.h | 1 +
3 files changed, 21 insertions(+), 16 deletions(-)
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 1a55debab6e5..f55188928f67 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -1017,6 +1017,7 @@ struct nfs_server *nfs_alloc_server(void)
INIT_LIST_HEAD(&server->ss_src_copies);
atomic_set(&server->active, 0);
+ atomic_long_set(&server->nr_active_delegations, 0);
server->io_stats = nfs_alloc_iostats();
if (!server->io_stats) {
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index d036796dbe69..621b635d1c56 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -27,7 +27,6 @@
#define NFS_DEFAULT_DELEGATION_WATERMARK (15000U)
-static atomic_long_t nfs_active_delegations;
static unsigned nfs_delegation_watermark = NFS_DEFAULT_DELEGATION_WATERMARK;
module_param_named(delegation_watermark, nfs_delegation_watermark, uint, 0644);
@@ -38,11 +37,12 @@ static void __nfs_free_delegation(struct nfs_delegation *delegation)
kfree_rcu(delegation, rcu);
}
-static void nfs_mark_delegation_revoked(struct nfs_delegation *delegation)
+static void nfs_mark_delegation_revoked(struct nfs_server *server,
+ struct nfs_delegation *delegation)
{
if (!test_and_set_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) {
delegation->stateid.type = NFS4_INVALID_STATEID_TYPE;
- atomic_long_dec(&nfs_active_delegations);
+ atomic_long_dec(&server->nr_active_delegations);
if (!test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
nfs_clear_verifier_delegated(delegation->inode);
}
@@ -60,9 +60,10 @@ static void nfs_put_delegation(struct nfs_delegation *delegation)
__nfs_free_delegation(delegation);
}
-static void nfs_free_delegation(struct nfs_delegation *delegation)
+static void nfs_free_delegation(struct nfs_server *server,
+ struct nfs_delegation *delegation)
{
- nfs_mark_delegation_revoked(delegation);
+ nfs_mark_delegation_revoked(server, delegation);
nfs_put_delegation(delegation);
}
@@ -261,7 +262,7 @@ void nfs_inode_reclaim_delegation(struct inode *inode, const struct cred *cred,
}
clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
if (test_and_clear_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
- atomic_long_inc(&nfs_active_delegations);
+ atomic_long_inc(&NFS_SERVER(inode)->nr_active_delegations);
spin_unlock(&delegation->lock);
rcu_read_unlock();
put_cred(oldcred);
@@ -413,7 +414,8 @@ nfs_update_delegation_cred(struct nfs_delegation *delegation,
}
static void
-nfs_update_inplace_delegation(struct nfs_delegation *delegation,
+nfs_update_inplace_delegation(struct nfs_server *server,
+ struct nfs_delegation *delegation,
const struct nfs_delegation *update)
{
if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid)) {
@@ -426,7 +428,7 @@ nfs_update_inplace_delegation(struct nfs_delegation *delegation,
nfs_update_delegation_cred(delegation, update->cred);
/* smp_mb__before_atomic() is implicit due to xchg() */
clear_bit(NFS_DELEGATION_REVOKED, &delegation->flags);
- atomic_long_inc(&nfs_active_delegations);
+ atomic_long_inc(&server->nr_active_delegations);
}
}
}
@@ -481,7 +483,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
if (nfs4_stateid_match_other(&old_delegation->stateid,
&delegation->stateid)) {
spin_lock(&old_delegation->lock);
- nfs_update_inplace_delegation(old_delegation,
+ nfs_update_inplace_delegation(server, old_delegation,
delegation);
spin_unlock(&old_delegation->lock);
goto out;
@@ -530,7 +532,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
rcu_assign_pointer(nfsi->delegation, delegation);
delegation = NULL;
- atomic_long_inc(&nfs_active_delegations);
+ atomic_long_inc(&server->nr_active_delegations);
trace_nfs4_set_delegation(inode, type);
@@ -544,7 +546,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
__nfs_free_delegation(delegation);
if (freeme != NULL) {
nfs_do_return_delegation(inode, freeme, 0);
- nfs_free_delegation(freeme);
+ nfs_free_delegation(server, freeme);
}
return status;
}
@@ -756,7 +758,7 @@ void nfs_inode_evict_delegation(struct inode *inode)
set_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
set_bit(NFS_DELEGATION_INODE_FREEING, &delegation->flags);
nfs_do_return_delegation(inode, delegation, 1);
- nfs_free_delegation(delegation);
+ nfs_free_delegation(NFS_SERVER(inode), delegation);
}
}
@@ -842,7 +844,8 @@ void nfs4_inode_return_delegation_on_close(struct inode *inode)
if (!delegation)
goto out;
if (test_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags) ||
- atomic_long_read(&nfs_active_delegations) >= nfs_delegation_watermark) {
+ atomic_long_read(&NFS_SERVER(inode)->nr_active_delegations) >=
+ nfs_delegation_watermark) {
spin_lock(&delegation->lock);
if (delegation->inode &&
list_empty(&NFS_I(inode)->open_files) &&
@@ -1018,7 +1021,7 @@ static void nfs_revoke_delegation(struct inode *inode,
}
spin_unlock(&delegation->lock);
}
- nfs_mark_delegation_revoked(delegation);
+ nfs_mark_delegation_revoked(NFS_SERVER(inode), delegation);
ret = true;
out:
rcu_read_unlock();
@@ -1050,7 +1053,7 @@ void nfs_delegation_mark_returned(struct inode *inode,
delegation->stateid.seqid = stateid->seqid;
}
- nfs_mark_delegation_revoked(delegation);
+ nfs_mark_delegation_revoked(NFS_SERVER(inode), delegation);
clear_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
spin_unlock(&delegation->lock);
if (nfs_detach_delegation(NFS_I(inode), delegation, NFS_SERVER(inode)))
@@ -1272,7 +1275,7 @@ static int nfs_server_reap_unclaimed_delegations(struct nfs_server *server,
if (delegation != NULL) {
if (nfs_detach_delegation(NFS_I(inode), delegation,
server) != NULL)
- nfs_free_delegation(delegation);
+ nfs_free_delegation(server, delegation);
/* Match nfs_start_delegation_return_locked */
nfs_put_delegation(delegation);
}
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 73bed04529a7..fe930d685780 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -255,6 +255,7 @@ struct nfs_server {
struct list_head state_owners_lru;
struct list_head layouts;
struct list_head delegations;
+ atomic_long_t nr_active_delegations;
struct list_head ss_copies;
struct list_head ss_src_copies;
--
2.47.2
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 4/4] NFS: use a hash table for delegation lookup
2025-07-14 11:16 use a hash for looking up delegation Christoph Hellwig
` (2 preceding siblings ...)
2025-07-14 11:16 ` [PATCH 3/4] NFS: track active delegations per-server Christoph Hellwig
@ 2025-07-14 11:16 ` Christoph Hellwig
2025-07-14 13:14 ` Jeff Layton
3 siblings, 1 reply; 15+ messages in thread
From: Christoph Hellwig @ 2025-07-14 11:16 UTC (permalink / raw)
To: Trond Myklebust; +Cc: Anna Schumaker, linux-nfs
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]);
+
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;
--
2.47.2
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 1/4] NFS: cleanup nfs_inode_reclaim_delegation
2025-07-14 11:16 ` [PATCH 1/4] NFS: cleanup nfs_inode_reclaim_delegation Christoph Hellwig
@ 2025-07-14 13:06 ` Jeff Layton
0 siblings, 0 replies; 15+ messages in thread
From: Jeff Layton @ 2025-07-14 13:06 UTC (permalink / raw)
To: Christoph Hellwig, Trond Myklebust; +Cc: Anna Schumaker, linux-nfs
On Mon, 2025-07-14 at 13:16 +0200, Christoph Hellwig wrote:
> Reduce a level of indentation for most of the code in this function.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
> fs/nfs/delegation.c | 48 ++++++++++++++++++++++-----------------------
> 1 file changed, 24 insertions(+), 24 deletions(-)
>
> diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
> index 519bdc91112c..56bb2a7e1793 100644
> --- a/fs/nfs/delegation.c
> +++ b/fs/nfs/delegation.c
> @@ -237,34 +237,34 @@ void nfs_inode_reclaim_delegation(struct inode *inode, const struct cred *cred,
>
> rcu_read_lock();
> delegation = rcu_dereference(NFS_I(inode)->delegation);
> - if (delegation != NULL) {
> - spin_lock(&delegation->lock);
> - nfs4_stateid_copy(&delegation->stateid, stateid);
> - delegation->type = type;
> - delegation->pagemod_limit = pagemod_limit;
> - oldcred = delegation->cred;
> - delegation->cred = get_cred(cred);
> - switch (deleg_type) {
> - case NFS4_OPEN_DELEGATE_READ_ATTRS_DELEG:
> - case NFS4_OPEN_DELEGATE_WRITE_ATTRS_DELEG:
> - set_bit(NFS_DELEGATION_DELEGTIME, &delegation->flags);
> - break;
> - default:
> - clear_bit(NFS_DELEGATION_DELEGTIME, &delegation->flags);
> - }
> - clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
> - if (test_and_clear_bit(NFS_DELEGATION_REVOKED,
> - &delegation->flags))
> - atomic_long_inc(&nfs_active_delegations);
> - spin_unlock(&delegation->lock);
> - rcu_read_unlock();
> - put_cred(oldcred);
> - trace_nfs4_reclaim_delegation(inode, type);
> - } else {
> + if (!delegation) {
> rcu_read_unlock();
> nfs_inode_set_delegation(inode, cred, type, stateid,
> pagemod_limit, deleg_type);
> + return;
> + }
> +
> + spin_lock(&delegation->lock);
> + nfs4_stateid_copy(&delegation->stateid, stateid);
> + delegation->type = type;
> + delegation->pagemod_limit = pagemod_limit;
> + oldcred = delegation->cred;
> + delegation->cred = get_cred(cred);
> + switch (deleg_type) {
> + case NFS4_OPEN_DELEGATE_READ_ATTRS_DELEG:
> + case NFS4_OPEN_DELEGATE_WRITE_ATTRS_DELEG:
> + set_bit(NFS_DELEGATION_DELEGTIME, &delegation->flags);
> + break;
> + default:
> + clear_bit(NFS_DELEGATION_DELEGTIME, &delegation->flags);
> }
> + clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
> + if (test_and_clear_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
> + atomic_long_inc(&nfs_active_delegations);
> + spin_unlock(&delegation->lock);
> + rcu_read_unlock();
> + put_cred(oldcred);
> + trace_nfs4_reclaim_delegation(inode, type);
> }
>
> static int nfs_do_return_delegation(struct inode *inode,
Reviewed-by: Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/4] NFS: move the delegation_watermark module parameter
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
0 siblings, 1 reply; 15+ messages in thread
From: Jeff Layton @ 2025-07-14 13:06 UTC (permalink / raw)
To: Christoph Hellwig, Trond Myklebust; +Cc: Anna Schumaker, linux-nfs
On Mon, 2025-07-14 at 13:16 +0200, Christoph Hellwig wrote:
> Keep the module_param_named next to the variable declaration instead of
> somewhere unrelated, following the best practice in the rest of the
> kernel.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
> fs/nfs/delegation.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
> index 56bb2a7e1793..d036796dbe69 100644
> --- a/fs/nfs/delegation.c
> +++ b/fs/nfs/delegation.c
> @@ -29,6 +29,7 @@
>
> static atomic_long_t nfs_active_delegations;
> static unsigned nfs_delegation_watermark = NFS_DEFAULT_DELEGATION_WATERMARK;
> +module_param_named(delegation_watermark, nfs_delegation_watermark, uint, 0644);
>
> static void __nfs_free_delegation(struct nfs_delegation *delegation)
> {
> @@ -1575,5 +1576,3 @@ bool nfs4_delegation_flush_on_close(const struct inode *inode)
> rcu_read_unlock();
> return ret;
> }
> -
> -module_param_named(delegation_watermark, nfs_delegation_watermark, uint, 0644);
Sure, but I'd just squash this into patch #3:
Reviewed-by: Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/4] NFS: track active delegations per-server
2025-07-14 11:16 ` [PATCH 3/4] NFS: track active delegations per-server Christoph Hellwig
@ 2025-07-14 13:07 ` Jeff Layton
0 siblings, 0 replies; 15+ messages in thread
From: Jeff Layton @ 2025-07-14 13:07 UTC (permalink / raw)
To: Christoph Hellwig, Trond Myklebust; +Cc: Anna Schumaker, linux-nfs
On Mon, 2025-07-14 at 13:16 +0200, Christoph Hellwig wrote:
> The active delegation watermark was added to avoid overloading servers.
> Track the active delegation per-server instead of globally so that clients
> talking to multiple servers aren't limited by the global limit.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
> fs/nfs/client.c | 1 +
> fs/nfs/delegation.c | 35 +++++++++++++++++++----------------
> include/linux/nfs_fs_sb.h | 1 +
> 3 files changed, 21 insertions(+), 16 deletions(-)
>
> diff --git a/fs/nfs/client.c b/fs/nfs/client.c
> index 1a55debab6e5..f55188928f67 100644
> --- a/fs/nfs/client.c
> +++ b/fs/nfs/client.c
> @@ -1017,6 +1017,7 @@ struct nfs_server *nfs_alloc_server(void)
> INIT_LIST_HEAD(&server->ss_src_copies);
>
> atomic_set(&server->active, 0);
> + atomic_long_set(&server->nr_active_delegations, 0);
>
> server->io_stats = nfs_alloc_iostats();
> if (!server->io_stats) {
> diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
> index d036796dbe69..621b635d1c56 100644
> --- a/fs/nfs/delegation.c
> +++ b/fs/nfs/delegation.c
> @@ -27,7 +27,6 @@
>
> #define NFS_DEFAULT_DELEGATION_WATERMARK (15000U)
>
> -static atomic_long_t nfs_active_delegations;
> static unsigned nfs_delegation_watermark = NFS_DEFAULT_DELEGATION_WATERMARK;
> module_param_named(delegation_watermark, nfs_delegation_watermark, uint, 0644);
>
> @@ -38,11 +37,12 @@ static void __nfs_free_delegation(struct nfs_delegation *delegation)
> kfree_rcu(delegation, rcu);
> }
>
> -static void nfs_mark_delegation_revoked(struct nfs_delegation *delegation)
> +static void nfs_mark_delegation_revoked(struct nfs_server *server,
> + struct nfs_delegation *delegation)
> {
> if (!test_and_set_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) {
> delegation->stateid.type = NFS4_INVALID_STATEID_TYPE;
> - atomic_long_dec(&nfs_active_delegations);
> + atomic_long_dec(&server->nr_active_delegations);
> if (!test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
> nfs_clear_verifier_delegated(delegation->inode);
> }
> @@ -60,9 +60,10 @@ static void nfs_put_delegation(struct nfs_delegation *delegation)
> __nfs_free_delegation(delegation);
> }
>
> -static void nfs_free_delegation(struct nfs_delegation *delegation)
> +static void nfs_free_delegation(struct nfs_server *server,
> + struct nfs_delegation *delegation)
> {
> - nfs_mark_delegation_revoked(delegation);
> + nfs_mark_delegation_revoked(server, delegation);
> nfs_put_delegation(delegation);
> }
>
> @@ -261,7 +262,7 @@ void nfs_inode_reclaim_delegation(struct inode *inode, const struct cred *cred,
> }
> clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
> if (test_and_clear_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
> - atomic_long_inc(&nfs_active_delegations);
> + atomic_long_inc(&NFS_SERVER(inode)->nr_active_delegations);
> spin_unlock(&delegation->lock);
> rcu_read_unlock();
> put_cred(oldcred);
> @@ -413,7 +414,8 @@ nfs_update_delegation_cred(struct nfs_delegation *delegation,
> }
>
> static void
> -nfs_update_inplace_delegation(struct nfs_delegation *delegation,
> +nfs_update_inplace_delegation(struct nfs_server *server,
> + struct nfs_delegation *delegation,
> const struct nfs_delegation *update)
> {
> if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid)) {
> @@ -426,7 +428,7 @@ nfs_update_inplace_delegation(struct nfs_delegation *delegation,
> nfs_update_delegation_cred(delegation, update->cred);
> /* smp_mb__before_atomic() is implicit due to xchg() */
> clear_bit(NFS_DELEGATION_REVOKED, &delegation->flags);
> - atomic_long_inc(&nfs_active_delegations);
> + atomic_long_inc(&server->nr_active_delegations);
> }
> }
> }
> @@ -481,7 +483,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
> if (nfs4_stateid_match_other(&old_delegation->stateid,
> &delegation->stateid)) {
> spin_lock(&old_delegation->lock);
> - nfs_update_inplace_delegation(old_delegation,
> + nfs_update_inplace_delegation(server, old_delegation,
> delegation);
> spin_unlock(&old_delegation->lock);
> goto out;
> @@ -530,7 +532,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
> rcu_assign_pointer(nfsi->delegation, delegation);
> delegation = NULL;
>
> - atomic_long_inc(&nfs_active_delegations);
> + atomic_long_inc(&server->nr_active_delegations);
>
> trace_nfs4_set_delegation(inode, type);
>
> @@ -544,7 +546,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
> __nfs_free_delegation(delegation);
> if (freeme != NULL) {
> nfs_do_return_delegation(inode, freeme, 0);
> - nfs_free_delegation(freeme);
> + nfs_free_delegation(server, freeme);
> }
> return status;
> }
> @@ -756,7 +758,7 @@ void nfs_inode_evict_delegation(struct inode *inode)
> set_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
> set_bit(NFS_DELEGATION_INODE_FREEING, &delegation->flags);
> nfs_do_return_delegation(inode, delegation, 1);
> - nfs_free_delegation(delegation);
> + nfs_free_delegation(NFS_SERVER(inode), delegation);
> }
> }
>
> @@ -842,7 +844,8 @@ void nfs4_inode_return_delegation_on_close(struct inode *inode)
> if (!delegation)
> goto out;
> if (test_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags) ||
> - atomic_long_read(&nfs_active_delegations) >= nfs_delegation_watermark) {
> + atomic_long_read(&NFS_SERVER(inode)->nr_active_delegations) >=
> + nfs_delegation_watermark) {
> spin_lock(&delegation->lock);
> if (delegation->inode &&
> list_empty(&NFS_I(inode)->open_files) &&
> @@ -1018,7 +1021,7 @@ static void nfs_revoke_delegation(struct inode *inode,
> }
> spin_unlock(&delegation->lock);
> }
> - nfs_mark_delegation_revoked(delegation);
> + nfs_mark_delegation_revoked(NFS_SERVER(inode), delegation);
> ret = true;
> out:
> rcu_read_unlock();
> @@ -1050,7 +1053,7 @@ void nfs_delegation_mark_returned(struct inode *inode,
> delegation->stateid.seqid = stateid->seqid;
> }
>
> - nfs_mark_delegation_revoked(delegation);
> + nfs_mark_delegation_revoked(NFS_SERVER(inode), delegation);
> clear_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
> spin_unlock(&delegation->lock);
> if (nfs_detach_delegation(NFS_I(inode), delegation, NFS_SERVER(inode)))
> @@ -1272,7 +1275,7 @@ static int nfs_server_reap_unclaimed_delegations(struct nfs_server *server,
> if (delegation != NULL) {
> if (nfs_detach_delegation(NFS_I(inode), delegation,
> server) != NULL)
> - nfs_free_delegation(delegation);
> + nfs_free_delegation(server, delegation);
> /* Match nfs_start_delegation_return_locked */
> nfs_put_delegation(delegation);
> }
> diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
> index 73bed04529a7..fe930d685780 100644
> --- a/include/linux/nfs_fs_sb.h
> +++ b/include/linux/nfs_fs_sb.h
> @@ -255,6 +255,7 @@ struct nfs_server {
> struct list_head state_owners_lru;
> struct list_head layouts;
> struct list_head delegations;
> + atomic_long_t nr_active_delegations;
> struct list_head ss_copies;
> struct list_head ss_src_copies;
>
Good idea. I like this.
Reviewed-by: Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 4/4] NFS: use a hash table for delegation lookup
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
2025-07-14 13:18 ` Christoph Hellwig
2025-07-15 8:58 ` Christoph Hellwig
0 siblings, 2 replies; 15+ messages in thread
From: Jeff Layton @ 2025-07-14 13:14 UTC (permalink / raw)
To: Christoph Hellwig, Trond Myklebust; +Cc: Anna Schumaker, linux-nfs
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>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 4/4] NFS: use a hash table for delegation lookup
2025-07-14 13:14 ` Jeff Layton
@ 2025-07-14 13:18 ` Christoph Hellwig
2025-07-15 8:58 ` Christoph Hellwig
1 sibling, 0 replies; 15+ messages in thread
From: Christoph Hellwig @ 2025-07-14 13:18 UTC (permalink / raw)
To: Jeff Layton; +Cc: Christoph Hellwig, Trond Myklebust, Anna Schumaker, linux-nfs
On Mon, Jul 14, 2025 at 09:14:27AM -0400, Jeff Layton wrote:
> > + 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?
Yeah, good idea.
> 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.
I did try that first. But the rhashtable expects the hash key to
be embedded into the structure that has the rhash_head embedded into
it, while delegations use the file handle embeded into the inode as
the key. So we'd have to bloat the deleations with a key copy for
that.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/4] NFS: move the delegation_watermark module parameter
2025-07-14 13:06 ` Jeff Layton
@ 2025-07-15 8:03 ` Christoph Hellwig
2025-07-15 11:15 ` Jeff Layton
0 siblings, 1 reply; 15+ messages in thread
From: Christoph Hellwig @ 2025-07-15 8:03 UTC (permalink / raw)
To: Jeff Layton; +Cc: Christoph Hellwig, Trond Myklebust, Anna Schumaker, linux-nfs
On Mon, Jul 14, 2025 at 09:06:42AM -0400, Jeff Layton wrote:
> > -
> > -module_param_named(delegation_watermark, nfs_delegation_watermark, uint, 0644);
>
> Sure, but I'd just squash this into patch #3:
Why? It's completely unrelated to the changes there.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 4/4] NFS: use a hash table for delegation lookup
2025-07-14 13:14 ` Jeff Layton
2025-07-14 13:18 ` Christoph Hellwig
@ 2025-07-15 8:58 ` Christoph Hellwig
2025-07-15 11:19 ` Jeff Layton
1 sibling, 1 reply; 15+ messages in thread
From: Christoph Hellwig @ 2025-07-15 8:58 UTC (permalink / raw)
To: Jeff Layton; +Cc: Christoph Hellwig, Trond Myklebust, Anna Schumaker, linux-nfs
On Mon, Jul 14, 2025 at 09:14:27AM -0400, Jeff Layton wrote:
> > + 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?
I tried that, but it crashes because the usual mount process goes
through nfs_clone_server, which then doesn't set up the hash table.
I think the best idea is to pass the version to nfs_allocate_server
and just make this code conditional, but I'm open to other suggestions.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/4] NFS: move the delegation_watermark module parameter
2025-07-15 8:03 ` Christoph Hellwig
@ 2025-07-15 11:15 ` Jeff Layton
0 siblings, 0 replies; 15+ messages in thread
From: Jeff Layton @ 2025-07-15 11:15 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: Trond Myklebust, Anna Schumaker, linux-nfs
On Tue, 2025-07-15 at 10:03 +0200, Christoph Hellwig wrote:
> On Mon, Jul 14, 2025 at 09:06:42AM -0400, Jeff Layton wrote:
> > > -
> > > -module_param_named(delegation_watermark, nfs_delegation_watermark, uint, 0644);
> >
> > Sure, but I'd just squash this into patch #3:
>
> Why? It's completely unrelated to the changes there.
It's a trivial change and patch #3 makes changes in the same area. It's
not a big deal though.
--
Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 4/4] NFS: use a hash table for delegation lookup
2025-07-15 8:58 ` Christoph Hellwig
@ 2025-07-15 11:19 ` Jeff Layton
0 siblings, 0 replies; 15+ messages in thread
From: Jeff Layton @ 2025-07-15 11:19 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: Trond Myklebust, Anna Schumaker, linux-nfs
On Tue, 2025-07-15 at 10:58 +0200, Christoph Hellwig wrote:
> On Mon, Jul 14, 2025 at 09:14:27AM -0400, Jeff Layton wrote:
> > > + 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?
>
> I tried that, but it crashes because the usual mount process goes
> through nfs_clone_server, which then doesn't set up the hash table.
>
> I think the best idea is to pass the version to nfs_allocate_server
> and just make this code conditional, but I'm open to other suggestions.
The other thing you could do is move the allocation and setup into a
helper function, and have nfs_clone_server() call that if the source
server has a hashtable present.
--
Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 2/4] NFS: move the delegation_watermark module parameter
2025-07-16 13:26 use a hash for looking up delegation v2 Christoph Hellwig
@ 2025-07-16 13:26 ` Christoph Hellwig
0 siblings, 0 replies; 15+ messages in thread
From: Christoph Hellwig @ 2025-07-16 13:26 UTC (permalink / raw)
To: Trond Myklebust; +Cc: Anna Schumaker, linux-nfs, Jeff Layton
Keep the module_param_named next to the variable declaration instead of
somewhere unrelated, following the best practice in the rest of the
kernel.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
---
fs/nfs/delegation.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 568d2e6d65fa..5f85966d7709 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -29,6 +29,7 @@
static atomic_long_t nfs_active_delegations;
static unsigned nfs_delegation_watermark = NFS_DEFAULT_DELEGATION_WATERMARK;
+module_param_named(delegation_watermark, nfs_delegation_watermark, uint, 0644);
static void __nfs_free_delegation(struct nfs_delegation *delegation)
{
@@ -1573,5 +1574,3 @@ bool nfs4_delegation_flush_on_close(const struct inode *inode)
rcu_read_unlock();
return ret;
}
-
-module_param_named(delegation_watermark, nfs_delegation_watermark, uint, 0644);
--
2.47.2
^ permalink raw reply related [flat|nested] 15+ messages in thread
end of thread, other threads:[~2025-07-16 13:27 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
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 2/4] NFS: move the delegation_watermark module parameter Christoph Hellwig
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox