3 * Minchan Kim <minchan@kernel.org>
5 * This work is licensed under the terms of the GNU GPL, version 2. See
6 * the COPYING file in the top-level directory.
8 #include <linux/types.h>
9 #include <linux/mutex.h>
10 #include <linux/slab.h>
11 #include <linux/buffer_head.h>
12 #include <linux/sched.h>
13 #include <linux/wait.h>
14 #include <linux/cpumask.h>
16 #include "squashfs_fs.h"
17 #include "squashfs_fs_sb.h"
18 #include "decompressor.h"
22 * This file implements multi-threaded decompression in the
23 * decompressor framework
28 * The reason that multiply two is that a CPU can request new I/O
29 * while it is waiting previous request.
31 #define MAX_DECOMPRESSOR (num_online_cpus() * 2)
34 int squashfs_max_decompressors(void)
36 return MAX_DECOMPRESSOR
;
40 struct squashfs_stream
{
42 struct list_head strm_list
;
45 wait_queue_head_t wait
;
49 struct decomp_stream
{
51 struct list_head list
;
55 static void put_decomp_stream(struct decomp_stream
*decomp_strm
,
56 struct squashfs_stream
*stream
)
58 mutex_lock(&stream
->mutex
);
59 list_add(&decomp_strm
->list
, &stream
->strm_list
);
60 mutex_unlock(&stream
->mutex
);
61 wake_up(&stream
->wait
);
64 void *squashfs_decompressor_create(struct squashfs_sb_info
*msblk
,
67 struct squashfs_stream
*stream
;
68 struct decomp_stream
*decomp_strm
= NULL
;
71 stream
= kzalloc(sizeof(*stream
), GFP_KERNEL
);
75 stream
->comp_opts
= comp_opts
;
76 mutex_init(&stream
->mutex
);
77 INIT_LIST_HEAD(&stream
->strm_list
);
78 init_waitqueue_head(&stream
->wait
);
81 * We should have a decompressor at least as default
82 * so if we fail to allocate new decompressor dynamically,
83 * we could always fall back to default decompressor and
86 decomp_strm
= kmalloc(sizeof(*decomp_strm
), GFP_KERNEL
);
90 decomp_strm
->stream
= msblk
->decompressor
->init(msblk
,
92 if (IS_ERR(decomp_strm
->stream
)) {
93 err
= PTR_ERR(decomp_strm
->stream
);
97 list_add(&decomp_strm
->list
, &stream
->strm_list
);
98 stream
->avail_decomp
= 1;
108 void squashfs_decompressor_destroy(struct squashfs_sb_info
*msblk
)
110 struct squashfs_stream
*stream
= msblk
->stream
;
112 struct decomp_stream
*decomp_strm
;
114 while (!list_empty(&stream
->strm_list
)) {
115 decomp_strm
= list_entry(stream
->strm_list
.prev
,
116 struct decomp_stream
, list
);
117 list_del(&decomp_strm
->list
);
118 msblk
->decompressor
->free(decomp_strm
->stream
);
120 stream
->avail_decomp
--;
122 WARN_ON(stream
->avail_decomp
);
123 kfree(stream
->comp_opts
);
129 static struct decomp_stream
*get_decomp_stream(struct squashfs_sb_info
*msblk
,
130 struct squashfs_stream
*stream
)
132 struct decomp_stream
*decomp_strm
;
135 mutex_lock(&stream
->mutex
);
137 /* There is available decomp_stream */
138 if (!list_empty(&stream
->strm_list
)) {
139 decomp_strm
= list_entry(stream
->strm_list
.prev
,
140 struct decomp_stream
, list
);
141 list_del(&decomp_strm
->list
);
142 mutex_unlock(&stream
->mutex
);
147 * If there is no available decomp and already full,
148 * let's wait for releasing decomp from other users.
150 if (stream
->avail_decomp
>= MAX_DECOMPRESSOR
)
153 /* Let's allocate new decomp */
154 decomp_strm
= kmalloc(sizeof(*decomp_strm
), GFP_KERNEL
);
158 decomp_strm
->stream
= msblk
->decompressor
->init(msblk
,
160 if (IS_ERR(decomp_strm
->stream
)) {
165 stream
->avail_decomp
++;
166 WARN_ON(stream
->avail_decomp
> MAX_DECOMPRESSOR
);
168 mutex_unlock(&stream
->mutex
);
172 * If system memory is tough, let's for other's
173 * releasing instead of hurting VM because it could
174 * make page cache thrashing.
176 mutex_unlock(&stream
->mutex
);
177 wait_event(stream
->wait
,
178 !list_empty(&stream
->strm_list
));
185 int squashfs_decompress(struct squashfs_sb_info
*msblk
, struct buffer_head
**bh
,
186 int b
, int offset
, int length
, struct squashfs_page_actor
*output
)
189 struct squashfs_stream
*stream
= msblk
->stream
;
190 struct decomp_stream
*decomp_stream
= get_decomp_stream(msblk
, stream
);
191 res
= msblk
->decompressor
->decompress(msblk
, decomp_stream
->stream
,
192 bh
, b
, offset
, length
, output
);
193 put_decomp_stream(decomp_stream
, stream
);
195 ERROR("%s decompression failed, data probably corrupt\n",
196 msblk
->decompressor
->name
);