diff mbox series

[RFC] jffs2: add support for zstd compression

Message ID 20210312095545.53765-1-rsalvaterra@gmail.com
State Changes Requested
Delegated to: Ambarus Tudor
Headers show
Series [RFC] jffs2: add support for zstd compression | expand

Commit Message

Rui Salvaterra March 12, 2021, 9:55 a.m. UTC
Implement support for zstd compression in jffs2 at the default compression
level (3).

Lightly tested in OpenWrt, on a single CPU embedded MIPS32 system (AirGrid M2).

Signed-off-by: Rui Salvaterra <rsalvaterra@gmail.com>
---
Sent as RFC, since I have no idea if locking is required (the crypto API
implementation doesn't do it, at least).

 fs/jffs2/Kconfig           |   9 +++
 fs/jffs2/Makefile          |   1 +
 fs/jffs2/compr.c           |  10 +++
 fs/jffs2/compr.h           |   6 ++
 fs/jffs2/compr_zstd.c      | 131 +++++++++++++++++++++++++++++++++++++
 fs/jffs2/super.c           |   7 ++
 include/uapi/linux/jffs2.h |   1 +
 7 files changed, 165 insertions(+)
 create mode 100644 fs/jffs2/compr_zstd.c

Comments

Rui Salvaterra March 16, 2021, 2:11 p.m. UTC | #1
Hi,

Please ignore this, I noticed a bug. I'll send a fixed v2 shortly.

Thanks,
Rui

On Fri, 12 Mar 2021 at 09:56, Rui Salvaterra <rsalvaterra@gmail.com> wrote:
>
> Implement support for zstd compression in jffs2 at the default compression
> level (3).
>
> Lightly tested in OpenWrt, on a single CPU embedded MIPS32 system (AirGrid M2).
>
> Signed-off-by: Rui Salvaterra <rsalvaterra@gmail.com>
> ---
> Sent as RFC, since I have no idea if locking is required (the crypto API
> implementation doesn't do it, at least).
>
>  fs/jffs2/Kconfig           |   9 +++
>  fs/jffs2/Makefile          |   1 +
>  fs/jffs2/compr.c           |  10 +++
>  fs/jffs2/compr.h           |   6 ++
>  fs/jffs2/compr_zstd.c      | 131 +++++++++++++++++++++++++++++++++++++
>  fs/jffs2/super.c           |   7 ++
>  include/uapi/linux/jffs2.h |   1 +
>  7 files changed, 165 insertions(+)
>  create mode 100644 fs/jffs2/compr_zstd.c
>
> diff --git a/fs/jffs2/Kconfig b/fs/jffs2/Kconfig
> index 7c96bc107218..31308eb7267b 100644
> --- a/fs/jffs2/Kconfig
> +++ b/fs/jffs2/Kconfig
> @@ -136,6 +136,15 @@ config JFFS2_LZO
>           This feature was added in July, 2007. Say 'N' if you need
>           compatibility with older bootloaders or kernels.
>
> +config JFFS2_ZSTD
> +       bool "JFFS2 zstd compression support" if JFFS2_COMPRESSION_OPTIONS
> +       select ZSTD_COMPRESS
> +       select ZSTD_DECOMPRESS
> +       depends on JFFS2_FS
> +       default n
> +       help
> +         Zstd compression.
> +
>  config JFFS2_RTIME
>         bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS
>         depends on JFFS2_FS
> diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile
> index 5294969d5bf9..75f84b1467c5 100644
> --- a/fs/jffs2/Makefile
> +++ b/fs/jffs2/Makefile
> @@ -19,4 +19,5 @@ jffs2-$(CONFIG_JFFS2_RUBIN)   += compr_rubin.o
>  jffs2-$(CONFIG_JFFS2_RTIME)    += compr_rtime.o
>  jffs2-$(CONFIG_JFFS2_ZLIB)     += compr_zlib.o
>  jffs2-$(CONFIG_JFFS2_LZO)      += compr_lzo.o
> +jffs2-$(CONFIG_JFFS2_ZSTD)     += compr_zstd.o
>  jffs2-$(CONFIG_JFFS2_SUMMARY)   += summary.o
> diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c
> index 4849a4c9a0e2..d65e0c39c9c5 100644
> --- a/fs/jffs2/compr.c
> +++ b/fs/jffs2/compr.c
> @@ -237,6 +237,10 @@ uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
>                 ret = jffs2_selected_compress(JFFS2_COMPR_ZLIB, data_in,
>                                 cpage_out, datalen, cdatalen);
>                 break;
> +       case JFFS2_COMPR_MODE_FORCEZSTD:
> +               ret = jffs2_selected_compress(JFFS2_COMPR_ZSTD, data_in,
> +                               cpage_out, datalen, cdatalen);
> +               break;
>         default:
>                 pr_err("unknown compression mode\n");
>         }
> @@ -378,6 +382,9 @@ int __init jffs2_compressors_init(void)
>  #ifdef CONFIG_JFFS2_LZO
>         jffs2_lzo_init();
>  #endif
> +#ifdef CONFIG_JFFS2_ZSTD
> +       jffs2_zstd_init();
> +#endif
>  /* Setting default compression mode */
>  #ifdef CONFIG_JFFS2_CMODE_NONE
>         jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
> @@ -413,6 +420,9 @@ int jffs2_compressors_exit(void)
>  #endif
>  #ifdef CONFIG_JFFS2_ZLIB
>         jffs2_zlib_exit();
> +#endif
> +#ifdef CONFIG_JFFS2_ZSTD
> +       jffs2_zstd_exit();
>  #endif
>         return 0;
>  }
> diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h
> index 5e91d578f4ed..8f7032c5ecb2 100644
> --- a/fs/jffs2/compr.h
> +++ b/fs/jffs2/compr.h
> @@ -31,6 +31,7 @@
>  #define JFFS2_RTIME_PRIORITY     50
>  #define JFFS2_ZLIB_PRIORITY      60
>  #define JFFS2_LZO_PRIORITY       80
> +#define JFFS2_ZSTD_PRIORITY      90
>
>
>  #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */
> @@ -42,6 +43,7 @@
>  #define JFFS2_COMPR_MODE_FAVOURLZO  3
>  #define JFFS2_COMPR_MODE_FORCELZO   4
>  #define JFFS2_COMPR_MODE_FORCEZLIB  5
> +#define JFFS2_COMPR_MODE_FORCEZSTD  6
>
>  #define FAVOUR_LZO_PERCENT 80
>
> @@ -101,5 +103,9 @@ void jffs2_zlib_exit(void);
>  int jffs2_lzo_init(void);
>  void jffs2_lzo_exit(void);
>  #endif
> +#ifdef CONFIG_JFFS2_ZSTD
> +int jffs2_zstd_init(void);
> +void jffs2_zstd_exit(void);
> +#endif
>
>  #endif /* __JFFS2_COMPR_H__ */
> diff --git a/fs/jffs2/compr_zstd.c b/fs/jffs2/compr_zstd.c
> new file mode 100644
> index 000000000000..86b3d28670d7
> --- /dev/null
> +++ b/fs/jffs2/compr_zstd.c
> @@ -0,0 +1,131 @@
> +
> +#include <linux/zstd.h>
> +#include "compr.h"
> +
> +#define ZSTD_DEF_LEVEL 3
> +
> +static ZSTD_CCtx *cctx;
> +static ZSTD_DCtx *dctx;
> +static void *cwksp;
> +static void *dwksp;
> +
> +static ZSTD_parameters zstd_params(void)
> +{
> +       return ZSTD_getParams(ZSTD_DEF_LEVEL, 0, 0);
> +}
> +
> +static int zstd_comp_init(void)
> +{
> +       int ret = 0;
> +       const ZSTD_parameters params = zstd_params();
> +       const size_t wksp_size = ZSTD_CCtxWorkspaceBound(params.cParams);
> +
> +       cwksp = vzalloc(wksp_size);
> +       if (!cwksp) {
> +               ret = -ENOMEM;
> +               goto out;
> +       }
> +
> +       cctx = ZSTD_initCCtx(cwksp, wksp_size);
> +       if (cctx) {
> +               ret = -EINVAL;
> +               goto out_free;
> +       }
> +out:
> +       return ret;
> +out_free:
> +       vfree(cwksp);
> +       goto out;
> +}
> +
> +static int zstd_decomp_init(void)
> +{
> +       int ret = 0;
> +       const size_t wksp_size = ZSTD_DCtxWorkspaceBound();
> +
> +       dwksp = vzalloc(wksp_size);
> +       if (!dwksp) {
> +               ret = -ENOMEM;
> +               goto out;
> +       }
> +
> +       dctx = ZSTD_initDCtx(dwksp, wksp_size);
> +       if (!dctx) {
> +               ret = -EINVAL;
> +               goto out_free;
> +       }
> +out:
> +       return ret;
> +out_free:
> +       vfree(dwksp);
> +       goto out;
> +}
> +
> +static void zstd_comp_exit(void)
> +{
> +       vfree(cwksp);
> +       cwksp = NULL;
> +       cctx = NULL;
> +}
> +
> +static void zstd_decomp_exit(void)
> +{
> +       vfree(dwksp);
> +       dwksp = NULL;
> +       dctx = NULL;
> +}
> +
> +static int jffs2_zstd_compress(unsigned char *data_in, unsigned char *cpage_out,
> +                             uint32_t *sourcelen, uint32_t *dstlen)
> +{
> +       size_t out_len;
> +       const ZSTD_parameters params = zstd_params();
> +
> +       out_len = ZSTD_compressCCtx(cctx, cpage_out, *dstlen, data_in, *sourcelen, params);
> +       if (ZSTD_isError(out_len) || out_len > *dstlen)
> +               return -1;
> +       *dstlen = out_len;
> +       return 0;
> +}
> +
> +static int jffs2_zstd_decompress(unsigned char *data_in, unsigned char *cpage_out,
> +                                uint32_t srclen, uint32_t destlen)
> +{
> +       size_t out_len;
> +
> +       out_len = ZSTD_decompressDCtx(dctx, cpage_out, destlen, data_in, srclen);
> +       if (ZSTD_isError(out_len) || out_len != destlen)
> +               return -1;
> +
> +       return 0;
> +}
> +
> +static struct jffs2_compressor jffs2_zstd_comp = {
> +       .priority = JFFS2_ZSTD_PRIORITY,
> +       .name = "zstd",
> +       .compr = JFFS2_COMPR_ZSTD,
> +       .compress = &jffs2_zstd_compress,
> +       .decompress = &jffs2_zstd_decompress,
> +       .disabled = 0,
> +};
> +
> +int __init jffs2_zstd_init(void)
> +{
> +       int ret;
> +
> +       ret = zstd_comp_init();
> +       if (ret)
> +               return ret;
> +       ret = zstd_decomp_init();
> +       if (ret)
> +               zstd_comp_exit();
> +       ret = jffs2_register_compressor(&jffs2_zstd_comp);
> +       return ret;
> +}
> +
> +void jffs2_zstd_exit(void)
> +{
> +       jffs2_unregister_compressor(&jffs2_zstd_comp);
> +       zstd_comp_exit();
> +       zstd_decomp_exit();
> +}
> diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
> index 81ca58c10b72..ddce95c55dde 100644
> --- a/fs/jffs2/super.c
> +++ b/fs/jffs2/super.c
> @@ -73,6 +73,10 @@ static const char *jffs2_compr_name(unsigned int compr)
>  #ifdef CONFIG_JFFS2_ZLIB
>         case JFFS2_COMPR_MODE_FORCEZLIB:
>                 return "zlib";
> +#endif
> +#ifdef CONFIG_JFFS2_ZSTD
> +       case JFFS2_COMPR_MODE_FORCEZSTD:
> +               return "zstd";
>  #endif
>         default:
>                 /* should never happen; programmer error */
> @@ -174,6 +178,9 @@ static const struct constant_table jffs2_param_compr[] = {
>  #endif
>  #ifdef CONFIG_JFFS2_ZLIB
>         {"zlib",        JFFS2_COMPR_MODE_FORCEZLIB },
> +#endif
> +#ifdef CONFIG_JFFS2_ZSTD
> +       {"zstd",        JFFS2_COMPR_MODE_FORCEZSTD },
>  #endif
>         {}
>  };
> diff --git a/include/uapi/linux/jffs2.h b/include/uapi/linux/jffs2.h
> index 784ba0b9690a..af4fb69c8d69 100644
> --- a/include/uapi/linux/jffs2.h
> +++ b/include/uapi/linux/jffs2.h
> @@ -46,6 +46,7 @@
>  #define JFFS2_COMPR_DYNRUBIN   0x05
>  #define JFFS2_COMPR_ZLIB       0x06
>  #define JFFS2_COMPR_LZO                0x07
> +#define JFFS2_COMPR_ZSTD       0x08
>  /* Compatibility flags. */
>  #define JFFS2_COMPAT_MASK 0xc000      /* What do to if an unknown nodetype is found */
>  #define JFFS2_NODE_ACCURATE 0x2000
> --
> 2.30.2
>
diff mbox series

