Skip to content

Commit 5c6154f

Browse files
committed
Merge tag 'erofs-for-6.11-rc5-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs
Pull erofs fixes from Gao Xiang: "As I mentioned in the merge window pull request, there is a regression which could cause system hang due to page migration. The corresponding fix landed upstream through MM tree last week (commit 2e6506e: "mm/migrate: fix deadlock in migrate_pages_batch() on large folios"), therefore large folios can be safely allowed for compressed inodes and stress tests have been running on my fleet for over 20 days without any regression. Users have explicitly requested this for months, so let's allow large folios for EROFS full cases now for wider testing. Additionally, there is a fix which addresses invalid memory accesses on a failure path triggered by fault injection and two minor cleanups to simplify the codebase. Summary: - Allow large folios on compressed inodes - Fix invalid memory accesses if z_erofs_gbuf_growsize() partially fails - Two minor cleanups" * tag 'erofs-for-6.11-rc5-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs: erofs: fix out-of-bound access when z_erofs_gbuf_growsize() partially fails erofs: allow large folios for compressed files erofs: get rid of check_layout_compatibility() erofs: simplify readdir operation
2 parents b311c1b + 0005e01 commit 5c6154f

File tree

6 files changed

+30
-56
lines changed

6 files changed

+30
-56
lines changed

Documentation/filesystems/erofs.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ Here are the main features of EROFS:
7575

7676
- Support merging tail-end data into a special inode as fragments.
7777

78-
- Support large folios for uncompressed files.
78+
- Support large folios to make use of THPs (Transparent Hugepages);
7979

8080
- Support direct I/O on uncompressed files to avoid double caching for loop
8181
devices;

fs/erofs/dir.c

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,15 @@
88

99
static int erofs_fill_dentries(struct inode *dir, struct dir_context *ctx,
1010
void *dentry_blk, struct erofs_dirent *de,
11-
unsigned int nameoff, unsigned int maxsize)
11+
unsigned int nameoff0, unsigned int maxsize)
1212
{
13-
const struct erofs_dirent *end = dentry_blk + nameoff;
13+
const struct erofs_dirent *end = dentry_blk + nameoff0;
1414

1515
while (de < end) {
16-
const char *de_name;
16+
unsigned char d_type = fs_ftype_to_dtype(de->file_type);
17+
unsigned int nameoff = le16_to_cpu(de->nameoff);
18+
const char *de_name = (char *)dentry_blk + nameoff;
1719
unsigned int de_namelen;
18-
unsigned char d_type;
19-
20-
d_type = fs_ftype_to_dtype(de->file_type);
21-
22-
nameoff = le16_to_cpu(de->nameoff);
23-
de_name = (char *)dentry_blk + nameoff;
2420

2521
/* the last dirent in the block? */
2622
if (de + 1 >= end)
@@ -52,21 +48,20 @@ static int erofs_readdir(struct file *f, struct dir_context *ctx)
5248
struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
5349
struct super_block *sb = dir->i_sb;
5450
unsigned long bsz = sb->s_blocksize;
55-
const size_t dirsize = i_size_read(dir);
56-
unsigned int i = erofs_blknr(sb, ctx->pos);
5751
unsigned int ofs = erofs_blkoff(sb, ctx->pos);
5852
int err = 0;
5953
bool initial = true;
6054

6155
buf.mapping = dir->i_mapping;
62-
while (ctx->pos < dirsize) {
56+
while (ctx->pos < dir->i_size) {
57+
erofs_off_t dbstart = ctx->pos - ofs;
6358
struct erofs_dirent *de;
6459
unsigned int nameoff, maxsize;
6560

66-
de = erofs_bread(&buf, erofs_pos(sb, i), EROFS_KMAP);
61+
de = erofs_bread(&buf, dbstart, EROFS_KMAP);
6762
if (IS_ERR(de)) {
6863
erofs_err(sb, "fail to readdir of logical block %u of nid %llu",
69-
i, EROFS_I(dir)->nid);
64+
erofs_blknr(sb, dbstart), EROFS_I(dir)->nid);
7065
err = PTR_ERR(de);
7166
break;
7267
}
@@ -79,25 +74,19 @@ static int erofs_readdir(struct file *f, struct dir_context *ctx)
7974
break;
8075
}
8176

82-
maxsize = min_t(unsigned int, dirsize - ctx->pos + ofs, bsz);
83-
77+
maxsize = min_t(unsigned int, dir->i_size - dbstart, bsz);
8478
/* search dirents at the arbitrary position */
8579
if (initial) {
8680
initial = false;
87-
8881
ofs = roundup(ofs, sizeof(struct erofs_dirent));
89-
ctx->pos = erofs_pos(sb, i) + ofs;
90-
if (ofs >= nameoff)
91-
goto skip_this;
82+
ctx->pos = dbstart + ofs;
9283
}
9384

9485
err = erofs_fill_dentries(dir, ctx, de, (void *)de + ofs,
9586
nameoff, maxsize);
9687
if (err)
9788
break;
98-
skip_this:
99-
ctx->pos = erofs_pos(sb, i) + maxsize;
100-
++i;
89+
ctx->pos = dbstart + maxsize;
10190
ofs = 0;
10291
}
10392
erofs_put_metabuf(&buf);

fs/erofs/inode.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -257,25 +257,23 @@ static int erofs_fill_inode(struct inode *inode)
257257
goto out_unlock;
258258
}
259259

