Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ocfs2: detect released suballocator BG for fh_to_[dentry|parent]

After ocfs2 gained the ability to reclaim suballocator free block group
(BGs), a suballocator block group may be released. This change causes the
xfstest case generic/426 to fail.

generic/426 expects return value -ENOENT or -ESTALE, but the current code
triggers -EROFS.

Call stack before ocfs2 gained the ability to reclaim bg:

ocfs2_fh_to_dentry //or ocfs2_fh_to_parent
ocfs2_get_dentry
+ ocfs2_test_inode_bit
| ocfs2_test_suballoc_bit
| + ocfs2_read_group_descriptor //Since ocfs2 never releases the bg,
| | //the bg block was always found.
| + *res = ocfs2_test_bit //unlink was called, and the bit is zero
|
+ if (!set) //because the above *res is 0
status = -ESTALE //the generic/426 expected return value

Current call stack that triggers -EROFS:

ocfs2_get_dentry
ocfs2_test_inode_bit
ocfs2_test_suballoc_bit
ocfs2_read_group_descriptor
+ if reading a released bg, validation fails and triggers -EROFS

How to fix:
Since the read BG is already released, we must avoid triggering -EROFS.
With this commit, we use ocfs2_read_hint_group_descriptor() to detect the
released BG block. This approach quietly handles this type of error and
returns -EINVAL, which triggers the caller's existing conversion path to
-ESTALE.

[dan.carpenter@linaro.org: fix uninitialized variable]
Link: https://lkml.kernel.org/r/dc37519fd2470909f8c65e26c5131b8b6dde2a5c.1766043917.git.dan.carpenter@linaro.org
Link: https://lkml.kernel.org/r/20251212074505.25962-3-heming.zhao@suse.com
Signed-off-by: Heming Zhao <heming.zhao@suse.com>
Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
Reviewed-by: Su Yue <glass.su@suse.com>
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Jun Piao <piaojun@huawei.com>
Cc: Heming Zhao <heming.zhao@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Heming Zhao and committed by
Andrew Morton
fd4d53bd 4a543316

+21 -11
+4 -2
fs/ocfs2/export.c
··· 74 74 * nice 75 75 */ 76 76 status = -ESTALE; 77 - } else 77 + } else if (status != -ESTALE) { 78 78 mlog(ML_ERROR, "test inode bit failed %d\n", status); 79 + } 79 80 goto unlock_nfs_sync; 80 81 } 81 82 ··· 163 162 if (status < 0) { 164 163 if (status == -EINVAL) { 165 164 status = -ESTALE; 166 - } else 165 + } else if (status != -ESTALE) { 167 166 mlog(ML_ERROR, "test inode bit failed %d\n", status); 167 + } 168 168 parent = ERR_PTR(status); 169 169 goto bail_unlock; 170 170 }
+17 -9
fs/ocfs2/suballoc.c
··· 3163 3163 struct ocfs2_group_desc *group; 3164 3164 struct buffer_head *group_bh = NULL; 3165 3165 u64 bg_blkno; 3166 - int status; 3166 + int status, quiet = 0, released = 0; 3167 3167 3168 3168 trace_ocfs2_test_suballoc_bit((unsigned long long)blkno, 3169 3169 (unsigned int)bit); ··· 3179 3179 3180 3180 bg_blkno = group_blkno ? group_blkno : 3181 3181 ocfs2_which_suballoc_group(blkno, bit); 3182 - status = ocfs2_read_group_descriptor(suballoc, alloc_di, bg_blkno, 3183 - &group_bh); 3184 - if (status < 0) { 3182 + status = ocfs2_read_hint_group_descriptor(suballoc, alloc_di, bg_blkno, 3183 + &group_bh, &released); 3184 + if (released) { 3185 + quiet = 1; 3186 + status = -ESTALE; 3187 + goto bail; 3188 + } else if (status < 0) { 3185 3189 mlog(ML_ERROR, "read group %llu failed %d\n", 3186 3190 (unsigned long long)bg_blkno, status); 3187 3191 goto bail; ··· 3197 3193 bail: 3198 3194 brelse(group_bh); 3199 3195 3200 - if (status) 3196 + if (status && !quiet) 3201 3197 mlog_errno(status); 3202 3198 return status; 3203 3199 } ··· 3217 3213 */ 3218 3214 int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res) 3219 3215 { 3220 - int status; 3216 + int status, quiet = 0; 3221 3217 u64 group_blkno = 0; 3222 3218 u16 suballoc_bit = 0, suballoc_slot = 0; 3223 3219 struct inode *inode_alloc_inode; ··· 3259 3255 3260 3256 status = ocfs2_test_suballoc_bit(osb, inode_alloc_inode, alloc_bh, 3261 3257 group_blkno, blkno, suballoc_bit, res); 3262 - if (status < 0) 3263 - mlog(ML_ERROR, "test suballoc bit failed %d\n", status); 3258 + if (status < 0) { 3259 + if (status == -ESTALE) 3260 + quiet = 1; 3261 + else 3262 + mlog(ML_ERROR, "test suballoc bit failed %d\n", status); 3263 + } 3264 3264 3265 3265 ocfs2_inode_unlock(inode_alloc_inode, 0); 3266 3266 inode_unlock(inode_alloc_inode); ··· 3272 3264 iput(inode_alloc_inode); 3273 3265 brelse(alloc_bh); 3274 3266 bail: 3275 - if (status) 3267 + if (status && !quiet) 3276 3268 mlog_errno(status); 3277 3269 return status; 3278 3270 }