Linux-EROFS Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH-v5] erofs-utils:code for calculating crc checksum of erofs blocks
@ 2019-10-19 15:08 Pratik Shinde
  2019-10-20  9:06 ` Gao Xiang via Linux-erofs
  2019-10-20 14:11 ` Gao Xiang via Linux-erofs
  0 siblings, 2 replies; 9+ messages in thread
From: Pratik Shinde @ 2019-10-19 15:08 UTC (permalink / raw)
  To: linux-erofs, bluce.liguifu, miaoxie, fangwei1

Added code for calculating crc of erofs blocks (4K size).for now it calculates
checksum of first block. but can modified to calculate crc for any no. of blocks

Fill 'feature_compat' field of erofs_super_block so that it
can be used on kernel side. also fixing one typo.

Signed-off-by: Pratik Shinde <pratikshinde320@gmail.com>
---
 include/erofs/internal.h |  1 +
 include/erofs/io.h       |  8 ++++++
 include/erofs_fs.h       |  5 ++--
 lib/io.c                 | 27 ++++++++++++++++++
 mkfs/main.c              | 71 ++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 110 insertions(+), 2 deletions(-)

diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 5384946..53335bc 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -55,6 +55,7 @@ struct erofs_sb_info {
 	u32 feature_incompat;
 	u64 build_time;
 	u32 build_time_nsec;
+	u32 feature;
 };
 
 /* global sbi */
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..9eda6c2 100644
--- a/include/erofs_fs.h
+++ b/include/erofs_fs.h
@@ -19,6 +19,7 @@
  */
 #define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING	0x00000001
 #define EROFS_ALL_FEATURE_INCOMPAT		EROFS_FEATURE_INCOMPAT_LZ4_0PADDING
+#define EROFS_FEATURE_SB_CHKSUM	0x0001
 
 /* 128-byte erofs on-disk super block */
 struct erofs_super_block {
@@ -39,8 +40,8 @@ struct erofs_super_block {
 	__u8 uuid[16];          /* 128-bit uuid for volume */
 	__u8 volume_name[16];   /* volume name */
 	__le32 feature_incompat;
-
-	__u8 reserved2[44];
+	__le32 chksum_blocks;	/* number of blocks used for checksum */
+	__u8 reserved2[40];
 };
 
 /*
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 91a018f..c7cb923 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -22,6 +22,9 @@
 
 #define EROFS_SUPER_END (EROFS_SUPER_OFFSET + sizeof(struct erofs_super_block))
 
+/* number of blocks for calculating checksum */
+#define EROFS_CKSUM_BLOCKS	1
+
 static void usage(void)
 {
 	fprintf(stderr, "usage: [options] FILE DIRECTORY\n\n");
@@ -85,6 +88,10 @@ static int parse_extended_opts(const char *opts)
 				return -EINVAL;
 			cfg.c_force_inodeversion = FORCE_INODE_EXTENDED;
 		}
+
+		if (MATCH_EXTENTED_OPT("nocrc", token, keylen)) {
+			sbi.feature &= ~EROFS_FEATURE_SB_CHKSUM;
+		}
 	}
 	return 0;
 }
@@ -180,6 +187,9 @@ int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh,
 		.meta_blkaddr  = sbi.meta_blkaddr,
 		.xattr_blkaddr = 0,
 		.feature_incompat = cpu_to_le32(sbi.feature_incompat),
+		.feature_compat = cpu_to_le32(sbi.feature),
+		.checksum = 0,
+		.chksum_blocks = cpu_to_le32(EROFS_CKSUM_BLOCKS)
 	};
 	const unsigned int sb_blksize =
 		round_up(EROFS_SUPER_END, EROFS_BLKSIZ);
@@ -202,6 +212,64 @@ int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh,
 	return 0;
 }
 
