]> www.infradead.org Git - users/hch/configfs.git/commitdiff
squashfs: add the mount parameter theads=<single|multi|percpu>
authorXiaoming Ni <nixiaoming@huawei.com>
Wed, 19 Oct 2022 03:09:29 +0000 (11:09 +0800)
committerAndrew Morton <akpm@linux-foundation.org>
Fri, 18 Nov 2022 21:55:08 +0000 (13:55 -0800)
Patch series 'squashfs: Add the mount parameter "threads="'.

Currently, Squashfs supports multiple decompressor parallel modes.
However, this mode can be configured only during kernel building and does
not support flexible selection during runtime.

In the current patch set, the mount parameter "threads=" is added to allow
users to select the parallel decompressor mode and configure the number of
decompressors when mounting a file system.

"threads=<single|multi|percpu|1|2|3|...>"
The upper limit is num_online_cpus() * 2.

This patch (of 2):

Squashfs supports three decompression concurrency modes:
Single-thread mode: concurrent reads are blocked and the memory
overhead is small.
Multi-thread mode/percpu mode: reduces concurrent read blocking but
increases memory overhead.

The corresponding schema must be fixed at compile time. During mounting,
the concurrent decompression mode cannot be adjusted based on file read
blocking.

The mount parameter theads=<single|multi|percpu> is added to select
the concurrent decompression mode of a single SquashFS file system
image.

Link: https://lkml.kernel.org/r/20221019030930.130456-1-nixiaoming@huawei.com
Link: https://lkml.kernel.org/r/20221019030930.130456-2-nixiaoming@huawei.com
Signed-off-by: Xiaoming Ni <nixiaoming@huawei.com>
Reviewed-by: Phillip Lougher <phillip@squashfs.org.uk>
Cc: Jianguo Chen <chenjianguo3@huawei.com>
Cc: Jubin Zhong <zhongjubin@huawei.com>
Cc: Zhang Yi <yi.zhang@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
fs/squashfs/Kconfig
fs/squashfs/block.c
fs/squashfs/decompressor.c
fs/squashfs/decompressor_multi.c
fs/squashfs/decompressor_multi_percpu.c
fs/squashfs/decompressor_single.c
fs/squashfs/squashfs.h
fs/squashfs/squashfs_fs_sb.h
fs/squashfs/super.c

index 916e78fabcaac819b1e9066f8394b91ea74f488a..218bacdd4298fd8b6ba3460f469086e249abac6f 100644 (file)
@@ -54,9 +54,36 @@ config SQUASHFS_FILE_DIRECT
 
 endchoice
 
+config SQUASHFS_DECOMP_SINGLE
+       depends on SQUASHFS
+       def_bool n
+
+config SQUASHFS_DECOMP_MULTI
+       depends on SQUASHFS
+       def_bool n
+
+config SQUASHFS_DECOMP_MULTI_PERCPU
+       depends on SQUASHFS
+       def_bool n
+
+config SQUASHFS_CHOICE_DECOMP_BY_MOUNT
+       bool "Select the parallel decompression mode during mount"
+       depends on SQUASHFS
+       default n
+       select SQUASHFS_DECOMP_SINGLE
+       select SQUASHFS_DECOMP_MULTI
+       select SQUASHFS_DECOMP_MULTI_PERCPU
+       help
+         Compile all parallel decompression modes and specify the
+         decompression mode by setting "threads=" during mount.
+           threads=<single|multi|percpu>
+
+         default Decompressor parallelisation is SQUASHFS_DECOMP_SINGLE
+
 choice
-       prompt "Decompressor parallelisation options"
+       prompt "Select decompression parallel mode at compile time"
        depends on SQUASHFS
+       depends on !SQUASHFS_CHOICE_DECOMP_BY_MOUNT
        help
          Squashfs now supports three parallelisation options for
          decompression.  Each one exhibits various trade-offs between
@@ -64,15 +91,17 @@ choice
 
          If in doubt, select "Single threaded compression"
 
