Currently, EROFS maintains a list of extra devices using a legacy IDR
structure (`sbi->devs->tree`). Modernize this to use a standard, more
efficient XArray instead.

This migration simplifies device management, removes legacy boilerplate,
and aligns EROFS device tracking with modern Linux kernel storage subsystem
conventions:
1. Convert `sbi->devs->tree` from a legacy IDR to an XArray initialized
   with `XA_FLAGS_ALLOC` flags.
2. Use `xa_alloc()` to safely register devices under `xa_limit_32b` limits.
3. Use `xa_load()` for direct, fast lookups.
4. Replace custom IDR traversal wrappers with modern `xa_for_each()`
   iterators.
5. Replace custom IDR releasing callback helpers with a clean
   `xa_for_each()` loop and clean up the tree with `xa_destroy()`.

Signed-off-by: Aditya Prakash Srivastava <[email protected]>
---
 fs/erofs/data.c     |  6 +++---
 fs/erofs/internal.h |  2 +-
 fs/erofs/super.c    | 43 +++++++++++++++++++++++--------------------
 3 files changed, 27 insertions(+), 24 deletions(-)

diff --git a/fs/erofs/data.c b/fs/erofs/data.c
index 9aa48c8d67d1..34a1a7d71559 100644
--- a/fs/erofs/data.c
+++ b/fs/erofs/data.c
@@ -211,13 +211,13 @@ int erofs_map_dev(struct super_block *sb, struct 
erofs_map_dev *map)
        struct erofs_dev_context *devs = EROFS_SB(sb)->devs;
        struct erofs_device_info *dif;
        erofs_off_t startoff;
-       int id;
+       unsigned long id;
 
        erofs_fill_from_devinfo(map, sb, &EROFS_SB(sb)->dif0);
        map->m_bdev = sb->s_bdev;       /* use s_bdev for the primary device */
        if (map->m_deviceid) {
                down_read(&devs->rwsem);
-               dif = idr_find(&devs->tree, map->m_deviceid - 1);
+               dif = xa_load(&devs->tree, map->m_deviceid - 1);
                if (!dif) {
                        up_read(&devs->rwsem);
                        return -ENODEV;
@@ -231,7 +231,7 @@ int erofs_map_dev(struct super_block *sb, struct 
erofs_map_dev *map)
                up_read(&devs->rwsem);
        } else if (devs->extra_devices && !devs->flatdev) {
                down_read(&devs->rwsem);
-               idr_for_each_entry(&devs->tree, dif, id) {
+               xa_for_each(&devs->tree, id, dif) {
                        if (!dif->uniaddr)
                                continue;
 
diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
index 580f8d9f14e7..f6126a7bfbc7 100644
--- a/fs/erofs/internal.h
+++ b/fs/erofs/internal.h
@@ -64,7 +64,7 @@ struct erofs_mount_opts {
 };
 
 struct erofs_dev_context {
-       struct idr tree;
+       struct xarray tree;
        struct rw_semaphore rwsem;
 
        unsigned int extra_devices;
diff --git a/fs/erofs/super.c b/fs/erofs/super.c
index 86fa5c6a0c70..08e6a9c57d59 100644
--- a/fs/erofs/super.c
+++ b/fs/erofs/super.c
@@ -188,7 +188,8 @@ static int erofs_scan_devices(struct super_block *sb,
        erofs_off_t pos;
        struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
        struct erofs_device_info *dif;
-       int id, err = 0;
+       int err = 0;
+       unsigned long id;
 
        sbi->total_blocks = sbi->dif0.blocks;
        if (!erofs_sb_has_device_table(sbi))
@@ -217,20 +218,22 @@ static int erofs_scan_devices(struct super_block *sb,
        pos = le16_to_cpu(dsb->devt_slotoff) * EROFS_DEVT_SLOT_SIZE;
        down_read(&sbi->devs->rwsem);
        if (sbi->devs->extra_devices) {
-               idr_for_each_entry(&sbi->devs->tree, dif, id) {
+               xa_for_each(&sbi->devs->tree, id, dif) {
                        err = erofs_init_device(&buf, sb, dif, &pos);
                        if (err)
                                break;
                }
        } else {
                for (id = 0; id < ondisk_extradevs; id++) {
+                       u32 id_val;
+
                        dif = kzalloc_obj(*dif);
                        if (!dif) {
                                err = -ENOMEM;
                                break;
                        }
 
-                       err = idr_alloc(&sbi->devs->tree, dif, 0, 0, 
GFP_KERNEL);
+                       err = xa_alloc(&sbi->devs->tree, &id_val, dif, 
xa_limit_32b, GFP_KERNEL);
                        if (err < 0) {
                                kfree(dif);
                                break;
@@ -480,7 +483,9 @@ static int erofs_fc_parse_param(struct fs_context *fc,
                if (!erofs_fc_set_dax_mode(fc, result.uint_32))
                        return -EINVAL;
                break;
-       case Opt_device:
+       case Opt_device: {
+               u32 id;
+
                dif = kzalloc_obj(*dif);
                if (!dif)
                        return -ENOMEM;
@@ -490,7 +495,7 @@ static int erofs_fc_parse_param(struct fs_context *fc,
                        return -ENOMEM;
                }
                down_write(&sbi->devs->rwsem);
-               ret = idr_alloc(&sbi->devs->tree, dif, 0, 0, GFP_KERNEL);
+               ret = xa_alloc(&sbi->devs->tree, &id, dif, xa_limit_32b, 
GFP_KERNEL);
                up_write(&sbi->devs->rwsem);
                if (ret < 0) {
                        kfree(dif->path);
@@ -499,6 +504,7 @@ static int erofs_fc_parse_param(struct fs_context *fc,
                }
                ++sbi->devs->extra_devices;
                break;
+       }
        case Opt_domain_id:
                if (!IS_ENABLED(CONFIG_EROFS_FS_PAGE_CACHE_SHARE)) {
                        errorfc(fc, "%s option not supported", 
erofs_fs_parameters[opt].name);
@@ -797,24 +803,21 @@ static int erofs_fc_reconfigure(struct fs_context *fc)
        return 0;
 }
 
-static int erofs_release_device_info(int id, void *ptr, void *data)
-{
-       struct erofs_device_info *dif = ptr;
-
-       fs_put_dax(dif->dax_dev, NULL);
-       if (dif->file)
-               fput(dif->file);
-       kfree(dif->path);
-       kfree(dif);
-       return 0;
-}
-
 static void erofs_free_dev_context(struct erofs_dev_context *devs)
 {
+       struct erofs_device_info *dif;
+       unsigned long index;
+
        if (!devs)
                return;
-       idr_for_each(&devs->tree, &erofs_release_device_info, NULL);
-       idr_destroy(&devs->tree);
+       xa_for_each(&devs->tree, index, dif) {
+               fs_put_dax(dif->dax_dev, NULL);
+               if (dif->file)
+                       fput(dif->file);
+               kfree(dif->path);
+               kfree(dif);
+       }
+       xa_destroy(&devs->tree);
        kfree(devs);
 }
 
@@ -858,7 +861,7 @@ static int erofs_init_fs_context(struct fs_context *fc)
        }
        fc->s_fs_info = sbi;
 
-       idr_init(&sbi->devs->tree);
+       xa_init_flags(&sbi->devs->tree, XA_FLAGS_ALLOC);
        init_rwsem(&sbi->devs->rwsem);
        erofs_default_options(sbi);
        fc->ops = &erofs_context_ops;
-- 
2.47.3


Reply via email to