1 /* 2 * Copyright (c) 2013 3 * Minchan Kim <minchan@kernel.org> 4 * 5 * This work is licensed under the terms of the GNU GPL, version 2. See 6 * the COPYING file in the top-level directory. 7 */ 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> 15 16 #include "squashfs_fs.h" 17 #include "squashfs_fs_sb.h" 18 #include "decompressor.h" 19 #include "squashfs.h" 20 21 /* 22 * This file implements multi-threaded decompression in the 23 * decompressor framework 24 */ 25 26 27 /* 28 * The reason that multiply two is that a CPU can request new I/O 29 * while it is waiting previous request. 30 */ 31 #define MAX_DECOMPRESSOR (num_online_cpus() * 2) 32 33 34 int squashfs_max_decompressors(void) 35 { 36 return MAX_DECOMPRESSOR; 37 } 38 39 40 struct squashfs_stream { 41 void *comp_opts; 42 struct list_head strm_list; 43 struct mutex mutex; 44 int avail_decomp; 45 wait_queue_head_t wait; 46 }; 47 48 49 struct decomp_stream { 50 void *stream; 51 struct list_head list; 52 }; 53 54 55 static void put_decomp_stream(struct decomp_stream *decomp_strm, 56 struct squashfs_stream *stream) 57 { 58 mutex_lock(&stream->mutex); 59 list_add(&decomp_strm->list, &stream->strm_list); 60 mutex_unlock(&stream->mutex); 61 wake_up(&stream->wait); 62 } 63 64 void *squashfs_decompressor_create(struct squashfs_sb_info *msblk, 65 void *comp_opts) 66 { 67 struct squashfs_stream *stream; 68 struct decomp_stream *decomp_strm = NULL; 69 int err = -ENOMEM; 70 71 stream = kzalloc(sizeof(*stream), GFP_KERNEL); 72 if (!stream) 73 goto out; 74 75 stream->comp_opts = comp_opts; 76 mutex_init(&stream->mutex); 77 INIT_LIST_HEAD(&stream->strm_list); 78 init_waitqueue_head(&stream->wait); 79 80 /* 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 84 * file system works. 85 */ 86 decomp_strm = kmalloc(sizeof(*decomp_strm), GFP_KERNEL); 87 if (!decomp_strm) 88 goto out; 89 90 decomp_strm->stream = msblk->decompressor->init(msblk, 91 stream->comp_opts); 92 if (IS_ERR(decomp_strm->stream)) { 93 err = PTR_ERR(decomp_strm->stream); 94 goto out; 95 } 96 97 list_add(&decomp_strm->list, &stream->strm_list); 98 stream->avail_decomp = 1; 99 return stream; 100 101 out: 102 kfree(decomp_strm); 103 kfree(stream); 104 return ERR_PTR(err); 105 } 106 107 108 void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk) 109 { 110 struct squashfs_stream *stream = msblk->stream; 111 if (stream) { 112 struct decomp_stream *decomp_strm; 113 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); 119 kfree(decomp_strm); 120 stream->avail_decomp--; 121 } 122 WARN_ON(stream->avail_decomp); 123 kfree(stream->comp_opts); 124 kfree(stream); 125 } 126 } 127 128 129 static struct decomp_stream *get_decomp_stream(struct squashfs_sb_info *msblk, 130 struct squashfs_stream *stream) 131 { 132 struct decomp_stream *decomp_strm; 133 134 while (1) { 135 mutex_lock(&stream->mutex); 136 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); 143 break; 144 } 145 146 /* 147 * If there is no available decomp and already full, 148 * let's wait for releasing decomp from other users. 149 */ 150 if (stream->avail_decomp >= MAX_DECOMPRESSOR) 151 goto wait; 152 153 /* Let's allocate new decomp */ 154 decomp_strm = kmalloc(sizeof(*decomp_strm), GFP_KERNEL); 155 if (!decomp_strm) 156 goto wait; 157 158 decomp_strm->stream = msblk->decompressor->init(msblk, 159 stream->comp_opts); 160 if (IS_ERR(decomp_strm->stream)) { 161 kfree(decomp_strm); 162 goto wait; 163 } 164 165 stream->avail_decomp++; 166 WARN_ON(stream->avail_decomp > MAX_DECOMPRESSOR); 167 168 mutex_unlock(&stream->mutex); 169 break; 170 wait: 171 /* 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. 175 */ 176 mutex_unlock(&stream->mutex); 177 wait_event(stream->wait, 178 !list_empty(&stream->strm_list)); 179 } 180 181 return decomp_strm; 182 } 183 184 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) 187 { 188 int res; 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); 194 if (res < 0) 195 ERROR("%s decompression failed, data probably corrupt\n", 196 msblk->decompressor->name); 197 return res; 198 } 199