-config SQUASHFS_DECOMP_SINGLE
+config SQUASHFS_COMPILE_DECOMP_SINGLE
        bool "Single threaded compression"
+       select SQUASHFS_DECOMP_SINGLE
        help
          Traditionally Squashfs has used single-threaded decompression.
          Only one block (data or metadata) can be decompressed at any
          one time.  This limits CPU and memory usage to a minimum.
 
-config SQUASHFS_DECOMP_MULTI
+config SQUASHFS_COMPILE_DECOMP_MULTI
        bool "Use multiple decompressors for parallel I/O"
+       select SQUASHFS_DECOMP_MULTI
        help
          By default Squashfs uses a single decompressor but it gives
          poor performance on parallel I/O workloads when using multiple CPU
@@ -85,8 +114,9 @@ config SQUASHFS_DECOMP_MULTI
          decompressors per core.  It dynamically allocates decompressors
          on a demand basis.
 
-config SQUASHFS_DECOMP_MULTI_PERCPU
+config SQUASHFS_COMPILE_DECOMP_MULTI_PERCPU
        bool "Use percpu multiple decompressors for parallel I/O"
+       select SQUASHFS_DECOMP_MULTI_PERCPU
        help
          By default Squashfs uses a single decompressor but it gives
          poor performance on parallel I/O workloads when using multiple CPU
@@ -95,7 +125,6 @@ config SQUASHFS_DECOMP_MULTI_PERCPU
          This decompressor implementation uses a maximum of one
          decompressor per core.  It uses percpu variables to ensure
          decompression is load-balanced across the cores.
-
 endchoice
 
 config SQUASHFS_XATTR
index 833aca92301f0e1d794bd4a1c1616e0a80fb84cd..bed3bb8b27fa3d81d278df0a4e6185c54752358a 100644 (file)
@@ -216,7 +216,7 @@ int squashfs_read_data(struct super_block *sb, u64 index, int length,
                        res = -EIO;
                        goto out_free_bio;
                }
-               res = squashfs_decompress(msblk, bio, offset, length, output);
+               res = msblk->thread_ops->decompress(msblk, bio, offset, length, output);
        } else {
                res = copy_bio_to_actor(bio, output, offset, length);
        }
index d57bef91ab0852a94457a29fdaf408a1fffa1027..8893cb9b4198336e7686cc59bbe9f8fc9d74558a 100644 (file)
@@ -134,7 +134,7 @@ void *squashfs_decompressor_setup(struct super_block *sb, unsigned short flags)
        if (IS_ERR(comp_opts))
                return comp_opts;
 
-       stream = squashfs_decompressor_create(msblk, comp_opts);
+       stream = msblk->thread_ops->create(msblk, comp_opts);
        if (IS_ERR(stream))
                kfree(comp_opts);
 
index db9f12a3ea0568aa3f81c50b117a5360248a2dcc..eb25432bd1494eecd3a4cfe3eb6ceb0b10b50b54 100644 (file)
 #define MAX_DECOMPRESSOR       (num_online_cpus() * 2)
 
 
-int squashfs_max_decompressors(void)
+static int squashfs_max_decompressors(void)
 {
        return MAX_DECOMPRESSOR;
 }
 
