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