260+
mapping_set_large_folios(inode->i_mapping);
260261
if (erofs_inode_is_data_compressed(vi->datalayout)) {
261262
#ifdef CONFIG_EROFS_FS_ZIP
262263
DO_ONCE_LITE_IF(inode->i_blkbits != PAGE_SHIFT,
263264
erofs_info, inode->i_sb,
264265
"EXPERIMENTAL EROFS subpage compressed block support in use. Use at your own risk!");
265266
inode->i_mapping->a_ops = &z_erofs_aops;
266-
err = 0;
267-
goto out_unlock;
268-
#endif
267+
#else
269268
err = -EOPNOTSUPP;
270-
goto out_unlock;
271-
}
272-
inode->i_mapping->a_ops = &erofs_raw_access_aops;
273-
mapping_set_large_folios(inode->i_mapping);
269+
#endif
270+
} else {
271+
inode->i_mapping->a_ops = &erofs_raw_access_aops;
274272
#ifdef CONFIG_EROFS_FS_ONDEMAND
275-
if (erofs_is_fscache_mode(inode->i_sb))
276-
inode->i_mapping->a_ops = &erofs_fscache_access_aops;
273+
if (erofs_is_fscache_mode(inode->i_sb))
274+
inode->i_mapping->a_ops = &erofs_fscache_access_aops;
277275
#endif
278-
276+
}
279277
out_unlock:
280278
erofs_put_metabuf(&buf);
281279
return err;

fs/erofs/internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ struct erofs_buf {
220220
};
221221
#define __EROFS_BUF_INITIALIZER ((struct erofs_buf){ .page = NULL })
222222

223-
#define erofs_blknr(sb, addr) ((addr) >> (sb)->s_blocksize_bits)
223+
#define erofs_blknr(sb, addr) ((erofs_blk_t)((addr) >> (sb)->s_blocksize_bits))
224224
#define erofs_blkoff(sb, addr) ((addr) & ((sb)->s_blocksize - 1))
225225
#define erofs_pos(sb, blk) ((erofs_off_t)(blk) << (sb)->s_blocksize_bits)
226226
#define erofs_iblks(i) (round_up((i)->i_size, i_blocksize(i)) >> (i)->i_blkbits)

fs/erofs/super.c

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -108,22 +108,6 @@ static void erofs_free_inode(struct inode *inode)
108108
kmem_cache_free(erofs_inode_cachep, vi);
109109
}
110110

111-
static bool check_layout_compatibility(struct super_block *sb,
112-
struct erofs_super_block *dsb)
113-
{
114-
const unsigned int feature = le32_to_cpu(dsb->feature_incompat);
115-
116-
EROFS_SB(sb)->feature_incompat = feature;
117-
118-
/* check if current kernel meets all mandatory requirements */
119-
if (feature & (~EROFS_ALL_FEATURE_INCOMPAT)) {
120-
erofs_err(sb, "unidentified incompatible feature %x, please upgrade kernel",
121-
feature & ~EROFS_ALL_FEATURE_INCOMPAT);
122-
return false;
123-
}
124-
return true;
125-
}
126-
127111
/* read variable-sized metadata, offset will be aligned by 4-byte */
128112
void *erofs_read_metadata(struct super_block *sb, struct erofs_buf *buf,
129113
erofs_off_t *offset, int *lengthp)
@@ -279,7 +263,7 @@ static int erofs_scan_devices(struct super_block *sb,
279263

280264
static int erofs_read_superblock(struct super_block *sb)
281265
{
282-
struct erofs_sb_info *sbi;
266+
struct erofs_sb_info *sbi = EROFS_SB(sb);
283267
struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
284268
struct erofs_super_block *dsb;
285269
void *data;
@@ -291,9 +275,7 @@ static int erofs_read_superblock(struct super_block *sb)
291275
return PTR_ERR(data);
292276
}
293277

294-
sbi = EROFS_SB(sb);
295278
dsb = (struct erofs_super_block *)(data + EROFS_SUPER_OFFSET);
296-
297279
ret = -EINVAL;
298280
if (le32_to_cpu(dsb->magic) != EROFS_SUPER_MAGIC_V1) {
299281
erofs_err(sb, "cannot find valid erofs superblock");
@@ -318,8 +300,12 @@ static int erofs_read_superblock(struct super_block *sb)
318300
}
319301

320302
ret = -EINVAL;
321-
if (!check_layout_compatibility(sb, dsb))
303+
sbi->feature_incompat = le32_to_cpu(dsb->feature_incompat);
304+
if (sbi->feature_incompat & ~EROFS_ALL_FEATURE_INCOMPAT) {
305+
erofs_err(sb, "unidentified incompatible feature %x, please upgrade kernel",
306+
sbi->feature_incompat & ~EROFS_ALL_FEATURE_INCOMPAT);
322307
goto out;
308+
}
323309

324310
sbi->sb_size = 128 + dsb->sb_extslots * EROFS_SB_EXTSLOT_SIZE;
325311
if (sbi->sb_size > PAGE_SIZE - EROFS_SUPER_OFFSET) {

fs/erofs/zutil.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ int z_erofs_gbuf_growsize(unsigned int nrpages)
111111
out:
112112
if (i < z_erofs_gbuf_count && tmp_pages) {
113113
for (j = 0; j < nrpages; ++j)
114-
if (tmp_pages[j] && tmp_pages[j] != gbuf->pages[j])
114+
if (tmp_pages[j] && (j >= gbuf->nrpages ||
115+
tmp_pages[j] != gbuf->pages[j]))
115116
__free_page(tmp_pages[j]);
116117
kfree(tmp_pages);
117118
}

0 commit comments

Comments
 (0)