[PATCH 2/2] erofs-utils: mkfs: fix location of xattr long prefixes
Gao Xiang
hsiangkao at linux.alibaba.com
Fri Sep 12 05:28:27 AEST 2025
Previously, xattr long prefixes were always kept in packed_inode
by mkfs.erofs [1], even when the fragments feature could be avoided.
This is messy, so let's fix the placement as follows:
COMPAT_PLAIN_XATTR_PFX is not set:
- If INCOMPAT_METABOX is set, place long prefixes into metabox_inode
(since it should be treated as metadata);
- If INCOMPAT_FRAGMENTS is set, place long prefixes into packed_inode
(for compatibility only);
Otherwise, always place long prefixes directly on disk.
[1] ff160922e94a ("erofs-utils: introduce on-disk format for long xattr name prefixes")
Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
include/erofs/internal.h | 1 +
include/erofs/xattr.h | 2 +-
include/erofs_fs.h | 1 +
lib/xattr.c | 71 +++++++++++++++++++++++++++++++---------
mkfs/main.c | 7 +++-
5 files changed, 65 insertions(+), 17 deletions(-)
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 3e1000d..cea6420 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -186,6 +186,7 @@ EROFS_FEATURE_FUNCS(48bit, incompat, INCOMPAT_48BIT)
EROFS_FEATURE_FUNCS(metabox, incompat, INCOMPAT_METABOX)
EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM)
EROFS_FEATURE_FUNCS(xattr_filter, compat, COMPAT_XATTR_FILTER)
+EROFS_FEATURE_FUNCS(plain_xattr_pfx, compat, COMPAT_PLAIN_XATTR_PFX)
#define EROFS_I_EA_INITED_BIT 0
#define EROFS_I_Z_INITED_BIT 1
diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h
index 81604b6..769791a 100644
--- a/include/erofs/xattr.h
+++ b/include/erofs/xattr.h
@@ -50,7 +50,7 @@ int erofs_build_shared_xattrs_from_path(struct erofs_sb_info *sbi, const char *p
int erofs_xattr_insert_name_prefix(const char *prefix);
void erofs_xattr_cleanup_name_prefixes(void);
-int erofs_xattr_flush_name_prefixes(struct erofs_sb_info *sbi);
+int erofs_xattr_flush_name_prefixes(struct erofs_sb_info *sbi, bool plain);
void erofs_xattr_prefixes_cleanup(struct erofs_sb_info *sbi);
int erofs_xattr_prefixes_init(struct erofs_sb_info *sbi);
diff --git a/include/erofs_fs.h b/include/erofs_fs.h
index df1af98..887f37f 100644
--- a/include/erofs_fs.h
+++ b/include/erofs_fs.h
@@ -16,6 +16,7 @@
#define EROFS_FEATURE_COMPAT_SB_CHKSUM 0x00000001
#define EROFS_FEATURE_COMPAT_MTIME 0x00000002
#define EROFS_FEATURE_COMPAT_XATTR_FILTER 0x00000004
+#define EROFS_FEATURE_COMPAT_PLAIN_XATTR_PFX 0x00000010
/*
* Any bits that aren't in EROFS_ALL_FEATURE_INCOMPAT should
diff --git a/lib/xattr.c b/lib/xattr.c
index 114e2bb..977031d 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -17,6 +17,7 @@
#include "erofs/xattr.h"
#include "erofs/fragments.h"
#include "liberofs_cache.h"
+#include "liberofs_metabox.h"
#include "liberofs_xxhash.h"
#include "liberofs_private.h"
@@ -804,23 +805,48 @@ static int comp_shared_xattr_item(const void *a, const void *b)
return la > lb;
}
-int erofs_xattr_flush_name_prefixes(struct erofs_sb_info *sbi)
+int erofs_xattr_flush_name_prefixes(struct erofs_sb_info *sbi, bool plain)
{
- int fd = erofs_packedfile(sbi);
+ bool may_fragments = cfg.c_fragments || erofs_sb_has_fragments(sbi);
+ struct erofs_vfile *vf = &sbi->bdev;
+ struct erofs_bufmgr *bmgr = sbi->bmgr;
+ struct erofs_buffer_head *bh = NULL;
+ struct erofs_vfile _vf;
struct ea_type_node *tnode;
- s64 offset;
+ s64 start, offset = 0;
int err;
if (!ea_prefix_count)
return 0;
- offset = lseek(fd, 0, SEEK_CUR);
- if (offset < 0)
- return -errno;
- offset = round_up(offset, 4);
+
+ if (plain) {
+ erofs_sb_set_plain_xattr_pfx(sbi);
+ if (may_fragments)
+ erofs_sb_set_metabox(sbi);
+ } else if (erofs_sb_has_metabox(sbi)) {
+ bmgr = erofs_metabox_bmgr(sbi);
+ vf = bmgr->vf;
+ } else if (may_fragments) {
+ erofs_sb_set_fragments(sbi);
+ _vf = (struct erofs_vfile){ .fd = erofs_packedfile(sbi) };
+ vf = &_vf;
+ offset = lseek(vf->fd, 0, SEEK_CUR);
+ if (offset < 0)
+ return -errno;
+ bmgr = NULL;
+ }
+
+ if (bmgr) {
+ bh = erofs_balloc(bmgr, XATTR, 0, 0);
+ if (IS_ERR(bh))
+ return PTR_ERR(bh);
+ (void)erofs_mapbh(bmgr, bh->block);
+ offset = erofs_btell(bh, false);
+ }
+
if ((offset >> 2) > UINT32_MAX)
return -EOVERFLOW;
- if (lseek(fd, offset, SEEK_SET) < 0)
- return -errno;
+ start = offset;
sbi->xattr_prefix_start = (u32)offset >> 2;
sbi->xattr_prefix_count = ea_prefix_count;
@@ -842,17 +868,27 @@ int erofs_xattr_flush_name_prefixes(struct erofs_sb_info *sbi)
infix_len);
len = sizeof(struct erofs_xattr_long_prefix) + infix_len;
u.s.size = cpu_to_le16(len);
- err = __erofs_io_write(fd, &u.s, sizeof(__le16) + len);
+ err = erofs_io_pwrite(vf, &u.s, offset, sizeof(__le16) + len);
if (err != sizeof(__le16) + len) {
if (err < 0)
- return -errno;
+ return err;
return -EIO;
}
offset = round_up(offset + sizeof(__le16) + len, 4);
- if (lseek(fd, offset, SEEK_SET) < 0)
+ }
+
+ if (bh) {
+ bh->op = &erofs_drop_directly_bhops;
+ err = erofs_bh_balloon(bh, offset - start);
+ if (err < 0)
+ return err;
+ bh->op = &erofs_drop_directly_bhops;
+ erofs_bdrop(bh, false);
+ } else {
+ DBG_BUGON(bmgr);
+ if (lseek(vf->fd, offset, SEEK_CUR) < 0)
return -errno;
}
- erofs_sb_set_fragments(sbi);
erofs_sb_set_xattr_prefixes(sbi);
return 0;
}
@@ -1641,6 +1677,7 @@ void erofs_xattr_prefixes_cleanup(struct erofs_sb_info *sbi)
int erofs_xattr_prefixes_init(struct erofs_sb_info *sbi)
{
+ bool plain = erofs_sb_has_plain_xattr_pfx(sbi);
erofs_off_t pos = (erofs_off_t)sbi->xattr_prefix_start << 2;
struct erofs_xattr_prefix_item *pfs;
erofs_nid_t nid = 0;
@@ -1650,8 +1687,12 @@ int erofs_xattr_prefixes_init(struct erofs_sb_info *sbi)
if (!sbi->xattr_prefix_count)
return 0;
- if (sbi->packed_nid)
- nid = sbi->packed_nid;
+ if (!plain) {
+ if (sbi->metabox_nid)
+ nid = sbi->metabox_nid;
+ else if (sbi->packed_nid)
+ nid = sbi->packed_nid;
+ }
pfs = calloc(sbi->xattr_prefix_count, sizeof(*pfs));
if (!pfs)
diff --git a/mkfs/main.c b/mkfs/main.c
index c328e0a..a8208d4 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -415,6 +415,7 @@ static struct {
};
static bool mkfs_no_datainline;
+static bool mkfs_plain_xattr_pfx;
static int parse_extended_opts(const char *opts)
{
@@ -491,6 +492,10 @@ static int parse_extended_opts(const char *opts)
if (vallen)
return -EINVAL;
cfg.c_xattr_name_filter = !clear;
+ } else if (MATCH_EXTENTED_OPT("plain-xattr-prefixes", token, keylen)) {
+ if (vallen)
+ return -EINVAL;
+ mkfs_plain_xattr_pfx = true;
} else {
int i, err;
@@ -1788,7 +1793,7 @@ int main(int argc, char **argv)
}
if (cfg.c_extra_ea_name_prefixes)
- erofs_xattr_flush_name_prefixes(&g_sbi);
+ erofs_xattr_flush_name_prefixes(&g_sbi, mkfs_plain_xattr_pfx);
root = erofs_new_inode(&g_sbi);
if (IS_ERR(root)) {
--
2.43.5
More information about the Linux-erofs
mailing list