From: Daeho Jeong <[email protected]>

I made a fsck.erofs tool to check erofs filesystem image integrity
and calculate filesystem compression ratio.
Here are options to support now.

fsck.erofs [options] IMAGE
-V      print the version number of fsck.erofs and exit.
-d#     set output message level to # (maximum 9)\n
-c      print total compression ratio of all compressed files
-C      print total compression ratio of all files

Signed-off-by: Daeho Jeong <[email protected]>
---
 Makefile.am              |   2 +-
 configure.ac             |   3 +-
 fsck/Makefile.am         |   9 +
 fsck/main.c              | 548 +++++++++++++++++++++++++++++++++++++++
 include/erofs/internal.h |   5 +
 include/erofs_fs.h       |  13 +
 lib/data.c               |   4 +-
 lib/namei.c              |   2 +-
 lib/super.c              |   1 +
 mkfs/main.c              |  13 -
 10 files changed, 582 insertions(+), 18 deletions(-)
 create mode 100644 fsck/Makefile.am
 create mode 100644 fsck/main.c

diff --git a/Makefile.am b/Makefile.am
index 24e1d38..fc464e8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,7 +2,7 @@
 
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = man lib mkfs dump
+SUBDIRS = man lib mkfs dump fsck
 if ENABLE_FUSE
 SUBDIRS += fuse
 endif
diff --git a/configure.ac b/configure.ac
index b2c3225..5698b2e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -298,5 +298,6 @@ AC_CONFIG_FILES([Makefile
                 lib/Makefile
                 mkfs/Makefile
                 dump/Makefile
-                fuse/Makefile])
+                fuse/Makefile
+                fsck/Makefile])
 AC_OUTPUT