-
 struct squashfs_stream {
        void                    *comp_opts;
        struct list_head        strm_list;
@@ -59,7 +58,7 @@ static void put_decomp_stream(struct decomp_stream *decomp_strm,
        wake_up(&stream->wait);
 }
 
-void *squashfs_decompressor_create(struct squashfs_sb_info *msblk,
+static void *squashfs_decompressor_create(struct squashfs_sb_info *msblk,
                                void *comp_opts)
 {
        struct squashfs_stream *stream;
@@ -103,7 +102,7 @@ out:
 }
 
 
-void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
+static void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
 {
        struct squashfs_stream *stream = msblk->stream;
        if (stream) {
@@ -180,7 +179,7 @@ wait:
 }
 
 
-int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
+static int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
                        int offset, int length,
                        struct squashfs_page_actor *output)
 {
@@ -195,3 +194,10 @@ int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
                        msblk->decompressor->name);
        return res;
 }
+
+const struct squashfs_decompressor_thread_ops squashfs_decompressor_multi = {
+       .create = squashfs_decompressor_create,
+       .destroy = squashfs_decompressor_destroy,
+       .decompress = squashfs_decompress,
+       .max_decompressors = squashfs_max_decompressors,
+};
index b881b9283b7ffd8be2c447a86eafcf003910b270..1dfadf76ed9ae8e0c2c19699804207990f1a96c9 100644 (file)
@@ -25,7 +25,7 @@ struct squashfs_stream {
        local_lock_t    lock;
 };
 
-void *squashfs_decompressor_create(struct squashfs_sb_info *msblk,
+static void *squashfs_decompressor_create(struct squashfs_sb_info *msblk,
                                                void *comp_opts)
 {
        struct squashfs_stream *stream;
@@ -59,7 +59,7 @@ out:
        return ERR_PTR(err);
 }
 
-void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
+static void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
 {
        struct squashfs_stream __percpu *percpu =
                        (struct squashfs_stream __percpu *) msblk->stream;
@@ -75,19 +75,21 @@ void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
        }
 }
 
-int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
+static int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
        int offset, int length, struct squashfs_page_actor *output)
 {
        struct squashfs_stream *stream;
+       struct squashfs_stream __percpu *percpu =
+                       (struct squashfs_stream __percpu *) msblk->stream;
        int res;
 
-       local_lock(&msblk->stream->lock);
-       stream = this_cpu_ptr(msblk->stream);
+       local_lock(&percpu->lock);
+       stream = this_cpu_ptr(percpu);
 
        res = msblk->decompressor->decompress(msblk, stream->stream, bio,
                                              offset, length, output);
 
-       local_unlock(&msblk->stream->lock);
+       local_unlock(&percpu->lock);
 
        if (res < 0)
                ERROR("%s decompression failed, data probably corrupt\n",
@@ -96,7 +98,14 @@ int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
        return res;
 }
 
-int squashfs_max_decompressors(void)
+static int squashfs_max_decompressors(void)
 {
        return num_possible_cpus();
 }
+
+const struct squashfs_decompressor_thread_ops squashfs_decompressor_percpu = {
+       .create = squashfs_decompressor_create,
+       .destroy = squashfs_decompressor_destroy,
+       .decompress = squashfs_decompress,
+       .max_decompressors = squashfs_max_decompressors,
+};
index 4eb3d083d45eb8a30c99fdd118941465f918d2cd..6f161887710bc47e2a0fc5fdde918931f3923531 100644 (file)
@@ -24,7 +24,7 @@ struct squashfs_stream {
        struct mutex    mutex;
 };
 
-void *squashfs_decompressor_create(struct squashfs_sb_info *msblk,
+static void *squashfs_decompressor_create(struct squashfs_sb_info *msblk,
                                                void *comp_opts)
 {
        struct squashfs_stream *stream;
@@ -49,7 +49,7 @@ out:
        return ERR_PTR(err);
 }
 
-void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
+static void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
 {
        struct squashfs_stream *stream = msblk->stream;
 
@@ -59,7 +59,7 @@ void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
        }
 }
 
-int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
+static int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
                        int offset, int length,
                        struct squashfs_page_actor *output)
 {
@@ -78,7 +78,14 @@ int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
        return res;
 }
 
-int squashfs_max_decompressors(void)
+static int squashfs_max_decompressors(void)
 {
        return 1;
 }
