* [PATCH v2 4/4] erofs: add on-disk compression configurations
@ 2021-03-29 1:23 ` Gao Xiang via Linux-erofs
0 siblings, 0 replies; 22+ messages in thread
From: Gao Xiang via Linux-erofs @ 2021-03-29 1:23 UTC (permalink / raw)
To: linux-erofs, Chao Yu, Chao Yu; +Cc: LKML
From: Gao Xiang <hsiangkao@redhat.com>
Add a bitmap for available compression algorithms and a variable-sized
on-disk table for compression options in preparation for upcoming big
pcluster and LZMA algorithm, which follows the end of super block.
To parse the compression options, the bitmap is scanned one by one.
For each available algorithm, there is data followed by 2-byte `length'
correspondingly (it's enough for most cases, or entire fs blocks should
be used.)
With such available algorithm bitmap, kernel itself can also refuse to
mount such filesystem if any unsupported compression algorithm exists.
Note that COMPR_CFGS feature will be enabled with BIG_PCLUSTER.
Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
---
fs/erofs/decompressor.c | 2 +-
fs/erofs/erofs_fs.h | 14 ++--
fs/erofs/internal.h | 5 +-
fs/erofs/super.c | 143 +++++++++++++++++++++++++++++++++++++++-
4 files changed, 157 insertions(+), 7 deletions(-)
diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c
index 97538ff24a19..27aa6a99b371 100644
--- a/fs/erofs/decompressor.c
+++ b/fs/erofs/decompressor.c
@@ -41,7 +41,7 @@ int z_erofs_load_lz4_config(struct super_block *sb,
}
distance = le16_to_cpu(lz4->max_distance);
} else {
- distance = le16_to_cpu(dsb->lz4_max_distance);
+ distance = le16_to_cpu(dsb->u1.lz4_max_distance);
}
EROFS_SB(sb)->lz4.max_distance_pages = distance ?
diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h
index e0f3c0db1f82..5a126493d4d9 100644
--- a/fs/erofs/erofs_fs.h
+++ b/fs/erofs/erofs_fs.h
@@ -18,15 +18,16 @@
* be incompatible with this kernel version.
*/
#define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING 0x00000001
+#define EROFS_FEATURE_INCOMPAT_COMPR_CFGS 0x00000002
#define EROFS_ALL_FEATURE_INCOMPAT EROFS_FEATURE_INCOMPAT_LZ4_0PADDING
-/* 128-byte erofs on-disk super block */
+/* erofs on-disk super block (currently 128 bytes) */
struct erofs_super_block {
__le32 magic; /* file system magic number */
__le32 checksum; /* crc32c(super_block) */
__le32 feature_compat;
__u8 blkszbits; /* support block_size == PAGE_SIZE only */
- __u8 reserved;
+ __u8 sb_extslots; /* superblock size = 128 + sb_extslots * 16 */
__le16 root_nid; /* nid of root directory */
__le64 inos; /* total valid ino # (== f_files - f_favail) */
@@ -39,8 +40,12 @@ struct erofs_super_block {
__u8 uuid[16]; /* 128-bit uuid for volume */
__u8 volume_name[16]; /* volume name */
__le32 feature_incompat;
- /* customized lz4 sliding window size instead of 64k by default */
- __le16 lz4_max_distance;
+ union {
+ /* bitmap for available compression algorithms */
+ __le16 available_compr_algs;
+ /* customized sliding window size instead of 64k by default */
+ __le16 lz4_max_distance;
+ } __packed u1;
__u8 reserved2[42];
};
@@ -196,6 +201,7 @@ enum {
Z_EROFS_COMPRESSION_LZ4 = 0,
Z_EROFS_COMPRESSION_MAX
};
+#define Z_EROFS_ALL_COMPR_ALGS (1 << (Z_EROFS_COMPRESSION_MAX - 1))
/* 14 bytes (+ length field = 16 bytes) */
struct z_erofs_lz4_cfgs {
diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
index 46b977f348eb..f3fa895d809f 100644
--- a/fs/erofs/internal.h
+++ b/fs/erofs/internal.h
@@ -75,6 +75,7 @@ struct erofs_sb_info {
struct xarray managed_pslots;
unsigned int shrinker_run_no;
+ u16 available_compr_algs;
/* pseudo inode to manage cached pages */
struct inode *managed_cache;
@@ -90,6 +91,7 @@ struct erofs_sb_info {
/* inode slot unit size in bit shift */
unsigned char islotbits;
+ u32 sb_size; /* total superblock size */
u32 build_time_nsec;
u64 build_time;
@@ -233,6 +235,7 @@ static inline bool erofs_sb_has_##name(struct erofs_sb_info *sbi) \
}
EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING)
+EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS)
EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM)
/* atomic flag definitions */
@@ -454,7 +457,7 @@ static inline int z_erofs_load_lz4_config(struct super_block *sb,
struct erofs_super_block *dsb,
struct z_erofs_lz4_cfgs *lz4, int len)
{
- if (lz4 || dsb->lz4_max_distance) {
+ if (lz4 || dsb->u1.lz4_max_distance) {
erofs_err(sb, "lz4 algorithm isn't enabled");
return -EINVAL;
}
diff --git a/fs/erofs/super.c b/fs/erofs/super.c
index 1ca8da3f2125..628c751634fe 100644
--- a/fs/erofs/super.c
+++ b/fs/erofs/super.c
@@ -122,6 +122,138 @@ static bool check_layout_compatibility(struct super_block *sb,
return true;
}
+#ifdef CONFIG_EROFS_FS_ZIP
+/* read variable-sized metadata, offset will be aligned by 4-byte */
+static void *erofs_read_metadata(struct super_block *sb, struct page **pagep,
+ erofs_off_t *offset, int *lengthp)
+{
+ struct page *page = *pagep;
+ u8 *buffer, *ptr;
+ int len, i, cnt;
+ erofs_blk_t blk;
+
+ *offset = round_up(*offset, 4);
+ blk = erofs_blknr(*offset);
+
+ if (!page || page->index != blk) {
+ if (page) {
+ unlock_page(page);
+ put_page(page);
+ }
+ page = erofs_get_meta_page(sb, blk);
+ if (IS_ERR(page))
+ goto err_nullpage;
+ }
+
+ ptr = kmap(page);
+ len = le16_to_cpu(*(__le16 *)&ptr[erofs_blkoff(*offset)]);
+ if (!len)
+ len = U16_MAX + 1;
+ buffer = kmalloc(len, GFP_KERNEL);
+ if (!buffer) {
+ buffer = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+ *offset += sizeof(__le16);
+ *lengthp = len;
+
+ for (i = 0; i < len; i += cnt) {
+ cnt = min(EROFS_BLKSIZ - (int)erofs_blkoff(*offset), len - i);
+ blk = erofs_blknr(*offset);
+
+ if (!page || page->index != blk) {
+ if (page) {
+ kunmap(page);
+ unlock_page(page);
+ put_page(page);
+ }
+ page = erofs_get_meta_page(sb, blk);
+ if (IS_ERR(page)) {
+ kfree(buffer);
+ goto err_nullpage;
+ }
+ ptr = kmap(page);
+ }
+ memcpy(buffer + i, ptr + erofs_blkoff(*offset), cnt);
+ *offset += cnt;
+ }
+out:
+ kunmap(page);
+ *pagep = page;
+ return buffer;
+err_nullpage:
+ *pagep = NULL;
+ return page;
+}
+
+static int erofs_load_compr_cfgs(struct super_block *sb,
+ struct erofs_super_block *dsb)
+{
+ struct erofs_sb_info *sbi;
+ struct page *page;
+ unsigned int algs, alg;
+ erofs_off_t offset;
+ int size, ret;
+
+ sbi = EROFS_SB(sb);
+ sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs);
+
+ if (sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS) {
+ erofs_err(sb,
+"try to load compressed image with unsupported algorithms %x",
+ sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
+ return -EINVAL;
+ }
+
+ offset = EROFS_SUPER_OFFSET + sbi->sb_size;
+ page = NULL;
+ alg = 0;
+ ret = 0;
+
+ for (algs = sbi->available_compr_algs; algs; algs >>= 1, ++alg) {
+ void *data;
+
+ if (!(algs & 1))
+ continue;
+
+ data = erofs_read_metadata(sb, &page, &offset, &size);
+ if (IS_ERR(data)) {
+ ret = PTR_ERR(data);
+ goto err;
+ }
+
+ switch (alg) {
+ case Z_EROFS_COMPRESSION_LZ4:
+ ret = z_erofs_load_lz4_config(sb, dsb, data, size);
+ break;
+ default:
+ DBG_BUGON(1);
+ ret = -EFAULT;
+ }
+ kfree(data);
+ if (ret)
+ goto err;
+ }
+err:
+ if (page) {
+ unlock_page(page);
+ put_page(page);
+ }
+ return ret;
+}
+#else
+static int erofs_load_compr_cfgs(struct super_block *sb,
+ struct erofs_super_block *dsb)
+{
+ if (dsb->u1.available_compr_algs) {
+ erofs_err(sb,
+"try to load compressed image when compression is disabled");
+ return -EINVAL;
+ }
+ return 0;
+}
+#endif
+
static int erofs_read_superblock(struct super_block *sb)
{
struct erofs_sb_info *sbi;
@@ -166,6 +298,12 @@ static int erofs_read_superblock(struct super_block *sb)
if (!check_layout_compatibility(sb, dsb))
goto out;
+ sbi->sb_size = 128 + dsb->sb_extslots * 16;
+ if (sbi->sb_size > EROFS_BLKSIZ) {
+ erofs_err(sb, "invalid sb_extslots %u (more than a fs block)",
+ sbi->sb_size);
+ goto out;
+ }
sbi->blocks = le32_to_cpu(dsb->blocks);
sbi->meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
#ifdef CONFIG_EROFS_FS_XATTR
@@ -189,7 +327,10 @@ static int erofs_read_superblock(struct super_block *sb)
}
/* parse on-disk compression configurations */
- ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0);
+ if (erofs_sb_has_compr_cfgs(sbi))
+ ret = erofs_load_compr_cfgs(sb, dsb);
+ else
+ ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0);
out:
kunmap(page);
put_page(page);
--
2.20.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH v2 4/4] erofs: add on-disk compression configurations
2021-03-29 1:23 ` Gao Xiang via Linux-erofs
@ 2021-03-29 6:26 ` Chao Yu
-1 siblings, 0 replies; 22+ messages in thread
From: Chao Yu @ 2021-03-29 6:26 UTC (permalink / raw)
To: Gao Xiang, linux-erofs, Chao Yu; +Cc: LKML, Gao Xiang
On 2021/3/29 9:23, Gao Xiang wrote:
> From: Gao Xiang <hsiangkao@redhat.com>
>
> Add a bitmap for available compression algorithms and a variable-sized
> on-disk table for compression options in preparation for upcoming big
> pcluster and LZMA algorithm, which follows the end of super block.
>
> To parse the compression options, the bitmap is scanned one by one.
> For each available algorithm, there is data followed by 2-byte `length'
> correspondingly (it's enough for most cases, or entire fs blocks should
> be used.)
>
> With such available algorithm bitmap, kernel itself can also refuse to
> mount such filesystem if any unsupported compression algorithm exists.
>
> Note that COMPR_CFGS feature will be enabled with BIG_PCLUSTER.
>
> Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
> ---
> fs/erofs/decompressor.c | 2 +-
> fs/erofs/erofs_fs.h | 14 ++--
> fs/erofs/internal.h | 5 +-
> fs/erofs/super.c | 143 +++++++++++++++++++++++++++++++++++++++-
> 4 files changed, 157 insertions(+), 7 deletions(-)
>
> diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c
> index 97538ff24a19..27aa6a99b371 100644
> --- a/fs/erofs/decompressor.c
> +++ b/fs/erofs/decompressor.c
> @@ -41,7 +41,7 @@ int z_erofs_load_lz4_config(struct super_block *sb,
> }
> distance = le16_to_cpu(lz4->max_distance);
> } else {
> - distance = le16_to_cpu(dsb->lz4_max_distance);
> + distance = le16_to_cpu(dsb->u1.lz4_max_distance);
> }
>
> EROFS_SB(sb)->lz4.max_distance_pages = distance ?
> diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h
> index e0f3c0db1f82..5a126493d4d9 100644
> --- a/fs/erofs/erofs_fs.h
> +++ b/fs/erofs/erofs_fs.h
> @@ -18,15 +18,16 @@
> * be incompatible with this kernel version.
> */
> #define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING 0x00000001
> +#define EROFS_FEATURE_INCOMPAT_COMPR_CFGS 0x00000002
> #define EROFS_ALL_FEATURE_INCOMPAT EROFS_FEATURE_INCOMPAT_LZ4_0PADDING
>
> -/* 128-byte erofs on-disk super block */
> +/* erofs on-disk super block (currently 128 bytes) */
> struct erofs_super_block {
> __le32 magic; /* file system magic number */
> __le32 checksum; /* crc32c(super_block) */
> __le32 feature_compat;
> __u8 blkszbits; /* support block_size == PAGE_SIZE only */
> - __u8 reserved;
> + __u8 sb_extslots; /* superblock size = 128 + sb_extslots * 16 */
>
> __le16 root_nid; /* nid of root directory */
> __le64 inos; /* total valid ino # (== f_files - f_favail) */
> @@ -39,8 +40,12 @@ struct erofs_super_block {
> __u8 uuid[16]; /* 128-bit uuid for volume */
> __u8 volume_name[16]; /* volume name */
> __le32 feature_incompat;
> - /* customized lz4 sliding window size instead of 64k by default */
> - __le16 lz4_max_distance;
> + union {
> + /* bitmap for available compression algorithms */
> + __le16 available_compr_algs;
> + /* customized sliding window size instead of 64k by default */
> + __le16 lz4_max_distance;
> + } __packed u1;
> __u8 reserved2[42];
> };
>
> @@ -196,6 +201,7 @@ enum {
> Z_EROFS_COMPRESSION_LZ4 = 0,
> Z_EROFS_COMPRESSION_MAX
> };
> +#define Z_EROFS_ALL_COMPR_ALGS (1 << (Z_EROFS_COMPRESSION_MAX - 1))
>
> /* 14 bytes (+ length field = 16 bytes) */
> struct z_erofs_lz4_cfgs {
> diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
> index 46b977f348eb..f3fa895d809f 100644
> --- a/fs/erofs/internal.h
> +++ b/fs/erofs/internal.h
> @@ -75,6 +75,7 @@ struct erofs_sb_info {
> struct xarray managed_pslots;
>
> unsigned int shrinker_run_no;
> + u16 available_compr_algs;
>
> /* pseudo inode to manage cached pages */
> struct inode *managed_cache;
> @@ -90,6 +91,7 @@ struct erofs_sb_info {
> /* inode slot unit size in bit shift */
> unsigned char islotbits;
>
> + u32 sb_size; /* total superblock size */
> u32 build_time_nsec;
> u64 build_time;
>
> @@ -233,6 +235,7 @@ static inline bool erofs_sb_has_##name(struct erofs_sb_info *sbi) \
> }
>
> EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING)
> +EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS)
> EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM)
>
> /* atomic flag definitions */
> @@ -454,7 +457,7 @@ static inline int z_erofs_load_lz4_config(struct super_block *sb,
> struct erofs_super_block *dsb,
> struct z_erofs_lz4_cfgs *lz4, int len)
> {
> - if (lz4 || dsb->lz4_max_distance) {
> + if (lz4 || dsb->u1.lz4_max_distance) {
> erofs_err(sb, "lz4 algorithm isn't enabled");
> return -EINVAL;
> }
> diff --git a/fs/erofs/super.c b/fs/erofs/super.c
> index 1ca8da3f2125..628c751634fe 100644
> --- a/fs/erofs/super.c
> +++ b/fs/erofs/super.c
> @@ -122,6 +122,138 @@ static bool check_layout_compatibility(struct super_block *sb,
> return true;
> }
>
> +#ifdef CONFIG_EROFS_FS_ZIP
> +/* read variable-sized metadata, offset will be aligned by 4-byte */
> +static void *erofs_read_metadata(struct super_block *sb, struct page **pagep,
> + erofs_off_t *offset, int *lengthp)
> +{
> + struct page *page = *pagep;
> + u8 *buffer, *ptr;
> + int len, i, cnt;
> + erofs_blk_t blk;
> +
> + *offset = round_up(*offset, 4);
> + blk = erofs_blknr(*offset);
> +
> + if (!page || page->index != blk) {
> + if (page) {
> + unlock_page(page);
> + put_page(page);
> + }
> + page = erofs_get_meta_page(sb, blk);
> + if (IS_ERR(page))
> + goto err_nullpage;
> + }
> +
> + ptr = kmap(page);
> + len = le16_to_cpu(*(__le16 *)&ptr[erofs_blkoff(*offset)]);
> + if (!len)
> + len = U16_MAX + 1;
> + buffer = kmalloc(len, GFP_KERNEL);
> + if (!buffer) {
> + buffer = ERR_PTR(-ENOMEM);
> + goto out;
> + }
> + *offset += sizeof(__le16);
> + *lengthp = len;
> +
> + for (i = 0; i < len; i += cnt) {
> + cnt = min(EROFS_BLKSIZ - (int)erofs_blkoff(*offset), len - i);
> + blk = erofs_blknr(*offset);
> +
> + if (!page || page->index != blk) {
> + if (page) {
> + kunmap(page);
> + unlock_page(page);
> + put_page(page);
> + }
> + page = erofs_get_meta_page(sb, blk);
> + if (IS_ERR(page)) {
> + kfree(buffer);
> + goto err_nullpage;
> + }
> + ptr = kmap(page);
> + }
> + memcpy(buffer + i, ptr + erofs_blkoff(*offset), cnt);
> + *offset += cnt;
> + }
> +out:
> + kunmap(page);
> + *pagep = page;
> + return buffer;
> +err_nullpage:
> + *pagep = NULL;
> + return page;
> +}
> +
> +static int erofs_load_compr_cfgs(struct super_block *sb,
> + struct erofs_super_block *dsb)
> +{
> + struct erofs_sb_info *sbi;
> + struct page *page;
> + unsigned int algs, alg;
> + erofs_off_t offset;
> + int size, ret;
> +
> + sbi = EROFS_SB(sb);
> + sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs);
> +
> + if (sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS) {
> + erofs_err(sb,
> +"try to load compressed image with unsupported algorithms %x",
Minor style issue:
"try to load compressed image with unsupported "
"algorithms %x",
sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
> + sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
> + return -EINVAL;
> + }
> +
> + offset = EROFS_SUPER_OFFSET + sbi->sb_size;
> + page = NULL;
> + alg = 0;
> + ret = 0;
> +
> + for (algs = sbi->available_compr_algs; algs; algs >>= 1, ++alg) {
> + void *data;
> +
> + if (!(algs & 1))
> + continue;
> +
> + data = erofs_read_metadata(sb, &page, &offset, &size);
> + if (IS_ERR(data)) {
> + ret = PTR_ERR(data);
> + goto err;
> + }
> +
> + switch (alg) {
> + case Z_EROFS_COMPRESSION_LZ4:
> + ret = z_erofs_load_lz4_config(sb, dsb, data, size);
> + break;
> + default:
> + DBG_BUGON(1);
> + ret = -EFAULT;
> + }
> + kfree(data);
> + if (ret)
> + goto err;
> + }
> +err:
> + if (page) {
> + unlock_page(page);
> + put_page(page);
> + }
> + return ret;
> +}
> +#else
> +static int erofs_load_compr_cfgs(struct super_block *sb,
> + struct erofs_super_block *dsb)
> +{
> + if (dsb->u1.available_compr_algs) {
> + erofs_err(sb,
> +"try to load compressed image when compression is disabled");
Ditto,
erofs_err(sb, "try to load compressed image when "
"compression is disabled");
> + return -EINVAL;
> + }
> + return 0;
> +}
> +#endif
> +
> static int erofs_read_superblock(struct super_block *sb)
> {
> struct erofs_sb_info *sbi;
> @@ -166,6 +298,12 @@ static int erofs_read_superblock(struct super_block *sb)
> if (!check_layout_compatibility(sb, dsb))
> goto out;
>
> + sbi->sb_size = 128 + dsb->sb_extslots * 16;
sbi->sb_size = sizeof(struct erofs_super_block) +
dsb->sb_extslots * EROFS_EXTSLOT_SIZE;
Otherwise it looks good to me,
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Thanks,
> + if (sbi->sb_size > EROFS_BLKSIZ) {
> + erofs_err(sb, "invalid sb_extslots %u (more than a fs block)",
> + sbi->sb_size);
> + goto out;
> + }
> sbi->blocks = le32_to_cpu(dsb->blocks);
> sbi->meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
> #ifdef CONFIG_EROFS_FS_XATTR
> @@ -189,7 +327,10 @@ static int erofs_read_superblock(struct super_block *sb)
> }
>
> /* parse on-disk compression configurations */
> - ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0);
> + if (erofs_sb_has_compr_cfgs(sbi))
> + ret = erofs_load_compr_cfgs(sb, dsb);
> + else
> + ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0);
> out:
> kunmap(page);
> put_page(page);
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v2 4/4] erofs: add on-disk compression configurations
@ 2021-03-29 6:26 ` Chao Yu
0 siblings, 0 replies; 22+ messages in thread
From: Chao Yu @ 2021-03-29 6:26 UTC (permalink / raw)
To: Gao Xiang, linux-erofs, Chao Yu; +Cc: LKML
On 2021/3/29 9:23, Gao Xiang wrote:
> From: Gao Xiang <hsiangkao@redhat.com>
>
> Add a bitmap for available compression algorithms and a variable-sized
> on-disk table for compression options in preparation for upcoming big
> pcluster and LZMA algorithm, which follows the end of super block.
>
> To parse the compression options, the bitmap is scanned one by one.
> For each available algorithm, there is data followed by 2-byte `length'
> correspondingly (it's enough for most cases, or entire fs blocks should
> be used.)
>
> With such available algorithm bitmap, kernel itself can also refuse to
> mount such filesystem if any unsupported compression algorithm exists.
>
> Note that COMPR_CFGS feature will be enabled with BIG_PCLUSTER.
>
> Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
> ---
> fs/erofs/decompressor.c | 2 +-
> fs/erofs/erofs_fs.h | 14 ++--
> fs/erofs/internal.h | 5 +-
> fs/erofs/super.c | 143 +++++++++++++++++++++++++++++++++++++++-
> 4 files changed, 157 insertions(+), 7 deletions(-)
>
> diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c
> index 97538ff24a19..27aa6a99b371 100644
> --- a/fs/erofs/decompressor.c
> +++ b/fs/erofs/decompressor.c
> @@ -41,7 +41,7 @@ int z_erofs_load_lz4_config(struct super_block *sb,
> }
> distance = le16_to_cpu(lz4->max_distance);
> } else {
> - distance = le16_to_cpu(dsb->lz4_max_distance);
> + distance = le16_to_cpu(dsb->u1.lz4_max_distance);
> }
>
> EROFS_SB(sb)->lz4.max_distance_pages = distance ?
> diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h
> index e0f3c0db1f82..5a126493d4d9 100644
> --- a/fs/erofs/erofs_fs.h
> +++ b/fs/erofs/erofs_fs.h
> @@ -18,15 +18,16 @@
> * be incompatible with this kernel version.
> */
> #define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING 0x00000001
> +#define EROFS_FEATURE_INCOMPAT_COMPR_CFGS 0x00000002
> #define EROFS_ALL_FEATURE_INCOMPAT EROFS_FEATURE_INCOMPAT_LZ4_0PADDING
>
> -/* 128-byte erofs on-disk super block */
> +/* erofs on-disk super block (currently 128 bytes) */
> struct erofs_super_block {
> __le32 magic; /* file system magic number */
> __le32 checksum; /* crc32c(super_block) */
> __le32 feature_compat;
> __u8 blkszbits; /* support block_size == PAGE_SIZE only */
> - __u8 reserved;
> + __u8 sb_extslots; /* superblock size = 128 + sb_extslots * 16 */
>
> __le16 root_nid; /* nid of root directory */
> __le64 inos; /* total valid ino # (== f_files - f_favail) */
> @@ -39,8 +40,12 @@ struct erofs_super_block {
> __u8 uuid[16]; /* 128-bit uuid for volume */
> __u8 volume_name[16]; /* volume name */
> __le32 feature_incompat;
> - /* customized lz4 sliding window size instead of 64k by default */
> - __le16 lz4_max_distance;
> + union {
> + /* bitmap for available compression algorithms */
> + __le16 available_compr_algs;
> + /* customized sliding window size instead of 64k by default */
> + __le16 lz4_max_distance;
> + } __packed u1;
> __u8 reserved2[42];
> };
>
> @@ -196,6 +201,7 @@ enum {
> Z_EROFS_COMPRESSION_LZ4 = 0,
> Z_EROFS_COMPRESSION_MAX
> };
> +#define Z_EROFS_ALL_COMPR_ALGS (1 << (Z_EROFS_COMPRESSION_MAX - 1))
>
> /* 14 bytes (+ length field = 16 bytes) */
> struct z_erofs_lz4_cfgs {
> diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
> index 46b977f348eb..f3fa895d809f 100644
> --- a/fs/erofs/internal.h
> +++ b/fs/erofs/internal.h
> @@ -75,6 +75,7 @@ struct erofs_sb_info {
> struct xarray managed_pslots;
>
> unsigned int shrinker_run_no;
> + u16 available_compr_algs;
>
> /* pseudo inode to manage cached pages */
> struct inode *managed_cache;
> @@ -90,6 +91,7 @@ struct erofs_sb_info {
> /* inode slot unit size in bit shift */
> unsigned char islotbits;
>
> + u32 sb_size; /* total superblock size */
> u32 build_time_nsec;
> u64 build_time;
>
> @@ -233,6 +235,7 @@ static inline bool erofs_sb_has_##name(struct erofs_sb_info *sbi) \
> }
>
> EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING)
> +EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS)
> EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM)
>
> /* atomic flag definitions */
> @@ -454,7 +457,7 @@ static inline int z_erofs_load_lz4_config(struct super_block *sb,
> struct erofs_super_block *dsb,
> struct z_erofs_lz4_cfgs *lz4, int len)
> {
> - if (lz4 || dsb->lz4_max_distance) {
> + if (lz4 || dsb->u1.lz4_max_distance) {
> erofs_err(sb, "lz4 algorithm isn't enabled");
> return -EINVAL;
> }
> diff --git a/fs/erofs/super.c b/fs/erofs/super.c
> index 1ca8da3f2125..628c751634fe 100644
> --- a/fs/erofs/super.c
> +++ b/fs/erofs/super.c
> @@ -122,6 +122,138 @@ static bool check_layout_compatibility(struct super_block *sb,
> return true;
> }
>
> +#ifdef CONFIG_EROFS_FS_ZIP
> +/* read variable-sized metadata, offset will be aligned by 4-byte */
> +static void *erofs_read_metadata(struct super_block *sb, struct page **pagep,
> + erofs_off_t *offset, int *lengthp)
> +{
> + struct page *page = *pagep;
> + u8 *buffer, *ptr;
> + int len, i, cnt;
> + erofs_blk_t blk;
> +
> + *offset = round_up(*offset, 4);
> + blk = erofs_blknr(*offset);
> +
> + if (!page || page->index != blk) {
> + if (page) {
> + unlock_page(page);
> + put_page(page);
> + }
> + page = erofs_get_meta_page(sb, blk);
> + if (IS_ERR(page))
> + goto err_nullpage;
> + }
> +
> + ptr = kmap(page);
> + len = le16_to_cpu(*(__le16 *)&ptr[erofs_blkoff(*offset)]);
> + if (!len)
> + len = U16_MAX + 1;
> + buffer = kmalloc(len, GFP_KERNEL);
> + if (!buffer) {
> + buffer = ERR_PTR(-ENOMEM);
> + goto out;
> + }
> + *offset += sizeof(__le16);
> + *lengthp = len;
> +
> + for (i = 0; i < len; i += cnt) {
> + cnt = min(EROFS_BLKSIZ - (int)erofs_blkoff(*offset), len - i);
> + blk = erofs_blknr(*offset);
> +
> + if (!page || page->index != blk) {
> + if (page) {
> + kunmap(page);
> + unlock_page(page);
> + put_page(page);
> + }
> + page = erofs_get_meta_page(sb, blk);
> + if (IS_ERR(page)) {
> + kfree(buffer);
> + goto err_nullpage;
> + }
> + ptr = kmap(page);
> + }
> + memcpy(buffer + i, ptr + erofs_blkoff(*offset), cnt);
> + *offset += cnt;
> + }
> +out:
> + kunmap(page);
> + *pagep = page;
> + return buffer;
> +err_nullpage:
> + *pagep = NULL;
> + return page;
> +}
> +
> +static int erofs_load_compr_cfgs(struct super_block *sb,
> + struct erofs_super_block *dsb)
> +{
> + struct erofs_sb_info *sbi;
> + struct page *page;
> + unsigned int algs, alg;
> + erofs_off_t offset;
> + int size, ret;
> +
> + sbi = EROFS_SB(sb);
> + sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs);
> +
> + if (sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS) {
> + erofs_err(sb,
> +"try to load compressed image with unsupported algorithms %x",
Minor style issue:
"try to load compressed image with unsupported "
"algorithms %x",
sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
> + sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
> + return -EINVAL;
> + }
> +
> + offset = EROFS_SUPER_OFFSET + sbi->sb_size;
> + page = NULL;
> + alg = 0;
> + ret = 0;
> +
> + for (algs = sbi->available_compr_algs; algs; algs >>= 1, ++alg) {
> + void *data;
> +
> + if (!(algs & 1))
> + continue;
> +
> + data = erofs_read_metadata(sb, &page, &offset, &size);
> + if (IS_ERR(data)) {
> + ret = PTR_ERR(data);
> + goto err;
> + }
> +
> + switch (alg) {
> + case Z_EROFS_COMPRESSION_LZ4:
> + ret = z_erofs_load_lz4_config(sb, dsb, data, size);
> + break;
> + default:
> + DBG_BUGON(1);
> + ret = -EFAULT;
> + }
> + kfree(data);
> + if (ret)
> + goto err;
> + }
> +err:
> + if (page) {
> + unlock_page(page);
> + put_page(page);
> + }
> + return ret;
> +}
> +#else
> +static int erofs_load_compr_cfgs(struct super_block *sb,
> + struct erofs_super_block *dsb)
> +{
> + if (dsb->u1.available_compr_algs) {
> + erofs_err(sb,
> +"try to load compressed image when compression is disabled");
Ditto,
erofs_err(sb, "try to load compressed image when "
"compression is disabled");
> + return -EINVAL;
> + }
> + return 0;
> +}
> +#endif
> +
> static int erofs_read_superblock(struct super_block *sb)
> {
> struct erofs_sb_info *sbi;
> @@ -166,6 +298,12 @@ static int erofs_read_superblock(struct super_block *sb)
> if (!check_layout_compatibility(sb, dsb))
> goto out;
>
> + sbi->sb_size = 128 + dsb->sb_extslots * 16;
sbi->sb_size = sizeof(struct erofs_super_block) +
dsb->sb_extslots * EROFS_EXTSLOT_SIZE;
Otherwise it looks good to me,
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Thanks,
> + if (sbi->sb_size > EROFS_BLKSIZ) {
> + erofs_err(sb, "invalid sb_extslots %u (more than a fs block)",
> + sbi->sb_size);
> + goto out;
> + }
> sbi->blocks = le32_to_cpu(dsb->blocks);
> sbi->meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
> #ifdef CONFIG_EROFS_FS_XATTR
> @@ -189,7 +327,10 @@ static int erofs_read_superblock(struct super_block *sb)
> }
>
> /* parse on-disk compression configurations */
> - ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0);
> + if (erofs_sb_has_compr_cfgs(sbi))
> + ret = erofs_load_compr_cfgs(sb, dsb);
> + else
> + ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0);
> out:
> kunmap(page);
> put_page(page);
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v2 4/4] erofs: add on-disk compression configurations
2021-03-29 6:26 ` Chao Yu
@ 2021-03-29 6:36 ` Gao Xiang
-1 siblings, 0 replies; 22+ messages in thread
From: Gao Xiang @ 2021-03-29 6:36 UTC (permalink / raw)
To: Chao Yu; +Cc: Gao Xiang, linux-erofs, Chao Yu, LKML
Hi Chao,
On Mon, Mar 29, 2021 at 02:26:05PM +0800, Chao Yu wrote:
> On 2021/3/29 9:23, Gao Xiang wrote:
> > From: Gao Xiang <hsiangkao@redhat.com>
> >
> > Add a bitmap for available compression algorithms and a variable-sized
> > on-disk table for compression options in preparation for upcoming big
> > pcluster and LZMA algorithm, which follows the end of super block.
> >
> > To parse the compression options, the bitmap is scanned one by one.
> > For each available algorithm, there is data followed by 2-byte `length'
> > correspondingly (it's enough for most cases, or entire fs blocks should
> > be used.)
> >
> > With such available algorithm bitmap, kernel itself can also refuse to
> > mount such filesystem if any unsupported compression algorithm exists.
> >
> > Note that COMPR_CFGS feature will be enabled with BIG_PCLUSTER.
> >
> > Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
> > ---
> > fs/erofs/decompressor.c | 2 +-
> > fs/erofs/erofs_fs.h | 14 ++--
> > fs/erofs/internal.h | 5 +-
> > fs/erofs/super.c | 143 +++++++++++++++++++++++++++++++++++++++-
> > 4 files changed, 157 insertions(+), 7 deletions(-)
> >
> > diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c
> > index 97538ff24a19..27aa6a99b371 100644
> > --- a/fs/erofs/decompressor.c
> > +++ b/fs/erofs/decompressor.c
> > @@ -41,7 +41,7 @@ int z_erofs_load_lz4_config(struct super_block *sb,
> > }
> > distance = le16_to_cpu(lz4->max_distance);
> > } else {
> > - distance = le16_to_cpu(dsb->lz4_max_distance);
> > + distance = le16_to_cpu(dsb->u1.lz4_max_distance);
> > }
> > EROFS_SB(sb)->lz4.max_distance_pages = distance ?
> > diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h
> > index e0f3c0db1f82..5a126493d4d9 100644
> > --- a/fs/erofs/erofs_fs.h
> > +++ b/fs/erofs/erofs_fs.h
> > @@ -18,15 +18,16 @@
> > * be incompatible with this kernel version.
> > */
> > #define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING 0x00000001
> > +#define EROFS_FEATURE_INCOMPAT_COMPR_CFGS 0x00000002
> > #define EROFS_ALL_FEATURE_INCOMPAT EROFS_FEATURE_INCOMPAT_LZ4_0PADDING
> > -/* 128-byte erofs on-disk super block */
> > +/* erofs on-disk super block (currently 128 bytes) */
> > struct erofs_super_block {
> > __le32 magic; /* file system magic number */
> > __le32 checksum; /* crc32c(super_block) */
> > __le32 feature_compat;
> > __u8 blkszbits; /* support block_size == PAGE_SIZE only */
> > - __u8 reserved;
> > + __u8 sb_extslots; /* superblock size = 128 + sb_extslots * 16 */
> > __le16 root_nid; /* nid of root directory */
> > __le64 inos; /* total valid ino # (== f_files - f_favail) */
> > @@ -39,8 +40,12 @@ struct erofs_super_block {
> > __u8 uuid[16]; /* 128-bit uuid for volume */
> > __u8 volume_name[16]; /* volume name */
> > __le32 feature_incompat;
> > - /* customized lz4 sliding window size instead of 64k by default */
> > - __le16 lz4_max_distance;
> > + union {
> > + /* bitmap for available compression algorithms */
> > + __le16 available_compr_algs;
> > + /* customized sliding window size instead of 64k by default */
> > + __le16 lz4_max_distance;
> > + } __packed u1;
> > __u8 reserved2[42];
> > };
> > @@ -196,6 +201,7 @@ enum {
> > Z_EROFS_COMPRESSION_LZ4 = 0,
> > Z_EROFS_COMPRESSION_MAX
> > };
> > +#define Z_EROFS_ALL_COMPR_ALGS (1 << (Z_EROFS_COMPRESSION_MAX - 1))
> > /* 14 bytes (+ length field = 16 bytes) */
> > struct z_erofs_lz4_cfgs {
> > diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
> > index 46b977f348eb..f3fa895d809f 100644
> > --- a/fs/erofs/internal.h
> > +++ b/fs/erofs/internal.h
> > @@ -75,6 +75,7 @@ struct erofs_sb_info {
> > struct xarray managed_pslots;
> > unsigned int shrinker_run_no;
> > + u16 available_compr_algs;
> > /* pseudo inode to manage cached pages */
> > struct inode *managed_cache;
> > @@ -90,6 +91,7 @@ struct erofs_sb_info {
> > /* inode slot unit size in bit shift */
> > unsigned char islotbits;
> > + u32 sb_size; /* total superblock size */
> > u32 build_time_nsec;
> > u64 build_time;
> > @@ -233,6 +235,7 @@ static inline bool erofs_sb_has_##name(struct erofs_sb_info *sbi) \
> > }
> > EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING)
> > +EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS)
> > EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM)
> > /* atomic flag definitions */
> > @@ -454,7 +457,7 @@ static inline int z_erofs_load_lz4_config(struct super_block *sb,
> > struct erofs_super_block *dsb,
> > struct z_erofs_lz4_cfgs *lz4, int len)
> > {
> > - if (lz4 || dsb->lz4_max_distance) {
> > + if (lz4 || dsb->u1.lz4_max_distance) {
> > erofs_err(sb, "lz4 algorithm isn't enabled");
> > return -EINVAL;
> > }
> > diff --git a/fs/erofs/super.c b/fs/erofs/super.c
> > index 1ca8da3f2125..628c751634fe 100644
> > --- a/fs/erofs/super.c
> > +++ b/fs/erofs/super.c
> > @@ -122,6 +122,138 @@ static bool check_layout_compatibility(struct super_block *sb,
> > return true;
> > }
> > +#ifdef CONFIG_EROFS_FS_ZIP
> > +/* read variable-sized metadata, offset will be aligned by 4-byte */
> > +static void *erofs_read_metadata(struct super_block *sb, struct page **pagep,
> > + erofs_off_t *offset, int *lengthp)
> > +{
> > + struct page *page = *pagep;
> > + u8 *buffer, *ptr;
> > + int len, i, cnt;
> > + erofs_blk_t blk;
> > +
> > + *offset = round_up(*offset, 4);
> > + blk = erofs_blknr(*offset);
> > +
> > + if (!page || page->index != blk) {
> > + if (page) {
> > + unlock_page(page);
> > + put_page(page);
> > + }
> > + page = erofs_get_meta_page(sb, blk);
> > + if (IS_ERR(page))
> > + goto err_nullpage;
> > + }
> > +
> > + ptr = kmap(page);
> > + len = le16_to_cpu(*(__le16 *)&ptr[erofs_blkoff(*offset)]);
> > + if (!len)
> > + len = U16_MAX + 1;
> > + buffer = kmalloc(len, GFP_KERNEL);
> > + if (!buffer) {
> > + buffer = ERR_PTR(-ENOMEM);
> > + goto out;
> > + }
> > + *offset += sizeof(__le16);
> > + *lengthp = len;
> > +
> > + for (i = 0; i < len; i += cnt) {
> > + cnt = min(EROFS_BLKSIZ - (int)erofs_blkoff(*offset), len - i);
> > + blk = erofs_blknr(*offset);
> > +
> > + if (!page || page->index != blk) {
> > + if (page) {
> > + kunmap(page);
> > + unlock_page(page);
> > + put_page(page);
> > + }
> > + page = erofs_get_meta_page(sb, blk);
> > + if (IS_ERR(page)) {
> > + kfree(buffer);
> > + goto err_nullpage;
> > + }
> > + ptr = kmap(page);
> > + }
> > + memcpy(buffer + i, ptr + erofs_blkoff(*offset), cnt);
> > + *offset += cnt;
> > + }
> > +out:
> > + kunmap(page);
> > + *pagep = page;
> > + return buffer;
> > +err_nullpage:
> > + *pagep = NULL;
> > + return page;
> > +}
> > +
> > +static int erofs_load_compr_cfgs(struct super_block *sb,
> > + struct erofs_super_block *dsb)
> > +{
> > + struct erofs_sb_info *sbi;
> > + struct page *page;
> > + unsigned int algs, alg;
> > + erofs_off_t offset;
> > + int size, ret;
> > +
> > + sbi = EROFS_SB(sb);
> > + sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs);
> > +
> > + if (sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS) {
> > + erofs_err(sb,
> > +"try to load compressed image with unsupported algorithms %x",
>
> Minor style issue:
>
> "try to load compressed image with unsupported "
> "algorithms %x",
> sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
If I remembered correctly, kernel code style suggests "don't break the print
message, it'd more easy to grep". Actually such style above is from XFS, and
can pass checkpatch.pl check, see:
(fs/xfs/xfs_log_recover.c) xlog_recover():
/*
* Version 5 superblock log feature mask validation. We know the
* log is dirty so check if there are any unknown log features
* in what we need to recover. If there are unknown features
* (e.g. unsupported transactions, then simply reject the
* attempt at recovery before touching anything.
*/
if (XFS_SB_VERSION_NUM(&log->l_mp->m_sb) == XFS_SB_VERSION_5 &&
xfs_sb_has_incompat_log_feature(&log->l_mp->m_sb,
XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN)) {
xfs_warn(log->l_mp,
"Superblock has unknown incompatible log features (0x%x) enabled.",
(log->l_mp->m_sb.sb_features_log_incompat &
XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN));
xfs_warn(log->l_mp,
"The log can not be fully and/or safely recovered by this kernel.");
xfs_warn(log->l_mp,
"Please recover the log on a kernel that supports the unknown features.");
return -EINVAL;
}
If that does't look ok for us, I could use > 80 line for this instead,
but I tend to not break the message ..
>
> > + sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
> > + return -EINVAL;
> > + }
> > +
> > + offset = EROFS_SUPER_OFFSET + sbi->sb_size;
> > + page = NULL;
> > + alg = 0;
> > + ret = 0;
> > +
> > + for (algs = sbi->available_compr_algs; algs; algs >>= 1, ++alg) {
> > + void *data;
> > +
> > + if (!(algs & 1))
> > + continue;
> > +
> > + data = erofs_read_metadata(sb, &page, &offset, &size);
> > + if (IS_ERR(data)) {
> > + ret = PTR_ERR(data);
> > + goto err;
> > + }
> > +
> > + switch (alg) {
> > + case Z_EROFS_COMPRESSION_LZ4:
> > + ret = z_erofs_load_lz4_config(sb, dsb, data, size);
> > + break;
> > + default:
> > + DBG_BUGON(1);
> > + ret = -EFAULT;
> > + }
> > + kfree(data);
> > + if (ret)
> > + goto err;
> > + }
> > +err:
> > + if (page) {
> > + unlock_page(page);
> > + put_page(page);
> > + }
> > + return ret;
> > +}
> > +#else
> > +static int erofs_load_compr_cfgs(struct super_block *sb,
> > + struct erofs_super_block *dsb)
> > +{
> > + if (dsb->u1.available_compr_algs) {
> > + erofs_err(sb,
> > +"try to load compressed image when compression is disabled");
>
> Ditto,
> erofs_err(sb, "try to load compressed image when "
> "compression is disabled");
>
The same above....
>
> > + return -EINVAL;
> > + }
> > + return 0;
> > +}
> > +#endif
> > +
> > static int erofs_read_superblock(struct super_block *sb)
> > {
> > struct erofs_sb_info *sbi;
> > @@ -166,6 +298,12 @@ static int erofs_read_superblock(struct super_block *sb)
> > if (!check_layout_compatibility(sb, dsb))
> > goto out;
> > + sbi->sb_size = 128 + dsb->sb_extslots * 16;
>
> sbi->sb_size = sizeof(struct erofs_super_block) +
> dsb->sb_extslots * EROFS_EXTSLOT_SIZE;
>
> Otherwise it looks good to me,
>
> Reviewed-by: Chao Yu <yuchao0@huawei.com>
Thanks for the review!
Thanks,
Gao Xiang
>
> Thanks,
>
> > + if (sbi->sb_size > EROFS_BLKSIZ) {
> > + erofs_err(sb, "invalid sb_extslots %u (more than a fs block)",
> > + sbi->sb_size);
> > + goto out;
> > + }
> > sbi->blocks = le32_to_cpu(dsb->blocks);
> > sbi->meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
> > #ifdef CONFIG_EROFS_FS_XATTR
> > @@ -189,7 +327,10 @@ static int erofs_read_superblock(struct super_block *sb)
> > }
> > /* parse on-disk compression configurations */
> > - ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0);
> > + if (erofs_sb_has_compr_cfgs(sbi))
> > + ret = erofs_load_compr_cfgs(sb, dsb);
> > + else
> > + ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0);
> > out:
> > kunmap(page);
> > put_page(page);
> >
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v2 4/4] erofs: add on-disk compression configurations
@ 2021-03-29 6:36 ` Gao Xiang
0 siblings, 0 replies; 22+ messages in thread
From: Gao Xiang @ 2021-03-29 6:36 UTC (permalink / raw)
To: Chao Yu; +Cc: linux-erofs, LKML
Hi Chao,
On Mon, Mar 29, 2021 at 02:26:05PM +0800, Chao Yu wrote:
> On 2021/3/29 9:23, Gao Xiang wrote:
> > From: Gao Xiang <hsiangkao@redhat.com>
> >
> > Add a bitmap for available compression algorithms and a variable-sized
> > on-disk table for compression options in preparation for upcoming big
> > pcluster and LZMA algorithm, which follows the end of super block.
> >
> > To parse the compression options, the bitmap is scanned one by one.
> > For each available algorithm, there is data followed by 2-byte `length'
> > correspondingly (it's enough for most cases, or entire fs blocks should
> > be used.)
> >
> > With such available algorithm bitmap, kernel itself can also refuse to
> > mount such filesystem if any unsupported compression algorithm exists.
> >
> > Note that COMPR_CFGS feature will be enabled with BIG_PCLUSTER.
> >
> > Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
> > ---
> > fs/erofs/decompressor.c | 2 +-
> > fs/erofs/erofs_fs.h | 14 ++--
> > fs/erofs/internal.h | 5 +-
> > fs/erofs/super.c | 143 +++++++++++++++++++++++++++++++++++++++-
> > 4 files changed, 157 insertions(+), 7 deletions(-)
> >
> > diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c
> > index 97538ff24a19..27aa6a99b371 100644
> > --- a/fs/erofs/decompressor.c
> > +++ b/fs/erofs/decompressor.c
> > @@ -41,7 +41,7 @@ int z_erofs_load_lz4_config(struct super_block *sb,
> > }
> > distance = le16_to_cpu(lz4->max_distance);
> > } else {
> > - distance = le16_to_cpu(dsb->lz4_max_distance);
> > + distance = le16_to_cpu(dsb->u1.lz4_max_distance);
> > }
> > EROFS_SB(sb)->lz4.max_distance_pages = distance ?
> > diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h
> > index e0f3c0db1f82..5a126493d4d9 100644
> > --- a/fs/erofs/erofs_fs.h
> > +++ b/fs/erofs/erofs_fs.h
> > @@ -18,15 +18,16 @@
> > * be incompatible with this kernel version.
> > */
> > #define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING 0x00000001
> > +#define EROFS_FEATURE_INCOMPAT_COMPR_CFGS 0x00000002
> > #define EROFS_ALL_FEATURE_INCOMPAT EROFS_FEATURE_INCOMPAT_LZ4_0PADDING
> > -/* 128-byte erofs on-disk super block */
> > +/* erofs on-disk super block (currently 128 bytes) */
> > struct erofs_super_block {
> > __le32 magic; /* file system magic number */
> > __le32 checksum; /* crc32c(super_block) */
> > __le32 feature_compat;
> > __u8 blkszbits; /* support block_size == PAGE_SIZE only */
> > - __u8 reserved;
> > + __u8 sb_extslots; /* superblock size = 128 + sb_extslots * 16 */
> > __le16 root_nid; /* nid of root directory */
> > __le64 inos; /* total valid ino # (== f_files - f_favail) */
> > @@ -39,8 +40,12 @@ struct erofs_super_block {
> > __u8 uuid[16]; /* 128-bit uuid for volume */
> > __u8 volume_name[16]; /* volume name */
> > __le32 feature_incompat;
> > - /* customized lz4 sliding window size instead of 64k by default */
> > - __le16 lz4_max_distance;
> > + union {
> > + /* bitmap for available compression algorithms */
> > + __le16 available_compr_algs;
> > + /* customized sliding window size instead of 64k by default */
> > + __le16 lz4_max_distance;
> > + } __packed u1;
> > __u8 reserved2[42];
> > };
> > @@ -196,6 +201,7 @@ enum {
> > Z_EROFS_COMPRESSION_LZ4 = 0,
> > Z_EROFS_COMPRESSION_MAX
> > };
> > +#define Z_EROFS_ALL_COMPR_ALGS (1 << (Z_EROFS_COMPRESSION_MAX - 1))
> > /* 14 bytes (+ length field = 16 bytes) */
> > struct z_erofs_lz4_cfgs {
> > diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
> > index 46b977f348eb..f3fa895d809f 100644
> > --- a/fs/erofs/internal.h
> > +++ b/fs/erofs/internal.h
> > @@ -75,6 +75,7 @@ struct erofs_sb_info {
> > struct xarray managed_pslots;
> > unsigned int shrinker_run_no;
> > + u16 available_compr_algs;
> > /* pseudo inode to manage cached pages */
> > struct inode *managed_cache;
> > @@ -90,6 +91,7 @@ struct erofs_sb_info {
> > /* inode slot unit size in bit shift */
> > unsigned char islotbits;
> > + u32 sb_size; /* total superblock size */
> > u32 build_time_nsec;
> > u64 build_time;
> > @@ -233,6 +235,7 @@ static inline bool erofs_sb_has_##name(struct erofs_sb_info *sbi) \
> > }
> > EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING)
> > +EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS)
> > EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM)
> > /* atomic flag definitions */
> > @@ -454,7 +457,7 @@ static inline int z_erofs_load_lz4_config(struct super_block *sb,
> > struct erofs_super_block *dsb,
> > struct z_erofs_lz4_cfgs *lz4, int len)
> > {
> > - if (lz4 || dsb->lz4_max_distance) {
> > + if (lz4 || dsb->u1.lz4_max_distance) {
> > erofs_err(sb, "lz4 algorithm isn't enabled");
> > return -EINVAL;
> > }
> > diff --git a/fs/erofs/super.c b/fs/erofs/super.c
> > index 1ca8da3f2125..628c751634fe 100644
> > --- a/fs/erofs/super.c
> > +++ b/fs/erofs/super.c
> > @@ -122,6 +122,138 @@ static bool check_layout_compatibility(struct super_block *sb,
> > return true;
> > }
> > +#ifdef CONFIG_EROFS_FS_ZIP
> > +/* read variable-sized metadata, offset will be aligned by 4-byte */
> > +static void *erofs_read_metadata(struct super_block *sb, struct page **pagep,
> > + erofs_off_t *offset, int *lengthp)
> > +{
> > + struct page *page = *pagep;
> > + u8 *buffer, *ptr;
> > + int len, i, cnt;
> > + erofs_blk_t blk;
> > +
> > + *offset = round_up(*offset, 4);
> > + blk = erofs_blknr(*offset);
> > +
> > + if (!page || page->index != blk) {
> > + if (page) {
> > + unlock_page(page);
> > + put_page(page);
> > + }
> > + page = erofs_get_meta_page(sb, blk);
> > + if (IS_ERR(page))
> > + goto err_nullpage;
> > + }
> > +
> > + ptr = kmap(page);
> > + len = le16_to_cpu(*(__le16 *)&ptr[erofs_blkoff(*offset)]);
> > + if (!len)
> > + len = U16_MAX + 1;
> > + buffer = kmalloc(len, GFP_KERNEL);
> > + if (!buffer) {
> > + buffer = ERR_PTR(-ENOMEM);
> > + goto out;
> > + }
> > + *offset += sizeof(__le16);
> > + *lengthp = len;
> > +
> > + for (i = 0; i < len; i += cnt) {
> > + cnt = min(EROFS_BLKSIZ - (int)erofs_blkoff(*offset), len - i);
> > + blk = erofs_blknr(*offset);
> > +
> > + if (!page || page->index != blk) {
> > + if (page) {
> > + kunmap(page);
> > + unlock_page(page);
> > + put_page(page);
> > + }
> > + page = erofs_get_meta_page(sb, blk);
> > + if (IS_ERR(page)) {
> > + kfree(buffer);
> > + goto err_nullpage;
> > + }
> > + ptr = kmap(page);
> > + }
> > + memcpy(buffer + i, ptr + erofs_blkoff(*offset), cnt);
> > + *offset += cnt;
> > + }
> > +out:
> > + kunmap(page);
> > + *pagep = page;
> > + return buffer;
> > +err_nullpage:
> > + *pagep = NULL;
> > + return page;
> > +}
> > +
> > +static int erofs_load_compr_cfgs(struct super_block *sb,
> > + struct erofs_super_block *dsb)
> > +{
> > + struct erofs_sb_info *sbi;
> > + struct page *page;
> > + unsigned int algs, alg;
> > + erofs_off_t offset;
> > + int size, ret;
> > +
> > + sbi = EROFS_SB(sb);
> > + sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs);
> > +
> > + if (sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS) {
> > + erofs_err(sb,
> > +"try to load compressed image with unsupported algorithms %x",
>
> Minor style issue:
>
> "try to load compressed image with unsupported "
> "algorithms %x",
> sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
If I remembered correctly, kernel code style suggests "don't break the print
message, it'd more easy to grep". Actually such style above is from XFS, and
can pass checkpatch.pl check, see:
(fs/xfs/xfs_log_recover.c) xlog_recover():
/*
* Version 5 superblock log feature mask validation. We know the
* log is dirty so check if there are any unknown log features
* in what we need to recover. If there are unknown features
* (e.g. unsupported transactions, then simply reject the
* attempt at recovery before touching anything.
*/
if (XFS_SB_VERSION_NUM(&log->l_mp->m_sb) == XFS_SB_VERSION_5 &&
xfs_sb_has_incompat_log_feature(&log->l_mp->m_sb,
XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN)) {
xfs_warn(log->l_mp,
"Superblock has unknown incompatible log features (0x%x) enabled.",
(log->l_mp->m_sb.sb_features_log_incompat &
XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN));
xfs_warn(log->l_mp,
"The log can not be fully and/or safely recovered by this kernel.");
xfs_warn(log->l_mp,
"Please recover the log on a kernel that supports the unknown features.");
return -EINVAL;
}
If that does't look ok for us, I could use > 80 line for this instead,
but I tend to not break the message ..
>
> > + sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
> > + return -EINVAL;
> > + }
> > +
> > + offset = EROFS_SUPER_OFFSET + sbi->sb_size;
> > + page = NULL;
> > + alg = 0;
> > + ret = 0;
> > +
> > + for (algs = sbi->available_compr_algs; algs; algs >>= 1, ++alg) {
> > + void *data;
> > +
> > + if (!(algs & 1))
> > + continue;
> > +
> > + data = erofs_read_metadata(sb, &page, &offset, &size);
> > + if (IS_ERR(data)) {
> > + ret = PTR_ERR(data);
> > + goto err;
> > + }
> > +
> > + switch (alg) {
> > + case Z_EROFS_COMPRESSION_LZ4:
> > + ret = z_erofs_load_lz4_config(sb, dsb, data, size);
> > + break;
> > + default:
> > + DBG_BUGON(1);
> > + ret = -EFAULT;
> > + }
> > + kfree(data);
> > + if (ret)
> > + goto err;
> > + }
> > +err:
> > + if (page) {
> > + unlock_page(page);
> > + put_page(page);
> > + }
> > + return ret;
> > +}
> > +#else
> > +static int erofs_load_compr_cfgs(struct super_block *sb,
> > + struct erofs_super_block *dsb)
> > +{
> > + if (dsb->u1.available_compr_algs) {
> > + erofs_err(sb,
> > +"try to load compressed image when compression is disabled");
>
> Ditto,
> erofs_err(sb, "try to load compressed image when "
> "compression is disabled");
>
The same above....
>
> > + return -EINVAL;
> > + }
> > + return 0;
> > +}
> > +#endif
> > +
> > static int erofs_read_superblock(struct super_block *sb)
> > {
> > struct erofs_sb_info *sbi;
> > @@ -166,6 +298,12 @@ static int erofs_read_superblock(struct super_block *sb)
> > if (!check_layout_compatibility(sb, dsb))
> > goto out;
> > + sbi->sb_size = 128 + dsb->sb_extslots * 16;
>
> sbi->sb_size = sizeof(struct erofs_super_block) +
> dsb->sb_extslots * EROFS_EXTSLOT_SIZE;
>
> Otherwise it looks good to me,
>
> Reviewed-by: Chao Yu <yuchao0@huawei.com>
Thanks for the review!
Thanks,
Gao Xiang
>
> Thanks,
>
> > + if (sbi->sb_size > EROFS_BLKSIZ) {
> > + erofs_err(sb, "invalid sb_extslots %u (more than a fs block)",
> > + sbi->sb_size);
> > + goto out;
> > + }
> > sbi->blocks = le32_to_cpu(dsb->blocks);
> > sbi->meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
> > #ifdef CONFIG_EROFS_FS_XATTR
> > @@ -189,7 +327,10 @@ static int erofs_read_superblock(struct super_block *sb)
> > }
> > /* parse on-disk compression configurations */
> > - ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0);
> > + if (erofs_sb_has_compr_cfgs(sbi))
> > + ret = erofs_load_compr_cfgs(sb, dsb);
> > + else
> > + ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0);
> > out:
> > kunmap(page);
> > put_page(page);
> >
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v2 4/4] erofs: add on-disk compression configurations
2021-03-29 6:36 ` Gao Xiang
@ 2021-03-29 6:43 ` Chao Yu
-1 siblings, 0 replies; 22+ messages in thread
From: Chao Yu @ 2021-03-29 6:43 UTC (permalink / raw)
To: Gao Xiang; +Cc: Gao Xiang, linux-erofs, Chao Yu, LKML
On 2021/3/29 14:36, Gao Xiang wrote:
> Hi Chao,
>
> On Mon, Mar 29, 2021 at 02:26:05PM +0800, Chao Yu wrote:
>> On 2021/3/29 9:23, Gao Xiang wrote:
>>> From: Gao Xiang <hsiangkao@redhat.com>
>>>
>>> Add a bitmap for available compression algorithms and a variable-sized
>>> on-disk table for compression options in preparation for upcoming big
>>> pcluster and LZMA algorithm, which follows the end of super block.
>>>
>>> To parse the compression options, the bitmap is scanned one by one.
>>> For each available algorithm, there is data followed by 2-byte `length'
>>> correspondingly (it's enough for most cases, or entire fs blocks should
>>> be used.)
>>>
>>> With such available algorithm bitmap, kernel itself can also refuse to
>>> mount such filesystem if any unsupported compression algorithm exists.
>>>
>>> Note that COMPR_CFGS feature will be enabled with BIG_PCLUSTER.
>>>
>>> Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
>>> ---
>>> fs/erofs/decompressor.c | 2 +-
>>> fs/erofs/erofs_fs.h | 14 ++--
>>> fs/erofs/internal.h | 5 +-
>>> fs/erofs/super.c | 143 +++++++++++++++++++++++++++++++++++++++-
>>> 4 files changed, 157 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c
>>> index 97538ff24a19..27aa6a99b371 100644
>>> --- a/fs/erofs/decompressor.c
>>> +++ b/fs/erofs/decompressor.c
>>> @@ -41,7 +41,7 @@ int z_erofs_load_lz4_config(struct super_block *sb,
>>> }
>>> distance = le16_to_cpu(lz4->max_distance);
>>> } else {
>>> - distance = le16_to_cpu(dsb->lz4_max_distance);
>>> + distance = le16_to_cpu(dsb->u1.lz4_max_distance);
>>> }
>>> EROFS_SB(sb)->lz4.max_distance_pages = distance ?
>>> diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h
>>> index e0f3c0db1f82..5a126493d4d9 100644
>>> --- a/fs/erofs/erofs_fs.h
>>> +++ b/fs/erofs/erofs_fs.h
>>> @@ -18,15 +18,16 @@
>>> * be incompatible with this kernel version.
>>> */
>>> #define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING 0x00000001
>>> +#define EROFS_FEATURE_INCOMPAT_COMPR_CFGS 0x00000002
>>> #define EROFS_ALL_FEATURE_INCOMPAT EROFS_FEATURE_INCOMPAT_LZ4_0PADDING
>>> -/* 128-byte erofs on-disk super block */
>>> +/* erofs on-disk super block (currently 128 bytes) */
>>> struct erofs_super_block {
>>> __le32 magic; /* file system magic number */
>>> __le32 checksum; /* crc32c(super_block) */
>>> __le32 feature_compat;
>>> __u8 blkszbits; /* support block_size == PAGE_SIZE only */
>>> - __u8 reserved;
>>> + __u8 sb_extslots; /* superblock size = 128 + sb_extslots * 16 */
>>> __le16 root_nid; /* nid of root directory */
>>> __le64 inos; /* total valid ino # (== f_files - f_favail) */
>>> @@ -39,8 +40,12 @@ struct erofs_super_block {
>>> __u8 uuid[16]; /* 128-bit uuid for volume */
>>> __u8 volume_name[16]; /* volume name */
>>> __le32 feature_incompat;
>>> - /* customized lz4 sliding window size instead of 64k by default */
>>> - __le16 lz4_max_distance;
>>> + union {
>>> + /* bitmap for available compression algorithms */
>>> + __le16 available_compr_algs;
>>> + /* customized sliding window size instead of 64k by default */
>>> + __le16 lz4_max_distance;
>>> + } __packed u1;
>>> __u8 reserved2[42];
>>> };
>>> @@ -196,6 +201,7 @@ enum {
>>> Z_EROFS_COMPRESSION_LZ4 = 0,
>>> Z_EROFS_COMPRESSION_MAX
>>> };
>>> +#define Z_EROFS_ALL_COMPR_ALGS (1 << (Z_EROFS_COMPRESSION_MAX - 1))
>>> /* 14 bytes (+ length field = 16 bytes) */
>>> struct z_erofs_lz4_cfgs {
>>> diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
>>> index 46b977f348eb..f3fa895d809f 100644
>>> --- a/fs/erofs/internal.h
>>> +++ b/fs/erofs/internal.h
>>> @@ -75,6 +75,7 @@ struct erofs_sb_info {
>>> struct xarray managed_pslots;
>>> unsigned int shrinker_run_no;
>>> + u16 available_compr_algs;
>>> /* pseudo inode to manage cached pages */
>>> struct inode *managed_cache;
>>> @@ -90,6 +91,7 @@ struct erofs_sb_info {
>>> /* inode slot unit size in bit shift */
>>> unsigned char islotbits;
>>> + u32 sb_size; /* total superblock size */
>>> u32 build_time_nsec;
>>> u64 build_time;
>>> @@ -233,6 +235,7 @@ static inline bool erofs_sb_has_##name(struct erofs_sb_info *sbi) \
>>> }
>>> EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING)
>>> +EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS)
>>> EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM)
>>> /* atomic flag definitions */
>>> @@ -454,7 +457,7 @@ static inline int z_erofs_load_lz4_config(struct super_block *sb,
>>> struct erofs_super_block *dsb,
>>> struct z_erofs_lz4_cfgs *lz4, int len)
>>> {
>>> - if (lz4 || dsb->lz4_max_distance) {
>>> + if (lz4 || dsb->u1.lz4_max_distance) {
>>> erofs_err(sb, "lz4 algorithm isn't enabled");
>>> return -EINVAL;
>>> }
>>> diff --git a/fs/erofs/super.c b/fs/erofs/super.c
>>> index 1ca8da3f2125..628c751634fe 100644
>>> --- a/fs/erofs/super.c
>>> +++ b/fs/erofs/super.c
>>> @@ -122,6 +122,138 @@ static bool check_layout_compatibility(struct super_block *sb,
>>> return true;
>>> }
>>> +#ifdef CONFIG_EROFS_FS_ZIP
>>> +/* read variable-sized metadata, offset will be aligned by 4-byte */
>>> +static void *erofs_read_metadata(struct super_block *sb, struct page **pagep,
>>> + erofs_off_t *offset, int *lengthp)
>>> +{
>>> + struct page *page = *pagep;
>>> + u8 *buffer, *ptr;
>>> + int len, i, cnt;
>>> + erofs_blk_t blk;
>>> +
>>> + *offset = round_up(*offset, 4);
>>> + blk = erofs_blknr(*offset);
>>> +
>>> + if (!page || page->index != blk) {
>>> + if (page) {
>>> + unlock_page(page);
>>> + put_page(page);
>>> + }
>>> + page = erofs_get_meta_page(sb, blk);
>>> + if (IS_ERR(page))
>>> + goto err_nullpage;
>>> + }
>>> +
>>> + ptr = kmap(page);
>>> + len = le16_to_cpu(*(__le16 *)&ptr[erofs_blkoff(*offset)]);
>>> + if (!len)
>>> + len = U16_MAX + 1;
>>> + buffer = kmalloc(len, GFP_KERNEL);
>>> + if (!buffer) {
>>> + buffer = ERR_PTR(-ENOMEM);
>>> + goto out;
>>> + }
>>> + *offset += sizeof(__le16);
>>> + *lengthp = len;
>>> +
>>> + for (i = 0; i < len; i += cnt) {
>>> + cnt = min(EROFS_BLKSIZ - (int)erofs_blkoff(*offset), len - i);
>>> + blk = erofs_blknr(*offset);
>>> +
>>> + if (!page || page->index != blk) {
>>> + if (page) {
>>> + kunmap(page);
>>> + unlock_page(page);
>>> + put_page(page);
>>> + }
>>> + page = erofs_get_meta_page(sb, blk);
>>> + if (IS_ERR(page)) {
>>> + kfree(buffer);
>>> + goto err_nullpage;
>>> + }
>>> + ptr = kmap(page);
>>> + }
>>> + memcpy(buffer + i, ptr + erofs_blkoff(*offset), cnt);
>>> + *offset += cnt;
>>> + }
>>> +out:
>>> + kunmap(page);
>>> + *pagep = page;
>>> + return buffer;
>>> +err_nullpage:
>>> + *pagep = NULL;
>>> + return page;
>>> +}
>>> +
>>> +static int erofs_load_compr_cfgs(struct super_block *sb,
>>> + struct erofs_super_block *dsb)
>>> +{
>>> + struct erofs_sb_info *sbi;
>>> + struct page *page;
>>> + unsigned int algs, alg;
>>> + erofs_off_t offset;
>>> + int size, ret;
>>> +
>>> + sbi = EROFS_SB(sb);
>>> + sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs);
>>> +
>>> + if (sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS) {
>>> + erofs_err(sb,
>>> +"try to load compressed image with unsupported algorithms %x",
>>
>> Minor style issue:
>>
>> "try to load compressed image with unsupported "
>> "algorithms %x",
>> sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
>
> If I remembered correctly, kernel code style suggests "don't break the print
> message, it'd more easy to grep". Actually such style above is from XFS, and
> can pass checkpatch.pl check, see:
>
> (fs/xfs/xfs_log_recover.c) xlog_recover():
> /*
> * Version 5 superblock log feature mask validation. We know the
> * log is dirty so check if there are any unknown log features
> * in what we need to recover. If there are unknown features
> * (e.g. unsupported transactions, then simply reject the
> * attempt at recovery before touching anything.
> */
> if (XFS_SB_VERSION_NUM(&log->l_mp->m_sb) == XFS_SB_VERSION_5 &&
> xfs_sb_has_incompat_log_feature(&log->l_mp->m_sb,
> XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN)) {
> xfs_warn(log->l_mp,
> "Superblock has unknown incompatible log features (0x%x) enabled.",
> (log->l_mp->m_sb.sb_features_log_incompat &
> XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN));
> xfs_warn(log->l_mp,
> "The log can not be fully and/or safely recovered by this kernel.");
> xfs_warn(log->l_mp,
> "Please recover the log on a kernel that supports the unknown features.");
> return -EINVAL;
> }
>
> If that does't look ok for us, I could use > 80 line for this instead,
> but I tend to not break the message ..
Xiang,
Ah, I didn't notice this is following above style, if it's fine to you,
let's use some tabs in front of message line, though it will cause
exceeding 80 line warning.
Thanks,
>
>>
>>> + sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
>>> + return -EINVAL;
>>> + }
>>> +
>>> + offset = EROFS_SUPER_OFFSET + sbi->sb_size;
>>> + page = NULL;
>>> + alg = 0;
>>> + ret = 0;
>>> +
>>> + for (algs = sbi->available_compr_algs; algs; algs >>= 1, ++alg) {
>>> + void *data;
>>> +
>>> + if (!(algs & 1))
>>> + continue;
>>> +
>>> + data = erofs_read_metadata(sb, &page, &offset, &size);
>>> + if (IS_ERR(data)) {
>>> + ret = PTR_ERR(data);
>>> + goto err;
>>> + }
>>> +
>>> + switch (alg) {
>>> + case Z_EROFS_COMPRESSION_LZ4:
>>> + ret = z_erofs_load_lz4_config(sb, dsb, data, size);
>>> + break;
>>> + default:
>>> + DBG_BUGON(1);
>>> + ret = -EFAULT;
>>> + }
>>> + kfree(data);
>>> + if (ret)
>>> + goto err;
>>> + }
>>> +err:
>>> + if (page) {
>>> + unlock_page(page);
>>> + put_page(page);
>>> + }
>>> + return ret;
>>> +}
>>> +#else
>>> +static int erofs_load_compr_cfgs(struct super_block *sb,
>>> + struct erofs_super_block *dsb)
>>> +{
>>> + if (dsb->u1.available_compr_algs) {
>>> + erofs_err(sb,
>>> +"try to load compressed image when compression is disabled");
>>
>> Ditto,
>> erofs_err(sb, "try to load compressed image when "
>> "compression is disabled");
>>
>
> The same above....
>
>>
>>> + return -EINVAL;
>>> + }
>>> + return 0;
>>> +}
>>> +#endif
>>> +
>>> static int erofs_read_superblock(struct super_block *sb)
>>> {
>>> struct erofs_sb_info *sbi;
>>> @@ -166,6 +298,12 @@ static int erofs_read_superblock(struct super_block *sb)
>>> if (!check_layout_compatibility(sb, dsb))
>>> goto out;
>>> + sbi->sb_size = 128 + dsb->sb_extslots * 16;
>>
>> sbi->sb_size = sizeof(struct erofs_super_block) +
>> dsb->sb_extslots * EROFS_EXTSLOT_SIZE;
>>
>> Otherwise it looks good to me,
>>
>> Reviewed-by: Chao Yu <yuchao0@huawei.com>
>
> Thanks for the review!
>
> Thanks,
> Gao Xiang
>
>>
>> Thanks,
>>
>>> + if (sbi->sb_size > EROFS_BLKSIZ) {
>>> + erofs_err(sb, "invalid sb_extslots %u (more than a fs block)",
>>> + sbi->sb_size);
>>> + goto out;
>>> + }
>>> sbi->blocks = le32_to_cpu(dsb->blocks);
>>> sbi->meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
>>> #ifdef CONFIG_EROFS_FS_XATTR
>>> @@ -189,7 +327,10 @@ static int erofs_read_superblock(struct super_block *sb)
>>> }
>>> /* parse on-disk compression configurations */
>>> - ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0);
>>> + if (erofs_sb_has_compr_cfgs(sbi))
>>> + ret = erofs_load_compr_cfgs(sb, dsb);
>>> + else
>>> + ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0);
>>> out:
>>> kunmap(page);
>>> put_page(page);
>>>
>>
>
> .
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v2 4/4] erofs: add on-disk compression configurations
@ 2021-03-29 6:43 ` Chao Yu
0 siblings, 0 replies; 22+ messages in thread
From: Chao Yu @ 2021-03-29 6:43 UTC (permalink / raw)
To: Gao Xiang; +Cc: linux-erofs, LKML
On 2021/3/29 14:36, Gao Xiang wrote:
> Hi Chao,
>
> On Mon, Mar 29, 2021 at 02:26:05PM +0800, Chao Yu wrote:
>> On 2021/3/29 9:23, Gao Xiang wrote:
>>> From: Gao Xiang <hsiangkao@redhat.com>
>>>
>>> Add a bitmap for available compression algorithms and a variable-sized
>>> on-disk table for compression options in preparation for upcoming big
>>> pcluster and LZMA algorithm, which follows the end of super block.
>>>
>>> To parse the compression options, the bitmap is scanned one by one.
>>> For each available algorithm, there is data followed by 2-byte `length'
>>> correspondingly (it's enough for most cases, or entire fs blocks should
>>> be used.)
>>>
>>> With such available algorithm bitmap, kernel itself can also refuse to
>>> mount such filesystem if any unsupported compression algorithm exists.
>>>
>>> Note that COMPR_CFGS feature will be enabled with BIG_PCLUSTER.
>>>
>>> Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
>>> ---
>>> fs/erofs/decompressor.c | 2 +-
>>> fs/erofs/erofs_fs.h | 14 ++--
>>> fs/erofs/internal.h | 5 +-
>>> fs/erofs/super.c | 143 +++++++++++++++++++++++++++++++++++++++-
>>> 4 files changed, 157 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c
>>> index 97538ff24a19..27aa6a99b371 100644
>>> --- a/fs/erofs/decompressor.c
>>> +++ b/fs/erofs/decompressor.c
>>> @@ -41,7 +41,7 @@ int z_erofs_load_lz4_config(struct super_block *sb,
>>> }
>>> distance = le16_to_cpu(lz4->max_distance);
>>> } else {
>>> - distance = le16_to_cpu(dsb->lz4_max_distance);
>>> + distance = le16_to_cpu(dsb->u1.lz4_max_distance);
>>> }
>>> EROFS_SB(sb)->lz4.max_distance_pages = distance ?
>>> diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h
>>> index e0f3c0db1f82..5a126493d4d9 100644
>>> --- a/fs/erofs/erofs_fs.h
>>> +++ b/fs/erofs/erofs_fs.h
>>> @@ -18,15 +18,16 @@
>>> * be incompatible with this kernel version.
>>> */
>>> #define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING 0x00000001
>>> +#define EROFS_FEATURE_INCOMPAT_COMPR_CFGS 0x00000002
>>> #define EROFS_ALL_FEATURE_INCOMPAT EROFS_FEATURE_INCOMPAT_LZ4_0PADDING
>>> -/* 128-byte erofs on-disk super block */
>>> +/* erofs on-disk super block (currently 128 bytes) */
>>> struct erofs_super_block {
>>> __le32 magic; /* file system magic number */
>>> __le32 checksum; /* crc32c(super_block) */
>>> __le32 feature_compat;
>>> __u8 blkszbits; /* support block_size == PAGE_SIZE only */
>>> - __u8 reserved;
>>> + __u8 sb_extslots; /* superblock size = 128 + sb_extslots * 16 */
>>> __le16 root_nid; /* nid of root directory */
>>> __le64 inos; /* total valid ino # (== f_files - f_favail) */
>>> @@ -39,8 +40,12 @@ struct erofs_super_block {
>>> __u8 uuid[16]; /* 128-bit uuid for volume */
>>> __u8 volume_name[16]; /* volume name */
>>> __le32 feature_incompat;
>>> - /* customized lz4 sliding window size instead of 64k by default */
>>> - __le16 lz4_max_distance;
>>> + union {
>>> + /* bitmap for available compression algorithms */
>>> + __le16 available_compr_algs;
>>> + /* customized sliding window size instead of 64k by default */
>>> + __le16 lz4_max_distance;
>>> + } __packed u1;
>>> __u8 reserved2[42];
>>> };
>>> @@ -196,6 +201,7 @@ enum {
>>> Z_EROFS_COMPRESSION_LZ4 = 0,
>>> Z_EROFS_COMPRESSION_MAX
>>> };
>>> +#define Z_EROFS_ALL_COMPR_ALGS (1 << (Z_EROFS_COMPRESSION_MAX - 1))
>>> /* 14 bytes (+ length field = 16 bytes) */
>>> struct z_erofs_lz4_cfgs {
>>> diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
>>> index 46b977f348eb..f3fa895d809f 100644
>>> --- a/fs/erofs/internal.h
>>> +++ b/fs/erofs/internal.h
>>> @@ -75,6 +75,7 @@ struct erofs_sb_info {
>>> struct xarray managed_pslots;
>>> unsigned int shrinker_run_no;
>>> + u16 available_compr_algs;
>>> /* pseudo inode to manage cached pages */
>>> struct inode *managed_cache;
>>> @@ -90,6 +91,7 @@ struct erofs_sb_info {
>>> /* inode slot unit size in bit shift */
>>> unsigned char islotbits;
>>> + u32 sb_size; /* total superblock size */
>>> u32 build_time_nsec;
>>> u64 build_time;
>>> @@ -233,6 +235,7 @@ static inline bool erofs_sb_has_##name(struct erofs_sb_info *sbi) \
>>> }
>>> EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING)
>>> +EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS)
>>> EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM)
>>> /* atomic flag definitions */
>>> @@ -454,7 +457,7 @@ static inline int z_erofs_load_lz4_config(struct super_block *sb,
>>> struct erofs_super_block *dsb,
>>> struct z_erofs_lz4_cfgs *lz4, int len)
>>> {
>>> - if (lz4 || dsb->lz4_max_distance) {
>>> + if (lz4 || dsb->u1.lz4_max_distance) {
>>> erofs_err(sb, "lz4 algorithm isn't enabled");
>>> return -EINVAL;
>>> }
>>> diff --git a/fs/erofs/super.c b/fs/erofs/super.c
>>> index 1ca8da3f2125..628c751634fe 100644
>>> --- a/fs/erofs/super.c
>>> +++ b/fs/erofs/super.c
>>> @@ -122,6 +122,138 @@ static bool check_layout_compatibility(struct super_block *sb,
>>> return true;
>>> }
>>> +#ifdef CONFIG_EROFS_FS_ZIP
>>> +/* read variable-sized metadata, offset will be aligned by 4-byte */
>>> +static void *erofs_read_metadata(struct super_block *sb, struct page **pagep,
>>> + erofs_off_t *offset, int *lengthp)
>>> +{
>>> + struct page *page = *pagep;
>>> + u8 *buffer, *ptr;
>>> + int len, i, cnt;
>>> + erofs_blk_t blk;
>>> +
>>> + *offset = round_up(*offset, 4);
>>> + blk = erofs_blknr(*offset);
>>> +
>>> + if (!page || page->index != blk) {
>>> + if (page) {
>>> + unlock_page(page);
>>> + put_page(page);
>>> + }
>>> + page = erofs_get_meta_page(sb, blk);
>>> + if (IS_ERR(page))
>>> + goto err_nullpage;
>>> + }
>>> +
>>> + ptr = kmap(page);
>>> + len = le16_to_cpu(*(__le16 *)&ptr[erofs_blkoff(*offset)]);
>>> + if (!len)
>>> + len = U16_MAX + 1;
>>> + buffer = kmalloc(len, GFP_KERNEL);
>>> + if (!buffer) {
>>> + buffer = ERR_PTR(-ENOMEM);
>>> + goto out;
>>> + }
>>> + *offset += sizeof(__le16);
>>> + *lengthp = len;
>>> +
>>> + for (i = 0; i < len; i += cnt) {
>>> + cnt = min(EROFS_BLKSIZ - (int)erofs_blkoff(*offset), len - i);
>>> + blk = erofs_blknr(*offset);
>>> +
>>> + if (!page || page->index != blk) {
>>> + if (page) {
>>> + kunmap(page);
>>> + unlock_page(page);
>>> + put_page(page);
>>> + }
>>> + page = erofs_get_meta_page(sb, blk);
>>> + if (IS_ERR(page)) {
>>> + kfree(buffer);
>>> + goto err_nullpage;
>>> + }
>>> + ptr = kmap(page);
>>> + }
>>> + memcpy(buffer + i, ptr + erofs_blkoff(*offset), cnt);
>>> + *offset += cnt;
>>> + }
>>> +out:
>>> + kunmap(page);
>>> + *pagep = page;
>>> + return buffer;
>>> +err_nullpage:
>>> + *pagep = NULL;
>>> + return page;
>>> +}
>>> +
>>> +static int erofs_load_compr_cfgs(struct super_block *sb,
>>> + struct erofs_super_block *dsb)
>>> +{
>>> + struct erofs_sb_info *sbi;
>>> + struct page *page;
>>> + unsigned int algs, alg;
>>> + erofs_off_t offset;
>>> + int size, ret;
>>> +
>>> + sbi = EROFS_SB(sb);
>>> + sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs);
>>> +
>>> + if (sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS) {
>>> + erofs_err(sb,
>>> +"try to load compressed image with unsupported algorithms %x",
>>
>> Minor style issue:
>>
>> "try to load compressed image with unsupported "
>> "algorithms %x",
>> sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
>
> If I remembered correctly, kernel code style suggests "don't break the print
> message, it'd more easy to grep". Actually such style above is from XFS, and
> can pass checkpatch.pl check, see:
>
> (fs/xfs/xfs_log_recover.c) xlog_recover():
> /*
> * Version 5 superblock log feature mask validation. We know the
> * log is dirty so check if there are any unknown log features
> * in what we need to recover. If there are unknown features
> * (e.g. unsupported transactions, then simply reject the
> * attempt at recovery before touching anything.
> */
> if (XFS_SB_VERSION_NUM(&log->l_mp->m_sb) == XFS_SB_VERSION_5 &&
> xfs_sb_has_incompat_log_feature(&log->l_mp->m_sb,
> XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN)) {
> xfs_warn(log->l_mp,
> "Superblock has unknown incompatible log features (0x%x) enabled.",
> (log->l_mp->m_sb.sb_features_log_incompat &
> XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN));
> xfs_warn(log->l_mp,
> "The log can not be fully and/or safely recovered by this kernel.");
> xfs_warn(log->l_mp,
> "Please recover the log on a kernel that supports the unknown features.");
> return -EINVAL;
> }
>
> If that does't look ok for us, I could use > 80 line for this instead,
> but I tend to not break the message ..
Xiang,
Ah, I didn't notice this is following above style, if it's fine to you,
let's use some tabs in front of message line, though it will cause
exceeding 80 line warning.
Thanks,
>
>>
>>> + sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
>>> + return -EINVAL;
>>> + }
>>> +
>>> + offset = EROFS_SUPER_OFFSET + sbi->sb_size;
>>> + page = NULL;
>>> + alg = 0;
>>> + ret = 0;
>>> +
>>> + for (algs = sbi->available_compr_algs; algs; algs >>= 1, ++alg) {
>>> + void *data;
>>> +
>>> + if (!(algs & 1))
>>> + continue;
>>> +
>>> + data = erofs_read_metadata(sb, &page, &offset, &size);
>>> + if (IS_ERR(data)) {
>>> + ret = PTR_ERR(data);
>>> + goto err;
>>> + }
>>> +
>>> + switch (alg) {
>>> + case Z_EROFS_COMPRESSION_LZ4:
>>> + ret = z_erofs_load_lz4_config(sb, dsb, data, size);
>>> + break;
>>> + default:
>>> + DBG_BUGON(1);
>>> + ret = -EFAULT;
>>> + }
>>> + kfree(data);
>>> + if (ret)
>>> + goto err;
>>> + }
>>> +err:
>>> + if (page) {
>>> + unlock_page(page);
>>> + put_page(page);
>>> + }
>>> + return ret;
>>> +}
>>> +#else
>>> +static int erofs_load_compr_cfgs(struct super_block *sb,
>>> + struct erofs_super_block *dsb)
>>> +{
>>> + if (dsb->u1.available_compr_algs) {
>>> + erofs_err(sb,
>>> +"try to load compressed image when compression is disabled");
>>
>> Ditto,
>> erofs_err(sb, "try to load compressed image when "
>> "compression is disabled");
>>
>
> The same above....
>
>>
>>> + return -EINVAL;
>>> + }
>>> + return 0;
>>> +}
>>> +#endif
>>> +
>>> static int erofs_read_superblock(struct super_block *sb)
>>> {
>>> struct erofs_sb_info *sbi;
>>> @@ -166,6 +298,12 @@ static int erofs_read_superblock(struct super_block *sb)
>>> if (!check_layout_compatibility(sb, dsb))
>>> goto out;
>>> + sbi->sb_size = 128 + dsb->sb_extslots * 16;
>>
>> sbi->sb_size = sizeof(struct erofs_super_block) +
>> dsb->sb_extslots * EROFS_EXTSLOT_SIZE;
>>
>> Otherwise it looks good to me,
>>
>> Reviewed-by: Chao Yu <yuchao0@huawei.com>
>
> Thanks for the review!
>
> Thanks,
> Gao Xiang
>
>>
>> Thanks,
>>
>>> + if (sbi->sb_size > EROFS_BLKSIZ) {
>>> + erofs_err(sb, "invalid sb_extslots %u (more than a fs block)",
>>> + sbi->sb_size);
>>> + goto out;
>>> + }
>>> sbi->blocks = le32_to_cpu(dsb->blocks);
>>> sbi->meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
>>> #ifdef CONFIG_EROFS_FS_XATTR
>>> @@ -189,7 +327,10 @@ static int erofs_read_superblock(struct super_block *sb)
>>> }
>>> /* parse on-disk compression configurations */
>>> - ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0);
>>> + if (erofs_sb_has_compr_cfgs(sbi))
>>> + ret = erofs_load_compr_cfgs(sb, dsb);
>>> + else
>>> + ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0);
>>> out:
>>> kunmap(page);
>>> put_page(page);
>>>
>>
>
> .
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v2 4/4] erofs: add on-disk compression configurations
2021-03-29 6:43 ` Chao Yu
@ 2021-03-29 6:55 ` Gao Xiang
-1 siblings, 0 replies; 22+ messages in thread
From: Gao Xiang @ 2021-03-29 6:55 UTC (permalink / raw)
To: Chao Yu; +Cc: Gao Xiang, linux-erofs, Chao Yu, LKML
On Mon, Mar 29, 2021 at 02:43:48PM +0800, Chao Yu wrote:
...
> > > > +
> > > > +static int erofs_load_compr_cfgs(struct super_block *sb,
> > > > + struct erofs_super_block *dsb)
> > > > +{
> > > > + struct erofs_sb_info *sbi;
> > > > + struct page *page;
> > > > + unsigned int algs, alg;
> > > > + erofs_off_t offset;
> > > > + int size, ret;
> > > > +
> > > > + sbi = EROFS_SB(sb);
> > > > + sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs);
> > > > +
> > > > + if (sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS) {
> > > > + erofs_err(sb,
> > > > +"try to load compressed image with unsupported algorithms %x",
> > >
> > > Minor style issue:
> > >
> > > "try to load compressed image with unsupported "
> > > "algorithms %x",
> > > sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
> >
> > If I remembered correctly, kernel code style suggests "don't break the print
> > message, it'd more easy to grep". Actually such style above is from XFS, and
> > can pass checkpatch.pl check, see:
> >
> > (fs/xfs/xfs_log_recover.c) xlog_recover():
> > /*
> > * Version 5 superblock log feature mask validation. We know the
> > * log is dirty so check if there are any unknown log features
> > * in what we need to recover. If there are unknown features
> > * (e.g. unsupported transactions, then simply reject the
> > * attempt at recovery before touching anything.
> > */
> > if (XFS_SB_VERSION_NUM(&log->l_mp->m_sb) == XFS_SB_VERSION_5 &&
> > xfs_sb_has_incompat_log_feature(&log->l_mp->m_sb,
> > XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN)) {
> > xfs_warn(log->l_mp,
> > "Superblock has unknown incompatible log features (0x%x) enabled.",
> > (log->l_mp->m_sb.sb_features_log_incompat &
> > XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN));
> > xfs_warn(log->l_mp,
> > "The log can not be fully and/or safely recovered by this kernel.");
> > xfs_warn(log->l_mp,
> > "Please recover the log on a kernel that supports the unknown features.");
> > return -EINVAL;
> > }
> >
> > If that does't look ok for us, I could use > 80 line for this instead,
> > but I tend to not break the message ..
>
> Xiang,
>
> Ah, I didn't notice this is following above style, if it's fine to you,
> let's use some tabs in front of message line, though it will cause
> exceeding 80 line warning.
>
I found a reference here,
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/coding-style.rst?h=v5.11#n99
also vaguely remembered some threads from Linus, but hard to find now :-(
ok, I will insert tabs instead, thanks for the suggestion!
Thanks,
Gao Xiang
> Thanks,
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v2 4/4] erofs: add on-disk compression configurations
@ 2021-03-29 6:55 ` Gao Xiang
0 siblings, 0 replies; 22+ messages in thread
From: Gao Xiang @ 2021-03-29 6:55 UTC (permalink / raw)
To: Chao Yu; +Cc: linux-erofs, LKML
On Mon, Mar 29, 2021 at 02:43:48PM +0800, Chao Yu wrote:
...
> > > > +
> > > > +static int erofs_load_compr_cfgs(struct super_block *sb,
> > > > + struct erofs_super_block *dsb)
> > > > +{
> > > > + struct erofs_sb_info *sbi;
> > > > + struct page *page;
> > > > + unsigned int algs, alg;
> > > > + erofs_off_t offset;
> > > > + int size, ret;
> > > > +
> > > > + sbi = EROFS_SB(sb);
> > > > + sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs);
> > > > +
> > > > + if (sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS) {
> > > > + erofs_err(sb,
> > > > +"try to load compressed image with unsupported algorithms %x",
> > >
> > > Minor style issue:
> > >
> > > "try to load compressed image with unsupported "
> > > "algorithms %x",
> > > sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
> >
> > If I remembered correctly, kernel code style suggests "don't break the print
> > message, it'd more easy to grep". Actually such style above is from XFS, and
> > can pass checkpatch.pl check, see:
> >
> > (fs/xfs/xfs_log_recover.c) xlog_recover():
> > /*
> > * Version 5 superblock log feature mask validation. We know the
> > * log is dirty so check if there are any unknown log features
> > * in what we need to recover. If there are unknown features
> > * (e.g. unsupported transactions, then simply reject the
> > * attempt at recovery before touching anything.
> > */
> > if (XFS_SB_VERSION_NUM(&log->l_mp->m_sb) == XFS_SB_VERSION_5 &&
> > xfs_sb_has_incompat_log_feature(&log->l_mp->m_sb,
> > XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN)) {
> > xfs_warn(log->l_mp,
> > "Superblock has unknown incompatible log features (0x%x) enabled.",
> > (log->l_mp->m_sb.sb_features_log_incompat &
> > XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN));
> > xfs_warn(log->l_mp,
> > "The log can not be fully and/or safely recovered by this kernel.");
> > xfs_warn(log->l_mp,
> > "Please recover the log on a kernel that supports the unknown features.");
> > return -EINVAL;
> > }
> >
> > If that does't look ok for us, I could use > 80 line for this instead,
> > but I tend to not break the message ..
>
> Xiang,
>
> Ah, I didn't notice this is following above style, if it's fine to you,
> let's use some tabs in front of message line, though it will cause
> exceeding 80 line warning.
>
I found a reference here,
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/coding-style.rst?h=v5.11#n99
also vaguely remembered some threads from Linus, but hard to find now :-(
ok, I will insert tabs instead, thanks for the suggestion!
Thanks,
Gao Xiang
> Thanks,
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v2 4/4] erofs: add on-disk compression configurations
2021-03-29 6:55 ` Gao Xiang
@ 2021-03-29 7:52 ` Chao Yu
-1 siblings, 0 replies; 22+ messages in thread
From: Chao Yu @ 2021-03-29 7:52 UTC (permalink / raw)
To: Gao Xiang; +Cc: Gao Xiang, linux-erofs, Chao Yu, LKML
On 2021/3/29 14:55, Gao Xiang wrote:
> I found a reference here,
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/coding-style.rst?h=v5.11#n99
> also vaguely remembered some threads from Linus, but hard to find now :-(
Sure, we can follow this rule for erofs code style. :)
Thanks,
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v3 4/4] erofs: add on-disk compression configurations
2021-03-29 1:23 ` Gao Xiang via Linux-erofs
@ 2021-03-29 10:00 ` Gao Xiang via Linux-erofs
-1 siblings, 0 replies; 22+ messages in thread
From: Gao Xiang @ 2021-03-29 10:00 UTC (permalink / raw)
To: linux-erofs, Chao Yu, Chao Yu; +Cc: LKML, Gao Xiang
From: Gao Xiang <hsiangkao@redhat.com>
Add a bitmap for available compression algorithms and a variable-sized
on-disk table for compression options in preparation for upcoming big
pcluster and LZMA algorithm, which follows the end of super block.
To parse the compression options, the bitmap is scanned one by one.
For each available algorithm, there is data followed by 2-byte `length'
correspondingly (it's enough for most cases, or entire fs blocks should
be used.)
With such available algorithm bitmap, kernel itself can also refuse to
mount such filesystem if any unsupported compression algorithm exists.
Note that COMPR_CFGS feature will be enabled with BIG_PCLUSTER.
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
---
changes since v2:
- move upwords print messages since even using a new extra line with
indentation, they still exceed 80 char;
- introduce EROFS_SB_EXTSLOT_SIZE but remaining 128 since
sizeof(struct erofs_super_block) could be changed in the future.
fs/erofs/decompressor.c | 2 +-
fs/erofs/erofs_fs.h | 16 +++--
fs/erofs/internal.h | 5 +-
fs/erofs/super.c | 141 +++++++++++++++++++++++++++++++++++++++-
4 files changed, 157 insertions(+), 7 deletions(-)
diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c
index 97538ff24a19..27aa6a99b371 100644
--- a/fs/erofs/decompressor.c
+++ b/fs/erofs/decompressor.c
@@ -41,7 +41,7 @@ int z_erofs_load_lz4_config(struct super_block *sb,
}
distance = le16_to_cpu(lz4->max_distance);
} else {
- distance = le16_to_cpu(dsb->lz4_max_distance);
+ distance = le16_to_cpu(dsb->u1.lz4_max_distance);
}
EROFS_SB(sb)->lz4.max_distance_pages = distance ?
diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h
index 700597e9c810..17bc0b5f117d 100644
--- a/fs/erofs/erofs_fs.h
+++ b/fs/erofs/erofs_fs.h
@@ -18,15 +18,18 @@
* be incompatible with this kernel version.
*/
#define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING 0x00000001
+#define EROFS_FEATURE_INCOMPAT_COMPR_CFGS 0x00000002
#define EROFS_ALL_FEATURE_INCOMPAT EROFS_FEATURE_INCOMPAT_LZ4_0PADDING
-/* 128-byte erofs on-disk super block */
+#define EROFS_SB_EXTSLOT_SIZE 16
+
+/* erofs on-disk super block (currently 128 bytes) */
struct erofs_super_block {
__le32 magic; /* file system magic number */
__le32 checksum; /* crc32c(super_block) */
__le32 feature_compat;
__u8 blkszbits; /* support block_size == PAGE_SIZE only */
- __u8 reserved;
+ __u8 sb_extslots; /* superblock size = 128 + sb_extslots * 16 */
__le16 root_nid; /* nid of root directory */
__le64 inos; /* total valid ino # (== f_files - f_favail) */
@@ -39,8 +42,12 @@ struct erofs_super_block {
__u8 uuid[16]; /* 128-bit uuid for volume */
__u8 volume_name[16]; /* volume name */
__le32 feature_incompat;
- /* customized lz4 sliding window size instead of 64k by default */
- __le16 lz4_max_distance;
+ union {
+ /* bitmap for available compression algorithms */
+ __le16 available_compr_algs;
+ /* customized sliding window size instead of 64k by default */
+ __le16 lz4_max_distance;
+ } __packed u1;
__u8 reserved2[42];
};
@@ -199,6 +206,7 @@ enum {
Z_EROFS_COMPRESSION_LZ4 = 0,
Z_EROFS_COMPRESSION_MAX
};
+#define Z_EROFS_ALL_COMPR_ALGS (1 << (Z_EROFS_COMPRESSION_MAX - 1))
/* 14 bytes (+ length field = 16 bytes) */
struct z_erofs_lz4_cfgs {
diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
index b02fc64fcece..60063bbbb91a 100644
--- a/fs/erofs/internal.h
+++ b/fs/erofs/internal.h
@@ -75,6 +75,7 @@ struct erofs_sb_info {
struct xarray managed_pslots;
unsigned int shrinker_run_no;
+ u16 available_compr_algs;
/* pseudo inode to manage cached pages */
struct inode *managed_cache;
@@ -90,6 +91,7 @@ struct erofs_sb_info {
/* inode slot unit size in bit shift */
unsigned char islotbits;
+ u32 sb_size; /* total superblock size */
u32 build_time_nsec;
u64 build_time;
@@ -233,6 +235,7 @@ static inline bool erofs_sb_has_##name(struct erofs_sb_info *sbi) \
}
EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING)
+EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS)
EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM)
/* atomic flag definitions */
@@ -452,7 +455,7 @@ static inline int z_erofs_load_lz4_config(struct super_block *sb,
struct erofs_super_block *dsb,
struct z_erofs_lz4_cfgs *lz4, int len)
{
- if (lz4 || dsb->lz4_max_distance) {
+ if (lz4 || dsb->u1.lz4_max_distance) {
erofs_err(sb, "lz4 algorithm isn't enabled");
return -EINVAL;
}
diff --git a/fs/erofs/super.c b/fs/erofs/super.c
index 1ca8da3f2125..ec9e5fb073b5 100644
--- a/fs/erofs/super.c
+++ b/fs/erofs/super.c
@@ -122,6 +122,136 @@ static bool check_layout_compatibility(struct super_block *sb,
return true;
}
+#ifdef CONFIG_EROFS_FS_ZIP
+/* read variable-sized metadata, offset will be aligned by 4-byte */
+static void *erofs_read_metadata(struct super_block *sb, struct page **pagep,
+ erofs_off_t *offset, int *lengthp)
+{
+ struct page *page = *pagep;
+ u8 *buffer, *ptr;
+ int len, i, cnt;
+ erofs_blk_t blk;
+
+ *offset = round_up(*offset, 4);
+ blk = erofs_blknr(*offset);
+
+ if (!page || page->index != blk) {
+ if (page) {
+ unlock_page(page);
+ put_page(page);
+ }
+ page = erofs_get_meta_page(sb, blk);
+ if (IS_ERR(page))
+ goto err_nullpage;
+ }
+
+ ptr = kmap(page);
+ len = le16_to_cpu(*(__le16 *)&ptr[erofs_blkoff(*offset)]);
+ if (!len)
+ len = U16_MAX + 1;
+ buffer = kmalloc(len, GFP_KERNEL);
+ if (!buffer) {
+ buffer = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+ *offset += sizeof(__le16);
+ *lengthp = len;
+
+ for (i = 0; i < len; i += cnt) {
+ cnt = min(EROFS_BLKSIZ - (int)erofs_blkoff(*offset), len - i);
+ blk = erofs_blknr(*offset);
+
+ if (!page || page->index != blk) {
+ if (page) {
+ kunmap(page);
+ unlock_page(page);
+ put_page(page);
+ }
+ page = erofs_get_meta_page(sb, blk);
+ if (IS_ERR(page)) {
+ kfree(buffer);
+ goto err_nullpage;
+ }
+ ptr = kmap(page);
+ }
+ memcpy(buffer + i, ptr + erofs_blkoff(*offset), cnt);
+ *offset += cnt;
+ }
+out:
+ kunmap(page);
+ *pagep = page;
+ return buffer;
+err_nullpage:
+ *pagep = NULL;
+ return page;
+}
+
+static int erofs_load_compr_cfgs(struct super_block *sb,
+ struct erofs_super_block *dsb)
+{
+ struct erofs_sb_info *sbi;
+ struct page *page;
+ unsigned int algs, alg;
+ erofs_off_t offset;
+ int size, ret;
+
+ sbi = EROFS_SB(sb);
+ sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs);
+
+ if (sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS) {
+ erofs_err(sb, "try to load compressed fs with unsupported algorithms %x",
+ sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
+ return -EINVAL;
+ }
+
+ offset = EROFS_SUPER_OFFSET + sbi->sb_size;
+ page = NULL;
+ alg = 0;
+ ret = 0;
+
+ for (algs = sbi->available_compr_algs; algs; algs >>= 1, ++alg) {
+ void *data;
+
+ if (!(algs & 1))
+ continue;
+
+ data = erofs_read_metadata(sb, &page, &offset, &size);
+ if (IS_ERR(data)) {
+ ret = PTR_ERR(data);
+ goto err;
+ }
+
+ switch (alg) {
+ case Z_EROFS_COMPRESSION_LZ4:
+ ret = z_erofs_load_lz4_config(sb, dsb, data, size);
+ break;
+ default:
+ DBG_BUGON(1);
+ ret = -EFAULT;
+ }
+ kfree(data);
+ if (ret)
+ goto err;
+ }
+err:
+ if (page) {
+ unlock_page(page);
+ put_page(page);
+ }
+ return ret;
+}
+#else
+static int erofs_load_compr_cfgs(struct super_block *sb,
+ struct erofs_super_block *dsb)
+{
+ if (dsb->u1.available_compr_algs) {
+ erofs_err(sb, "try to load compressed fs when compression is disabled");
+ return -EINVAL;
+ }
+ return 0;
+}
+#endif
+
static int erofs_read_superblock(struct super_block *sb)
{
struct erofs_sb_info *sbi;
@@ -166,6 +296,12 @@ static int erofs_read_superblock(struct super_block *sb)
if (!check_layout_compatibility(sb, dsb))
goto out;
+ sbi->sb_size = 128 + dsb->sb_extslots * EROFS_SB_EXTSLOT_SIZE;
+ if (sbi->sb_size > EROFS_BLKSIZ) {
+ erofs_err(sb, "invalid sb_extslots %u (more than a fs block)",
+ sbi->sb_size);
+ goto out;
+ }
sbi->blocks = le32_to_cpu(dsb->blocks);
sbi->meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
#ifdef CONFIG_EROFS_FS_XATTR
@@ -189,7 +325,10 @@ static int erofs_read_superblock(struct super_block *sb)
}
/* parse on-disk compression configurations */
- ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0);
+ if (erofs_sb_has_compr_cfgs(sbi))
+ ret = erofs_load_compr_cfgs(sb, dsb);
+ else
+ ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0);
out:
kunmap(page);
put_page(page);
--
2.20.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 4/4] erofs: add on-disk compression configurations
@ 2021-03-29 10:00 ` Gao Xiang via Linux-erofs
0 siblings, 0 replies; 22+ messages in thread
From: Gao Xiang via Linux-erofs @ 2021-03-29 10:00 UTC (permalink / raw)
To: linux-erofs, Chao Yu, Chao Yu; +Cc: LKML
From: Gao Xiang <hsiangkao@redhat.com>
Add a bitmap for available compression algorithms and a variable-sized
on-disk table for compression options in preparation for upcoming big
pcluster and LZMA algorithm, which follows the end of super block.
To parse the compression options, the bitmap is scanned one by one.
For each available algorithm, there is data followed by 2-byte `length'
correspondingly (it's enough for most cases, or entire fs blocks should
be used.)
With such available algorithm bitmap, kernel itself can also refuse to
mount such filesystem if any unsupported compression algorithm exists.
Note that COMPR_CFGS feature will be enabled with BIG_PCLUSTER.
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
---
changes since v2:
- move upwords print messages since even using a new extra line with
indentation, they still exceed 80 char;
- introduce EROFS_SB_EXTSLOT_SIZE but remaining 128 since
sizeof(struct erofs_super_block) could be changed in the future.
fs/erofs/decompressor.c | 2 +-
fs/erofs/erofs_fs.h | 16 +++--
fs/erofs/internal.h | 5 +-
fs/erofs/super.c | 141 +++++++++++++++++++++++++++++++++++++++-
4 files changed, 157 insertions(+), 7 deletions(-)
diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c
index 97538ff24a19..27aa6a99b371 100644
--- a/fs/erofs/decompressor.c
+++ b/fs/erofs/decompressor.c
@@ -41,7 +41,7 @@ int z_erofs_load_lz4_config(struct super_block *sb,
}
distance = le16_to_cpu(lz4->max_distance);
} else {
- distance = le16_to_cpu(dsb->lz4_max_distance);
+ distance = le16_to_cpu(dsb->u1.lz4_max_distance);
}
EROFS_SB(sb)->lz4.max_distance_pages = distance ?
diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h
index 700597e9c810..17bc0b5f117d 100644
--- a/fs/erofs/erofs_fs.h
+++ b/fs/erofs/erofs_fs.h
@@ -18,15 +18,18 @@
* be incompatible with this kernel version.
*/
#define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING 0x00000001
+#define EROFS_FEATURE_INCOMPAT_COMPR_CFGS 0x00000002
#define EROFS_ALL_FEATURE_INCOMPAT EROFS_FEATURE_INCOMPAT_LZ4_0PADDING
-/* 128-byte erofs on-disk super block */
+#define EROFS_SB_EXTSLOT_SIZE 16
+
+/* erofs on-disk super block (currently 128 bytes) */
struct erofs_super_block {
__le32 magic; /* file system magic number */
__le32 checksum; /* crc32c(super_block) */
__le32 feature_compat;
__u8 blkszbits; /* support block_size == PAGE_SIZE only */
- __u8 reserved;
+ __u8 sb_extslots; /* superblock size = 128 + sb_extslots * 16 */
__le16 root_nid; /* nid of root directory */
__le64 inos; /* total valid ino # (== f_files - f_favail) */
@@ -39,8 +42,12 @@ struct erofs_super_block {
__u8 uuid[16]; /* 128-bit uuid for volume */
__u8 volume_name[16]; /* volume name */
__le32 feature_incompat;
- /* customized lz4 sliding window size instead of 64k by default */
- __le16 lz4_max_distance;
+ union {
+ /* bitmap for available compression algorithms */
+ __le16 available_compr_algs;
+ /* customized sliding window size instead of 64k by default */
+ __le16 lz4_max_distance;
+ } __packed u1;
__u8 reserved2[42];
};
@@ -199,6 +206,7 @@ enum {
Z_EROFS_COMPRESSION_LZ4 = 0,
Z_EROFS_COMPRESSION_MAX
};
+#define Z_EROFS_ALL_COMPR_ALGS (1 << (Z_EROFS_COMPRESSION_MAX - 1))
/* 14 bytes (+ length field = 16 bytes) */
struct z_erofs_lz4_cfgs {
diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
index b02fc64fcece..60063bbbb91a 100644
--- a/fs/erofs/internal.h
+++ b/fs/erofs/internal.h
@@ -75,6 +75,7 @@ struct erofs_sb_info {
struct xarray managed_pslots;
unsigned int shrinker_run_no;
+ u16 available_compr_algs;
/* pseudo inode to manage cached pages */
struct inode *managed_cache;
@@ -90,6 +91,7 @@ struct erofs_sb_info {
/* inode slot unit size in bit shift */
unsigned char islotbits;
+ u32 sb_size; /* total superblock size */
u32 build_time_nsec;
u64 build_time;
@@ -233,6 +235,7 @@ static inline bool erofs_sb_has_##name(struct erofs_sb_info *sbi) \
}
EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING)
+EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS)
EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM)
/* atomic flag definitions */
@@ -452,7 +455,7 @@ static inline int z_erofs_load_lz4_config(struct super_block *sb,
struct erofs_super_block *dsb,
struct z_erofs_lz4_cfgs *lz4, int len)
{
- if (lz4 || dsb->lz4_max_distance) {
+ if (lz4 || dsb->u1.lz4_max_distance) {
erofs_err(sb, "lz4 algorithm isn't enabled");
return -EINVAL;
}
diff --git a/fs/erofs/super.c b/fs/erofs/super.c
index 1ca8da3f2125..ec9e5fb073b5 100644
--- a/fs/erofs/super.c
+++ b/fs/erofs/super.c
@@ -122,6 +122,136 @@ static bool check_layout_compatibility(struct super_block *sb,
return true;
}
+#ifdef CONFIG_EROFS_FS_ZIP
+/* read variable-sized metadata, offset will be aligned by 4-byte */
+static void *erofs_read_metadata(struct super_block *sb, struct page **pagep,
+ erofs_off_t *offset, int *lengthp)
+{
+ struct page *page = *pagep;
+ u8 *buffer, *ptr;
+ int len, i, cnt;
+ erofs_blk_t blk;
+
+ *offset = round_up(*offset, 4);
+ blk = erofs_blknr(*offset);
+
+ if (!page || page->index != blk) {
+ if (page) {
+ unlock_page(page);
+ put_page(page);
+ }
+ page = erofs_get_meta_page(sb, blk);
+ if (IS_ERR(page))
+ goto err_nullpage;
+ }
+
+ ptr = kmap(page);
+ len = le16_to_cpu(*(__le16 *)&ptr[erofs_blkoff(*offset)]);
+ if (!len)
+ len = U16_MAX + 1;
+ buffer = kmalloc(len, GFP_KERNEL);
+ if (!buffer) {
+ buffer = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+ *offset += sizeof(__le16);
+ *lengthp = len;
+
+ for (i = 0; i < len; i += cnt) {
+ cnt = min(EROFS_BLKSIZ - (int)erofs_blkoff(*offset), len - i);
+ blk = erofs_blknr(*offset);
+
+ if (!page || page->index != blk) {
+ if (page) {
+ kunmap(page);
+ unlock_page(page);
+ put_page(page);
+ }
+ page = erofs_get_meta_page(sb, blk);
+ if (IS_ERR(page)) {
+ kfree(buffer);
+ goto err_nullpage;
+ }
+ ptr = kmap(page);
+ }
+ memcpy(buffer + i, ptr + erofs_blkoff(*offset), cnt);
+ *offset += cnt;
+ }
+out:
+ kunmap(page);
+ *pagep = page;
+ return buffer;
+err_nullpage:
+ *pagep = NULL;
+ return page;
+}
+
+static int erofs_load_compr_cfgs(struct super_block *sb,
+ struct erofs_super_block *dsb)
+{
+ struct erofs_sb_info *sbi;
+ struct page *page;
+ unsigned int algs, alg;
+ erofs_off_t offset;
+ int size, ret;
+
+ sbi = EROFS_SB(sb);
+ sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs);
+
+ if (sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS) {
+ erofs_err(sb, "try to load compressed fs with unsupported algorithms %x",
+ sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
+ return -EINVAL;
+ }
+
+ offset = EROFS_SUPER_OFFSET + sbi->sb_size;
+ page = NULL;
+ alg = 0;
+ ret = 0;
+
+ for (algs = sbi->available_compr_algs; algs; algs >>= 1, ++alg) {
+ void *data;
+
+ if (!(algs & 1))
+ continue;
+
+ data = erofs_read_metadata(sb, &page, &offset, &size);
+ if (IS_ERR(data)) {
+ ret = PTR_ERR(data);
+ goto err;
+ }
+
+ switch (alg) {
+ case Z_EROFS_COMPRESSION_LZ4:
+ ret = z_erofs_load_lz4_config(sb, dsb, data, size);
+ break;
+ default:
+ DBG_BUGON(1);
+ ret = -EFAULT;
+ }
+ kfree(data);
+ if (ret)
+ goto err;
+ }
+err:
+ if (page) {
+ unlock_page(page);
+ put_page(page);
+ }
+ return ret;
+}
+#else
+static int erofs_load_compr_cfgs(struct super_block *sb,
+ struct erofs_super_block *dsb)
+{
+ if (dsb->u1.available_compr_algs) {
+ erofs_err(sb, "try to load compressed fs when compression is disabled");
+ return -EINVAL;
+ }
+ return 0;
+}
+#endif
+
static int erofs_read_superblock(struct super_block *sb)
{
struct erofs_sb_info *sbi;
@@ -166,6 +296,12 @@ static int erofs_read_superblock(struct super_block *sb)
if (!check_layout_compatibility(sb, dsb))
goto out;
+ sbi->sb_size = 128 + dsb->sb_extslots * EROFS_SB_EXTSLOT_SIZE;
+ if (sbi->sb_size > EROFS_BLKSIZ) {
+ erofs_err(sb, "invalid sb_extslots %u (more than a fs block)",
+ sbi->sb_size);
+ goto out;
+ }
sbi->blocks = le32_to_cpu(dsb->blocks);
sbi->meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
#ifdef CONFIG_EROFS_FS_XATTR
@@ -189,7 +325,10 @@ static int erofs_read_superblock(struct super_block *sb)
}
/* parse on-disk compression configurations */
- ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0);
+ if (erofs_sb_has_compr_cfgs(sbi))
+ ret = erofs_load_compr_cfgs(sb, dsb);
+ else
+ ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0);
out:
kunmap(page);
put_page(page);
--
2.20.1
^ permalink raw reply related [flat|nested] 22+ messages in thread