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

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 2e6506e1c4ee:
"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

+31 -57
+1 -1
Documentation/filesystems/erofs.rst
··· 75 75 76 76 - Support merging tail-end data into a special inode as fragments. 77 77 78 - - Support large folios for uncompressed files. 78 + - Support large folios to make use of THPs (Transparent Hugepages); 79 79 80 80 - Support direct I/O on uncompressed files to avoid double caching for loop 81 81 devices;
+12 -23
fs/erofs/dir.c
··· 8 8 9 9 static int erofs_fill_dentries(struct inode *dir, struct dir_context *ctx, 10 10 void *dentry_blk, struct erofs_dirent *de, 11 - unsigned int nameoff, unsigned int maxsize) 11 + unsigned int nameoff0, unsigned int maxsize) 12 12 { 13 - const struct erofs_dirent *end = dentry_blk + nameoff; 13 + const struct erofs_dirent *end = dentry_blk + nameoff0; 14 14 15 15 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; 17 19 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; 24 20 25 21 /* the last dirent in the block? */ 26 22 if (de + 1 >= end) ··· 48 52 struct erofs_buf buf = __EROFS_BUF_INITIALIZER; 49 53 struct super_block *sb = dir->i_sb; 50 54 unsigned long bsz = sb->s_blocksize; 51 - const size_t dirsize = i_size_read(dir); 52 - unsigned int i = erofs_blknr(sb, ctx->pos); 53 55 unsigned int ofs = erofs_blkoff(sb, ctx->pos); 54 56 int err = 0; 55 57 bool initial = true; 56 58 57 59 buf.mapping = dir->i_mapping; 58 - while (ctx->pos < dirsize) { 60 + while (ctx->pos < dir->i_size) { 61 + erofs_off_t dbstart = ctx->pos - ofs; 59 62 struct erofs_dirent *de; 60 63 unsigned int nameoff, maxsize; 61 64 62 - de = erofs_bread(&buf, erofs_pos(sb, i), EROFS_KMAP); 65 + de = erofs_bread(&buf, dbstart, EROFS_KMAP); 63 66 if (IS_ERR(de)) { 64 67 erofs_err(sb, "fail to readdir of logical block %u of nid %llu", 65 - i, EROFS_I(dir)->nid); 68 + erofs_blknr(sb, dbstart), EROFS_I(dir)->nid); 66 69 err = PTR_ERR(de); 67 70 break; 68 71 } ··· 74 79 break; 75 80 } 76 81 77 - maxsize = min_t(unsigned int, dirsize - ctx->pos + ofs, bsz); 78 - 82 + maxsize = min_t(unsigned int, dir->i_size - dbstart, bsz); 79 83 /* search dirents at the arbitrary position */ 80 84 if (initial) { 81 85 initial = false; 82 - 83 86 ofs = roundup(ofs, sizeof(struct erofs_dirent)); 84 - ctx->pos = erofs_pos(sb, i) + ofs; 85 - if (ofs >= nameoff) 86 - goto skip_this; 87 + ctx->pos = dbstart + ofs; 87 88 } 88 89 89 90 err = erofs_fill_dentries(dir, ctx, de, (void *)de + ofs, 90 91 nameoff, maxsize); 91 92 if (err) 92 93 break; 93 - skip_this: 94 - ctx->pos = erofs_pos(sb, i) + maxsize; 95 - ++i; 94 + ctx->pos = dbstart + maxsize; 96 95 ofs = 0; 97 96 } 98 97 erofs_put_metabuf(&buf);
+9 -11
fs/erofs/inode.c
··· 257 257 goto out_unlock; 258 258 } 259 259 260 + mapping_set_large_folios(inode->i_mapping); 260 261 if (erofs_inode_is_data_compressed(vi->datalayout)) { 261 262 #ifdef CONFIG_EROFS_FS_ZIP 262 263 DO_ONCE_LITE_IF(inode->i_blkbits != PAGE_SHIFT, 263 264 erofs_info, inode->i_sb, 264 265 "EXPERIMENTAL EROFS subpage compressed block support in use. Use at your own risk!"); 265 266 inode->i_mapping->a_ops = &z_erofs_aops; 266 - err = 0; 267 - goto out_unlock; 268 - #endif 267 + #else 269 268 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); 274 - #ifdef CONFIG_EROFS_FS_ONDEMAND 275 - if (erofs_is_fscache_mode(inode->i_sb)) 276 - inode->i_mapping->a_ops = &erofs_fscache_access_aops; 277 269 #endif 278 - 270 + } else { 271 + inode->i_mapping->a_ops = &erofs_raw_access_aops; 272 + #ifdef CONFIG_EROFS_FS_ONDEMAND 273 + if (erofs_is_fscache_mode(inode->i_sb)) 274 + inode->i_mapping->a_ops = &erofs_fscache_access_aops; 275 + #endif 276 + } 279 277 out_unlock: 280 278 erofs_put_metabuf(&buf); 281 279 return err;
+1 -1
fs/erofs/internal.h
··· 220 220 }; 221 221 #define __EROFS_BUF_INITIALIZER ((struct erofs_buf){ .page = NULL }) 222 222 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)) 224 224 #define erofs_blkoff(sb, addr) ((addr) & ((sb)->s_blocksize - 1)) 225 225 #define erofs_pos(sb, blk) ((erofs_off_t)(blk) << (sb)->s_blocksize_bits) 226 226 #define erofs_iblks(i) (round_up((i)->i_size, i_blocksize(i)) >> (i)->i_blkbits)
+6 -20
fs/erofs/super.c
··· 108 108 kmem_cache_free(erofs_inode_cachep, vi); 109 109 } 110 110 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 - 127 111 /* read variable-sized metadata, offset will be aligned by 4-byte */ 128 112 void *erofs_read_metadata(struct super_block *sb, struct erofs_buf *buf, 129 113 erofs_off_t *offset, int *lengthp) ··· 263 279 264 280 static int erofs_read_superblock(struct super_block *sb) 265 281 { 266 - struct erofs_sb_info *sbi; 282 + struct erofs_sb_info *sbi = EROFS_SB(sb); 267 283 struct erofs_buf buf = __EROFS_BUF_INITIALIZER; 268 284 struct erofs_super_block *dsb; 269 285 void *data; ··· 275 291 return PTR_ERR(data); 276 292 } 277 293 278 - sbi = EROFS_SB(sb); 279 294 dsb = (struct erofs_super_block *)(data + EROFS_SUPER_OFFSET); 280 - 281 295 ret = -EINVAL; 282 296 if (le32_to_cpu(dsb->magic) != EROFS_SUPER_MAGIC_V1) { 283 297 erofs_err(sb, "cannot find valid erofs superblock"); ··· 300 318 } 301 319 302 320 ret = -EINVAL; 303 - if (!check_layout_compatibility(sb, dsb)) 321 + sbi->feature_incompat = le32_to_cpu(dsb->feature_incompat); 322 + if (sbi->feature_incompat & ~EROFS_ALL_FEATURE_INCOMPAT) { 323 + erofs_err(sb, "unidentified incompatible feature %x, please upgrade kernel", 324 + sbi->feature_incompat & ~EROFS_ALL_FEATURE_INCOMPAT); 304 325 goto out; 326 + } 305 327 306 328 sbi->sb_size = 128 + dsb->sb_extslots * EROFS_SB_EXTSLOT_SIZE; 307 329 if (sbi->sb_size > PAGE_SIZE - EROFS_SUPER_OFFSET) {
+2 -1
fs/erofs/zutil.c
··· 111 111 out: 112 112 if (i < z_erofs_gbuf_count && tmp_pages) { 113 113 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])) 115 116 __free_page(tmp_pages[j]); 116 117 kfree(tmp_pages); 117 118 }