From: Yuezhang Mo <yuezhang...@sony.com> [ Upstream commit c6993c4cb91803fceb82d6b5e0ec5e0aec2d0ad6 ]
If using multiple devices, we should check if the extra device support DAX instead of checking the primary device when deciding if to use DAX to access a file. If an extra device does not support DAX we should fallback to normal access otherwise the data on that device will be inaccessible. Signed-off-by: Yuezhang Mo <yuezhang...@sony.com> Reviewed-by: Friendy Su <friendy...@sony.com> Reviewed-by: Jacky Cao <jacky....@sony.com> Reviewed-by: Daniel Palmer <daniel.pal...@sony.com> Reviewed-by: Gao Xiang <hsiang...@linux.alibaba.com> Reviewed-by: Hongbo Li <lihongb...@huawei.com> Link: https://lore.kernel.org/r/20250804082030.3667257-2-yuezhang...@sony.com Signed-off-by: Gao Xiang <hsiang...@linux.alibaba.com> Signed-off-by: Sasha Levin <sas...@kernel.org> --- LLM Generated explanations, may be completely bogus: Based on my comprehensive analysis of this commit, I can now provide a definitive assessment: ## Backport Status: **YES** This commit should be backported to stable kernel trees for the following reasons: ### 1. **Critical Bug Fix** The commit fixes a serious bug where files on extra devices become **completely inaccessible** when DAX is enabled. Looking at the code changes: - **Before the fix**: When `DAX_ALWAYS` was set, only the primary device (`sbi->dif0.dax_dev`) was checked for DAX support - **After the fix**: Each extra device is checked individually, and if any device doesn't support DAX, the system falls back to normal access This is evident in lines 176-179 of the patch where DAX support checking is moved into the `erofs_init_device()` function to check each device individually. ### 2. **Data Accessibility Issue** The commit message explicitly states: *"If an extra device does not support DAX we should fallback to normal access otherwise the data on that device will be inaccessible."* This is a critical functionality bug that prevents users from accessing their data. ### 3. **Small and Contained Fix** The patch is minimal with only 14 insertions and 10 deletions in a single file (`fs/erofs/super.c`). The changes are: - Moving DAX capability checking from mount time to per-device initialization - Adding informational messages when DAX is disabled - No architectural changes or new features ### 4. **Affects Existing Functionality Since v5.15** Looking at the git history: - DAX support was added in commit `06252e9ce05b` (August 2021, v5.15) - Multiple device support was added in commit `dfeab2e95a75` (October 2021, v5.16) - This bug has existed since these features could be used together ### 5. **No Risk of Regression** The fix only changes behavior when: - Multiple devices are configured - DAX_ALWAYS option is enabled - Some devices don't support DAX In all other cases, the behavior remains unchanged. The fix gracefully degrades functionality rather than failing completely. ### 6. **Clear Bug Reproduction Path** The bug occurs when: 1. User mounts an EROFS filesystem with `dax=always` option 2. The filesystem uses multiple devices 3. The primary device supports DAX but extra devices don't 4. Result: Files on extra devices become inaccessible ### 7. **Follows Stable Tree Rules** According to stable kernel rules, this commit qualifies because it: - Fixes a real bug that affects users (data inaccessibility) - Is already upstream with proper review (6 reviewers including maintainer) - Has minimal changes confined to one subsystem - Contains no new features or risky architectural changes The commit should be backported to all stable kernels that have both DAX support (v5.15+) and multiple device support (v5.16+) in EROFS, making it applicable to v5.16 and later stable trees. fs/erofs/super.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/fs/erofs/super.c b/fs/erofs/super.c index e1e9f06e8342..02f865c6ec7c 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -174,6 +174,11 @@ static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb, if (!erofs_is_fileio_mode(sbi)) { dif->dax_dev = fs_dax_get_by_bdev(file_bdev(file), &dif->dax_part_off, NULL, NULL); + if (!dif->dax_dev && test_opt(&sbi->opt, DAX_ALWAYS)) { + erofs_info(sb, "DAX unsupported by %s. Turning off DAX.", + dif->path); + clear_opt(&sbi->opt, DAX_ALWAYS); + } } else if (!S_ISREG(file_inode(file)->i_mode)) { fput(file); return -EINVAL; @@ -210,8 +215,13 @@ static int erofs_scan_devices(struct super_block *sb, ondisk_extradevs, sbi->devs->extra_devices); return -EINVAL; } - if (!ondisk_extradevs) + if (!ondisk_extradevs) { + if (test_opt(&sbi->opt, DAX_ALWAYS) && !sbi->dif0.dax_dev) { + erofs_info(sb, "DAX unsupported by block device. Turning off DAX."); + clear_opt(&sbi->opt, DAX_ALWAYS); + } return 0; + } if (!sbi->devs->extra_devices && !erofs_is_fscache_mode(sb)) sbi->devs->flatdev = true; @@ -330,7 +340,6 @@ static int erofs_read_superblock(struct super_block *sb) if (ret < 0) goto out; - /* handle multiple devices */ ret = erofs_scan_devices(sb, dsb); if (erofs_sb_has_48bit(sbi)) @@ -661,14 +670,9 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc) return invalfc(fc, "cannot use fsoffset in fscache mode"); } - if (test_opt(&sbi->opt, DAX_ALWAYS)) { - if (!sbi->dif0.dax_dev) { - errorfc(fc, "DAX unsupported by block device. Turning off DAX."); - clear_opt(&sbi->opt, DAX_ALWAYS); - } else if (sbi->blkszbits != PAGE_SHIFT) { - errorfc(fc, "unsupported blocksize for DAX"); - clear_opt(&sbi->opt, DAX_ALWAYS); - } + if (test_opt(&sbi->opt, DAX_ALWAYS) && sbi->blkszbits != PAGE_SHIFT) { + erofs_info(sb, "unsupported blocksize for DAX"); + clear_opt(&sbi->opt, DAX_ALWAYS); } sb->s_time_gran = 1; -- 2.50.1