+
+const struct squashfs_decompressor_thread_ops squashfs_decompressor_single = {
+       .create = squashfs_decompressor_create,
+       .destroy = squashfs_decompressor_destroy,
+       .decompress = squashfs_decompress,
+       .max_decompressors = squashfs_max_decompressors,
+};
index 9783e01c81004106db75a70298d43d27f1f2c334..a6164fdf9435db66e15b1639e046e000a9c9d729 100644 (file)
@@ -38,11 +38,24 @@ extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int);
 extern void *squashfs_decompressor_setup(struct super_block *, unsigned short);
 
 /* decompressor_xxx.c */
-extern void *squashfs_decompressor_create(struct squashfs_sb_info *, void *);
-extern void squashfs_decompressor_destroy(struct squashfs_sb_info *);
-extern int squashfs_decompress(struct squashfs_sb_info *, struct bio *,
-                               int, int, struct squashfs_page_actor *);
-extern int squashfs_max_decompressors(void);
+
+struct squashfs_decompressor_thread_ops {
+       void * (*create)(struct squashfs_sb_info *msblk, void *comp_opts);
+       void (*destroy)(struct squashfs_sb_info *msblk);
+       int (*decompress)(struct squashfs_sb_info *msblk, struct bio *bio,
+                         int offset, int length, struct squashfs_page_actor *output);
+       int (*max_decompressors)(void);
+};
+
+#ifdef CONFIG_SQUASHFS_DECOMP_SINGLE
+extern const struct squashfs_decompressor_thread_ops squashfs_decompressor_single;
+#endif
+#ifdef CONFIG_SQUASHFS_DECOMP_MULTI
+extern const struct squashfs_decompressor_thread_ops squashfs_decompressor_multi;
+#endif
+#ifdef CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU
+extern const struct squashfs_decompressor_thread_ops squashfs_decompressor_percpu;
+#endif
 
 /* export.c */
 extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, u64,