Patch

diff --git a/fs/jffs2/Kconfig b/fs/jffs2/Kconfig
index 7c96bc107218..31308eb7267b 100644
--- a/fs/jffs2/Kconfig
+++ b/fs/jffs2/Kconfig
@@ -136,6 +136,15 @@  config JFFS2_LZO
 	  This feature was added in July, 2007. Say 'N' if you need
 	  compatibility with older bootloaders or kernels.
 
+config JFFS2_ZSTD
+	bool "JFFS2 zstd compression support" if JFFS2_COMPRESSION_OPTIONS
+	select ZSTD_COMPRESS
+	select ZSTD_DECOMPRESS
+	depends on JFFS2_FS
+	default n
+	help
+	  Zstd compression.
+
 config JFFS2_RTIME
 	bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS
 	depends on JFFS2_FS
diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile
index 5294969d5bf9..75f84b1467c5 100644
--- a/fs/jffs2/Makefile
+++ b/fs/jffs2/Makefile
@@ -19,4 +19,5 @@  jffs2-$(CONFIG_JFFS2_RUBIN)	+= compr_rubin.o
 jffs2-$(CONFIG_JFFS2_RTIME)	+= compr_rtime.o
 jffs2-$(CONFIG_JFFS2_ZLIB)	+= compr_zlib.o
 jffs2-$(CONFIG_JFFS2_LZO)	+= compr_lzo.o
