On 2026/1/22 09:08, Hongbo Li wrote:
Hi, Xiang

On 2026/1/21 11:19, Gao Xiang wrote:
Based on the original Hongbo's version [1], it enables storing the
SHA-256 digest of each inode as an extended attribute, in preparation
for the upcoming page cache sharing feature.

Example usage:
  $ mkfs.erofs --xattr-inode-digest=system.erofs.fingerprint [-zlz4hc] 
foo.erofs foo/

[1] https://lore.kernel.org/r/[email protected]

Co-developed-by: Hongbo Li <[email protected]>
Signed-off-by: Gao Xiang <[email protected]>
Tested-by: Hongbo Li <[email protected]>
---
v2: 
https://lore.kernel.org/r/[email protected]
v3:
  - Support the hidden xattr namespace, so that user programs cannot
    access inode fingerprints via normal mounts in any case.

  include/erofs/internal.h |   2 +
  include/erofs/xattr.h    |   2 +
  include/erofs_fs.h       |   4 +-
  lib/inode.c              |  46 +++++++++-
  lib/super.c              |  13 ++-
  lib/xattr.c              |  19 +++-
  mkfs/main.c              | 187 ++++++++++++++++++++++-----------------
  7 files changed, 182 insertions(+), 91 deletions(-)

diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 26bf612..ef019a5 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -130,6 +130,7 @@ struct erofs_sb_info {
      u32 xattr_prefix_start;
      u8 xattr_prefix_count;
+    u8 ishare_xattr_prefix_id;
      struct erofs_xattr_prefix_item *xattr_prefixes;
      struct erofs_vfile bdev;
@@ -190,6 +191,7 @@ 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)
+EROFS_FEATURE_FUNCS(ishare_xattrs, compat, COMPAT_ISHARE_XATTRS)
  #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 941bed7..9654636 100644
--- a/include/erofs/xattr.h
+++ b/include/erofs/xattr.h
@@ -33,6 +33,8 @@ char *erofs_export_xattr_ibody(struct erofs_inode *inode);
  int erofs_load_shared_xattrs_from_path(struct erofs_sb_info *sbi, const char 
*path,
                         long inlinexattr_tolerance);
  int erofs_xattr_insert_name_prefix(const char *prefix);
+int erofs_xattr_set_ishare_prefix(struct erofs_sb_info *sbi,
+                  const char *prefix);
  void erofs_xattr_cleanup_name_prefixes(void);
  int erofs_xattr_flush_name_prefixes(struct erofs_importer *im, bool plain);
  int erofs_xattr_prefixes_init(struct erofs_sb_info *sbi);
diff --git a/include/erofs_fs.h b/include/erofs_fs.h
index 887f37f..8b0d155 100644
--- a/include/erofs_fs.h
+++ b/include/erofs_fs.h
@@ -17,6 +17,7 @@
  #define EROFS_FEATURE_COMPAT_MTIME              0x00000002
  #define EROFS_FEATURE_COMPAT_XATTR_FILTER    0x00000004
  #define EROFS_FEATURE_COMPAT_PLAIN_XATTR_PFX    0x00000010
+#define EROFS_FEATURE_COMPAT_ISHARE_XATTRS    0x00000020
  /*
   * Any bits that aren't in EROFS_ALL_FEATURE_INCOMPAT should
@@ -82,7 +83,8 @@ struct erofs_super_block {
      __le32 xattr_prefix_start;    /* start of long xattr prefixes */
      __le64 packed_nid;    /* nid of the special packed inode */
      __u8 xattr_filter_reserved; /* reserved for xattr name filter */
-    __u8 reserved[3];
+    __u8 ishare_xattr_prefix_id;
+    __u8 reserved[2];
      __le32 build_time;    /* seconds added to epoch for mkfs time */
      __le64 rootnid_8b;    /* (48BIT on) nid of root directory */
      __le64 reserved2;
diff --git a/lib/inode.c b/lib/inode.c
index 299ec46..e3ee79a 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -31,6 +31,7 @@
  #include "liberofs_metabox.h"
  #include "liberofs_private.h"
  #include "liberofs_rebuild.h"
