Commit 80f78409 authored by Xiaoming Ni's avatar Xiaoming Ni Committed by Andrew Morton
Browse files

squashfs: add the mount parameter theads=<single|multi|percpu>

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: default avatarXiaoming Ni <nixiaoming@huawei.com>
Reviewed-by: default avatarPhillip 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: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 4197530b
Loading
Loading
Loading
Loading
+34 −5
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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);
	}
+1 −1
Original line number Diff line number Diff line
@@ -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);

+11 −5
Original line number Diff line number Diff line
@@ -29,12 +29,11 @@
#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 @@ void *squashfs_decompressor_create(struct squashfs_sb_info *msblk,
}


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 @@ static struct decomp_stream *get_decomp_stream(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)
{
@@ -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,
};
+16 −7
Original line number Diff line number Diff line
@@ -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 @@ void *squashfs_decompressor_create(struct squashfs_sb_info *msblk,
	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,
};
Loading