+jffs2-$(CONFIG_JFFS2_ZSTD)	+= compr_zstd.o
 jffs2-$(CONFIG_JFFS2_SUMMARY)   += summary.o
diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c
index 4849a4c9a0e2..d65e0c39c9c5 100644
--- a/fs/jffs2/compr.c
+++ b/fs/jffs2/compr.c
@@ -237,6 +237,10 @@  uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
 		ret = jffs2_selected_compress(JFFS2_COMPR_ZLIB, data_in,
 				cpage_out, datalen, cdatalen);
 		break;
+	case JFFS2_COMPR_MODE_FORCEZSTD:
+		ret = jffs2_selected_compress(JFFS2_COMPR_ZSTD, data_in,
+				cpage_out, datalen, cdatalen);
+		break;
 	default:
 		pr_err("unknown compression mode\n");
 	}
@@ -378,6 +382,9 @@  int __init jffs2_compressors_init(void)
 #ifdef CONFIG_JFFS2_LZO
 	jffs2_lzo_init();
 #endif
+#ifdef CONFIG_JFFS2_ZSTD
+	jffs2_zstd_init();
+#endif
 /* Setting default compression mode */
 #ifdef CONFIG_JFFS2_CMODE_NONE
 	jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
@@ -413,6 +420,9 @@  int jffs2_compressors_exit(void)
 #endif
 #ifdef CONFIG_JFFS2_ZLIB
 	jffs2_zlib_exit();