+#include "sha256.h"
  static inline bool erofs_is_special_identifier(const char *path)
  {
@@ -1954,6 +1955,37 @@ static int erofs_prepare_dir_inode(const struct 
erofs_mkfs_btctx *ctx,
      return 0;
  }
+static int erofs_set_inode_fingerprint(struct erofs_inode *inode, int fd,
+                       erofs_off_t pos)
+{
+    u8 ishare_xattr_prefix_id = inode->sbi->ishare_xattr_prefix_id;
+    erofs_off_t remaining = inode->i_size;
+    struct erofs_vfile vf = { .fd = fd };
+    struct sha256_state md;
+    u8 out[32 + sizeof("sha256:") - 1];
+    int ret;
+
+    if (!ishare_xattr_prefix_id)
+        return 0;
+    erofs_sha256_init(&md);
+    do {
+        u8 buf[32768];
+
+        ret = erofs_io_pread(&vf, buf,
+                     min_t(u64, remaining, sizeof(buf)), pos);
+        if (ret < 0)
+            return ret;
+        if (ret > 0)
+            erofs_sha256_process(&md, buf, ret);
+        remaining -= ret;
+        pos += ret;
+    } while (remaining);
+    erofs_sha256_done(&md, out + sizeof("sha256:") - 1);
+    memcpy(out, "sha256:", sizeof("sha256:") - 1);
+    return erofs_setxattr(inode, ishare_xattr_prefix_id, "",
+                  out, sizeof(out));
+}
+
  static int erofs_mkfs_begin_nondirectory(const struct erofs_mkfs_btctx *btctx,
                       struct erofs_inode *inode)
  {
@@ -1973,11 +2005,18 @@ static int erofs_mkfs_begin_nondirectory(const struct 
erofs_mkfs_btctx *btctx,
              ctx.fd = open(inode->i_srcpath, O_RDONLY | O_BINARY);
              if (ctx.fd < 0)
                  return -errno;
-            __erofs_fallthrough;
-        default:
              break;
+        default:
+            goto out;
          }
-        if (ctx.fd >= 0 && cfg.c_compr_opts[0].alg &&
+
+        if (S_ISREG(inode->i_mode) && inode->i_size) {
+            ret = erofs_set_inode_fingerprint(inode, ctx.fd, ctx.fpos);
+            if (ret < 0)
+                return ret;
+        }
+
+        if (cfg.c_compr_opts[0].alg &&
              erofs_file_is_compressible(im, inode)) {
              ctx.ictx = erofs_prepare_compressed_file(im, inode);
              if (IS_ERR(ctx.ictx))
@@ -1989,6 +2028,7 @@ static int erofs_mkfs_begin_nondirectory(const struct 
erofs_mkfs_btctx *btctx,
                  return ret;
          }
      }
+out:
      return erofs_mkfs_go(btctx, EROFS_MKFS_JOB_NDIR, &ctx, sizeof(ctx));
  }
diff --git a/lib/super.c b/lib/super.c
index a203f96..0180087 100644
--- a/lib/super.c
+++ b/lib/super.c
@@ -146,7 +146,15 @@ int erofs_read_superblock(struct erofs_sb_info *sbi)
      sbi->build_time = le32_to_cpu(dsb->build_time);
      memcpy(&sbi->uuid, dsb->uuid, sizeof(dsb->uuid));
-
+    if (erofs_sb_has_ishare_xattrs(sbi)) {
+        if (dsb->ishare_xattr_prefix_id >= sbi->xattr_prefix_count) {
+            erofs_err("invalid ishare xattr prefix id %d",
+                  dsb->ishare_xattr_prefix_id);
+            return -EFSCORRUPTED;
+        }
+        sbi->ishare_xattr_prefix_id =
+            dsb->ishare_xattr_prefix_id | EROFS_XATTR_LONG_PREFIX;
+    }
      ret = z_erofs_parse_cfgs(sbi, dsb);
      if (ret)
          return ret;
@@ -160,7 +168,6 @@ int erofs_read_superblock(struct erofs_sb_info *sbi)
          free(sbi->devs);
          sbi->devs = NULL;
      }
-
      sbi->sb_valid = !ret;
      return ret;
  }
@@ -206,6 +213,8 @@ int erofs_writesb(struct erofs_sb_info *sbi)
          .extra_devices = cpu_to_le16(sbi->extra_devices),
          .devt_slotoff = cpu_to_le16(sbi->devt_slotoff),
          .packed_nid = cpu_to_le64(sbi->packed_nid),
+        .ishare_xattr_prefix_id = sbi->ishare_xattr_prefix_id &
+            EROFS_XATTR_LONG_PREFIX_MASK,
      };
      char *buf;
      int ret;
diff --git a/lib/xattr.c b/lib/xattr.c
index 9b0f2ca..d8c7bff 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -1483,8 +1483,9 @@ int erofs_xattr_insert_name_prefix(const char *prefix)
      if (!erofs_xattr_prefix_matches(prefix, &tnode->base_index,
                      &tnode->base_len)) {
-        free(tnode);
-        return -ENODATA;
+        /* Use internal hidden xattrs */
+        tnode->base_index = 0;
+        tnode->base_len = 0;

So, should we add parameter bool hidden to this helper to distinct the cases?

Others looks good to me!

Nope, just my own thought, I think for other xattr prefix cases
(if they really would like to add a hidden xattr prefix), that
should be okay too.

Thanks,
Gao Xiang



Thanks,
Hongbo


Reply via email to