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 <hsiang...@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


Reply via email to