+#endif
+#ifdef CONFIG_JFFS2_ZSTD
+	jffs2_zstd_exit();
 #endif
 	return 0;
 }
diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h
index 5e91d578f4ed..8f7032c5ecb2 100644
--- a/fs/jffs2/compr.h
+++ b/fs/jffs2/compr.h
@@ -31,6 +31,7 @@ 
 #define JFFS2_RTIME_PRIORITY     50
 #define JFFS2_ZLIB_PRIORITY      60
 #define JFFS2_LZO_PRIORITY       80
+#define JFFS2_ZSTD_PRIORITY      90
 
 
 #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */
@@ -42,6 +43,7 @@ 
 #define JFFS2_COMPR_MODE_FAVOURLZO  3
 #define JFFS2_COMPR_MODE_FORCELZO   4
 #define JFFS2_COMPR_MODE_FORCEZLIB  5
+#define JFFS2_COMPR_MODE_FORCEZSTD  6
 
 #define FAVOUR_LZO_PERCENT 80
 
@@ -101,5 +103,9 @@  void jffs2_zlib_exit(void);
 int jffs2_lzo_init(void);
 void jffs2_lzo_exit(void);
 #endif
+#ifdef CONFIG_JFFS2_ZSTD
+int jffs2_zstd_init(void);
+void jffs2_zstd_exit(void);
+#endif
 
 #endif /* __JFFS2_COMPR_H__ */
