summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-02-25 16:39:25 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2026-02-25 16:39:25 -0800
commitf4d0ec0aa20d49f09dc01d82894ce80d72de0560 (patch)
tree89d234e64069fac5c8d96a9c75ed377f58a2080a
parentd9d32e5bd5a4e57675f2b70ddf73c3dc5cf44fc2 (diff)
parent4a2d046e4b13202a6301a993961f5b30ae4d7119 (diff)
Merge tag 'erofs-for-7.0-rc2-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofsHEADmaster
Pull erofs fixes from Gao Xiang: - Do not share the page cache if the real @aops differs - Fix the incomplete condition for interlaced plain extents - Get rid of more unnecessary #ifdefs * tag 'erofs-for-7.0-rc2-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs: erofs: fix interlaced plain identification for encoded extents erofs: remove more unnecessary #ifdefs erofs: allow sharing page cache with the same aops only
-rw-r--r--fs/erofs/inode.c7
-rw-r--r--fs/erofs/internal.h16
-rw-r--r--fs/erofs/ishare.c14
-rw-r--r--fs/erofs/super.c85
-rw-r--r--fs/erofs/zmap.c9
5 files changed, 63 insertions, 68 deletions
diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c
index 4f86169c23f1..4b3d21402e10 100644
--- a/fs/erofs/inode.c
+++ b/fs/erofs/inode.c
@@ -222,6 +222,7 @@ err_out:
static int erofs_fill_inode(struct inode *inode)
{
+ const struct address_space_operations *aops;
int err;
trace_erofs_fill_inode(inode);
@@ -254,7 +255,11 @@ static int erofs_fill_inode(struct inode *inode)
}
mapping_set_large_folios(inode->i_mapping);
- return erofs_inode_set_aops(inode, inode, false);
+ aops = erofs_get_aops(inode, false);
+ if (IS_ERR(aops))
+ return PTR_ERR(aops);
+ inode->i_mapping->a_ops = aops;
+ return 0;
}
/*
diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
index d1634455e389..a4f0a42cf8c3 100644
--- a/fs/erofs/internal.h
+++ b/fs/erofs/internal.h
@@ -471,26 +471,24 @@ static inline void *erofs_vm_map_ram(struct page **pages, unsigned int count)
return NULL;
}
-static inline int erofs_inode_set_aops(struct inode *inode,
- struct inode *realinode, bool no_fscache)
+static inline const struct address_space_operations *
+erofs_get_aops(struct inode *realinode, bool no_fscache)
{
if (erofs_inode_is_data_compressed(EROFS_I(realinode)->datalayout)) {
if (!IS_ENABLED(CONFIG_EROFS_FS_ZIP))
- return -EOPNOTSUPP;
+ return ERR_PTR(-EOPNOTSUPP);
DO_ONCE_LITE_IF(realinode->i_blkbits != PAGE_SHIFT,
erofs_info, realinode->i_sb,
"EXPERIMENTAL EROFS subpage compressed block support in use. Use at your own risk!");
- inode->i_mapping->a_ops = &z_erofs_aops;
- return 0;
+ return &z_erofs_aops;
}
- inode->i_mapping->a_ops = &erofs_aops;
if (IS_ENABLED(CONFIG_EROFS_FS_ONDEMAND) && !no_fscache &&
erofs_is_fscache_mode(realinode->i_sb))
- inode->i_mapping->a_ops = &erofs_fscache_access_aops;
+ return &erofs_fscache_access_aops;
if (IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE) &&
erofs_is_fileio_mode(EROFS_SB(realinode->i_sb)))
- inode->i_mapping->a_ops = &erofs_fileio_aops;
- return 0;
+ return &erofs_fileio_aops;
+ return &erofs_aops;
}
int erofs_register_sysfs(struct super_block *sb);
diff --git a/fs/erofs/ishare.c b/fs/erofs/ishare.c
index ce980320a8b9..829d50d5c717 100644
--- a/fs/erofs/ishare.c
+++ b/fs/erofs/ishare.c
@@ -40,10 +40,14 @@ bool erofs_ishare_fill_inode(struct inode *inode)
{
struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb);
struct erofs_inode *vi = EROFS_I(inode);
+ const struct address_space_operations *aops;
struct erofs_inode_fingerprint fp;
struct inode *sharedinode;
unsigned long hash;
+ aops = erofs_get_aops(inode, true);
+ if (IS_ERR(aops))
+ return false;
if (erofs_xattr_fill_inode_fingerprint(&fp, inode, sbi->domain_id))
return false;
hash = xxh32(fp.opaque, fp.size, 0);
@@ -56,15 +60,15 @@ bool erofs_ishare_fill_inode(struct inode *inode)
}
if (inode_state_read_once(sharedinode) & I_NEW) {
- if (erofs_inode_set_aops(sharedinode, inode, true)) {
- iget_failed(sharedinode);
- kfree(fp.opaque);
- return false;
- }
+ sharedinode->i_mapping->a_ops = aops;
sharedinode->i_size = vi->vfs_inode.i_size;
unlock_new_inode(sharedinode);
} else {
kfree(fp.opaque);
+ if (aops != sharedinode->i_mapping->a_ops) {
+ iput(sharedinode);
+ return false;
+ }
if (sharedinode->i_size != vi->vfs_inode.i_size) {
_erofs_printk(inode->i_sb, KERN_WARNING
"size(%lld:%lld) not matches for the same fingerprint\n",
diff --git a/fs/erofs/super.c b/fs/erofs/super.c
index d4995686ac6c..972a0c82198d 100644
--- a/fs/erofs/super.c
+++ b/fs/erofs/super.c
@@ -424,26 +424,23 @@ static const struct fs_parameter_spec erofs_fs_parameters[] = {
static bool erofs_fc_set_dax_mode(struct fs_context *fc, unsigned int mode)
{
-#ifdef CONFIG_FS_DAX
- struct erofs_sb_info *sbi = fc->s_fs_info;
-
- switch (mode) {
- case EROFS_MOUNT_DAX_ALWAYS:
- set_opt(&sbi->opt, DAX_ALWAYS);
- clear_opt(&sbi->opt, DAX_NEVER);
- return true;
- case EROFS_MOUNT_DAX_NEVER:
- set_opt(&sbi->opt, DAX_NEVER);
- clear_opt(&sbi->opt, DAX_ALWAYS);
- return true;
- default:
+ if (IS_ENABLED(CONFIG_FS_DAX)) {
+ struct erofs_sb_info *sbi = fc->s_fs_info;
+
+ if (mode == EROFS_MOUNT_DAX_ALWAYS) {
+ set_opt(&sbi->opt, DAX_ALWAYS);
+ clear_opt(&sbi->opt, DAX_NEVER);
+ return true;
+ } else if (mode == EROFS_MOUNT_DAX_NEVER) {
+ set_opt(&sbi->opt, DAX_NEVER);
+ clear_opt(&sbi->opt, DAX_ALWAYS);
+ return true;
+ }
DBG_BUGON(1);
return false;
}
-#else
errorfc(fc, "dax options not supported");
return false;
-#endif
}
static int erofs_fc_parse_param(struct fs_context *fc,
@@ -460,31 +457,26 @@ static int erofs_fc_parse_param(struct fs_context *fc,
switch (opt) {
case Opt_user_xattr:
-#ifdef CONFIG_EROFS_FS_XATTR
- if (result.boolean)
+ if (!IS_ENABLED(CONFIG_EROFS_FS_XATTR))
+ errorfc(fc, "{,no}user_xattr options not supported");
+ else if (result.boolean)
set_opt(&sbi->opt, XATTR_USER);
else
clear_opt(&sbi->opt, XATTR_USER);
-#else
- errorfc(fc, "{,no}user_xattr options not supported");
-#endif
break;
case Opt_acl:
-#ifdef CONFIG_EROFS_FS_POSIX_ACL
- if (result.boolean)
+ if (!IS_ENABLED(CONFIG_EROFS_FS_POSIX_ACL))
+ errorfc(fc, "{,no}acl options not supported");
+ else if (result.boolean)
set_opt(&sbi->opt, POSIX_ACL);
else
clear_opt(&sbi->opt, POSIX_ACL);
-#else
- errorfc(fc, "{,no}acl options not supported");
-#endif
break;
case Opt_cache_strategy:
-#ifdef CONFIG_EROFS_FS_ZIP
- sbi->opt.cache_strategy = result.uint_32;
-#else
- errorfc(fc, "compression not supported, cache_strategy ignored");
-#endif
+ if (!IS_ENABLED(CONFIG_EROFS_FS_ZIP))
+ errorfc(fc, "compression not supported, cache_strategy ignored");
+ else
+ sbi->opt.cache_strategy = result.uint_32;
break;
case Opt_dax:
if (!erofs_fc_set_dax_mode(fc, EROFS_MOUNT_DAX_ALWAYS))
@@ -533,24 +525,21 @@ static int erofs_fc_parse_param(struct fs_context *fc,
break;
#endif
case Opt_directio:
-#ifdef CONFIG_EROFS_FS_BACKED_BY_FILE
- if (result.boolean)
+ if (!IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE))
+ errorfc(fc, "%s option not supported", erofs_fs_parameters[opt].name);
+ else if (result.boolean)
set_opt(&sbi->opt, DIRECT_IO);
else
clear_opt(&sbi->opt, DIRECT_IO);
-#else
- errorfc(fc, "%s option not supported", erofs_fs_parameters[opt].name);
-#endif
break;
case Opt_fsoffset:
sbi->dif0.fsoff = result.uint_64;
break;
case Opt_inode_share:
-#ifdef CONFIG_EROFS_FS_PAGE_CACHE_SHARE
- set_opt(&sbi->opt, INODE_SHARE);
-#else
- errorfc(fc, "%s option not supported", erofs_fs_parameters[opt].name);
-#endif
+ if (!IS_ENABLED(CONFIG_EROFS_FS_PAGE_CACHE_SHARE))
+ errorfc(fc, "%s option not supported", erofs_fs_parameters[opt].name);
+ else
+ set_opt(&sbi->opt, INODE_SHARE);
break;
}
return 0;
@@ -809,8 +798,7 @@ static int erofs_fc_get_tree(struct fs_context *fc)
ret = get_tree_bdev_flags(fc, erofs_fc_fill_super,
IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE) ?
GET_TREE_BDEV_QUIET_LOOKUP : 0);
-#ifdef CONFIG_EROFS_FS_BACKED_BY_FILE
- if (ret == -ENOTBLK) {
+ if (IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE) && ret == -ENOTBLK) {
struct file *file;
if (!fc->source)
@@ -824,7 +812,6 @@ static int erofs_fc_get_tree(struct fs_context *fc)
sbi->dif0.file->f_mapping->a_ops->read_folio)
return get_tree_nodev(fc, erofs_fc_fill_super);
}
-#endif
return ret;
}
@@ -1108,12 +1095,12 @@ static int erofs_show_options(struct seq_file *seq, struct dentry *root)
seq_puts(seq, ",dax=never");
if (erofs_is_fileio_mode(sbi) && test_opt(opt, DIRECT_IO))
seq_puts(seq, ",directio");
-#ifdef CONFIG_EROFS_FS_ONDEMAND
- if (sbi->fsid)
- seq_printf(seq, ",fsid=%s", sbi->fsid);
- if (sbi->domain_id)
- seq_printf(seq, ",domain_id=%s", sbi->domain_id);
-#endif
+ if (IS_ENABLED(CONFIG_EROFS_FS_ONDEMAND)) {
+ if (sbi->fsid)
+ seq_printf(seq, ",fsid=%s", sbi->fsid);
+ if (sbi->domain_id)
+ seq_printf(seq, ",domain_id=%s", sbi->domain_id);
+ }
if (sbi->dif0.fsoff)
seq_printf(seq, ",fsoffset=%llu", sbi->dif0.fsoff);
if (test_opt(opt, INODE_SHARE))
diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c
index c8d8e129eb4b..30775502b56d 100644
--- a/fs/erofs/zmap.c
+++ b/fs/erofs/zmap.c
@@ -513,6 +513,7 @@ static int z_erofs_map_blocks_ext(struct inode *inode,
unsigned int recsz = z_erofs_extent_recsize(vi->z_advise);
erofs_off_t pos = round_up(Z_EROFS_MAP_HEADER_END(erofs_iloc(inode) +
vi->inode_isize + vi->xattr_isize), recsz);
+ unsigned int bmask = sb->s_blocksize - 1;
bool in_mbox = erofs_inode_in_metabox(inode);
erofs_off_t lend = inode->i_size;
erofs_off_t l, r, mid, pa, la, lstart;
@@ -596,17 +597,17 @@ static int z_erofs_map_blocks_ext(struct inode *inode,
map->m_flags |= EROFS_MAP_MAPPED |
EROFS_MAP_FULL_MAPPED | EROFS_MAP_ENCODED;
fmt = map->m_plen >> Z_EROFS_EXTENT_PLEN_FMT_BIT;
+ if (map->m_plen & Z_EROFS_EXTENT_PLEN_PARTIAL)
+ map->m_flags |= EROFS_MAP_PARTIAL_REF;
+ map->m_plen &= Z_EROFS_EXTENT_PLEN_MASK;
if (fmt)
map->m_algorithmformat = fmt - 1;
- else if (interlaced && !erofs_blkoff(sb, map->m_pa))
+ else if (interlaced && !((map->m_pa | map->m_plen) & bmask))
map->m_algorithmformat =
Z_EROFS_COMPRESSION_INTERLACED;
else
map->m_algorithmformat =
Z_EROFS_COMPRESSION_SHIFTED;
- if (map->m_plen & Z_EROFS_EXTENT_PLEN_PARTIAL)
- map->m_flags |= EROFS_MAP_PARTIAL_REF;
- map->m_plen &= Z_EROFS_EXTENT_PLEN_MASK;
}
}
map->m_llen = lend - map->m_la;