index 1e90c2575f9bffbcd1d1b3a0261ea8902a6dff1b..f1e5dad8ae0afc8e785024a1e63c226713be10d0 100644 (file)
@@ -53,7 +53,7 @@ struct squashfs_sb_info {
        __le64                                  *xattr_id_table;
        struct mutex                            meta_index_mutex;
        struct meta_index                       *meta_index;
-       struct squashfs_stream                  *stream;
+       void                                    *stream;
        __le64                                  *inode_lookup_table;
        u64                                     inode_table;
        u64                                     directory_table;
@@ -66,5 +66,6 @@ struct squashfs_sb_info {
        int                                     xattr_ids;
        unsigned int                            ids;
        bool                                    panic_on_errors;
+       const struct squashfs_decompressor_thread_ops *thread_ops;
 };
 #endif
index 32565dafa7f3bab04862a095d6011183af76dd79..aac3ea72a9ba76ed98e542dba0714ef73d34480e 100644 (file)
@@ -47,10 +47,12 @@ enum Opt_errors {
 
 enum squashfs_param {
        Opt_errors,
+       Opt_threads,
 };
 
 struct squashfs_mount_opts {
        enum Opt_errors errors;
+       const struct squashfs_decompressor_thread_ops *thread_ops;
 };
 
 static const struct constant_table squashfs_param_errors[] = {
@@ -61,9 +63,29 @@ static const struct constant_table squashfs_param_errors[] = {
 
 static const struct fs_parameter_spec squashfs_fs_parameters[] = {
        fsparam_enum("errors", Opt_errors, squashfs_param_errors),
+       fsparam_string("threads", Opt_threads),
        {}
 };
 
+static int squashfs_parse_param_threads(const char *str, struct squashfs_mount_opts *opts)
+{
+#ifdef CONFIG_SQUASHFS_CHOICE_DECOMP_BY_MOUNT
+       if (strcmp(str, "single") == 0) {
+               opts->thread_ops = &squashfs_decompressor_single;
+               return 0;
+       }
+       if (strcmp(str, "multi") == 0) {
+               opts->thread_ops = &squashfs_decompressor_multi;
+               return 0;
+       }
+       if (strcmp(str, "percpu") == 0) {
+               opts->thread_ops = &squashfs_decompressor_percpu;
+               return 0;
+       }
+#endif
+       return -EINVAL;
+}
+
 static int squashfs_parse_param(struct fs_context *fc, struct fs_parameter *param)
 {
        struct squashfs_mount_opts *opts = fc->fs_private;
@@ -78,6 +100,10 @@ static int squashfs_parse_param(struct fs_context *fc, struct fs_parameter *para
        case Opt_errors:
                opts->errors = result.uint_32;
                break;
+       case Opt_threads:
+               if (squashfs_parse_param_threads(param->string, opts) != 0)
+                       return -EINVAL;
+               break;
        default:
                return -EINVAL;
        }
@@ -167,6 +193,7 @@ static int squashfs_fill_super(struct super_block *sb, struct fs_context *fc)
                               sb->s_bdev);
                goto failed_mount;
        }
+       msblk->thread_ops = opts->thread_ops;
 
        /* Check the MAJOR & MINOR versions and lookup compression type */
        msblk->decompressor = supported_squashfs_filesystem(
@@ -252,7 +279,7 @@ static int squashfs_fill_super(struct super_block *sb, struct fs_context *fc)
 
        /* Allocate read_page block */
        msblk->read_page = squashfs_cache_init("data",
-               squashfs_max_decompressors(), msblk->block_size);
+               msblk->thread_ops->max_decompressors(), msblk->block_size);
        if (msblk->read_page == NULL) {
                errorf(fc, "Failed to allocate read_page block");
                goto failed_mount;
@@ -383,7 +410,7 @@ failed_mount:
        squashfs_cache_delete(msblk->block_cache);
        squashfs_cache_delete(msblk->fragment_cache);
        squashfs_cache_delete(msblk->read_page);
-       squashfs_decompressor_destroy(msblk);
+       msblk->thread_ops->destroy(msblk);
        kfree(msblk->inode_lookup_table);
        kfree(msblk->fragment_index);
        kfree(msblk->id_table);
@@ -435,6 +462,20 @@ static int squashfs_show_options(struct seq_file *s, struct dentry *root)
        else
                seq_puts(s, ",errors=continue");
 
+#ifdef CONFIG_SQUASHFS_CHOICE_DECOMP_BY_MOUNT
+       if (msblk->thread_ops == &squashfs_decompressor_single) {
+               seq_puts(s, ",threads=single");
+               return 0;
+       }
+       if (msblk->thread_ops == &squashfs_decompressor_multi) {
+               seq_puts(s, ",threads=multi");
+               return 0;
+       }
+       if (msblk->thread_ops == &squashfs_decompressor_percpu) {
+               seq_puts(s, ",threads=percpu");
+               return 0;
+       }
+#endif
        return 0;
 }
 
@@ -446,6 +487,15 @@ static int squashfs_init_fs_context(struct fs_context *fc)
        if (!opts)
                return -ENOMEM;
 
+#ifdef CONFIG_SQUASHFS_DECOMP_SINGLE
+       opts->thread_ops = &squashfs_decompressor_single;
+#elif defined(CONFIG_SQUASHFS_DECOMP_MULTI)
+       opts->thread_ops = &squashfs_decompressor_multi;
+#elif defined(CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU)
+       opts->thread_ops = &squashfs_decompressor_percpu;
+#else
+#error "fail: unknown squashfs decompression thread mode?"
+#endif
        fc->fs_private = opts;
        fc->ops = &squashfs_context_ops;
        return 0;
@@ -478,7 +528,7 @@ static void squashfs_put_super(struct super_block *sb)
                squashfs_cache_delete(sbi->block_cache);
                squashfs_cache_delete(sbi->fragment_cache);
                squashfs_cache_delete(sbi->read_page);
-               squashfs_decompressor_destroy(sbi);
+               sbi->thread_ops->destroy(sbi);
                kfree(sbi->id_table);
                kfree(sbi->fragment_index);
                kfree(sbi->meta_index);