diff --git a/fs/jffs2/compr_zstd.c b/fs/jffs2/compr_zstd.c
new file mode 100644
index 000000000000..86b3d28670d7
--- /dev/null
+++ b/fs/jffs2/compr_zstd.c
@@ -0,0 +1,131 @@ 
+
+#include <linux/zstd.h>
+#include "compr.h"
+
+#define ZSTD_DEF_LEVEL	3
+
+static ZSTD_CCtx *cctx;
+static ZSTD_DCtx *dctx;
+static void *cwksp;
+static void *dwksp;
+
+static ZSTD_parameters zstd_params(void)
+{
+	return ZSTD_getParams(ZSTD_DEF_LEVEL, 0, 0);
+}
+
+static int zstd_comp_init(void)
+{
+	int ret = 0;
+	const ZSTD_parameters params = zstd_params();
+	const size_t wksp_size = ZSTD_CCtxWorkspaceBound(params.cParams);
+
+	cwksp = vzalloc(wksp_size);
+	if (!cwksp) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	cctx = ZSTD_initCCtx(cwksp, wksp_size);
+	if (cctx) {
+		ret = -EINVAL;
+		goto out_free;
+	}
+out:
+	return ret;
+out_free:
+	vfree(cwksp);
+	goto out;
+}
+
+static int zstd_decomp_init(void)
+{
+	int ret = 0;
+	const size_t wksp_size = ZSTD_DCtxWorkspaceBound();
+
+	dwksp = vzalloc(wksp_size);
+	if (!dwksp) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	dctx = ZSTD_initDCtx(dwksp, wksp_size);
+	if (!dctx) {
+		ret = -EINVAL;
+		goto out_free;
+	}
+out:
+	return ret;
+out_free:
+	vfree(dwksp);
+	goto out;
+}
+
+static void zstd_comp_exit(void)
+{
+	vfree(cwksp);
+	cwksp = NULL;
+	cctx = NULL;
+}
+
+static void zstd_decomp_exit(void)
+{
+	vfree(dwksp);
+	dwksp = NULL;
+	dctx = NULL;
+}
+
+static int jffs2_zstd_compress(unsigned char *data_in, unsigned char *cpage_out,
+			      uint32_t *sourcelen, uint32_t *dstlen)
+{
+	size_t out_len;
+	const ZSTD_parameters params = zstd_params();
+
+	out_len = ZSTD_compressCCtx(cctx, cpage_out, *dstlen, data_in, *sourcelen, params);
+	if (ZSTD_isError(out_len) || out_len > *dstlen)
+		return -1;
+	*dstlen = out_len;
+	return 0;
+}
+
+static int jffs2_zstd_decompress(unsigned char *data_in, unsigned char *cpage_out,
+				 uint32_t srclen, uint32_t destlen)
+{
+	size_t out_len;
+
+	out_len = ZSTD_decompressDCtx(dctx, cpage_out, destlen, data_in, srclen);
+	if (ZSTD_isError(out_len) || out_len != destlen)
+		return -1;
+
+	return 0;
+}
+
+static struct jffs2_compressor jffs2_zstd_comp = {
+	.priority = JFFS2_ZSTD_PRIORITY,
+	.name = "zstd",
+	.compr = JFFS2_COMPR_ZSTD,
+	.compress = &jffs2_zstd_compress,
+	.decompress = &jffs2_zstd_decompress,
+	.disabled = 0,
+};
+
+int __init jffs2_zstd_init(void)
+{
+	int ret;
+
+	ret = zstd_comp_init();
+	if (ret)
+		return ret;
+	ret = zstd_decomp_init();
+	if (ret)
+		zstd_comp_exit();
+	ret = jffs2_register_compressor(&jffs2_zstd_comp);
+	return ret;
+}
+
+void jffs2_zstd_exit(void)
+{
+	jffs2_unregister_compressor(&jffs2_zstd_comp);
+	zstd_comp_exit();
+	zstd_decomp_exit();
+}
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 81ca58c10b72..ddce95c55dde 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -73,6 +73,10 @@  static const char *jffs2_compr_name(unsigned int compr)
 #ifdef CONFIG_JFFS2_ZLIB
 	case JFFS2_COMPR_MODE_FORCEZLIB:
 		return "zlib";
