1 // SPDX-License-Identifier: GPL-2.0-only
4 * Minchan Kim <minchan@kernel.org>
6 #include <linux/types.h>
7 #include <linux/mutex.h>
8 #include <linux/slab.h>
10 #include <linux/sched.h>
11 #include <linux/wait.h>
12 #include <linux/cpumask.h>
14 #include "squashfs_fs.h"
15 #include "squashfs_fs_sb.h"
16 #include "decompressor.h"
20 * This file implements multi-threaded decompression in the
21 * decompressor framework
26 * The reason that multiply two is that a CPU can request new I/O
27 * while it is waiting previous request.
29 #define MAX_DECOMPRESSOR (num_online_cpus() * 2)
32 int squashfs_max_decompressors(void)
34 return MAX_DECOMPRESSOR
;
38 struct squashfs_stream
{
40 struct list_head strm_list
;
43 wait_queue_head_t wait
;
47 struct decomp_stream
{
49 struct list_head list
;
53 static void put_decomp_stream(struct decomp_stream
*decomp_strm
,
54 struct squashfs_stream
*stream
)
56 mutex_lock(&stream
->mutex
);
57 list_add(&decomp_strm
->list
, &stream
->strm_list
);
58 mutex_unlock(&stream
->mutex
);
59 wake_up(&stream
->wait
);
62 void *squashfs_decompressor_create(struct squashfs_sb_info
*msblk
,
65 struct squashfs_stream
*stream
;
66 struct decomp_stream
*decomp_strm
= NULL
;
69 stream
= kzalloc(sizeof(*stream
), GFP_KERNEL
);
73 stream
->comp_opts
= comp_opts
;
74 mutex_init(&stream
->mutex
);
75 INIT_LIST_HEAD(&stream
->strm_list
);
76 init_waitqueue_head(&stream
->wait
);
79 * We should have a decompressor at least as default
80 * so if we fail to allocate new decompressor dynamically,
81 * we could always fall back to default decompressor and
84 decomp_strm
= kmalloc(sizeof(*decomp_strm
), GFP_KERNEL
);
88 decomp_strm
->stream
= msblk
->decompressor
->init(msblk
,
90 if (IS_ERR(decomp_strm
->stream
)) {
91 err
= PTR_ERR(decomp_strm
->stream
);
95 list_add(&decomp_strm
->list
, &stream
->strm_list
);
96 stream
->avail_decomp
= 1;
106 void squashfs_decompressor_destroy(struct squashfs_sb_info
*msblk
)
108 struct squashfs_stream
*stream
= msblk
->stream
;
110 struct decomp_stream
*decomp_strm
;
112 while (!list_empty(&stream
->strm_list
)) {
113 decomp_strm
= list_entry(stream
->strm_list
.prev
,
114 struct decomp_stream
, list
);
115 list_del(&decomp_strm
->list
);
116 msblk
->decompressor
->free(decomp_strm
->stream
);
118 stream
->avail_decomp
--;
120 WARN_ON(stream
->avail_decomp
);
121 kfree(stream
->comp_opts
);
127 static struct decomp_stream
*get_decomp_stream(struct squashfs_sb_info
*msblk
,
128 struct squashfs_stream
*stream
)
130 struct decomp_stream
*decomp_strm
;
133 mutex_lock(&stream
->mutex
);
135 /* There is available decomp_stream */
136 if (!list_empty(&stream
->strm_list
)) {
137 decomp_strm
= list_entry(stream
->strm_list
.prev
,
138 struct decomp_stream
, list
);
139 list_del(&decomp_strm
->list
);
140 mutex_unlock(&stream
->mutex
);
145 * If there is no available decomp and already full,
146 * let's wait for releasing decomp from other users.
148 if (stream
->avail_decomp
>= MAX_DECOMPRESSOR
)
151 /* Let's allocate new decomp */
152 decomp_strm
= kmalloc(sizeof(*decomp_strm
), GFP_KERNEL
);
156 decomp_strm
->stream
= msblk
->decompressor
->init(msblk
,
158 if (IS_ERR(decomp_strm
->stream
)) {
163 stream
->avail_decomp
++;
164 WARN_ON(stream
->avail_decomp
> MAX_DECOMPRESSOR
);
166 mutex_unlock(&stream
->mutex
);
170 * If system memory is tough, let's for other's
171 * releasing instead of hurting VM because it could
172 * make page cache thrashing.
174 mutex_unlock(&stream
->mutex
);
175 wait_event(stream
->wait
,
176 !list_empty(&stream
->strm_list
));
183 int squashfs_decompress(struct squashfs_sb_info
*msblk
, struct bio
*bio
,
184 int offset
, int length
,
185 struct squashfs_page_actor
*output
)
188 struct squashfs_stream
*stream
= msblk
->stream
;
189 struct decomp_stream
*decomp_stream
= get_decomp_stream(msblk
, stream
);
190 res
= msblk
->decompressor
->decompress(msblk
, decomp_stream
->stream
,
191 bio
, offset
, length
, output
);
192 put_decomp_stream(decomp_stream
, stream
);
194 ERROR("%s decompression failed, data probably corrupt\n",
195 msblk
->decompressor
->name
);