summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPratik Shinde <pratikshinde320@gmail.com>2019-11-07 12:03:26 +0800
committerGao Xiang <hsiangkao@aol.com>2019-11-08 21:50:24 +0800
commitfb757ede69e7f310e2c91cd3672e2e4049a1d348 (patch)
tree991208d72a7514f2ca24a7f8685d58026ad5daf3
parenta34f86beb16b25cb0f44c85934acb93749fc844c (diff)
erofs-utils: support calculating checksum of superblock
Added code for calculating crc of superblock. Note that the first 1024 bytes are not checksummed to allow for the installation of x86 boot sectors and other oddities. Fill 'feature_compat' field of erofs_super_block so that it can be used on kernel side. also fixing one typo. Link: https://lore.kernel.org/r/20191107040327.93369-1-gaoxiang25@huawei.com Signed-off-by: Pratik Shinde <pratikshinde320@gmail.com> Reviewed-by: Chao Yu <yuchao0@huawei.com> Reviewed-by: Li Guifu <blucerlee@gmail.com> Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
-rw-r--r--include/erofs/internal.h1
-rw-r--r--include/erofs/io.h8
-rw-r--r--include/erofs_fs.h3
-rw-r--r--lib/io.c27
-rw-r--r--mkfs/main.c69
5 files changed, 107 insertions, 1 deletions
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 25ce7b5..9e2bb9c 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -52,6 +52,7 @@ struct erofs_sb_info {
erofs_blk_t meta_blkaddr;
erofs_blk_t xattr_blkaddr;
+ u32 feature_compat;
u32 feature_incompat;
u64 build_time;
u32 build_time_nsec;
diff --git a/include/erofs/io.h b/include/erofs/io.h
index 9775047..e0ca8d9 100644
--- a/include/erofs/io.h
+++ b/include/erofs/io.h
@@ -19,6 +19,7 @@
int dev_open(const char *devname);
void dev_close(void);
int dev_write(const void *buf, u64 offset, size_t len);
+int dev_read(void *buf, u64 offset, size_t len);
int dev_fillzero(u64 offset, size_t len, bool padding);
int dev_fsync(void);
int dev_resize(erofs_blk_t nblocks);
@@ -31,5 +32,12 @@ static inline int blk_write(const void *buf, erofs_blk_t blkaddr,
blknr_to_addr(nblocks));
}
+static inline int blk_read(void *buf, erofs_blk_t start,
+ u32 nblocks)
+{
+ return dev_read(buf, blknr_to_addr(start),
+ blknr_to_addr(nblocks));
+}
+
#endif
diff --git a/include/erofs_fs.h b/include/erofs_fs.h
index f29aa25..bcc4f0c 100644
--- a/include/erofs_fs.h
+++ b/include/erofs_fs.h
@@ -13,6 +13,8 @@
#define EROFS_SUPER_MAGIC_V1 0xE0F5E1E2
#define EROFS_SUPER_OFFSET 1024
+#define EROFS_FEATURE_COMPAT_SB_CHKSUM 0x00000001
+
/*
* Any bits that aren't in EROFS_ALL_FEATURE_INCOMPAT should
* be incompatible with this kernel version.
@@ -39,7 +41,6 @@ struct erofs_super_block {
__u8 uuid[16]; /* 128-bit uuid for volume */
__u8 volume_name[16]; /* volume name */
__le32 feature_incompat;
-
__u8 reserved2[44];
};
diff --git a/lib/io.c b/lib/io.c
index 7f5f94d..52f9424 100644
--- a/lib/io.c
+++ b/lib/io.c
@@ -207,3 +207,30 @@ int dev_resize(unsigned int blocks)
return dev_fillzero(st.st_size, length, true);
}
+int dev_read(void *buf, u64 offset, size_t len)
+{
+ int ret;
+
+ if (cfg.c_dry_run)
+ return 0;
+
+ if (!buf) {
+ erofs_err("buf is NULL");
+ return -EINVAL;
+ }
+ if (offset >= erofs_devsz || len > erofs_devsz ||
+ offset > erofs_devsz - len) {
+ erofs_err("read posion[%" PRIu64 ", %zd] is too large beyond"
+ "the end of device(%" PRIu64 ").",
+ offset, len, erofs_devsz);
+ return -EINVAL;
+ }
+
+ ret = pread64(erofs_devfd, buf, len, (off64_t)offset);
+ if (ret != (int)len) {
+ erofs_err("Failed to read data from device - %s:[%" PRIu64 ", %zd].",
+ erofs_devname, offset, len);
+ return -errno;
+ }
+ return 0;
+}
diff --git a/mkfs/main.c b/mkfs/main.c
index ab57896..9187c43 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -109,6 +109,12 @@ static int parse_extended_opts(const char *opts)
return -EINVAL;
cfg.c_force_inodeversion = FORCE_INODE_EXTENDED;
}
+
+ if (MATCH_EXTENTED_OPT("nosbcrc", token, keylen)) {
+ if (vallen)
+ return -EINVAL;
+ sbi.feature_compat &= ~EROFS_FEATURE_COMPAT_SB_CHKSUM;
+ }
}
return 0;
}
@@ -218,6 +224,8 @@ int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh,
.meta_blkaddr = sbi.meta_blkaddr,
.xattr_blkaddr = sbi.xattr_blkaddr,
.feature_incompat = cpu_to_le32(sbi.feature_incompat),
+ .feature_compat = cpu_to_le32(sbi.feature_compat &
+ ~EROFS_FEATURE_COMPAT_SB_CHKSUM),
};
const unsigned int sb_blksize =
round_up(EROFS_SUPER_END, EROFS_BLKSIZ);
@@ -240,6 +248,63 @@ 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;
+ 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 set checksum: %s",
+ erofs_strerror(ret));
+ return ret;
+ }
+
+ /*
+ * skip the first 1024 bytes, to allow for the installation
+ * of x86 boot sectors and other oddities.
+ */
+ sb = (struct erofs_super_block *)(buf + EROFS_SUPER_OFFSET);
+
+ if (le32_to_cpu(sb->magic) != EROFS_SUPER_MAGIC_V1) {
+ erofs_err("internal error: not an erofs valid image");
+ return -EFAULT;
+ }
+
+ /* turn on checksum feature */
+ sb->feature_compat = cpu_to_le32(le32_to_cpu(sb->feature_compat) |
+ EROFS_FEATURE_COMPAT_SB_CHKSUM);
+ crc = crc32c(~0, (u8 *)sb, EROFS_BLKSIZ - EROFS_SUPER_OFFSET);
+
+ /* set up checksum field to erofs_super_block */
+ sb->checksum = cpu_to_le32(crc);
+
+ ret = blk_write(buf, 0, 1);
+ if (ret) {
+ erofs_err("failed to write checksummed superblock: %s",
+ erofs_strerror(ret));
+ return ret;
+ }
+
+ erofs_info("superblock checksum 0x%08x written", crc);
+ return 0;
+}
+
int main(int argc, char **argv)
{
int err = 0;
@@ -255,6 +320,7 @@ int main(int argc, char **argv)
cfg.c_legacy_compress = false;
sbi.feature_incompat = EROFS_FEATURE_INCOMPAT_LZ4_0PADDING;
+ sbi.feature_compat = EROFS_FEATURE_COMPAT_SB_CHKSUM;
err = mkfs_parse_options_cfg(argc, argv);
if (err) {
@@ -337,6 +403,9 @@ int main(int argc, char **argv)
err = -EIO;
else
err = dev_resize(nblocks);
+
+ if (!err && (sbi.feature_compat & EROFS_FEATURE_COMPAT_SB_CHKSUM))
+ err = erofs_mkfs_superblock_csum_set();
exit:
z_erofs_compress_exit();
dev_close();