[PATCH] kernfs: Convert idr to xarray

Su Hui posted 1 patch 11 months ago
fs/kernfs/dir.c             | 34 ++++++++++++++--------------------
fs/kernfs/kernfs-internal.h |  3 ++-
2 files changed, 16 insertions(+), 21 deletions(-)
[PATCH] kernfs: Convert idr to xarray
Posted by Su Hui 11 months ago
IDR is deprecated. Use xarray instead.

Signed-off-by: Su Hui <suhui@nfschina.com>
---
 fs/kernfs/dir.c             | 34 ++++++++++++++--------------------
 fs/kernfs/kernfs-internal.h |  3 ++-
 2 files changed, 16 insertions(+), 21 deletions(-)

diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 458519e416fe..8d0af0ae6c99 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -10,7 +10,7 @@
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/namei.h>
-#include <linux/idr.h>
+#include <linux/xarray.h>
 #include <linux/slab.h>
 #include <linux/security.h>
 #include <linux/hash.h>
@@ -27,7 +27,6 @@ static DEFINE_RWLOCK(kernfs_rename_lock);	/* kn->parent and ->name */
  */
 static DEFINE_SPINLOCK(kernfs_pr_cont_lock);
 static char kernfs_pr_cont_buf[PATH_MAX];	/* protected by pr_cont_lock */
-static DEFINE_SPINLOCK(kernfs_idr_lock);	/* root->ino_idr */
 
 #define rb_to_kn(X) rb_entry((X), struct kernfs_node, rb)
 
@@ -571,9 +570,7 @@ void kernfs_put(struct kernfs_node *kn)
 	if (kernfs_type(kn) == KERNFS_LINK)
 		kernfs_put(kn->symlink.target_kn);
 
-	spin_lock(&kernfs_idr_lock);
-	idr_remove(&root->ino_idr, (u32)kernfs_ino(kn));
-	spin_unlock(&kernfs_idr_lock);
+	xa_erase(&root->ino_xa, (u32)kernfs_ino(kn));
 
 	call_rcu(&kn->rcu, kernfs_free_rcu);
 
@@ -583,7 +580,7 @@ void kernfs_put(struct kernfs_node *kn)
 			goto repeat;
 	} else {
 		/* just released the root kn, free @root too */
-		idr_destroy(&root->ino_idr);
+		xa_destroy(&root->ino_xa);
 		kfree_rcu(root, rcu);
 	}
 }
@@ -616,6 +613,7 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
 	struct kernfs_node *kn;
 	u32 id_highbits;
 	int ret;
+	u32 id;
 
 	name = kstrdup_const(name, GFP_KERNEL);
 	if (!name)
@@ -625,19 +623,16 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
 	if (!kn)
 		goto err_out1;
 
-	idr_preload(GFP_KERNEL);
-	spin_lock(&kernfs_idr_lock);
-	ret = idr_alloc_cyclic(&root->ino_idr, kn, 1, 0, GFP_ATOMIC);
-	if (ret >= 0 && ret < root->last_id_lowbits)
+	ret = xa_alloc_cyclic(&root->ino_xa, &id, kn, XA_LIMIT(1, INT_MAX),
+			      &root->ino_xa_next_id, GFP_ATOMIC);
+	if (ret >= 0 && id < root->last_id_lowbits)
 		root->id_highbits++;
 	id_highbits = root->id_highbits;
-	root->last_id_lowbits = ret;
-	spin_unlock(&kernfs_idr_lock);
-	idr_preload_end();
+	root->last_id_lowbits = id;
 	if (ret < 0)
 		goto err_out2;
 
-	kn->id = (u64)id_highbits << 32 | ret;
+	kn->id = (u64)id_highbits << 32 | id;
 
 	atomic_set(&kn->count, 1);
 	atomic_set(&kn->active, KN_DEACTIVATED_BIAS);
@@ -668,9 +663,7 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
 	return kn;
 
  err_out3:
-	spin_lock(&kernfs_idr_lock);
-	idr_remove(&root->ino_idr, (u32)kernfs_ino(kn));
-	spin_unlock(&kernfs_idr_lock);
+	xa_erase(&root->ino_xa, (u32)kernfs_ino(kn));
  err_out2:
 	kmem_cache_free(kernfs_node_cache, kn);
  err_out1:
@@ -726,7 +719,7 @@ struct kernfs_node *kernfs_find_and_get_node_by_id(struct kernfs_root *root,
 
 	rcu_read_lock();
 
-	kn = idr_find(&root->ino_idr, (u32)ino);
+	kn = xa_load(&root->ino_xa, (u32)ino);
 	if (!kn)
 		goto err_unlock;
 
@@ -968,11 +961,12 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
 	if (!root)
 		return ERR_PTR(-ENOMEM);
 
-	idr_init(&root->ino_idr);
+	xa_init_flags(&root->ino_xa, XA_FLAGS_ALLOC1);
 	init_rwsem(&root->kernfs_rwsem);
 	init_rwsem(&root->kernfs_iattr_rwsem);
 	init_rwsem(&root->kernfs_supers_rwsem);
 	INIT_LIST_HEAD(&root->supers);
+	root->ino_xa_next_id = 1;
 
 	/*
 	 * On 64bit ino setups, id is ino.  On 32bit, low 32bits are ino.
@@ -989,7 +983,7 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
 			       GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
 			       KERNFS_DIR);
 	if (!kn) {
-		idr_destroy(&root->ino_idr);
+		xa_destroy(&root->ino_xa);
 		kfree(root);
 		return ERR_PTR(-ENOMEM);
 	}
diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h
index b42ee6547cdc..1b77e1a6e5a1 100644
--- a/fs/kernfs/kernfs-internal.h
+++ b/fs/kernfs/kernfs-internal.h
@@ -37,7 +37,8 @@ struct kernfs_root {
 	unsigned int		flags;	/* KERNFS_ROOT_* flags */
 
 	/* private fields, do not use outside kernfs proper */
-	struct idr		ino_idr;
+	struct xarray		ino_xa;
+	u32			ino_xa_next_id;
 	u32			last_id_lowbits;
 	u32			id_highbits;
 	struct kernfs_syscall_ops *syscall_ops;
-- 
2.30.2
Re: [PATCH] kernfs: Convert idr to xarray
Posted by Greg KH 11 months ago
On Thu, Jan 16, 2025 at 04:48:02PM +0800, Su Hui wrote:
> IDR is deprecated. Use xarray instead.

Why?  What helped by doing this?  Is it faster?  Slower?  Less memory?
More memory?  Where did the lock go?

You need to provide so much more information here than you provided in
order for us to be able to even consider reviewing this change.  Please
read the documentation for how to write a good changelog text, that is
very important, ESPECIALLY when dealing with core kernel bits.

thanks,

greg k-h
Re: [PATCH] kernfs: Convert idr to xarray
Posted by Su Hui 11 months ago
On 2025/1/16 17:54, Greg KH wrote:
> On Thu, Jan 16, 2025 at 04:48:02PM +0800, Su Hui wrote:
>> IDR is deprecated. Use xarray instead.
> Why?  What helped by doing this?  Is it faster?  Slower?  Less memory?
> More memory?  Where did the lock go?
>
> You need to provide so much more information here than you provided in
> order for us to be able to even consider reviewing this change.  Please
> read the documentation for how to write a good changelog text, that is
> very important, ESPECIALLY when dealing with core kernel bits.
Sorry for the poor information, I will collect more information and data 
later.
Thanks for your suggestion.

Su Hui