diff --git a/fsck/Makefile.am b/fsck/Makefile.am
new file mode 100644
index 0000000..82973ba
--- /dev/null
+++ b/fsck/Makefile.am
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Makefile.am
+
+AUTOMAKE_OPTIONS = foreign
+bin_PROGRAMS     = fsck.erofs
+AM_CPPFLAGS = ${libuuid_CFLAGS}
+fsck_erofs_SOURCES = main.c
+fsck_erofs_CFLAGS = -Wall -Werror -I$(top_srcdir)/include
+fsck_erofs_LDADD = $(top_builddir)/lib/liberofs.la ${libuuid_LIBS} 
${liblz4_LIBS}
diff --git a/fsck/main.c b/fsck/main.c
new file mode 100644
index 0000000..c397d19
--- /dev/null
+++ b/fsck/main.c
@@ -0,0 +1,548 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021 Google LLC
+ * Author: Daeho Jeong <[email protected]>
+ */
+#include <stdlib.h>
+#include <getopt.h>
+#include <time.h>
+#include "erofs/print.h"
+#include "erofs/io.h"
+
+enum {
+       NO_PRINT_COMP_RATIO             = 0,
+       PRINT_COMP_RATIO_ALL            = 1,
+       PRINT_COMP_RATIO_COMP_FILE      = 2,
+};
+
+static void erofs_check_inode(erofs_nid_t pnid, erofs_nid_t nid);
+
+struct erofsfsck_cfg {
+       bool corrupted;
+       int print_comp_ratio;
+       u64 ondisk_len;
+       u64 logical_len;
+};
+static struct erofsfsck_cfg fsckcfg;
+
+static struct option long_options[] = {
+       {"help", no_argument, 0, 1},
+       {0, 0, 0, 0},
+};
+
+static void usage(void)
+{
+       fputs("usage: [options] IMAGE\n\n"
+             "Check erofs filesystem integrity of IMAGE, and [options] are:\n"
+             " -V      print the version number of fsck.erofs and exit.\n"
+             " -d#     set output message level to # (maximum 9)\n"
+             " -c      print total compression ratio of all compressed files\n"
+             " -C      print total compression ratio of all files\n"
+             " --help  display this help and exit.\n",
+             stderr);
+}
+
+static void erofsfsck_print_version(void)
+{
+       fprintf(stderr, "fsck.erofs %s\n", cfg.c_version);
+}
+
+static int erofsfsck_parse_options_cfg(int argc, char **argv)
+{
+       int opt, i;
+
+       while ((opt = getopt_long(argc, argv, "Vd:Cc",
+                                 long_options, NULL)) != -1) {
+               switch (opt) {
+               case 'V':
+                       erofsfsck_print_version();
+                       exit(0);
+               case 'd':
+                       i = atoi(optarg);
+                       if (i < EROFS_MSG_MIN || i > EROFS_MSG_MAX) {
+                               erofs_err("invalid debug level %d", i);
+                               return -EINVAL;
+                       }
+                       cfg.c_dbg_lvl = i;
+                       break;
+               case 'C':
+                       fsckcfg.print_comp_ratio = PRINT_COMP_RATIO_ALL;
+                       break;
+               case 'c':
+                       fsckcfg.print_comp_ratio = PRINT_COMP_RATIO_COMP_FILE;
+                       break;
+               case 1:
+                       usage();
+                       exit(0);
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       if (optind >= argc)
+               return -EINVAL;
+
+       cfg.c_img_path = strdup(argv[optind++]);
+       if (!cfg.c_img_path)
+               return -ENOMEM;
+
+       if (optind < argc) {
+               erofs_err("unexpected argument: %s\n", argv[optind]);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int erofs_check_sb_chksum(void)
+{
+       int ret;
+       u8 buf[EROFS_BLKSIZ];
+       u32 crc;
+       struct erofs_super_block *sb;
+
+       ret = blk_read(buf, 0, 1);
+       if (ret) {
+               erofs_err("failed to read superblock to check checksum: "
+                         "errno(%d)", ret);
+               return -1;
+       }
+
+       sb = (struct erofs_super_block *)(buf + EROFS_SUPER_OFFSET);
+       sb->checksum = 0;
+
+       crc = crc32c(~0, (u8 *)sb, EROFS_BLKSIZ - EROFS_SUPER_OFFSET);
+       if (crc != sbi.checksum) {
+               erofs_err("superblock checksum doesn't match: saved(0x%08x) "
+                         "calculated(0x%08x)", sbi.checksum, crc);
+               fsckcfg.corrupted = true;
+               return -1;
+       }
+       return 0;
+}
+
+static int check_special_dentries(struct erofs_dirent *de, const char *de_name,
+                                 unsigned int de_namelen, erofs_nid_t nid,
+                                 erofs_nid_t pnid, bool is_curdir)
+{
+       unsigned int dirname_len = is_curdir ? 1 : 2;
+       const char *dirname = is_curdir ? "." : "..";
+       erofs_nid_t correct_nid = is_curdir ? nid : pnid;
+
+       if (de_namelen != dirname_len || memcmp(de_name, dirname, de_namelen)) {
+               char *dbgname = strndup(de_name, de_namelen);
+
+               BUG_ON(!dbgname);
+               if (is_curdir)
+                       erofs_err("wrong current dir name(%s) @ nid(%llu)",
+                                 dbgname, nid | 0ULL);
+               else
+                       erofs_err("wrong parent dir name(%s) @ nid(%llu)",
+                                 dbgname, nid | 0ULL);
+               free(dbgname);
+               return -1;
+       }
+
+       if (de->nid != correct_nid) {
+               if (is_curdir)
+                       erofs_err("wrong current dir nid(%llu) @ nid(%llu)",
+                                 de->nid | 0ULL, nid | 0ULL);
+               else
+                       erofs_err("wrong parent dir nid(%llu): "
+                                 "pnid(%llu) @ nid(%llu)",
+                                 de->nid | 0ULL, pnid | 0ULL, nid | 0ULL);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int traverse_dirents(erofs_nid_t pnid, erofs_nid_t nid,
+                           void *dentry_blk, erofs_off_t offset,
+                           unsigned int next_nameoff, unsigned int maxsize)
+{
+       struct erofs_dirent *de = dentry_blk;
+       const struct erofs_dirent *end = dentry_blk + next_nameoff;
+       unsigned int idx = 0;
+
+       erofs_dbg("traversing pnid(%llu), nid(%llu)", pnid | 0ULL, nid | 0ULL);
+
+       if (offset == 0 && (next_nameoff < 2 * sizeof(struct erofs_dirent))) {
+               erofs_err("too small dirents of size(%d) in nid(%llu)",
+                         next_nameoff, nid | 0ULL);
+               return -EFSCORRUPTED;
+       }
+
+       while (de < end) {
+               const char *de_name;
+               unsigned int de_namelen;
+               unsigned int nameoff;
+               char *dbgname;
+
+               nameoff = le16_to_cpu(de->nameoff);
+               de_name = (char *)dentry_blk + nameoff;
+
+               /* the last dirent check */
+               if (de + 1 >= end)
+                       de_namelen = strnlen(de_name, maxsize - nameoff);
+               else
+                       de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
+
+               if (cfg.c_dbg_lvl >= EROFS_DBG) {
+                       dbgname = strndup(de_name, de_namelen);
+                       BUG_ON(!dbgname);
+                       erofs_dbg("traversed filename(%s)", dbgname);
+                       free(dbgname);
+               }
+
+               /* corrupted entry check */
+               if (nameoff != next_nameoff) {
+                       erofs_err("bogus dirent with nameoff(%u): expected(%d) "
+                                 "@ nid(%llu), offset(%llu), idx(%u)",
+                                 nameoff, next_nameoff, nid | 0ULL,
+                                 offset | 0ULL, idx);
+                       return -EFSCORRUPTED;
+               }
+
+               if (nameoff + de_namelen > maxsize ||
+                               de_namelen > EROFS_NAME_LEN) {
+                       erofs_err("bogus dirent with namelen(%u) @ nid(%llu), "
+                                 "offset(%llu), idx(%u)",
+                                 de_namelen, nid | 0ULL, offset | 0ULL, idx);
+                       return -EFSCORRUPTED;
+               }
+
+               if (offset == 0 && (idx == 0 || idx == 1)) {
+                       if (check_special_dentries(de, de_name, de_namelen, nid,
+                                                  pnid, idx == 0))
+                               return -EFSCORRUPTED;
+               } else {
+                       erofs_check_inode(nid, de->nid);
+                       if (fsckcfg.corrupted)
+                               return -EFSCORRUPTED;
+               }
+
+               next_nameoff += de_namelen;
+               ++de;
+               ++idx;
+       }
+
+       erofs_dbg("traversing ... done nid(%llu)", nid | 0ULL);
+       return 0;
+}
+
+static int verify_raw_data_chunk(struct erofs_inode *inode)
+{
+       struct erofs_map_blocks map = {
+               .index = UINT_MAX,
+       };
+       int ret;
+       erofs_off_t ptr = 0;
+
+       if (fsckcfg.print_comp_ratio == PRINT_COMP_RATIO_ALL) {
+               fsckcfg.logical_len += inode->i_size;
+               fsckcfg.ondisk_len += inode->i_size;
+       }
+
+       while (ptr < inode->i_size) {
+               map.m_la = ptr;
+               ret = erofs_map_blocks(inode, &map, 0);
+               if (ret)
+                       return ret;
+
+               if (map.m_plen != map.m_llen || ptr != map.m_la) {
+                       erofs_err("broken data chunk layout m_la %" PRIu64
+                                 " ptr %" PRIu64 " m_llen %" PRIu64 " m_plen %"
+                                 PRIu64, map.m_la, ptr, map.m_llen,
+                                 map.m_plen);
+                       return -EFSCORRUPTED;
+               }
+
+               if (!(map.m_flags & EROFS_MAP_MAPPED) && !map.m_llen) {
+                       /* readched EOF */
+                       ptr = inode->i_size;
+                       continue;
+               }
+
+               ptr += map.m_llen;
+       }
+       return 0;
+}
+
+static int verify_compressed_chunk(struct erofs_inode *inode)
+{
+       struct erofs_map_blocks map = {
+               .index = UINT_MAX,
+       };
+       int ret = 0;
+       bool count_pchunk = fsckcfg.print_comp_ratio != NO_PRINT_COMP_RATIO;
+       u64 pchunk_len = 0;
+       erofs_off_t offset = 0, end = inode->i_size;
+
+       while (end > offset) {
+               map.m_la = end - 1;
+
+               ret = z_erofs_map_blocks_iter(inode, &map);
+               if (ret)
+                       return ret;
+
+               if (end > map.m_la + map.m_llen) {
+                       erofs_err("broken compressed chunk layout m_la %" PRIu64
+                                 " m_llen %" PRIu64 " end %" PRIu64,
+                                 map.m_la, map.m_llen, end);
+                       return -EFSCORRUPTED;
+               }
+
+               if (count_pchunk)
+                       pchunk_len += map.m_plen;
+
+               end = map.m_la;
+       }
+
+       if (count_pchunk) {
+               fsckcfg.logical_len += inode->i_size;
+               fsckcfg.ondisk_len += pchunk_len;
+       }
+
+       return 0;
+}
+
+static int erofs_verify_xattr(struct erofs_inode *inode)
+{
+       unsigned int xattr_hdr_size = sizeof(struct erofs_xattr_ibody_header);
+       unsigned int xattr_entry_size = sizeof(struct erofs_xattr_entry);
+       erofs_off_t addr;
+       unsigned int ofs, xattr_shared_count;
+       struct erofs_xattr_ibody_header *ih;
+       struct erofs_xattr_entry *entry;
+       int i, remaining = inode->xattr_isize, ret = 0;
+       char *buf = calloc(EROFS_BLKSIZ, 1);
+
+       BUG_ON(!buf);
+
+       if (inode->xattr_isize == xattr_hdr_size) {
+               erofs_err("xattr_isize %d of nid %llu is not supported yet",
+                         inode->xattr_isize, inode->nid | 0ULL);
+               ret = -EFSCORRUPTED;
+               goto out;
+       } else if (inode->xattr_isize < xattr_hdr_size) {
+               if (inode->xattr_isize) {
+                       erofs_err("bogus xattr ibody @ nid %llu",
+                                 inode->nid | 0ULL);
+                       ret = -EFSCORRUPTED;
+                       goto out;
+               }
+       }
+
+       addr = iloc(inode->nid) + inode->inode_isize;
+       ret = dev_read(buf, addr, xattr_hdr_size);
+       if (ret < 0) {
+               erofs_err("an error occurred when reading xattr header "
+                         "of nid(%llu): errno(%d)", inode->nid | 0ULL, ret);
+               goto out;
+       }
+       ih = (struct erofs_xattr_ibody_header *)buf;
+       xattr_shared_count = ih->h_shared_count;
+
+       ofs = erofs_blkoff(addr) + xattr_hdr_size;
+       addr += xattr_hdr_size;
+       remaining -= xattr_hdr_size;
+       for (i = 0; i < xattr_shared_count; ++i) {
+               if (ofs >= EROFS_BLKSIZ) {
+                       if (ofs != EROFS_BLKSIZ) {
+                               erofs_err("unaligned xattr entry in "
+                                         "xattr shared area of nid(%llu)",
+                                         inode->nid | 0ULL);
+                               ret = -EFSCORRUPTED;
+                               goto out;
+                       }
+                       ofs = 0;
+               }
+               ofs += xattr_entry_size;
+               addr += xattr_entry_size;
+               remaining -= xattr_entry_size;
+       }
+
+       while (remaining > 0) {
+               unsigned int entry_sz;
+
+               ret = dev_read(buf, addr, xattr_entry_size);
+               if (ret) {
+                       erofs_err("an error occurred when reading xattr entry "
+                                 "of nid(%llu): errno(%d)",
+                                 inode->nid | 0ULL, ret);
+                       goto out;
+               }
+
+               entry = (struct erofs_xattr_entry *)buf;
+               entry_sz = erofs_xattr_entry_size(entry);
+               if (remaining < entry_sz) {
+                       erofs_err("xattr on-disk corruption: xattr entry "
+                                 "beyond xattr_isize of nid(%llu)",
+                                 inode->nid | 0ULL);
+                       ret = -EFSCORRUPTED;
+                       goto out;
+               }
+               addr += entry_sz;
+               remaining -= entry_sz;
+       }
+out:
+       free(buf);
+       return ret;
+}
+
+static int erofs_verify_data_chunk(struct erofs_inode *inode)
+{
+       int ret;
+
+       erofs_dbg("verify data chunk of nid(%llu): type(%d)",
+                 inode->nid | 0ULL, inode->datalayout);
+
+       switch (inode->datalayout) {
+       case EROFS_INODE_FLAT_PLAIN:
+       case EROFS_INODE_FLAT_INLINE:
+       case EROFS_INODE_CHUNK_BASED:
+               ret = verify_raw_data_chunk(inode);
+               break;
+       case EROFS_INODE_FLAT_COMPRESSION_LEGACY:
+       case EROFS_INODE_FLAT_COMPRESSION:
+               ret = verify_compressed_chunk(inode);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       if (ret == -EIO)
+               erofs_err("I/O error occurred when verifying "
+                         "data chunk of nid(%llu)", inode->nid | 0ULL);
+
+       return ret;
+}
+
+static void erofs_check_inode(erofs_nid_t pnid, erofs_nid_t nid)
+{
+       int ret;
+       struct erofs_inode *inode;
+       char *buf;
+       erofs_off_t offset;
+
+       erofs_dbg("check inode: nid(%llu)", nid | 0ULL);
+       inode = calloc(1, sizeof(struct erofs_inode));
+       BUG_ON(!inode);
+       buf = calloc(EROFS_BLKSIZ, 1);
+       BUG_ON(!buf);
+
+       inode->nid = nid;
+       ret = erofs_read_inode_from_disk(inode);
+       if (ret) {
+               if (ret == -EIO)
+                       erofs_err("I/O error occurred when reading nid(%llu)",
+                                 nid | 0ULL);
+               goto out;
+       }
+
+       /* verify xattr field */
+       ret = erofs_verify_xattr(inode);
+       if (ret)
+               goto out;
+
+       /* verify data chunk layout */
+       ret = erofs_verify_data_chunk(inode);
+       if (ret)
+               goto out;
+
+       if ((inode->i_mode & S_IFMT) != S_IFDIR)
+               goto out;
+
+       offset = 0;
+       while (offset < inode->i_size) {
+               erofs_off_t maxsize = min_t(erofs_off_t,
+                                       inode->i_size - offset, EROFS_BLKSIZ);
+               struct erofs_dirent *de = (void *)buf;
+               unsigned int nameoff;
+
+               ret = erofs_pread(inode, buf, maxsize, offset);
+               if (ret) {
+                       erofs_err("I/O error occurred when reading dirents: "
+                                 "nid(%llu), offset(%llu), size(%llu)",
+                                 nid | 0ULL, offset | 0ULL, maxsize | 0ULL);
+                       goto out;
+               }
+
+               nameoff = le16_to_cpu(de->nameoff);
+               if (nameoff < sizeof(struct erofs_dirent) ||
+                               nameoff >= PAGE_SIZE) {
+                       erofs_err("invalid de[0].nameoff %u @ nid(%llu), "
+                                 "offset(%llu)",
+                                 nameoff, nid | 0ULL, offset | 0ULL);
+                       ret = -EFSCORRUPTED;
+                       goto out;
+               }
+
+               ret = traverse_dirents(pnid, nid, buf, offset,
+                                      nameoff, maxsize);
+               if (ret)
+                       goto out;
+
+               offset += maxsize;
+       }
+out:
+       free(buf);
+       free(inode);
+       if (ret && ret != -EIO)
+               fsckcfg.corrupted = true;
+}
+
+int main(int argc, char **argv)
+{
+       int err;
+
+       erofs_init_configure();
+
+       fsckcfg.corrupted = false;
+       fsckcfg.print_comp_ratio = NO_PRINT_COMP_RATIO;
+       fsckcfg.logical_len = 0;
+       fsckcfg.ondisk_len = 0;
+
+       err = erofsfsck_parse_options_cfg(argc, argv);
+       if (err) {
+               if (err == -EINVAL)
+                       usage();
+               goto exit;
+       }
+
+       err = dev_open_ro(cfg.c_img_path);
+       if (err) {
+               erofs_err("failed to open image file");
+               goto exit;
+       }
+
+       err = erofs_read_superblock();
+       if (err) {
+               erofs_err("failed to read superblock");
+               goto exit;
+       }
+
+       if (erofs_sb_has_sb_chksum() && erofs_check_sb_chksum()) {
+               erofs_err("failed to verify superblock checksum");
+               goto exit;
+       }
+
+       erofs_check_inode(sbi.root_nid, sbi.root_nid);
+
+       if (fsckcfg.corrupted) {
+               fprintf(stderr, "Found some filesystem corruption\n");
+       } else {
+               fprintf(stderr, "No error found\n");
+               if (fsckcfg.print_comp_ratio != NO_PRINT_COMP_RATIO) {
+                       double comp_ratio = (double)fsckcfg.ondisk_len * 100 /
+                                           (double)fsckcfg.logical_len;
+                       fprintf(stderr, "Compression Ratio: %.2f(%%)\n",
+                               comp_ratio);
+               }
+       }
+
+exit:
+       erofs_exit_configure();
+       return err;
+}
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 8b154ed..80065b2 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -82,6 +82,8 @@ struct erofs_sb_info {
 
        u16 available_compr_algs;
        u16 lz4_max_distance;
+
+       u32 checksum;
 };
 
 /* global sbi */
@@ -264,10 +266,13 @@ int erofs_read_superblock(void);
 
 /* namei.c */
 int erofs_ilookup(const char *path, struct erofs_inode *vi);
+int erofs_read_inode_from_disk(struct erofs_inode *vi);
 
 /* data.c */
 int erofs_pread(struct erofs_inode *inode, char *buf,
                erofs_off_t count, erofs_off_t offset);
+int erofs_map_blocks(struct erofs_inode *inode,
+                    struct erofs_map_blocks *map, int flags);
 /* zmap.c */
 int z_erofs_fill_inode(struct erofs_inode *vi);
 int z_erofs_map_blocks_iter(struct erofs_inode *vi,
diff --git a/include/erofs_fs.h b/include/erofs_fs.h
index 66a68e3..62e9981 100644
--- a/include/erofs_fs.h
+++ b/include/erofs_fs.h
@@ -400,4 +400,17 @@ static inline void 
erofs_check_ondisk_layout_definitions(void)
                     Z_EROFS_VLE_CLUSTER_TYPE_MAX - 1);
 }
 
+#define CRC32C_POLY_LE 0x82F63B78
+static inline u32 crc32c(u32 crc, const u8 *in, size_t len)
+{
+       int i;
+
+       while (len--) {
+               crc ^= *in++;
+               for (i = 0; i < 8; i++)
+                       crc = (crc >> 1) ^ ((crc & 1) ? CRC32C_POLY_LE : 0);
+       }
+       return crc;
+}
+
 #endif
diff --git a/lib/data.c b/lib/data.c
index 641d840..6cb7eeb 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -61,8 +61,8 @@ err_out:
        return err;
 }
 
-static int erofs_map_blocks(struct erofs_inode *inode,
-                           struct erofs_map_blocks *map, int flags)
+int erofs_map_blocks(struct erofs_inode *inode,
+                    struct erofs_map_blocks *map, int flags)
 {
        struct erofs_inode *vi = inode;
        struct erofs_inode_chunk_index *idx;
diff --git a/lib/namei.c b/lib/namei.c
index b4bdabf..56f199a 100644
--- a/lib/namei.c
+++ b/lib/namei.c
@@ -22,7 +22,7 @@ static dev_t erofs_new_decode_dev(u32 dev)
        return makedev(major, minor);
 }
 
-static int erofs_read_inode_from_disk(struct erofs_inode *vi)
+int erofs_read_inode_from_disk(struct erofs_inode *vi)
 {
        int ret, ifmt;
        char buf[sizeof(struct erofs_inode_extended)];
diff --git a/lib/super.c b/lib/super.c
index 0fa69ab..0c30403 100644
--- a/lib/super.c
+++ b/lib/super.c
@@ -62,6 +62,7 @@ int erofs_read_superblock(void)
        sbi.islotbits = EROFS_ISLOTBITS;
        sbi.root_nid = le16_to_cpu(dsb->root_nid);
        sbi.inos = le64_to_cpu(dsb->inos);
+       sbi.checksum = le32_to_cpu(dsb->checksum);
 
        sbi.build_time = le64_to_cpu(dsb->build_time);
        sbi.build_time_nsec = le32_to_cpu(dsb->build_time_nsec);
diff --git a/mkfs/main.c b/mkfs/main.c
index 1c8dea5..b9b46f5 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -424,19 +424,6 @@ int erofs_mkfs_update_super_block(struct erofs_buffer_head 
*bh,
        return 0;
 }
 
-#define CRC32C_POLY_LE 0x82F63B78
-static inline u32 crc32c(u32 crc, const u8 *in, size_t len)
-{
-       int i;
-
-       while (len--) {
-               crc ^= *in++;
-               for (i = 0; i < 8; i++)
-                       crc = (crc >> 1) ^ ((crc & 1) ? CRC32C_POLY_LE : 0);
-       }
-       return crc;
-}
-
 static int erofs_mkfs_superblock_csum_set(void)
 {
        int ret;
-- 
2.33.0.1079.g6e70778dc9-goog

Reply via email to