+#endif
+#ifdef CONFIG_JFFS2_ZSTD
+	case JFFS2_COMPR_MODE_FORCEZSTD:
+		return "zstd";
 #endif
 	default:
 		/* should never happen; programmer error */
@@ -174,6 +178,9 @@  static const struct constant_table jffs2_param_compr[] = {
 #endif
 #ifdef CONFIG_JFFS2_ZLIB
 	{"zlib",	JFFS2_COMPR_MODE_FORCEZLIB },
+#endif
+#ifdef CONFIG_JFFS2_ZSTD
+	{"zstd",	JFFS2_COMPR_MODE_FORCEZSTD },
 #endif
 	{}
 };
diff --git a/include/uapi/linux/jffs2.h b/include/uapi/linux/jffs2.h
index 784ba0b9690a..af4fb69c8d69 100644
--- a/include/uapi/linux/jffs2.h
+++ b/include/uapi/linux/jffs2.h
@@ -46,6 +46,7 @@ 
 #define JFFS2_COMPR_DYNRUBIN	0x05
 #define JFFS2_COMPR_ZLIB	0x06
 #define JFFS2_COMPR_LZO		0x07
+#define JFFS2_COMPR_ZSTD	0x08
 /* Compatibility flags. */
 #define JFFS2_COMPAT_MASK 0xc000      /* What do to if an unknown nodetype is found */
 #define JFFS2_NODE_ACCURATE 0x2000