summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap1
-rw-r--r--Documentation/filesystems/erofs.rst7
-rw-r--r--MAINTAINERS4
-rw-r--r--fs/erofs/data.c34
-rw-r--r--fs/erofs/decompressor.c2
-rw-r--r--fs/erofs/fileio.c157
-rw-r--r--fs/erofs/internal.h12
-rw-r--r--fs/erofs/ishare.c4
-rw-r--r--fs/erofs/super.c56
9 files changed, 142 insertions, 135 deletions
diff --git a/.mailmap b/.mailmap
index 0a0be49bc4de..abb09aab44c6 100644
--- a/.mailmap
+++ b/.mailmap
@@ -321,6 +321,7 @@ Gao Xiang <xiang@kernel.org> <gaoxiang25@huawei.com>
Gao Xiang <xiang@kernel.org> <hsiangkao@aol.com>
Gao Xiang <xiang@kernel.org> <hsiangkao@linux.alibaba.com>
Gao Xiang <xiang@kernel.org> <hsiangkao@redhat.com>
+Gao Xiang <xiang@kernel.org> <xiang.gao@docker.com>
Geliang Tang <geliang@kernel.org> <geliang.tang@linux.dev>
Geliang Tang <geliang@kernel.org> <geliang.tang@suse.com>
Geliang Tang <geliang@kernel.org> <geliangtang@xiaomi.com>
diff --git a/Documentation/filesystems/erofs.rst b/Documentation/filesystems/erofs.rst
index d301d9ac946a..02caf3b061fe 100644
--- a/Documentation/filesystems/erofs.rst
+++ b/Documentation/filesystems/erofs.rst
@@ -139,6 +139,9 @@ inode_share Enable inode page sharing for this filesystem. Inodes wi
page cache.
source=%s (For file-backed mounts) Specify the backing image as a path
or as an already-opened file descriptor.
+superblock_share (For file-backed mounts) Share the superblock when the same
+ backing file is mounted more than once with compatible
+ options. Remount is not allowed on shared superblocks.
=================== =========================================================
File-backed mounts
@@ -156,6 +159,10 @@ Only regular files are accepted as backing files; to mount an image that
resides on a block device, use the traditional block device mount path
instead.
+When superblock_share is specified, multiple mounts of the same backing
+file at the same fsoffset with compatible mount options can share a single
+superblock. Remount is not allowed on shared superblocks.
+
Sysfs Entries
=============
diff --git a/MAINTAINERS b/MAINTAINERS
index 7a85e966d094..7b5cab72d851 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9715,14 +9715,14 @@ EROFS FILE SYSTEM
M: Gao Xiang <xiang@kernel.org>
M: Chao Yu <chao@kernel.org>
R: Yue Hu <zbestahu@gmail.com>
-R: Jeffle Xu <jefflexu@linux.alibaba.com>
+R: Jingbo Xu <jefflexu@163.com>
R: Sandeep Dhavale <dhavale@google.com>
R: Hongbo Li <hongbohbli@tencent.com>
R: Chunhai Guo <guochunhai@vivo.com>
L: linux-erofs@lists.ozlabs.org
S: Maintained
W: https://erofs.docs.kernel.org
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git dev
F: Documentation/ABI/testing/sysfs-fs-erofs
F: Documentation/filesystems/erofs.rst
F: fs/erofs/
diff --git a/fs/erofs/data.c b/fs/erofs/data.c
index be63b89f0862..f09c152d5516 100644
--- a/fs/erofs/data.c
+++ b/fs/erofs/data.c
@@ -33,7 +33,10 @@ void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, bool need_kmap)
if (buf->page) {
folio = page_folio(buf->page);
- if (folio_file_page(folio, index) != buf->page)
+ if (folio->mapping != buf->mapping)
+ /* the cached folio belongs to another address_space */
+ folio = NULL;
+ else if (folio_file_page(folio, index) != buf->page)
erofs_unmap_metabuf(buf);
}
if (!folio || !folio_contains(folio, index)) {
@@ -278,12 +281,6 @@ void erofs_onlinefolio_end(struct folio *folio, int err, bool dirty)
folio_end_read(folio, !(v & BIT(EROFS_ONLINEFOLIO_EIO)));
}
-struct erofs_iomap_iter_ctx {
- struct page *page;
- void *base;
- struct inode *realinode;
-};
-
static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
unsigned int flags, struct iomap *iomap, struct iomap *srcmap)
{
@@ -305,6 +302,7 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
iomap->length = map.m_llen;
iomap->flags = 0;
iomap->addr = IOMAP_NULL_ADDR;
+ iomap->private = NULL;
if (!(map.m_flags & EROFS_MAP_MAPPED)) {
iomap->type = IOMAP_HOLE;
return 0;
@@ -319,6 +317,7 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
if (ret)
return ret;
+ iomap->private = mdev.m_dif;
if (flags & IOMAP_DAX)
iomap->dax_dev = mdev.m_dif->dax_dev;
else
@@ -393,14 +392,16 @@ int erofs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
*/
static int erofs_read_folio(struct file *file, struct folio *folio)
{
- struct iomap_read_folio_ctx read_ctx = {
- .ops = &iomap_bio_read_ops,
- .cur_folio = folio,
- };
bool need_iput;
struct erofs_iomap_iter_ctx iter_ctx = {
.realinode = erofs_real_inode(folio_inode(folio), &need_iput),
};
+ struct erofs_sb_info *sbi = EROFS_I_SB(iter_ctx.realinode);
+ struct iomap_read_folio_ctx read_ctx = {
+ .ops = erofs_is_fileio_mode(sbi) ?
+ &erofs_fileio_iomap_read_ops : &iomap_bio_read_ops,
+ .cur_folio = folio,
+ };
trace_erofs_read_folio(iter_ctx.realinode, folio, true);
iomap_read_folio(&erofs_iomap_ops, &read_ctx, &iter_ctx);
@@ -411,14 +412,16 @@ static int erofs_read_folio(struct file *file, struct folio *folio)
static void erofs_readahead(struct readahead_control *rac)
{
- struct iomap_read_folio_ctx read_ctx = {
- .ops = &iomap_bio_read_ops,
- .rac = rac,
- };
bool need_iput;
struct erofs_iomap_iter_ctx iter_ctx = {
.realinode = erofs_real_inode(rac->mapping->host, &need_iput),
};
+ struct erofs_sb_info *sbi = EROFS_I_SB(iter_ctx.realinode);
+ struct iomap_read_folio_ctx read_ctx = {
+ .ops = erofs_is_fileio_mode(sbi) ?
+ &erofs_fileio_iomap_read_ops : &iomap_bio_read_ops,
+ .rac = rac,
+ };
trace_erofs_readahead(iter_ctx.realinode, readahead_index(rac),
readahead_count(rac), true);
@@ -454,7 +457,6 @@ static ssize_t erofs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
return filemap_read(iocb, to, 0);
}
-/* for uncompressed (aligned) files and raw access for other files */
const struct address_space_operations erofs_aops = {
.read_folio = erofs_read_folio,
.readahead = erofs_readahead,
diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c
index d387b27c4ee2..771d862afc2e 100644
--- a/fs/erofs/decompressor.c
+++ b/fs/erofs/decompressor.c
@@ -23,7 +23,7 @@ static int z_erofs_load_lz4_config(struct super_block *sb,
if (!sbi->lz4.max_pclusterblks) {
sbi->lz4.max_pclusterblks = 1; /* reserved case */
} else if (sbi->lz4.max_pclusterblks >
- erofs_blknr(sb, Z_EROFS_PCLUSTER_MAX_SIZE)) {
+ Z_EROFS_PCLUSTER_MAX_SIZE >> sbi->blkszbits) {
erofs_err(sb, "too large lz4 pclusterblks %u",
sbi->lz4.max_pclusterblks);
return -EINVAL;
diff --git a/fs/erofs/fileio.c b/fs/erofs/fileio.c
index ebb81a7ffd4c..c36a90a1a4cb 100644
--- a/fs/erofs/fileio.c
+++ b/fs/erofs/fileio.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2024, Alibaba Cloud
+ * Copyright 2026 Docker, Inc.
*/
#include "internal.h"
#include <trace/events/erofs.h>
@@ -30,7 +31,8 @@ static void erofs_fileio_ki_complete(struct kiocb *iocb, long ret)
if (!rq->bio.bi_end_io) {
bio_for_each_folio_all(fi, &rq->bio) {
DBG_BUGON(folio_test_uptodate(fi.folio));
- erofs_onlinefolio_end(fi.folio, ret < 0, false);
+ iomap_finish_folio_read(fi.folio, fi.offset, fi.length,
+ ret < 0 ? ret : 0);
}
} else if (ret < 0 && !rq->bio.bi_status) {
rq->bio.bi_status = errno_to_blk_status(ret);
@@ -64,137 +66,76 @@ static void erofs_fileio_rq_submit(struct erofs_fileio_rq *rq)
kfree(rq);
}
-static struct erofs_fileio_rq *erofs_fileio_rq_alloc(struct erofs_map_dev *mdev)
+static struct erofs_fileio_rq *erofs_fileio_rq_alloc(struct super_block *sb,
+ struct file *file)
{
struct erofs_fileio_rq *rq = kzalloc_obj(*rq, GFP_KERNEL | __GFP_NOFAIL);
bio_init(&rq->bio, NULL, rq->bvecs, ARRAY_SIZE(rq->bvecs), REQ_OP_READ);
- rq->iocb.ki_filp = mdev->m_dif->file;
- rq->sb = mdev->m_sb;
+ rq->iocb.ki_filp = file;
+ rq->sb = sb;
refcount_set(&rq->ref, 2);
return rq;
}
struct bio *erofs_fileio_bio_alloc(struct erofs_map_dev *mdev)
{
- return &erofs_fileio_rq_alloc(mdev)->bio;
+ return &erofs_fileio_rq_alloc(mdev->m_sb, mdev->m_dif->file)->bio;
}
void erofs_fileio_submit_bio(struct bio *bio)
{
- return erofs_fileio_rq_submit(container_of(bio, struct erofs_fileio_rq,
- bio));
+ erofs_fileio_rq_submit(container_of(bio, struct erofs_fileio_rq, bio));
}
-static int erofs_fileio_scan_folio(struct erofs_fileio *io,
- struct inode *inode, struct folio *folio)
+static void erofs_fileio_iomap_submit_read(const struct iomap_iter *iter,
+ struct iomap_read_folio_ctx *ctx)
{
- struct erofs_map_blocks *map = &io->map;
- unsigned int cur = 0, end = folio_size(folio), len, attached = 0;
- loff_t pos = folio_pos(folio), ofs;
- int err = 0;
-
- erofs_onlinefolio_init(folio);
- while (cur < end) {
- if (!in_range(pos + cur, map->m_la, map->m_llen)) {
- map->m_la = pos + cur;
- map->m_llen = end - cur;
- err = erofs_map_blocks(inode, map);
- if (err)
- break;
- }
-
- ofs = folio_pos(folio) + cur - map->m_la;
- len = min_t(loff_t, map->m_llen - ofs, end - cur);
- if (map->m_flags & EROFS_MAP_META) {
- struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
- void *src;
-
- src = erofs_read_metabuf(&buf, inode->i_sb,
- map->m_pa + ofs, erofs_inode_in_metabox(inode));
- if (IS_ERR(src)) {
- err = PTR_ERR(src);
- break;
- }
- memcpy_to_folio(folio, cur, src, len);
- erofs_put_metabuf(&buf);
- } else if (!(map->m_flags & EROFS_MAP_MAPPED)) {
- folio_zero_segment(folio, cur, cur + len);
- attached = 0;
- } else {
- if (io->rq && (map->m_pa + ofs != io->dev.m_pa ||
- map->m_deviceid != io->dev.m_deviceid)) {
-io_retry:
- erofs_fileio_rq_submit(io->rq);
- io->rq = NULL;
- }
-
- if (!io->rq) {
- io->dev = (struct erofs_map_dev) {
- .m_pa = io->map.m_pa + ofs,
- .m_deviceid = io->map.m_deviceid,
- };
- err = erofs_map_dev(inode->i_sb, &io->dev);
- if (err)
- break;
- io->rq = erofs_fileio_rq_alloc(&io->dev);
- io->rq->bio.bi_iter.bi_sector =
- (io->dev.m_dif->fsoff + io->dev.m_pa) >> 9;
- attached = 0;
- }
- if (!bio_add_folio(&io->rq->bio, folio, len, cur))
- goto io_retry;
- if (!attached++)
- erofs_onlinefolio_split(folio);
- io->dev.m_pa += len;
- }
- cur += len;
- }
- erofs_onlinefolio_end(folio, err, false);
- return err;
+ erofs_fileio_rq_submit((struct erofs_fileio_rq *)ctx->read_ctx);
+ ctx->read_ctx = NULL;
}
-static int erofs_fileio_read_folio(struct file *file, struct folio *folio)
+static int erofs_fileio_iomap_read_folio_range(const struct iomap_iter *iter,
+ struct iomap_read_folio_ctx *ctx, size_t plen)
{
- bool need_iput;
- struct inode *realinode = erofs_real_inode(folio_inode(folio), &need_iput);
- struct erofs_fileio io = {};
- int err;
-
- trace_erofs_read_folio(realinode, folio, true);
- err = erofs_fileio_scan_folio(&io, realinode, folio);
- erofs_fileio_rq_submit(io.rq);
- if (need_iput)
- iput(realinode);
- return err;
+ struct erofs_iomap_iter_ctx *iter_ctx = iter->private;
+ struct folio *folio = ctx->cur_folio;
+ struct erofs_fileio_rq *rq = ctx->read_ctx;
+ sector_t sector = iomap_sector(&iter->iomap, iter->pos);
+
+ if (!rq || bio_end_sector(&rq->bio) != sector ||
+ !bio_add_folio(&rq->bio, folio, plen,
+ offset_in_folio(folio, iter->pos))) {
+ struct super_block *sb = iter_ctx->realinode->i_sb;
+ struct erofs_device_info *dif = iter->iomap.private;
+
+ /* submit the existing range if there was one. */
+ if (ctx->read_ctx)
+ erofs_fileio_iomap_submit_read(iter, ctx);
+ rq = erofs_fileio_rq_alloc(sb, dif->file);
+ rq->bio.bi_iter.bi_sector = sector;
+ bio_add_folio_nofail(&rq->bio, folio, plen,
+ offset_in_folio(folio, iter->pos));
+ ctx->read_ctx = rq;
+ ctx->read_ctx_file_offset = iter->pos;
+ }
+ return 0;
}
-static void erofs_fileio_readahead(struct readahead_control *rac)
+const struct iomap_read_ops erofs_fileio_iomap_read_ops = {
+ .read_folio_range = erofs_fileio_iomap_read_folio_range,
+ .submit_read = erofs_fileio_iomap_submit_read,
+};
+
+static void erofs_fileio_meta_endio(struct bio *bio)
{
- bool need_iput;
- struct inode *realinode = erofs_real_inode(rac->mapping->host, &need_iput);
- struct erofs_fileio io = {};
- struct folio *folio;
- int err;
+ bool uptodate = !bio->bi_status;
+ struct folio_iter fi;
- trace_erofs_readahead(realinode, readahead_index(rac),
- readahead_count(rac), true);
- while ((folio = readahead_folio(rac))) {
- err = erofs_fileio_scan_folio(&io, realinode, folio);
- if (err && err != -EINTR)
- erofs_err(realinode->i_sb, "readahead error at folio %lu @ nid %llu",
- folio->index, EROFS_I(realinode)->nid);
- }
- erofs_fileio_rq_submit(io.rq);
- if (need_iput)
- iput(realinode);
+ bio_for_each_folio_all(fi, bio)
+ folio_end_read(fi.folio, uptodate);
}
-const struct address_space_operations erofs_fileio_aops = {
- .read_folio = erofs_fileio_read_folio,
- .readahead = erofs_fileio_readahead,
-};
-
int erofs_read_meta_folio(struct file *file, struct folio *folio)
{
struct erofs_fileio io = {
@@ -207,10 +148,10 @@ int erofs_read_meta_folio(struct file *file, struct folio *folio)
if (err)
return err;
- io.rq = erofs_fileio_rq_alloc(&io.dev);
+ io.rq = erofs_fileio_rq_alloc(inode->i_sb, io.dev.m_dif->file);
+ io.rq->bio.bi_end_io = erofs_fileio_meta_endio;
io.rq->bio.bi_iter.bi_sector =
(io.dev.m_dif->fsoff + io.dev.m_pa) >> 9;
- erofs_onlinefolio_init(folio);
bio_add_folio_nofail(&io.rq->bio, folio, folio_size(folio), 0);
erofs_fileio_rq_submit(io.rq);
return 0;
diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
index ab817091bd29..8363c0c051f6 100644
--- a/fs/erofs/internal.h
+++ b/fs/erofs/internal.h
@@ -150,6 +150,7 @@ struct erofs_sb_info {
#define EROFS_MOUNT_DAX_NEVER 0x00000080
#define EROFS_MOUNT_DIRECT_IO 0x00000100
#define EROFS_MOUNT_INODE_SHARE 0x00000200
+#define EROFS_MOUNT_SUPERBLOCK_SHARE 0x00000400
#define clear_opt(opt, option) ((opt)->mount_opt &= ~EROFS_MOUNT_##option)
#define set_opt(opt, option) ((opt)->mount_opt |= EROFS_MOUNT_##option)
@@ -379,7 +380,6 @@ struct erofs_map_dev {
extern const struct super_operations erofs_sops;
extern const struct address_space_operations erofs_aops;
-extern const struct address_space_operations erofs_fileio_aops;
extern const struct address_space_operations z_erofs_aops;
extern const struct inode_operations erofs_generic_iops;
@@ -391,7 +391,14 @@ extern const struct file_operations erofs_file_fops;
extern const struct file_operations erofs_dir_fops;
extern const struct file_operations erofs_ishare_fops;
+struct erofs_iomap_iter_ctx {
+ struct page *page;
+ void *base;
+ struct inode *realinode;
+};
+
extern const struct iomap_ops z_erofs_iomap_report_ops;
+extern const struct iomap_read_ops erofs_fileio_iomap_read_ops;
int erofs_setup_managed_cache(struct super_block *sb);
#ifdef CONFIG_EROFS_FS_BACKED_BY_FILE
@@ -449,9 +456,6 @@ erofs_get_aops(struct inode *realinode)
"EXPERIMENTAL EROFS subpage compressed block support in use. Use at your own risk!");
return &z_erofs_aops;
}
- if (IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE) &&
- erofs_is_fileio_mode(EROFS_SB(realinode->i_sb)))
- return &erofs_fileio_aops;
return &erofs_aops;
}
diff --git a/fs/erofs/ishare.c b/fs/erofs/ishare.c
index a1cf2aff8d32..db32d16517a5 100644
--- a/fs/erofs/ishare.c
+++ b/fs/erofs/ishare.c
@@ -54,11 +54,13 @@ bool erofs_ishare_fill_inode(struct inode *inode)
si->i_mapping->a_ops = aops;
si->i_mode = 0444 | S_IFREG;
si->i_size = inode->i_size;
+ si->i_blkbits = inode->i_blkbits;
mapping_set_large_folios(si->i_mapping);
unlock_new_inode(si);
} else {
kfree(fp.opaque);
- if (!si || aops != si->i_mapping->a_ops) {
+ if (!si || aops != si->i_mapping->a_ops ||
+ si->i_blkbits != inode->i_blkbits) {
iput(si);
return false;
}
diff --git a/fs/erofs/super.c b/fs/erofs/super.c
index 0967aace9f7f..16fa3b853f1b 100644
--- a/fs/erofs/super.c
+++ b/fs/erofs/super.c
@@ -386,7 +386,7 @@ static void erofs_default_options(struct erofs_sb_info *sbi)
enum {
Opt_user_xattr, Opt_acl, Opt_cache_strategy, Opt_dax, Opt_dax_enum,
Opt_device, Opt_domain_id, Opt_directio, Opt_fsoffset, Opt_inode_share,
- Opt_source,
+ Opt_source, Opt_superblock_share,
};
static const struct constant_table erofs_param_cache_strategy[] = {
@@ -415,6 +415,7 @@ static const struct fs_parameter_spec erofs_fs_parameters[] = {
fsparam_u64("fsoffset", Opt_fsoffset),
fsparam_flag("inode_share", Opt_inode_share),
fsparam_file_or_string("source", Opt_source),
+ fsparam_flag("superblock_share", Opt_superblock_share),
{}
};
@@ -560,6 +561,12 @@ static int erofs_fc_parse_param(struct fs_context *fc,
else
set_opt(&sbi->opt, INODE_SHARE);
break;
+ case Opt_superblock_share:
+ if (!IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE))
+ errorfc(fc, "%s option not supported", erofs_fs_parameters[opt].name);
+ else
+ set_opt(&sbi->opt, SUPERBLOCK_SHARE);
+ break;
case Opt_source:
return erofs_fc_parse_source(fc, param);
}
@@ -667,6 +674,16 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc)
errorfc(fc, "FSDAX is not allowed when inode_share is on");
return -EINVAL;
}
+ if (test_opt(&sbi->opt, SUPERBLOCK_SHARE) &&
+ test_opt(&sbi->opt, INODE_SHARE)) {
+ errorfc(fc, "superblock_share is not allowed when inode_share is on");
+ return -EINVAL;
+ }
+ if (test_opt(&sbi->opt, SUPERBLOCK_SHARE) &&
+ sbi->devs->extra_devices) {
+ errorfc(fc, "superblock_share does not support extra devices");
+ return -EINVAL;
+ }
sbi->blkszbits = PAGE_SHIFT;
if (erofs_is_fileio_mode(sbi)) {
@@ -794,6 +811,35 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc)
return 0;
}
+/*
+ * The function is used only with a sbi that has SUPERBLOCK_SHARE set,
+ * so that the memcmp later ensures new_sbi is also shareable.
+ */
+static int erofs_sb_share_test_super(struct super_block *sb,
+ struct fs_context *fc)
+{
+ struct erofs_sb_info *sbi = EROFS_SB(sb);
+ struct erofs_sb_info *new_sbi = fc->s_fs_info;
+
+ if (sb->s_iflags & SB_I_RETIRED)
+ return 0;
+ if (!sbi->dif0.file || !new_sbi->dif0.file)
+ return 0;
+ return file_inode(sbi->dif0.file) == file_inode(new_sbi->dif0.file) &&
+ sbi->dif0.fsoff == new_sbi->dif0.fsoff &&
+ !memcmp(&sbi->opt, &new_sbi->opt, sizeof(sbi->opt));
+}
+
+static int erofs_file_get_tree(struct fs_context *fc)
+{
+ struct erofs_sb_info *sbi = fc->s_fs_info;
+
+ if (!test_opt(&sbi->opt, SUPERBLOCK_SHARE))
+ return get_tree_nodev(fc, erofs_fc_fill_super);
+
+ return get_tree_super(fc, erofs_sb_share_test_super, erofs_fc_fill_super);
+}
+
static int erofs_fc_get_tree(struct fs_context *fc)
{
struct erofs_sb_info *sbi = fc->s_fs_info;
@@ -809,7 +855,7 @@ static int erofs_fc_get_tree(struct fs_context *fc)
errorfc(fc, "source is unsupported");
return -EINVAL;
}
- return get_tree_nodev(fc, erofs_fc_fill_super);
+ return erofs_file_get_tree(fc);
}
ret = get_tree_bdev_flags(fc, erofs_fc_fill_super,
@@ -827,7 +873,7 @@ static int erofs_fc_get_tree(struct fs_context *fc)
if (S_ISREG(file_inode(sbi->dif0.file)->i_mode) &&
sbi->dif0.file->f_mapping->a_ops->read_folio)
- return get_tree_nodev(fc, erofs_fc_fill_super);
+ return erofs_file_get_tree(fc);
}
return ret;
}
@@ -840,6 +886,10 @@ static int erofs_fc_reconfigure(struct fs_context *fc)
DBG_BUGON(!sb_rdonly(sb));
+ /* Shared superblocks must not be reconfigured. */
+ if (test_opt(&sbi->opt, SUPERBLOCK_SHARE))
+ return -EBUSY;
+
if (new_sbi->domain_id)
erofs_info(sb, "ignoring reconfiguration for domain_id.");