+#define CRCPOLY	0x82F63B78
+static inline u32 crc32c(u32 seed, unsigned char const *in, size_t len)
+{
+	int i;
+	u32 crc = seed;
+
+	while (len--) {
+		crc ^= *in++;
+		for (i = 0; i < 8; i++) {
+			crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY : 0);
+		}
+	}
+	return crc;
+}
+
+/* calculate checksum for first n blocks */
+u32 erofs_calc_blk_checksum(erofs_blk_t nblks, u32 *crc)
+{
+	char *buf;
+	int err = 0;
+
+	buf = malloc(nblks * EROFS_BLKSIZ);
+	err = blk_read(buf, 0, nblks);
+	if (err) {
+		return err;
+	}
+	*crc = crc32c(0, (const unsigned char *)buf, nblks * EROFS_BLKSIZ);
+	free(buf);
+	return 0;
+}
+
+void erofs_write_sb_checksum()
+{
+	struct erofs_super_block *sb;
+	char buf[EROFS_BLKSIZ];
+	int ret = 0;
+	u32 crc;
+
+	ret = erofs_calc_blk_checksum(EROFS_CKSUM_BLOCKS, &crc);
+	if (ret) {
+		return;
+	}
+	ret = blk_read(buf, 0, 1);
+	if (ret) {
+		return;
+	}
+
+	sb = (struct erofs_super_block *)((u8 *)buf + EROFS_SUPER_OFFSET);
+	if (le32_to_cpu(sb->magic) != EROFS_SUPER_MAGIC_V1) {
+		return;
+	}
+	sb->checksum = cpu_to_le32(crc);
+	ret = blk_write(buf, 0, 1);
+	if (ret) {
+		return;
+	}
+}
+
 int main(int argc, char **argv)
 {
 	int err = 0;
@@ -217,6 +285,7 @@ int main(int argc, char **argv)
 
 	cfg.c_legacy_compress = false;
 	sbi.feature_incompat = EROFS_FEATURE_INCOMPAT_LZ4_0PADDING;
+	sbi.feature = EROFS_FEATURE_SB_CHKSUM;
 
 	err = mkfs_parse_options_cfg(argc, argv);
 	if (err) {
@@ -301,6 +370,8 @@ int main(int argc, char **argv)
 		err = -EIO;
 	else
 		err = dev_resize(nblocks);
+	if (sbi.feature & EROFS_FEATURE_SB_CHKSUM)
+		erofs_write_sb_checksum();
 exit:
 	z_erofs_compress_exit();
 	dev_close();
-- 
2.9.3


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH-v5] erofs-utils:code for calculating crc checksum of erofs blocks
  2019-10-19 15:08 [PATCH-v5] erofs-utils:code for calculating crc checksum of erofs blocks Pratik Shinde
@ 2019-10-20  9:06 ` Gao Xiang via Linux-erofs
  2019-10-20 14:11 ` Gao Xiang via Linux-erofs
  1 sibling, 0 replies; 9+ messages in thread
From: Gao Xiang via Linux-erofs @ 2019-10-20  9:06 UTC (permalink / raw)
  To: Pratik Shinde; +Cc: miaoxie, linux-erofs

Hi Pratik,

I was attending "China Linux Storage and File System (CLSF) Workshop
2019" (with EROFS roadmap discussed) these days, sorry about delaying
... I will take this version with little print messages added this
evening... Don't worry, I will certainly do. :-)

Thanks,
Gao Xiang

On Sat, Oct 19, 2019 at 08:38:03PM +0530, Pratik Shinde wrote:
> Added code for calculating crc of erofs blocks (4K size).for now it calculates
> checksum of first block. but can modified to calculate crc for any no. of blocks
> 
> Fill 'feature_compat' field of erofs_super_block so that it
> can be used on kernel side. also fixing one typo.
> 
> Signed-off-by: Pratik Shinde <pratikshinde320@gmail.com>
> ---
>  include/erofs/internal.h |  1 +
>  include/erofs/io.h       |  8 ++++++
>  include/erofs_fs.h       |  5 ++--
>  lib/io.c                 | 27 ++++++++++++++++++
>  mkfs/main.c              | 71 ++++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 110 insertions(+), 2 deletions(-)
> 
> diff --git a/include/erofs/internal.h b/include/erofs/internal.h
> index 5384946..53335bc 100644
> --- a/include/erofs/internal.h
> +++ b/include/erofs/internal.h
> @@ -55,6 +55,7 @@ struct erofs_sb_info {
>  	u32 feature_incompat;
>  	u64 build_time;
>  	u32 build_time_nsec;
> +	u32 feature;
>  };
>  
>  /* global sbi */
> 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..9eda6c2 100644
> --- a/include/erofs_fs.h
> +++ b/include/erofs_fs.h
> @@ -19,6 +19,7 @@
>   */
>  #define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING	0x00000001
>  #define EROFS_ALL_FEATURE_INCOMPAT		EROFS_FEATURE_INCOMPAT_LZ4_0PADDING
> +#define EROFS_FEATURE_SB_CHKSUM	0x0001
>  
>  /* 128-byte erofs on-disk super block */
>  struct erofs_super_block {
> @@ -39,8 +40,8 @@ struct erofs_super_block {
>  	__u8 uuid[16];          /* 128-bit uuid for volume */
>  	__u8 volume_name[16];   /* volume name */
>  	__le32 feature_incompat;
> -
> -	__u8 reserved2[44];
> +	__le32 chksum_blocks;	/* number of blocks used for checksum */
> +	__u8 reserved2[40];
>  };
>  
>  /*
> 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 91a018f..c7cb923 100644
> --- a/mkfs/main.c
> +++ b/mkfs/main.c
> @@ -22,6 +22,9 @@
>  
>  #define EROFS_SUPER_END (EROFS_SUPER_OFFSET + sizeof(struct erofs_super_block))
>  
> +/* number of blocks for calculating checksum */
> +#define EROFS_CKSUM_BLOCKS	1
> +
>  static void usage(void)
>  {
>  	fprintf(stderr, "usage: [options] FILE DIRECTORY\n\n");
> @@ -85,6 +88,10 @@ static int parse_extended_opts(const char *opts)
>  				return -EINVAL;
>  			cfg.c_force_inodeversion = FORCE_INODE_EXTENDED;
>  		}
> +
> +		if (MATCH_EXTENTED_OPT("nocrc", token, keylen)) {
> +			sbi.feature &= ~EROFS_FEATURE_SB_CHKSUM;
> +		}
>  	}
>  	return 0;
>  }
> @@ -180,6 +187,9 @@ int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh,
>  		.meta_blkaddr  = sbi.meta_blkaddr,
>  		.xattr_blkaddr = 0,
>  		.feature_incompat = cpu_to_le32(sbi.feature_incompat),
> +		.feature_compat = cpu_to_le32(sbi.feature),
> +		.checksum = 0,
> +		.chksum_blocks = cpu_to_le32(EROFS_CKSUM_BLOCKS)
>  	};
>  	const unsigned int sb_blksize =
>  		round_up(EROFS_SUPER_END, EROFS_BLKSIZ);
> @@ -202,6 +212,64 @@ int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh,
>  	return 0;
>  }
>  
> +#define CRCPOLY	0x82F63B78
> +static inline u32 crc32c(u32 seed, unsigned char const *in, size_t len)
> +{
> +	int i;
> +	u32 crc = seed;
> +
> +	while (len--) {
> +		crc ^= *in++;
> +		for (i = 0; i < 8; i++) {
> +			crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY : 0);
> +		}
> +	}
> +	return crc;
> +}
> +
> +/* calculate checksum for first n blocks */
> +u32 erofs_calc_blk_checksum(erofs_blk_t nblks, u32 *crc)
> +{
> +	char *buf;
> +	int err = 0;
> +
> +	buf = malloc(nblks * EROFS_BLKSIZ);
> +	err = blk_read(buf, 0, nblks);
> +	if (err) {
> +		return err;
> +	}
> +	*crc = crc32c(0, (const unsigned char *)buf, nblks * EROFS_BLKSIZ);
> +	free(buf);
> +	return 0;
> +}
> +
> +void erofs_write_sb_checksum()
> +{
> +	struct erofs_super_block *sb;
> +	char buf[EROFS_BLKSIZ];
> +	int ret = 0;
> +	u32 crc;
> +
> +	ret = erofs_calc_blk_checksum(EROFS_CKSUM_BLOCKS, &crc);
> +	if (ret) {
> +		return;
> +	}
> +	ret = blk_read(buf, 0, 1);
> +	if (ret) {
> +		return;
> +	}
> +
> +	sb = (struct erofs_super_block *)((u8 *)buf + EROFS_SUPER_OFFSET);
> +	if (le32_to_cpu(sb->magic) != EROFS_SUPER_MAGIC_V1) {
> +		return;
> +	}
> +	sb->checksum = cpu_to_le32(crc);
> +	ret = blk_write(buf, 0, 1);
> +	if (ret) {
> +		return;
> +	}
> +}
> +
>  int main(int argc, char **argv)
>  {
>  	int err = 0;
> @@ -217,6 +285,7 @@ int main(int argc, char **argv)
>  
>  	cfg.c_legacy_compress = false;
>  	sbi.feature_incompat = EROFS_FEATURE_INCOMPAT_LZ4_0PADDING;
> +	sbi.feature = EROFS_FEATURE_SB_CHKSUM;
>  
>  	err = mkfs_parse_options_cfg(argc, argv);
>  	if (err) {
> @@ -301,6 +370,8 @@ int main(int argc, char **argv)
>  		err = -EIO;
>  	else
>  		err = dev_resize(nblocks);
> +	if (sbi.feature & EROFS_FEATURE_SB_CHKSUM)
> +		erofs_write_sb_checksum();
>  exit:
>  	z_erofs_compress_exit();
>  	dev_close();
> -- 
> 2.9.3
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH-v5] erofs-utils:code for calculating crc checksum of erofs blocks
  2019-10-19 15:08 [PATCH-v5] erofs-utils:code for calculating crc checksum of erofs blocks Pratik Shinde
  2019-10-20  9:06 ` Gao Xiang via Linux-erofs
@ 2019-10-20 14:11 ` Gao Xiang via Linux-erofs
  2019-10-23  3:49   ` [PATCH v7] erofs-utils: support calculating " Gao Xiang
  1 sibling, 1 reply; 9+ messages in thread
From: Gao Xiang via Linux-erofs @ 2019-10-20 14:11 UTC (permalink / raw)
  To: Pratik Shinde; +Cc: miaoxie, linux-erofs

Hi Pratik and other folks,

On Sat, Oct 19, 2019 at 08:38:03PM +0530, Pratik Shinde wrote:
> Added code for calculating crc of erofs blocks (4K size).for now it calculates
> checksum of first block. but can modified to calculate crc for any no. of blocks
> 
> Fill 'feature_compat' field of erofs_super_block so that it
> can be used on kernel side. also fixing one typo.
> 
> Signed-off-by: Pratik Shinde <pratikshinde320@gmail.com>

I will submit the following patch to experimental branch, some
TODOs in it (and an additional TODO which is not mentioned in code
is to move crc32c() to include/erofs/crc32.h).

Further updates or comments for this version are welcomed.

BTW, for all valid fields in feature_compat or feature_incompat,
I'd like to introduce a -O option to toggle them as well (e.g.
-O +sbcrc or -O -sbcrc), which is not in this version as well...

Thanks,
Gao Xiang

From d96b797f86f2526e4f94a483d6b6442b53e61861 Mon Sep 17 00:00:00 2001
From: Pratik Shinde <pratikshinde320@gmail.com>
Date: Sat, 19 Oct 2019 20:38:03 +0530
Subject: [PATCH v6] erofs-utils: code for calculating crc checksum of erofs
 blocks

Added code for calculating crc of erofs blocks (4K size).
For now it calculates checksum of first block. but it can
be modified to calculate crc for any no. of blocks

Fill 'feature_compat' field of erofs_super_block so that it
can be used on kernel side. also fixing one typo.

Signed-off-by: Pratik Shinde <pratikshinde320@gmail.com>
[ Gao Xiang: minor updates based on Pratik patch. ]
Signed-off-by: Gao Xiang <hsiangkao@aol.com>
---
change since v5:
 - rename 'feature' to 'feature_compat' (so does related macro).
 - add some print messages;
 - fill all checksum fields in erofs_write_sb_checksum();
 - fix a memory leak in error handling path.

 include/erofs/internal.h |  1 +
 include/erofs/io.h       |  8 ++++
 include/erofs_fs.h       |  6 ++-
 lib/io.c                 | 27 ++++++++++++
 mkfs/main.c              | 92 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 132 insertions(+), 2 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..8daf043 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,8 +41,8 @@ struct erofs_super_block {
 	__u8 uuid[16];          /* 128-bit uuid for volume */
 	__u8 volume_name[16];   /* volume name */
 	__le32 feature_incompat;
-
-	__u8 reserved2[44];
+	__le32 chksum_blocks;	/* number of blocks used for checksum */
+	__u8 reserved2[40];
 };
 
 /*
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 71c81f5..fe84441 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -23,6 +23,9 @@
 
 #define EROFS_SUPER_END (EROFS_SUPER_OFFSET + sizeof(struct erofs_super_block))
 
+/* number of blocks for calculating checksum */
+#define EROFS_CKSUM_BLOCKS	1
+
 static void usage(void)
 {
 	fprintf(stderr, "usage: [options] FILE DIRECTORY\n\n");
@@ -87,6 +90,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;
 }
@@ -191,6 +200,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);
@@ -213,6 +224,83 @@ int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh,
 	return 0;
 }
 
+#define CRCPOLY	0x82F63B78
+static inline u32 crc32c(u32 seed, const u8 *in, size_t len)
+{
+	int i;
+	u32 crc = seed;
+
+	while (len--) {
+		crc ^= *in++;
+		for (i = 0; i < 8; i++) {
+			crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY : 0);
+		}
+	}
+	return crc;
+}
+
+/* calculate checksum for first n blocks */
+static int erofs_calc_blk_checksum(erofs_blk_t nblks, u32 *crc)
+{
+	char *buf;
+	int err;
+
+	/* TODO: limit memory size by mutiple reads */
+	buf = malloc(nblks * EROFS_BLKSIZ);
+	if (!buf)
+		return -ENOMEM;
+
+	err = blk_read(buf, 0, nblks);
+	if (err)
+		goto out;
+
+	*crc = crc32c(0, (const u8 *)buf, nblks * EROFS_BLKSIZ);
+out:
+	free(buf);
+	return err;
+}
+
+static int erofs_write_sb_checksum(void)
+{
+	struct erofs_super_block *sb;
+	char buf[EROFS_BLKSIZ];
+	int ret;
+	u32 crc;
+
+	ret = erofs_calc_blk_checksum(EROFS_CKSUM_BLOCKS, &crc);
+	if (ret) {
+		erofs_err("failed to calculate checksum: %s",
+			  erofs_strerror(ret));
+		return ret;
+	}
+
+	/* TODO: no need to reread super block */
+	ret = blk_read(buf, 0, 1);
+	if (ret) {
+		erofs_err("failed to read superblock to fill checksum");
+		return -EIO;
+	}
+
+	sb = (struct erofs_super_block *)((u8 *)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;
+	}
+	/* set up checksum field to erofs_super_block */
+	sb->feature_compat = cpu_to_le32(le32_to_cpu(sb->feature_compat) |
+					 EROFS_FEATURE_COMPAT_SB_CHKSUM);
+	sb->chksum_blocks = cpu_to_le32(EROFS_CKSUM_BLOCKS);
+	sb->checksum = cpu_to_le32(crc);
+	ret = blk_write(buf, 0, 1);
+	if (ret) {
+		erofs_err("failed to write checksumed 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;
@@ -228,6 +316,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) {
@@ -310,6 +399,9 @@ int main(int argc, char **argv)
 		err = -EIO;
 	else
 		err = dev_resize(nblocks);
+
+	if (sbi.feature_compat & EROFS_FEATURE_COMPAT_SB_CHKSUM)
+		erofs_write_sb_checksum();
 exit:
 	z_erofs_compress_exit();
 	dev_close();
-- 
2.17.1



^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v7] erofs-utils: support calculating checksum of erofs blocks
  2019-10-20 14:11 ` Gao Xiang via Linux-erofs
@ 2019-10-23  3:49   ` " Gao Xiang
  2019-10-28 14:23     ` [PATCH v8] " Gao Xiang
  0 siblings, 1 reply; 9+ messages in thread
From: Gao Xiang @ 2019-10-23  3:49 UTC (permalink / raw)
  To: Pratik Shinde, Li Guifu, linux-erofs; +Cc: Miao Xie

From: Pratik Shinde <pratikshinde320@gmail.com>

Added code for calculating crc of erofs blocks (4K size).
For now it calculates checksum of first block. but it can
be modified to calculate crc for any no. of blocks.

Note that the first 1024 bytes are not checksumed 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.

Signed-off-by: Pratik Shinde <pratikshinde320@gmail.com>
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
---

changes since v6:
 - the first 1024 bytes are not checksumed as mentioned in
   the current commit message;
 - co-tested with kernel side;

 include/erofs/internal.h |   1 +
 include/erofs/io.h       |   8 +++
 include/erofs_fs.h       |   6 ++-
 lib/io.c                 |  27 ++++++++++
 mkfs/main.c              | 104 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 144 insertions(+), 2 deletions(-)

diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 25ce7b54442d..9e2bb9ce33b6 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 97750478b5ab..e0ca8d949130 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 f29aa2516a99..8daf0432f811 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,8 +41,8 @@ struct erofs_super_block {
 	__u8 uuid[16];          /* 128-bit uuid for volume */
 	__u8 volume_name[16];   /* volume name */
 	__le32 feature_incompat;
-
-	__u8 reserved2[44];
+	__le32 chksum_blocks;	/* number of blocks used for checksum */
+	__u8 reserved2[40];
 };
 
 /*
diff --git a/lib/io.c b/lib/io.c
index 7f5f94dd6b1e..52f9424d201b 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 1161b3f0f7cc..ac12b94e2306 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -24,6 +24,9 @@
 
 #define EROFS_SUPER_END (EROFS_SUPER_OFFSET + sizeof(struct erofs_super_block))
 
+/* number of blocks for calculating checksum */
+#define EROFS_CKSUM_BLOCKS	1
+
 static struct option long_options[] = {
 	{"help", no_argument, 0, 1},
 	{0, 0, 0, 0},
@@ -109,6 +112,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 +227,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 +251,95 @@ 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;
+}
+
+/* calculate checksum for 1~n blocks */
+static int erofs_calc_blk_checksum(erofs_blk_t nblks, u32 *crc)
+{
+	u8 *buf;
+	int err;
+
+	if (!nblks)
+		return 0;
+
+	/* TODO: limit memory size by mutiple reads */
+	buf = malloc(nblks * EROFS_BLKSIZ);
+	if (!buf)
+		return -ENOMEM;
+
+	err = blk_read(buf, 1, nblks);
+	if (err)
+		goto out;
+
+	*crc = crc32c(*crc, buf, nblks * EROFS_BLKSIZ);
+out:
+	free(buf);
+	return err;
+}
+
+static int erofs_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 fill checksum");
+		return -EIO;
+	}
+
+	/*
+	 * 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);
+	sb->chksum_blocks = cpu_to_le32(EROFS_CKSUM_BLOCKS);
+
+	crc = crc32c(~0, (u8 *)sb, EROFS_BLKSIZ - EROFS_SUPER_OFFSET);
+
+	ret = erofs_calc_blk_checksum(EROFS_CKSUM_BLOCKS - 1, &crc);
+	if (ret) {
+		erofs_err("failed to calculate checksum: %s",
+			  erofs_strerror(ret));
+		return ret;
+	}
+
+	/* 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 checksumed 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 +355,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 +438,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_superblock_csum_set();
 exit:
 	z_erofs_compress_exit();
 	dev_close();
-- 
2.17.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v8] erofs-utils: support calculating checksum of erofs blocks
  2019-10-23  3:49   ` [PATCH v7] erofs-utils: support calculating " Gao Xiang
@ 2019-10-28 14:23     ` " Gao Xiang
  2019-10-30  2:39       ` Chao Yu
  0 siblings, 1 reply; 9+ messages in thread
From: Gao Xiang @ 2019-10-28 14:23 UTC (permalink / raw)
  To: Pratik Shinde, Li Guifu, linux-erofs; +Cc: Miao Xie

From: Pratik Shinde <pratikshinde320@gmail.com>

Added code for calculating crc of erofs blocks (4K size).
For now it calculates checksum of first block. but it can
be modified to calculate crc for any no. of blocks.

Note that the first 1024 bytes are not checksumed 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.

Signed-off-by: Pratik Shinde <pratikshinde320@gmail.com>
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
---

changes since v7:
 - get rid of `chksum_blocks' pointed out by Chao.


 include/erofs/internal.h |  1 +
 include/erofs/io.h       |  8 +++++
 include/erofs_fs.h       |  3 +-
 lib/io.c                 | 27 ++++++++++++++++
 mkfs/main.c              | 68 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 106 insertions(+), 1 deletion(-)

diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 25ce7b54442d..9e2bb9ce33b6 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 97750478b5ab..e0ca8d949130 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 f29aa2516a99..bcc4f0c630ad 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 7f5f94dd6b1e..52f9424d201b 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 ab57896e9ca8..eeb6ccc55b82 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,62 @@ 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_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 fill checksum");
+		return -EIO;
+	}
+
+	/*
+	 * 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 checksumed 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 +319,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 +402,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_superblock_csum_set();
 exit:
 	z_erofs_compress_exit();
 	dev_close();
-- 
2.17.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v8] erofs-utils: support calculating checksum of erofs blocks
  2019-10-28 14:23     ` [PATCH v8] " Gao Xiang
@ 2019-10-30  2:39       ` Chao Yu
  2019-10-30  2:55         ` Gao Xiang
  0 siblings, 1 reply; 9+ messages in thread
From: Chao Yu @ 2019-10-30  2:39 UTC (permalink / raw)
  To: Gao Xiang, Pratik Shinde, Li Guifu, linux-erofs; +Cc: Miao Xie

On 2019/10/28 22:23, Gao Xiang wrote:
> From: Pratik Shinde <pratikshinde320@gmail.com>
> 
> Added code for calculating crc of erofs blocks (4K size).
> For now it calculates checksum of first block. but it can
> be modified to calculate crc for any no. of blocks.
> 
> Note that the first 1024 bytes are not checksumed 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.
> 
> Signed-off-by: Pratik Shinde <pratikshinde320@gmail.com>
> Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
> ---
> 
> changes since v7:
>  - get rid of `chksum_blocks' pointed out by Chao.
> 
> 
>  include/erofs/internal.h |  1 +
>  include/erofs/io.h       |  8 +++++
>  include/erofs_fs.h       |  3 +-
>  lib/io.c                 | 27 ++++++++++++++++
>  mkfs/main.c              | 68 ++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 106 insertions(+), 1 deletion(-)
> 
> diff --git a/include/erofs/internal.h b/include/erofs/internal.h
> index 25ce7b54442d..9e2bb9ce33b6 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 97750478b5ab..e0ca8d949130 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 f29aa2516a99..bcc4f0c630ad 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 7f5f94dd6b1e..52f9424d201b 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;

Minor thing, I notice caller wrap this errno to EIO, so we'd better print errno
here or by caller? Other part looks good to me anyway.

Reviewed-by: Chao Yu <yuchao0@huawei.com>

Thanks,

> +	}
> +	return 0;
> +}
> diff --git a/mkfs/main.c b/mkfs/main.c
> index ab57896e9ca8..eeb6ccc55b82 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,62 @@ 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_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 fill checksum");
> +		return -EIO;
> +	}
> +
> +	/*
> +	 * 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 checksumed 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 +319,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 +402,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_superblock_csum_set();
>  exit:
>  	z_erofs_compress_exit();
>  	dev_close();
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v8] erofs-utils: support calculating checksum of erofs blocks
  2019-10-30  2:39       ` Chao Yu
@ 2019-10-30  2:55         ` Gao Xiang
  2019-10-30  6:28           ` [PATCH v9] " Gao Xiang
  0 siblings, 1 reply; 9+ messages in thread
From: Gao Xiang @ 2019-10-30  2:55 UTC (permalink / raw)
  To: Chao Yu; +Cc: Miao Xie, linux-erofs

Hi Chao,

On Wed, Oct 30, 2019 at 10:39:18AM +0800, Chao Yu wrote:
> On 2019/10/28 22:23, Gao Xiang wrote:
> > From: Pratik Shinde <pratikshinde320@gmail.com>
> > 
> > Added code for calculating crc of erofs blocks (4K size).
> > For now it calculates checksum of first block. but it can
> > be modified to calculate crc for any no. of blocks.
> > 
> > Note that the first 1024 bytes are not checksumed 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.
> > 
> > Signed-off-by: Pratik Shinde <pratikshinde320@gmail.com>
> > Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
> > ---
> > 
> > changes since v7:
> >  - get rid of `chksum_blocks' pointed out by Chao.
> > 
> > 
> >  include/erofs/internal.h |  1 +
> >  include/erofs/io.h       |  8 +++++
> >  include/erofs_fs.h       |  3 +-
> >  lib/io.c                 | 27 ++++++++++++++++
> >  mkfs/main.c              | 68 ++++++++++++++++++++++++++++++++++++++++
> >  5 files changed, 106 insertions(+), 1 deletion(-)
> > 
> > diff --git a/include/erofs/internal.h b/include/erofs/internal.h
> > index 25ce7b54442d..9e2bb9ce33b6 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 97750478b5ab..e0ca8d949130 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 f29aa2516a99..bcc4f0c630ad 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 7f5f94dd6b1e..52f9424d201b 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;
> 
> Minor thing, I notice caller wrap this errno to EIO, so we'd better print errno
> here or by caller? Other part looks good to me anyway.

Oops, I didn't notice that... that's a good point,
let me resend with fix later...

> 
> Reviewed-by: Chao Yu <yuchao0@huawei.com>

Thanks for taking time on utils as well :-)

Thanks,
Gao Xiang

> 
> Thanks,
> 
> > +	}
> > +	return 0;
> > +}
> > diff --git a/mkfs/main.c b/mkfs/main.c
> > index ab57896e9ca8..eeb6ccc55b82 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,62 @@ 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_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 fill checksum");
> > +		return -EIO;
> > +	}
> > +
> > +	/*
> > +	 * 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 checksumed 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 +319,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 +402,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_superblock_csum_set();
> >  exit:
> >  	z_erofs_compress_exit();
> >  	dev_close();
> > 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v9] erofs-utils: support calculating checksum of erofs blocks
  2019-10-30  2:55         ` Gao Xiang
@ 2019-10-30  6:28           ` " Gao Xiang
  2019-11-08 13:37             ` Li Guifu
  0 siblings, 1 reply; 9+ messages in thread
From: Gao Xiang @ 2019-10-30  6:28 UTC (permalink / raw)
  To: Pratik Shinde, Li Guifu, Chao Yu, linux-erofs; +Cc: Miao Xie

From: Pratik Shinde <pratikshinde320@gmail.com>

Added code for calculating crc of erofs blocks (4K size).
For now it calculates checksum of first block. but it can
be modified to calculate crc for any no. of blocks.

Note that the first 1024 bytes are not checksumed 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.

Signed-off-by: Pratik Shinde <pratikshinde320@gmail.com>
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
---

changes since v8:
 - propagate the error code to the caller reported by Chao,
   which I didn't notice and is definitely an unintended
   behavior.

 include/erofs/internal.h |  1 +
 include/erofs/io.h       |  8 +++++
 include/erofs_fs.h       |  3 +-
 lib/io.c                 | 27 ++++++++++++++++
 mkfs/main.c              | 69 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 107 insertions(+), 1 deletion(-)

diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 25ce7b54442d..9e2bb9ce33b6 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 97750478b5ab..e0ca8d949130 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 f29aa2516a99..bcc4f0c630ad 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 7f5f94dd6b1e..52f9424d201b 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 ab57896e9ca8..32e3c88215fd 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_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 checksumed 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_superblock_csum_set();
 exit:
 	z_erofs_compress_exit();
 	dev_close();
-- 
2.17.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v9] erofs-utils: support calculating checksum of erofs blocks
  2019-10-30  6:28           ` [PATCH v9] " Gao Xiang
@ 2019-11-08 13:37             ` Li Guifu
  0 siblings, 0 replies; 9+ messages in thread
From: Li Guifu @ 2019-11-08 13:37 UTC (permalink / raw)
  To: Gao Xiang, Pratik Shinde, Li Guifu, Chao Yu, linux-erofs; +Cc: Miao Xie



On 2019/10/30 14:28, Gao Xiang wrote:
> From: Pratik Shinde <pratikshinde320@gmail.com>
> 
> Added code for calculating crc of erofs blocks (4K size).
> For now it calculates checksum of first block. but it can
> be modified to calculate crc for any no. of blocks.
> 
> Note that the first 1024 bytes are not checksumed 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.
> 
> Signed-off-by: Pratik Shinde <pratikshinde320@gmail.com>
> Reviewed-by: Chao Yu <yuchao0@huawei.com>
> Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
> ---
> 
It looks good
Reviewed-by: Li Guifu <blucerlee@gmail.com>

Thanks,

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, back to index

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-19 15:08 [PATCH-v5] erofs-utils:code for calculating crc checksum of erofs blocks Pratik Shinde
2019-10-20  9:06 ` Gao Xiang via Linux-erofs
2019-10-20 14:11 ` Gao Xiang via Linux-erofs
2019-10-23  3:49   ` [PATCH v7] erofs-utils: support calculating " Gao Xiang
2019-10-28 14:23     ` [PATCH v8] " Gao Xiang
2019-10-30  2:39       ` Chao Yu
2019-10-30  2:55         ` Gao Xiang
2019-10-30  6:28           ` [PATCH v9] " Gao Xiang
2019-11-08 13:37             ` Li Guifu

Linux-EROFS Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-erofs/0 linux-erofs/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-erofs linux-erofs/ https://lore.kernel.org/linux-erofs \
		linux-erofs@lists.ozlabs.org linux-erofs@ozlabs.org
	public-inbox-index linux-erofs

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.ozlabs.lists.linux-erofs


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git