~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/squashfs/decompressor_multi.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  *  Copyright (c) 2013
  4  *  Minchan Kim <minchan@kernel.org>
  5  */
  6 #include <linux/types.h>
  7 #include <linux/mutex.h>
  8 #include <linux/slab.h>
  9 #include <linux/bio.h>
 10 #include <linux/sched.h>
 11 #include <linux/wait.h>
 12 #include <linux/cpumask.h>
 13 
 14 #include "squashfs_fs.h"
 15 #include "squashfs_fs_sb.h"
 16 #include "decompressor.h"
 17 #include "squashfs.h"
 18 
 19 /*
 20  * This file implements multi-threaded decompression in the
 21  * decompressor framework
 22  */
 23 
 24 
 25 /*
 26  * The reason that multiply two is that a CPU can request new I/O
 27  * while it is waiting previous request.
 28  */
 29 #define MAX_DECOMPRESSOR        (num_online_cpus() * 2)
 30 
 31 
 32 static int squashfs_max_decompressors(void)
 33 {
 34         return MAX_DECOMPRESSOR;
 35 }
 36 
 37 struct squashfs_stream {
 38         void                    *comp_opts;
 39         struct list_head        strm_list;
 40         struct mutex            mutex;
 41         int                     avail_decomp;
 42         wait_queue_head_t       wait;
 43 };
 44 
 45 
 46 struct decomp_stream {
 47         void *stream;
 48         struct list_head list;
 49 };
 50 
 51 
 52 static void put_decomp_stream(struct decomp_stream *decomp_strm,
 53                                 struct squashfs_stream *stream)
 54 {
 55         mutex_lock(&stream->mutex);
 56         list_add(&decomp_strm->list, &stream->strm_list);
 57         mutex_unlock(&stream->mutex);
 58         wake_up(&stream->wait);
 59 }
 60 
 61 static void *squashfs_decompressor_create(struct squashfs_sb_info *msblk,
 62                                 void *comp_opts)
 63 {
 64         struct squashfs_stream *stream;
 65         struct decomp_stream *decomp_strm = NULL;
 66         int err = -ENOMEM;
 67 
 68         stream = kzalloc(sizeof(*stream), GFP_KERNEL);
 69         if (!stream)
 70                 goto out;
 71 
 72         stream->comp_opts = comp_opts;
 73         mutex_init(&stream->mutex);
 74         INIT_LIST_HEAD(&stream->strm_list);
 75         init_waitqueue_head(&stream->wait);
 76 
 77         /*
 78          * We should have a decompressor at least as default
 79          * so if we fail to allocate new decompressor dynamically,
 80          * we could always fall back to default decompressor and
 81          * file system works.
 82          */
 83         decomp_strm = kmalloc(sizeof(*decomp_strm), GFP_KERNEL);
 84         if (!decomp_strm)
 85                 goto out;
 86 
 87         decomp_strm->stream = msblk->decompressor->init(msblk,
 88                                                 stream->comp_opts);
 89         if (IS_ERR(decomp_strm->stream)) {
 90                 err = PTR_ERR(decomp_strm->stream);
 91                 goto out;
 92         }
 93 
 94         list_add(&decomp_strm->list, &stream->strm_list);
 95         stream->avail_decomp = 1;
 96         return stream;
 97 
 98 out:
 99         kfree(decomp_strm);
100         kfree(stream);
101         return ERR_PTR(err);
102 }
103 
104 
105 static void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
106 {
107         struct squashfs_stream *stream = msblk->stream;
108         if (stream) {
109                 struct decomp_stream *decomp_strm;
110 
111                 while (!list_empty(&stream->strm_list)) {
112                         decomp_strm = list_entry(stream->strm_list.prev,
113                                                 struct decomp_stream, list);
114                         list_del(&decomp_strm->list);
115                         msblk->decompressor->free(decomp_strm->stream);
116                         kfree(decomp_strm);
117                         stream->avail_decomp--;
118                 }
119                 WARN_ON(stream->avail_decomp);
120                 kfree(stream->comp_opts);
121                 kfree(stream);
122         }
123 }
124 
125 
126 static struct decomp_stream *get_decomp_stream(struct squashfs_sb_info *msblk,
127                                         struct squashfs_stream *stream)
128 {
129         struct decomp_stream *decomp_strm;
130 
131         while (1) {
132                 mutex_lock(&stream->mutex);
133 
134                 /* There is available decomp_stream */
135                 if (!list_empty(&stream->strm_list)) {
136                         decomp_strm = list_entry(stream->strm_list.prev,
137                                 struct decomp_stream, list);
138                         list_del(&decomp_strm->list);
139                         mutex_unlock(&stream->mutex);
140                         break;
141                 }
142 
143                 /*
144                  * If there is no available decomp and already full,
145                  * let's wait for releasing decomp from other users.
146                  */
147                 if (stream->avail_decomp >= msblk->max_thread_num)
148                         goto wait;
149 
150                 /* Let's allocate new decomp */
151                 decomp_strm = kmalloc(sizeof(*decomp_strm), GFP_KERNEL);
152                 if (!decomp_strm)
153                         goto wait;
154 
155                 decomp_strm->stream = msblk->decompressor->init(msblk,
156                                                 stream->comp_opts);
157                 if (IS_ERR(decomp_strm->stream)) {
158                         kfree(decomp_strm);
159                         goto wait;
160                 }
161 
162                 stream->avail_decomp++;
163                 WARN_ON(stream->avail_decomp > msblk->max_thread_num);
164 
165                 mutex_unlock(&stream->mutex);
166                 break;
167 wait:
168                 /*
169                  * If system memory is tough, let's for other's
170                  * releasing instead of hurting VM because it could
171                  * make page cache thrashing.
172                  */
173                 mutex_unlock(&stream->mutex);
174                 wait_event(stream->wait,
175                         !list_empty(&stream->strm_list));
176         }
177 
178         return decomp_strm;
179 }
180 
181 
182 static int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
183                         int offset, int length,
184                         struct squashfs_page_actor *output)
185 {
186         int res;
187         struct squashfs_stream *stream = msblk->stream;
188         struct decomp_stream *decomp_stream = get_decomp_stream(msblk, stream);
189         res = msblk->decompressor->decompress(msblk, decomp_stream->stream,
190                 bio, offset, length, output);
191         put_decomp_stream(decomp_stream, stream);
192         if (res < 0)
193                 ERROR("%s decompression failed, data probably corrupt\n",
194                         msblk->decompressor->name);
195         return res;
196 }
197 
198 const struct squashfs_decompressor_thread_ops squashfs_decompressor_multi = {
199         .create = squashfs_decompressor_create,
200         .destroy = squashfs_decompressor_destroy,
201         .decompress = squashfs_decompress,
202         .max_decompressors = squashfs_max_decompressors,
203 };
204 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php