rev |
line source |
pascal@17214
|
1 --- cloop.h
|
pascal@17214
|
2 +++ cloop.h
|
pascal@23761
|
3 @@ -1,15 +1,50 @@
|
pascal@23761
|
4 +#define CLOOP_SIGNATURE "#!/bin/sh" /* @ offset 0 */
|
pascal@23761
|
5 +#define CLOOP_SIGNATURE_SIZE 9
|
pascal@23761
|
6 +#define CLOOP_SIGNATURE_OFFSET 0x0
|
pascal@23761
|
7 +
|
pascal@23761
|
8 #ifndef _COMPRESSED_LOOP_H
|
pascal@23761
|
9 #define _COMPRESSED_LOOP_H
|
pascal@23761
|
10
|
pascal@23761
|
11 -#define CLOOP_HEADROOM 128
|
pascal@23761
|
12 +/*************************************************************************\
|
pascal@23761
|
13 +* Starting with Format V4.0 (cloop version 4.x), cloop can now have two *
|
pascal@23761
|
14 +* alternative structures: *
|
pascal@23761
|
15 +* *
|
pascal@23761
|
16 +* 1. Header first: "robust" format, handles missing blocks well *
|
pascal@23761
|
17 +* 2. Footer (header last): "streaming" format, easier to create *
|
pascal@23761
|
18 +* *
|
pascal@23761
|
19 +* The cloop kernel module autodetects both formats, and can (currently) *
|
pascal@23761
|
20 +* still handle the V2.0 format as well. *
|
pascal@23761
|
21 +* *
|
pascal@23761
|
22 +* 1. Header first: *
|
pascal@23761
|
23 +* +---------------------------- FIXED SIZE ---------------------------+ *
|
pascal@23761
|
24 +* |Signature (128 bytes) | *
|
pascal@23761
|
25 +* |block_size (32bit number, network order) | *
|
pascal@23761
|
26 +* |num_blocks (32bit number, network order) | *
|
pascal@23761
|
27 +* +--------------------------- VARIABLE SIZE -------------------------+ *
|
pascal@23761
|
28 +* |num_blocks * FlagsOffset (upper 4 bits flags, lower 64 bits offset)| *
|
pascal@23761
|
29 +* |compressed data blocks of variable size ... | *
|
pascal@23761
|
30 +* +-------------------------------------------------------------------+ *
|
pascal@23761
|
31 +* *
|
pascal@23761
|
32 +* 2. Footer (header last): *
|
pascal@23761
|
33 +* +--------------------------- VARIABLE SIZE -------------------------+ *
|
pascal@23761
|
34 +* |compressed data blocks of variable size ... | *
|
pascal@23761
|
35 +* |num_blocks * FlagsOffset (upper 4 bits flags, lower 64 bits offset)| *
|
pascal@23761
|
36 +* +---------------------------- FIXED SIZE ---------------------------+ *
|
pascal@23761
|
37 +* |Signature (128 bytes) | *
|
pascal@23761
|
38 +* |block_size (32bit number, network order) | *
|
pascal@23761
|
39 +* |num_blocks (32bit number, network order) | *
|
pascal@23761
|
40 +* +-------------------------------------------------------------------+ *
|
pascal@23761
|
41 +* *
|
pascal@23761
|
42 +* Offsets are always relative to beginning of file, in all formats. *
|
pascal@23761
|
43 +* The block index contains num_blocks+1 offsets, followed (1) or *
|
pascal@23761
|
44 +* preceded (2) by the compressed blocks. *
|
pascal@23761
|
45 +\*************************************************************************/
|
pascal@23761
|
46
|
pascal@23761
|
47 -/* The cloop header usually looks like this: */
|
pascal@23761
|
48 -/* #!/bin/sh */
|
pascal@23761
|
49 -/* #V2.00 Format */
|
pascal@23761
|
50 -/* ...padding up to CLOOP_HEADROOM... */
|
pascal@23761
|
51 -/* block_size (32bit number, network order) */
|
pascal@23761
|
52 -/* num_blocks (32bit number, network order) */
|
pascal@23761
|
53 +#include <linux/types.h> /* u_int32_t */
|
pascal@23761
|
54 +
|
pascal@23761
|
55 +#define CLOOP_HEADROOM 128
|
pascal@23761
|
56
|
pascal@23761
|
57 +/* Header of fixed length, can be located at beginning or end of file */
|
pascal@23761
|
58 struct cloop_head
|
pascal@23761
|
59 {
|
pascal@23761
|
60 char preamble[CLOOP_HEADROOM];
|
pascal@23761
|
61 @@ -17,9 +52,163 @@
|
pascal@23761
|
62 u_int32_t num_blocks;
|
pascal@23761
|
63 };
|
pascal@23761
|
64
|
pascal@23761
|
65 +/************************************************************************\
|
pascal@23761
|
66 +* CLOOP4 flags for each compressed block *
|
pascal@23761
|
67 +* Value Meaning *
|
pascal@23761
|
68 +* 0 GZIP/7ZIP compression (compatible with V2.0 Format) *
|
pascal@23761
|
69 +* 1 no compression (incompressible data) *
|
pascal@23761
|
70 +* 2 xz compression (currently best space saver) *
|
pascal@23761
|
71 +* 3 lz4 compression *
|
pascal@23761
|
72 +* 4 lzo compression (fastest) *
|
pascal@23761
|
73 +\************************************************************************/
|
pascal@23761
|
74 +
|
pascal@23761
|
75 +typedef uint64_t cloop_block_ptr;
|
pascal@23761
|
76 +
|
pascal@23761
|
77 +/* Get value of first 4 bits */
|
pascal@23761
|
78 +#define CLOOP_BLOCK_FLAGS(x) ((unsigned int)(((x) & 0xf000000000000000LLU) >> 60))
|
pascal@23761
|
79 +/* Get value of last 60 bits */
|
pascal@23761
|
80 +#define CLOOP_BLOCK_OFFSET(x) ((x) & 0x0fffffffffffffffLLU)
|
pascal@23761
|
81 +
|
pascal@23761
|
82 +#define CLOOP_COMPRESSOR_ZLIB 0x0
|
pascal@23761
|
83 +#define CLOOP_COMPRESSOR_NONE 0x1
|
pascal@23761
|
84 +#define CLOOP_COMPRESSOR_XZ 0x2
|
pascal@23761
|
85 +#define CLOOP_COMPRESSOR_LZ4 0x3
|
pascal@23761
|
86 +#define CLOOP_COMPRESSOR_LZO1X 0x4
|
pascal@23761
|
87 +
|
pascal@23761
|
88 +#define CLOOP_COMPRESSOR_VALID(x) ((x) >= CLOOP_COMPRESSOR_ZLIB && (x) <= CLOOP_COMPRESSOR_LZO1X)
|
pascal@23761
|
89 +
|
pascal@23761
|
90 +#define CLOOP_COMPRESSOR_LINK 0xF
|
pascal@23761
|
91 +
|
pascal@23761
|
92 +
|
pascal@17214
|
93 /* data_index (num_blocks 64bit pointers, network order)... */
|
pascal@17214
|
94 /* compressed data (gzip block compressed format)... */
|
pascal@17214
|
95
|
pascal@17214
|
96 +struct cloop_tail
|
pascal@17214
|
97 +{
|
pascal@23761
|
98 + u_int32_t table_size;
|
pascal@23761
|
99 + u_int32_t index_size; /* size:4 comp:3 ctrl-c:1 lastlen:24 */
|
pascal@23761
|
100 +#define CLOOP3_INDEX_SIZE(x) ((unsigned int)((x) & 0xF))
|
pascal@23761
|
101 +#define CLOOP3_BLOCKS_FLAGS(x) ((unsigned int)((x) & 0x70) >> 4)
|
pascal@23761
|
102 +#define CLOOP3_TRUNCATED(x) ((unsigned int)((x) & 0x80) >> 7)
|
pascal@23761
|
103 +#define CLOOP3_LASTLEN(x) (unsigned int)((x) >> 8)
|
pascal@17214
|
104 + u_int32_t num_blocks;
|
pascal@17214
|
105 +};
|
pascal@17214
|
106 +
|
pascal@23761
|
107 +#define GZIP_MAX_BUFFER(n) ((n) + (n)/1000 + 12)
|
pascal@23761
|
108 +
|
pascal@17214
|
109 +struct block_info
|
pascal@17214
|
110 +{
|
pascal@17214
|
111 + loff_t offset; /* 64-bit offsets of compressed block */
|
pascal@17214
|
112 + u_int32_t size; /* 32-bit compressed block size */
|
pascal@23761
|
113 + u_int32_t flags; /* 32-bit compression flags */
|
pascal@17214
|
114 +};
|
pascal@17214
|
115 +
|
pascal@23761
|
116 +static inline char *build_index(struct block_info *offsets, unsigned long n,
|
pascal@23761
|
117 + unsigned long block_size, unsigned global_flags)
|
pascal@17214
|
118 +{
|
pascal@17214
|
119 + u_int32_t *ofs32 = (u_int32_t *) offsets;
|
pascal@17214
|
120 + loff_t *ofs64 = (loff_t *) offsets;
|
pascal@23761
|
121 +
|
pascal@23761
|
122 + /* v3 64bits bug: v1 assumed */
|
pascal@23761
|
123 + unsigned long v3_64 = (n+1)/2;
|
pascal@23761
|
124 + loff_t prev;
|
pascal@23761
|
125 +
|
pascal@23761
|
126 + if (ofs32[0] != 0 && ofs32[1] == 0) {
|
pascal@23761
|
127 + for (prev=__le64_to_cpu(ofs64[v3_64]);
|
pascal@23761
|
128 + v3_64 > 0 && __le64_to_cpu(ofs64[--v3_64]) < prev;
|
pascal@23761
|
129 + prev=__le64_to_cpu(ofs64[v3_64]));
|
pascal@23761
|
130 + }
|
pascal@23761
|
131 +
|
pascal@17214
|
132 + if (ofs32[0] == 0) {
|
pascal@17214
|
133 + if (ofs32[2]) { /* ACCELERATED KNOPPIX V1.0 */
|
pascal@17214
|
134 + while (n--) {
|
pascal@17214
|
135 + offsets[n].offset = __be64_to_cpu(offsets[n].offset);
|
pascal@17214
|
136 + offsets[n].size = ntohl(offsets[n].size);
|
pascal@23761
|
137 + offsets[n].flags = 0;
|
pascal@17214
|
138 + }
|
pascal@17214
|
139 + return (char *) "128BE accelerated knoppix 1.0";
|
pascal@17214
|
140 + }
|
pascal@23761
|
141 + else { /* V2.0/V4.0 */
|
pascal@23761
|
142 + loff_t last = CLOOP_BLOCK_OFFSET(__be64_to_cpu(ofs64[n]));
|
pascal@23761
|
143 + u_int32_t flags;
|
pascal@23761
|
144 + static char v4[11];
|
pascal@23761
|
145 + unsigned long i = n;
|
pascal@23761
|
146 +
|
pascal@23761
|
147 + for (flags = 0; n-- ;) {
|
pascal@23761
|
148 + loff_t data = __be64_to_cpu(ofs64[n]);
|
pascal@23761
|
149 +
|
pascal@17214
|
150 + offsets[n].size = last -
|
pascal@23761
|
151 + (offsets[n].offset = CLOOP_BLOCK_OFFSET(data));
|
pascal@17214
|
152 + last = offsets[n].offset;
|
pascal@23761
|
153 + offsets[n].flags = CLOOP_BLOCK_FLAGS(data);
|
pascal@23761
|
154 + flags |= 1 << offsets[n].flags;
|
pascal@17214
|
155 + }
|
pascal@23761
|
156 + if (flags < 2) return (char *) "64BE v2.0";
|
pascal@23761
|
157 + while (i--) {
|
pascal@23761
|
158 + if (offsets[i].flags == CLOOP_COMPRESSOR_LINK) {
|
pascal@23761
|
159 + offsets[i] = offsets[offsets[i].offset];
|
pascal@23761
|
160 + }
|
pascal@23761
|
161 + }
|
pascal@23761
|
162 + strcpy(v4, (char *) "64BE v4.0a");
|
pascal@23761
|
163 + v4[10] = 'a' + ((flags-1) & 0xF); // compressors used
|
pascal@23761
|
164 + if (flags > 0x10) { // with links ?
|
pascal@23761
|
165 + v4[10] += 'A' - 'a';
|
pascal@23761
|
166 + }
|
pascal@23761
|
167 + return v4;
|
pascal@17214
|
168 + }
|
pascal@17214
|
169 + }
|
pascal@23761
|
170 + else if (ofs32[1] == 0 && v3_64 == 0) { /* V1.0 */
|
pascal@23761
|
171 + loff_t last = __le64_to_cpu(ofs64[n]);
|
pascal@17214
|
172 + while (n--) {
|
pascal@17214
|
173 + offsets[n].size = last -
|
pascal@17214
|
174 + (offsets[n].offset = __le64_to_cpu(ofs64[n]));
|
pascal@17214
|
175 + last = offsets[n].offset;
|
pascal@23761
|
176 + offsets[n].flags = 0;
|
pascal@17214
|
177 + }
|
pascal@17214
|
178 + return (char *) "64LE v1.0";
|
pascal@17214
|
179 + }
|
pascal@23761
|
180 + else { /* V3.0 or V0.68 */
|
pascal@17214
|
181 + unsigned long i;
|
pascal@17214
|
182 + loff_t j;
|
pascal@23761
|
183 + static char v3[11];
|
pascal@17214
|
184 +
|
pascal@23761
|
185 + for (i = 0; i < n && ntohl(ofs32[i]) < ntohl(ofs32[i+1]); i++);
|
pascal@23761
|
186 + if (i == n && ntohl(ofs32[0]) == (4*n) + 0x8C) { /* V0.68 */
|
pascal@23761
|
187 + loff_t last = ntohl(ofs32[n]);
|
pascal@23761
|
188 + while (n--) {
|
pascal@23761
|
189 + offsets[n].size = last -
|
pascal@23761
|
190 + (offsets[n].offset = ntohl(ofs32[n]));
|
pascal@23761
|
191 + last = offsets[n].offset;
|
pascal@23761
|
192 + offsets[n].flags = 0;
|
pascal@23761
|
193 + }
|
pascal@23761
|
194 + return (char *) "32BE v0.68";
|
pascal@23761
|
195 + }
|
pascal@23761
|
196 +
|
pascal@23761
|
197 + v3_64 = (ofs32[1] == 0);
|
pascal@17214
|
198 + for (i = n; i-- != 0; )
|
pascal@23761
|
199 + offsets[i].size = ntohl(ofs32[i << v3_64]);
|
pascal@17214
|
200 + for (i = 0, j = sizeof(struct cloop_head); i < n; i++) {
|
pascal@17214
|
201 + offsets[i].offset = j;
|
pascal@23761
|
202 + offsets[i].flags = global_flags;
|
pascal@23761
|
203 + if (offsets[i].size == 0xFFFFFFFF) {
|
pascal@23761
|
204 + offsets[i].flags = CLOOP_COMPRESSOR_NONE;
|
pascal@23761
|
205 + offsets[i].size = block_size;
|
pascal@23761
|
206 + }
|
pascal@23761
|
207 + if ((offsets[i].size & 0x80000000) == 0) {
|
pascal@23761
|
208 + j += offsets[i].size;
|
pascal@23761
|
209 + }
|
pascal@23761
|
210 + }
|
pascal@23761
|
211 + for (i = 0; i < n; i++) {
|
pascal@18828
|
212 + if (offsets[i].size & 0x80000000) {
|
pascal@23761
|
213 + offsets[i] = offsets[offsets[i].size & 0x7FFFFFFF];
|
pascal@18828
|
214 + }
|
pascal@17214
|
215 + }
|
pascal@23761
|
216 + strcpy(v3, (char *) (v3_64) ? "64BE v3.0a" : "32BE v3.0a");
|
pascal@23761
|
217 + v3[10] += global_flags;
|
pascal@23761
|
218 + return v3;
|
pascal@17214
|
219 + }
|
pascal@17214
|
220 +}
|
pascal@17214
|
221 +
|
pascal@17214
|
222 /* Cloop suspend IOCTL */
|
pascal@17214
|
223 #define CLOOP_SUSPEND 0x4C07
|
pascal@17214
|
224
|
pascal@17214
|
225 --- cloop.c
|
pascal@17214
|
226 +++ cloop.c
|
pascal@23761
|
227 @@ -1,26 +1,23 @@
|
pascal@23761
|
228 -/*
|
pascal@23761
|
229 - * compressed_loop.c: Read-only compressed loop blockdevice
|
pascal@23761
|
230 - * hacked up by Rusty in 1999, extended and maintained by Klaus Knopper
|
pascal@23761
|
231 - *
|
pascal@23761
|
232 - * A cloop file looks like this:
|
pascal@23761
|
233 - * [32-bit uncompressed block size: network order]
|
pascal@23761
|
234 - * [32-bit number of blocks (n_blocks): network order]
|
pascal@17214
|
235 - * [64-bit file offsets of start of blocks: network order]
|
pascal@23761
|
236 - * ...
|
pascal@23761
|
237 - * (n_blocks + 1).
|
pascal@23761
|
238 - * n_blocks consisting of:
|
pascal@23761
|
239 - * [compressed block]
|
pascal@23761
|
240 - *
|
pascal@23761
|
241 - * Every version greatly inspired by code seen in loop.c
|
pascal@23761
|
242 - * by Theodore Ts'o, 3/29/93.
|
pascal@23761
|
243 - *
|
pascal@23761
|
244 - * Copyright 1999-2009 by Paul `Rusty' Russell & Klaus Knopper.
|
pascal@23761
|
245 - * Redistribution of this file is permitted under the GNU Public License.
|
pascal@23761
|
246 - *
|
pascal@23761
|
247 - */
|
pascal@23761
|
248 +/************************************************************************\
|
pascal@23761
|
249 +* cloop.c: Read-only compressed loop blockdevice *
|
pascal@23761
|
250 +* hacked up by Rusty in 1999, extended and maintained by Klaus Knopper *
|
pascal@23761
|
251 +* *
|
pascal@23761
|
252 +* For all supported cloop file formats, please check the file "cloop.h" *
|
pascal@23761
|
253 +* New in Version 4: *
|
pascal@23761
|
254 +* - Header can be first or last in cloop file, *
|
pascal@23761
|
255 +* - Different compression algorithms supported (compression type *
|
pascal@23761
|
256 +* encoded in first 4 bytes of block offset address) *
|
pascal@23761
|
257 +* *
|
pascal@23761
|
258 +* Every version greatly inspired by code seen in loop.c *
|
pascal@23761
|
259 +* by Theodore Ts'o, 3/29/93. *
|
pascal@23761
|
260 +* *
|
pascal@23761
|
261 +* Copyright 1999-2009 by Paul `Rusty' Russell & Klaus Knopper. *
|
pascal@23761
|
262 +* Redistribution of this file is permitted under the GNU Public License *
|
pascal@23761
|
263 +* V2. *
|
pascal@23761
|
264 +\************************************************************************/
|
pascal@23761
|
265
|
pascal@23761
|
266 #define CLOOP_NAME "cloop"
|
pascal@23761
|
267 -#define CLOOP_VERSION "2.639"
|
pascal@23761
|
268 +#define CLOOP_VERSION "4.12"
|
pascal@23761
|
269 #define CLOOP_MAX 8
|
pascal@23761
|
270
|
pascal@23761
|
271 #ifndef KBUILD_MODNAME
|
pascal@23761
|
272 @@ -47,8 +44,27 @@
|
pascal@23761
|
273 #include <asm/div64.h> /* do_div() for 64bit division */
|
pascal@23761
|
274 #include <asm/uaccess.h>
|
pascal@23761
|
275 #include <asm/byteorder.h>
|
pascal@23761
|
276 -/* Use zlib_inflate from lib/zlib_inflate */
|
pascal@23761
|
277 +/* Check for ZLIB, LZO1X, LZ4 decompression algorithms in kernel. */
|
pascal@23761
|
278 +#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE))
|
pascal@23761
|
279 #include <linux/zutil.h>
|
pascal@23761
|
280 +#endif
|
pascal@23761
|
281 +#if (defined(CONFIG_LZO_DECOMPRESS) || defined(CONFIG_LZO_DECOMPRESS_MODULE))
|
pascal@23761
|
282 +#include <linux/lzo.h>
|
pascal@23761
|
283 +#endif
|
pascal@23761
|
284 +#if (defined(CONFIG_DECOMPRESS_LZ4) || defined(CONFIG_DECOMPRESS_LZ4_MODULE))
|
pascal@23761
|
285 +#include <linux/lz4.h>
|
pascal@23761
|
286 +#endif
|
pascal@23761
|
287 +#if (defined(CONFIG_DECOMPRESS_LZMA) || defined(CONFIG_DECOMPRESS_LZMA_MODULE))
|
pascal@23761
|
288 +#include <linux/decompress/unlzma.h>
|
pascal@23761
|
289 +#endif
|
pascal@23761
|
290 +#if (defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE))
|
pascal@23761
|
291 +#include <linux/xz.h>
|
pascal@23761
|
292 +#endif
|
pascal@23761
|
293 +
|
pascal@23761
|
294 +#if (!(defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE) || defined(CONFIG_LZO_DECOMPRESS) || defined(CONFIG_LZO_DECOMPRESS_MODULE) || defined(CONFIG_DECOMPRESS_LZ4) || defined(CONFIG_DECOMPRESS_LZ4_MODULE) || defined(CONFIG_DECOMPRESS_LZMA) || defined(CONFIG_DECOMPRESS_LZMA_MODULE) || defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE)))
|
pascal@23761
|
295 +#error "No decompression library selected in kernel config!"
|
pascal@23761
|
296 +#endif
|
pascal@23761
|
297 +
|
pascal@23761
|
298 #include <linux/loop.h>
|
pascal@23761
|
299 #include <linux/kthread.h>
|
pascal@23761
|
300 #include <linux/compat.h>
|
pascal@23761
|
301 @@ -92,47 +108,64 @@
|
pascal@23761
|
302 #define DEBUGP(format, x...)
|
pascal@23761
|
303 #endif
|
pascal@23761
|
304
|
pascal@23761
|
305 +/* Default size of buffer to keep some decompressed blocks in memory to speed up access */
|
pascal@23761
|
306 +#define BLOCK_BUFFER_MEM (16*65536)
|
pascal@23761
|
307 +
|
pascal@23761
|
308 /* One file can be opened at module insertion time */
|
pascal@23761
|
309 /* insmod cloop file=/path/to/file */
|
pascal@23761
|
310 static char *file=NULL;
|
pascal@23761
|
311 static unsigned int preload=0;
|
pascal@23761
|
312 static unsigned int cloop_max=CLOOP_MAX;
|
pascal@23761
|
313 +static unsigned int buffers=BLOCK_BUFFER_MEM;
|
pascal@23761
|
314 module_param(file, charp, 0);
|
pascal@23761
|
315 module_param(preload, uint, 0);
|
pascal@23761
|
316 module_param(cloop_max, uint, 0);
|
pascal@23761
|
317 MODULE_PARM_DESC(file, "Initial cloop image file (full path) for /dev/cloop");
|
pascal@23761
|
318 MODULE_PARM_DESC(preload, "Preload n blocks of cloop data into memory");
|
pascal@23761
|
319 MODULE_PARM_DESC(cloop_max, "Maximum number of cloop devices (default 8)");
|
pascal@23761
|
320 +MODULE_PARM_DESC(buffers, "Size of buffer to keep uncompressed blocks in memory in MiB (default 1)");
|
pascal@23761
|
321
|
pascal@23761
|
322 static struct file *initial_file=NULL;
|
pascal@23761
|
323 static int cloop_major=MAJOR_NR;
|
pascal@23761
|
324
|
pascal@23761
|
325 -/* Number of buffered decompressed blocks */
|
pascal@23761
|
326 -#define BUFFERED_BLOCKS 8
|
pascal@23761
|
327 struct cloop_device
|
pascal@23761
|
328 {
|
pascal@23761
|
329 - /* Copied straight from the file */
|
pascal@23761
|
330 + /* Header filled from the file */
|
pascal@17214
|
331 struct cloop_head head;
|
pascal@23761
|
332 + int header_first;
|
pascal@23761
|
333 + int file_format;
|
pascal@17214
|
334
|
pascal@23761
|
335 - /* An array of offsets of compressed blocks within the file */
|
pascal@17214
|
336 - loff_t *offsets;
|
pascal@23761
|
337 + /* An or'd sum of all flags of each compressed block (v3) */
|
pascal@23761
|
338 + u_int32_t allflags;
|
pascal@23761
|
339 +
|
pascal@23761
|
340 + /* An array of cloop_ptr flags/offset for compressed blocks within the file */
|
pascal@23761
|
341 + struct block_info *block_ptrs;
|
pascal@17214
|
342
|
pascal@17214
|
343 /* We buffer some uncompressed blocks for performance */
|
pascal@23761
|
344 - int buffered_blocknum[BUFFERED_BLOCKS];
|
pascal@23761
|
345 - int current_bufnum;
|
pascal@23761
|
346 - void *buffer[BUFFERED_BLOCKS];
|
pascal@23761
|
347 - void *compressed_buffer;
|
pascal@23761
|
348 - size_t preload_array_size; /* Size of pointer array in blocks */
|
pascal@23761
|
349 - size_t preload_size; /* Number of successfully allocated blocks */
|
pascal@23761
|
350 - char **preload_cache; /* Pointers to preloaded blocks */
|
pascal@23761
|
351 + size_t num_buffered_blocks; /* how many uncompressed blocks buffered for performance */
|
pascal@23761
|
352 + int *buffered_blocknum; /* list of numbers of uncompressed blocks in buffer */
|
pascal@23761
|
353 + int current_bufnum; /* which block is current */
|
pascal@23761
|
354 + unsigned char **buffer; /* cache space for num_buffered_blocks uncompressed blocks */
|
pascal@23761
|
355 + void *compressed_buffer; /* space for the largest compressed block */
|
pascal@23761
|
356 + size_t preload_array_size; /* Size of pointer array in blocks */
|
pascal@23761
|
357 + size_t preload_size; /* Number of successfully allocated blocks */
|
pascal@23761
|
358 + char **preload_cache; /* Pointers to preloaded blocks */
|
pascal@17214
|
359
|
pascal@23761
|
360 +#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE))
|
pascal@23761
|
361 z_stream zstream;
|
pascal@23761
|
362 +#endif
|
pascal@23761
|
363 +#if (defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE))
|
pascal@23761
|
364 + struct xz_dec *xzdecoderstate;
|
pascal@23761
|
365 + struct xz_buf xz_buffer;
|
pascal@23761
|
366 +#endif
|
pascal@23761
|
367
|
pascal@23761
|
368 struct file *backing_file; /* associated file */
|
pascal@23761
|
369 struct inode *backing_inode; /* for bmap */
|
pascal@23761
|
370
|
pascal@23761
|
371 + unsigned char *underlying_filename;
|
pascal@23761
|
372 unsigned long largest_block;
|
pascal@23761
|
373 unsigned int underlying_blksize;
|
pascal@23761
|
374 + loff_t underlying_total_size;
|
pascal@23761
|
375 int clo_number;
|
pascal@23761
|
376 int refcnt;
|
pascal@23761
|
377 struct block_device *bdev;
|
pascal@23761
|
378 @@ -147,7 +180,6 @@
|
pascal@23761
|
379 struct request_queue *clo_queue;
|
pascal@23761
|
380 struct gendisk *clo_disk;
|
pascal@23761
|
381 int suspended;
|
pascal@23761
|
382 - char clo_file_name[LO_NAME_SIZE];
|
pascal@23761
|
383 };
|
pascal@23761
|
384
|
pascal@23761
|
385 /* Changed in 2.639: cloop_dev is now a an array of cloop_dev pointers,
|
pascal@23761
|
386 @@ -156,52 +188,113 @@
|
pascal@23761
|
387 static const char *cloop_name=CLOOP_NAME;
|
pascal@23761
|
388 static int cloop_count = 0;
|
pascal@23761
|
389
|
pascal@23761
|
390 -#if (!(defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE))) /* Must be compiled into kernel. */
|
pascal@23761
|
391 -#error "Invalid Kernel configuration. CONFIG_ZLIB_INFLATE support is needed for cloop."
|
pascal@23761
|
392 -#endif
|
pascal@23761
|
393 -
|
pascal@23761
|
394 -/* Use __get_free_pages instead of vmalloc, allows up to 32 pages,
|
pascal@23761
|
395 - * 2MB in one piece */
|
pascal@23761
|
396 static void *cloop_malloc(size_t size)
|
pascal@23761
|
397 {
|
pascal@23761
|
398 - int order = get_order(size);
|
pascal@23761
|
399 - if(order <= KMALLOC_MAX_ORDER)
|
pascal@23761
|
400 - return (void *)kmalloc(size, GFP_KERNEL);
|
pascal@23761
|
401 - else if(order < MAX_ORDER)
|
pascal@23761
|
402 - return (void *)__get_free_pages(GFP_KERNEL, order);
|
pascal@23761
|
403 + /* kmalloc will fail after the system is running for a while, */
|
pascal@23761
|
404 + /* when large orders can't return contiguous memory. */
|
pascal@23761
|
405 + /* Let's just use vmalloc for now. :-/ */
|
pascal@23761
|
406 + /* int order = get_order(size); */
|
pascal@23761
|
407 + /* if(order <= KMALLOC_MAX_ORDER) */
|
pascal@23761
|
408 + /* return (void *)kmalloc(size, GFP_KERNEL); */
|
pascal@23761
|
409 + /* else if(order < MAX_ORDER) */
|
pascal@23761
|
410 + /* return (void *)__get_free_pages(GFP_KERNEL, order); */
|
pascal@23761
|
411 return (void *)vmalloc(size);
|
pascal@23761
|
412 }
|
pascal@23761
|
413
|
pascal@23761
|
414 static void cloop_free(void *mem, size_t size)
|
pascal@23761
|
415 {
|
pascal@23761
|
416 - int order = get_order(size);
|
pascal@23761
|
417 - if(order <= KMALLOC_MAX_ORDER)
|
pascal@23761
|
418 - kfree(mem);
|
pascal@23761
|
419 - else if(order < MAX_ORDER)
|
pascal@23761
|
420 - free_pages((unsigned long)mem, order);
|
pascal@23761
|
421 - else vfree(mem);
|
pascal@23761
|
422 + /* int order = get_order(size); */
|
pascal@23761
|
423 + /* if(order <= KMALLOC_MAX_ORDER) */
|
pascal@23761
|
424 + /* kfree(mem); */
|
pascal@23761
|
425 + /* else if(order < MAX_ORDER) */
|
pascal@23761
|
426 + /* free_pages((unsigned long)mem, order); */
|
pascal@23761
|
427 + /* else */
|
pascal@23761
|
428 + vfree(mem);
|
pascal@23761
|
429 }
|
pascal@23761
|
430
|
pascal@23761
|
431 -static int uncompress(struct cloop_device *clo,
|
pascal@23761
|
432 - unsigned char *dest, unsigned long *destLen,
|
pascal@23761
|
433 - unsigned char *source, unsigned long sourceLen)
|
pascal@23761
|
434 +static int uncompress(struct cloop_device *clo, unsigned char *dest, unsigned long *destLen, unsigned char *source, unsigned long sourceLen, int flags)
|
pascal@23761
|
435 {
|
pascal@23761
|
436 - /* Most of this code can be found in fs/cramfs/uncompress.c */
|
pascal@23761
|
437 - int err;
|
pascal@23761
|
438 - clo->zstream.next_in = source;
|
pascal@23761
|
439 - clo->zstream.avail_in = sourceLen;
|
pascal@23761
|
440 - clo->zstream.next_out = dest;
|
pascal@23761
|
441 - clo->zstream.avail_out = *destLen;
|
pascal@23761
|
442 - err = zlib_inflateReset(&clo->zstream);
|
pascal@23761
|
443 - if (err != Z_OK)
|
pascal@23761
|
444 - {
|
pascal@23761
|
445 - printk(KERN_ERR "%s: zlib_inflateReset error %d\n", cloop_name, err);
|
pascal@23761
|
446 - zlib_inflateEnd(&clo->zstream); zlib_inflateInit(&clo->zstream);
|
pascal@23761
|
447 - }
|
pascal@23761
|
448 - err = zlib_inflate(&clo->zstream, Z_FINISH);
|
pascal@23761
|
449 - *destLen = clo->zstream.total_out;
|
pascal@23761
|
450 - if (err != Z_STREAM_END) return err;
|
pascal@23761
|
451 - return Z_OK;
|
pascal@23761
|
452 + int err = -1;
|
pascal@23761
|
453 + switch(flags)
|
pascal@23761
|
454 + {
|
pascal@23761
|
455 + case CLOOP_COMPRESSOR_NONE:
|
pascal@23761
|
456 + memcpy(dest, source, *destLen = sourceLen);
|
pascal@23761
|
457 + err = Z_OK;
|
pascal@23761
|
458 + break;
|
pascal@23761
|
459 +#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE))
|
pascal@23761
|
460 + case CLOOP_COMPRESSOR_ZLIB:
|
pascal@23761
|
461 + clo->zstream.next_in = source;
|
pascal@23761
|
462 + clo->zstream.avail_in = sourceLen;
|
pascal@23761
|
463 + clo->zstream.next_out = dest;
|
pascal@23761
|
464 + clo->zstream.avail_out = *destLen;
|
pascal@23761
|
465 + err = zlib_inflateReset(&clo->zstream);
|
pascal@23761
|
466 + if (err != Z_OK)
|
pascal@23761
|
467 + {
|
pascal@23761
|
468 + printk(KERN_ERR "%s: zlib_inflateReset error %d\n", cloop_name, err);
|
pascal@23761
|
469 + zlib_inflateEnd(&clo->zstream); zlib_inflateInit(&clo->zstream);
|
pascal@23761
|
470 + }
|
pascal@23761
|
471 + err = zlib_inflate(&clo->zstream, Z_FINISH);
|
pascal@23761
|
472 + *destLen = clo->zstream.total_out;
|
pascal@23761
|
473 + if (err == Z_STREAM_END) err = 0;
|
pascal@23761
|
474 + DEBUGP("cloop: zlib decompression done, ret =%d, size =%lu\n", err, *destLen);
|
pascal@23761
|
475 + break;
|
pascal@23761
|
476 +#endif
|
pascal@23761
|
477 +#if (defined(CONFIG_LZO_DECOMPRESS) || defined(CONFIG_LZO_DECOMPRESS_MODULE))
|
pascal@23761
|
478 + case CLOOP_COMPRESSOR_LZO1X:
|
pascal@23761
|
479 + {
|
pascal@23761
|
480 + size_t tmp = (size_t) clo->head.block_size;
|
pascal@23761
|
481 + err = lzo1x_decompress_safe(source, sourceLen,
|
pascal@23761
|
482 + dest, &tmp);
|
pascal@23761
|
483 + if (err == LZO_E_OK) *destLen = (u_int32_t) tmp;
|
pascal@23761
|
484 + }
|
pascal@23761
|
485 + break;
|
pascal@23761
|
486 +#endif
|
pascal@23761
|
487 +#if (defined(CONFIG_DECOMPRESS_LZ4) || defined(CONFIG_DECOMPRESS_LZ4_MODULE))
|
pascal@23761
|
488 + case CLOOP_COMPRESSOR_LZ4:
|
pascal@23761
|
489 + {
|
pascal@23761
|
490 + size_t outputSize = *destLen;
|
pascal@23761
|
491 + /* We should adjust outputSize here, in case the last block is smaller than block_size */
|
pascal@23761
|
492 +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) /* field removed */
|
pascal@23761
|
493 + err = lz4_decompress(source, (size_t *) &sourceLen,
|
pascal@23761
|
494 + dest, outputSize);
|
pascal@23761
|
495 +#else
|
pascal@23761
|
496 + err = LZ4_decompress_safe(source,
|
pascal@23761
|
497 + dest,
|
pascal@23761
|
498 + sourceLen, outputSize);
|
pascal@23761
|
499 +#endif
|
pascal@23761
|
500 + if (err >= 0)
|
pascal@23761
|
501 + {
|
pascal@23761
|
502 + err = 0;
|
pascal@23761
|
503 + *destLen = outputSize;
|
pascal@23761
|
504 + }
|
pascal@23761
|
505 + }
|
pascal@23761
|
506 + break;
|
pascal@23761
|
507 +#endif
|
pascal@23761
|
508 +#if (defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE))
|
pascal@23761
|
509 + case CLOOP_COMPRESSOR_XZ:
|
pascal@23761
|
510 + clo->xz_buffer.in = source;
|
pascal@23761
|
511 + clo->xz_buffer.in_pos = 0;
|
pascal@23761
|
512 + clo->xz_buffer.in_size = sourceLen;
|
pascal@23761
|
513 + clo->xz_buffer.out = dest;
|
pascal@23761
|
514 + clo->xz_buffer.out_pos = 0;
|
pascal@23761
|
515 + clo->xz_buffer.out_size = *destLen;
|
pascal@23761
|
516 + xz_dec_reset(clo->xzdecoderstate);
|
pascal@23761
|
517 + err = xz_dec_run(clo->xzdecoderstate, &clo->xz_buffer);
|
pascal@23761
|
518 + if (err == XZ_STREAM_END || err == XZ_OK)
|
pascal@23761
|
519 + {
|
pascal@23761
|
520 + err = 0;
|
pascal@23761
|
521 + }
|
pascal@23761
|
522 + else
|
pascal@23761
|
523 + {
|
pascal@23761
|
524 + printk(KERN_ERR "%s: xz_dec_run error %d\n", cloop_name, err);
|
pascal@23761
|
525 + err = 1;
|
pascal@23761
|
526 + }
|
pascal@23761
|
527 + break;
|
pascal@23761
|
528 +#endif
|
pascal@23761
|
529 + default:
|
pascal@23761
|
530 + printk(KERN_ERR "%s: compression method is not supported!\n", cloop_name);
|
pascal@23761
|
531 + }
|
pascal@23761
|
532 + return err;
|
pascal@23761
|
533 }
|
pascal@23761
|
534
|
pascal@23761
|
535 static ssize_t cloop_read_from_file(struct cloop_device *clo, struct file *f, char *buf,
|
pascal@23761
|
536 @@ -220,7 +313,7 @@
|
pascal@23761
|
537
|
pascal@23761
|
538 if(size_read <= 0)
|
pascal@23761
|
539 {
|
pascal@23761
|
540 - printk(KERN_ERR "%s: Read error %d at pos %Lu in file %s, "
|
pascal@23761
|
541 + printk(KERN_ERR "%s: Read error %d at pos %llu in file %s, "
|
pascal@23761
|
542 "%d bytes lost.\n", cloop_name, (int)size_read, pos,
|
pascal@23761
|
543 file, (int)size);
|
pascal@23761
|
544 memset(buf + buf_len - size, 0, size);
|
pascal@23761
|
545 @@ -232,72 +325,84 @@
|
pascal@23761
|
546 }
|
pascal@23761
|
547
|
pascal@23761
|
548 /* This looks more complicated than it is */
|
pascal@23761
|
549 -/* Returns number of block buffer to use for this request */
|
pascal@23761
|
550 +/* Returns number of cache block buffer to use for this request */
|
pascal@23761
|
551 static int cloop_load_buffer(struct cloop_device *clo, int blocknum)
|
pascal@23761
|
552 {
|
pascal@23761
|
553 - unsigned int buf_done = 0;
|
pascal@23761
|
554 - unsigned long buflen;
|
pascal@23761
|
555 - unsigned int buf_length;
|
pascal@23761
|
556 + loff_t compressed_block_offset;
|
pascal@23761
|
557 + long compressed_block_len;
|
pascal@23761
|
558 + long uncompressed_block_len=0;
|
pascal@23761
|
559 int ret;
|
pascal@23761
|
560 int i;
|
pascal@23761
|
561 - if(blocknum > ntohl(clo->head.num_blocks) || blocknum < 0)
|
pascal@23761
|
562 - {
|
pascal@23761
|
563 - printk(KERN_WARNING "%s: Invalid block number %d requested.\n",
|
pascal@23761
|
564 - cloop_name, blocknum);
|
pascal@23761
|
565 - return -1;
|
pascal@23761
|
566 - }
|
pascal@23761
|
567 + if(blocknum > clo->head.num_blocks || blocknum < 0)
|
pascal@23761
|
568 + {
|
pascal@23761
|
569 + printk(KERN_WARNING "%s: Invalid block number %d requested.\n",
|
pascal@23761
|
570 + cloop_name, blocknum);
|
pascal@23761
|
571 + return -1;
|
pascal@23761
|
572 + }
|
pascal@23761
|
573
|
pascal@23761
|
574 /* Quick return if the block we seek is already in one of the buffers. */
|
pascal@23761
|
575 /* Return number of buffer */
|
pascal@23761
|
576 - for(i=0; i<BUFFERED_BLOCKS; i++)
|
pascal@23761
|
577 + for(i=0; i<clo->num_buffered_blocks; i++)
|
pascal@23761
|
578 if (blocknum == clo->buffered_blocknum[i])
|
pascal@23761
|
579 - {
|
pascal@23761
|
580 - DEBUGP(KERN_INFO "cloop_load_buffer: Found buffered block %d\n", i);
|
pascal@23761
|
581 - return i;
|
pascal@23761
|
582 - }
|
pascal@23761
|
583 -
|
pascal@17214
|
584 - buf_length = be64_to_cpu(clo->offsets[blocknum+1]) - be64_to_cpu(clo->offsets[blocknum]);
|
pascal@23761
|
585 -
|
pascal@23761
|
586 -/* Load one compressed block from the file. */
|
pascal@23761
|
587 - cloop_read_from_file(clo, clo->backing_file, (char *)clo->compressed_buffer,
|
pascal@23761
|
588 - be64_to_cpu(clo->offsets[blocknum]), buf_length);
|
pascal@23761
|
589 + {
|
pascal@23761
|
590 + DEBUGP(KERN_INFO "cloop_load_buffer: Found buffered block %d\n", i);
|
pascal@23761
|
591 + return i;
|
pascal@23761
|
592 + }
|
pascal@17214
|
593
|
pascal@23761
|
594 - buflen = ntohl(clo->head.block_size);
|
pascal@23761
|
595 + compressed_block_offset = clo->block_ptrs[blocknum].offset;
|
pascal@23761
|
596 + compressed_block_len = (long) (clo->block_ptrs[blocknum].size) ;
|
pascal@17214
|
597
|
pascal@23761
|
598 - /* Go to next position in the block ring buffer */
|
pascal@23761
|
599 - clo->current_bufnum++;
|
pascal@23761
|
600 - if(clo->current_bufnum >= BUFFERED_BLOCKS) clo->current_bufnum = 0;
|
pascal@23761
|
601 + /* Load one compressed block from the file. */
|
pascal@23761
|
602 + if(compressed_block_offset > 0 && compressed_block_len >= 0) /* sanity check */
|
pascal@23761
|
603 + {
|
pascal@23761
|
604 + size_t n = cloop_read_from_file(clo, clo->backing_file, (char *)clo->compressed_buffer,
|
pascal@23761
|
605 + compressed_block_offset, compressed_block_len);
|
pascal@23761
|
606 + if (n!= compressed_block_len)
|
pascal@23761
|
607 + {
|
pascal@23761
|
608 + printk(KERN_ERR "%s: error while reading %lu bytes @ %llu from file %s\n",
|
pascal@23761
|
609 + cloop_name, compressed_block_len, clo->block_ptrs[blocknum].offset, clo->underlying_filename);
|
pascal@23761
|
610 + /* return -1; */
|
pascal@23761
|
611 + }
|
pascal@23761
|
612 + } else {
|
pascal@23761
|
613 + printk(KERN_ERR "%s: invalid data block len %ld bytes @ %lld from file %s\n",
|
pascal@23761
|
614 + cloop_name, compressed_block_len, clo->block_ptrs[blocknum].offset, clo->underlying_filename);
|
pascal@23761
|
615 + return -1;
|
pascal@23761
|
616 + }
|
pascal@23761
|
617 +
|
pascal@23761
|
618 + /* Go to next position in the cache block buffer (which is used as a cyclic buffer) */
|
pascal@23761
|
619 + if(++clo->current_bufnum >= clo->num_buffered_blocks) clo->current_bufnum = 0;
|
pascal@17214
|
620
|
pascal@23761
|
621 /* Do the uncompression */
|
pascal@23761
|
622 - ret = uncompress(clo, clo->buffer[clo->current_bufnum], &buflen, clo->compressed_buffer,
|
pascal@23761
|
623 - buf_length);
|
pascal@23761
|
624 + uncompressed_block_len = clo->head.block_size;
|
pascal@23761
|
625 + ret = uncompress(clo, clo->buffer[clo->current_bufnum], &uncompressed_block_len,
|
pascal@23761
|
626 + clo->compressed_buffer, compressed_block_len, clo->block_ptrs[blocknum].flags);
|
pascal@23761
|
627 /* DEBUGP("cloop: buflen after uncompress: %ld\n",buflen); */
|
pascal@17214
|
628 if (ret != 0)
|
pascal@23761
|
629 - {
|
pascal@23761
|
630 - printk(KERN_ERR "%s: zlib decompression error %i uncompressing block %u %u/%lu/%u/%u "
|
pascal@23761
|
631 - "%Lu-%Lu\n", cloop_name, ret, blocknum,
|
pascal@23761
|
632 - ntohl(clo->head.block_size), buflen, buf_length, buf_done,
|
pascal@23761
|
633 - be64_to_cpu(clo->offsets[blocknum]), be64_to_cpu(clo->offsets[blocknum+1]));
|
pascal@23761
|
634 - clo->buffered_blocknum[clo->current_bufnum] = -1;
|
pascal@23761
|
635 - return -1;
|
pascal@23761
|
636 - }
|
pascal@23761
|
637 + {
|
pascal@23761
|
638 + printk(KERN_ERR "%s: decompression error %i uncompressing block %u %lu bytes @ %llu, flags %u\n",
|
pascal@23761
|
639 + cloop_name, ret, blocknum,
|
pascal@23761
|
640 + compressed_block_len, clo->block_ptrs[blocknum].offset,
|
pascal@23761
|
641 + clo->block_ptrs[blocknum].flags);
|
pascal@23761
|
642 + clo->buffered_blocknum[clo->current_bufnum] = -1;
|
pascal@23761
|
643 + return -1;
|
pascal@23761
|
644 + }
|
pascal@23761
|
645 clo->buffered_blocknum[clo->current_bufnum] = blocknum;
|
pascal@23761
|
646 return clo->current_bufnum;
|
pascal@23761
|
647 }
|
pascal@23761
|
648
|
pascal@23761
|
649 /* This function does all the real work. */
|
pascal@23761
|
650 -/* returns "uptodate" */
|
pascal@23761
|
651 +/* returns "uptodate" */
|
pascal@23761
|
652 static int cloop_handle_request(struct cloop_device *clo, struct request *req)
|
pascal@23761
|
653 {
|
pascal@23761
|
654 int buffered_blocknum = -1;
|
pascal@23761
|
655 int preloaded = 0;
|
pascal@23761
|
656 loff_t offset = (loff_t) blk_rq_pos(req)<<9; /* req->sector<<9 */
|
pascal@23761
|
657 - struct bio_vec *bvec;
|
pascal@23761
|
658 + struct bio_vec bvec;
|
pascal@23761
|
659 struct req_iterator iter;
|
pascal@23761
|
660 rq_for_each_segment(bvec, req, iter)
|
pascal@17214
|
661 {
|
pascal@23761
|
662 - unsigned long len = bvec->bv_len;
|
pascal@23761
|
663 - char *to_ptr = kmap(bvec->bv_page) + bvec->bv_offset;
|
pascal@23761
|
664 + unsigned long len = bvec.bv_len;
|
pascal@23761
|
665 + char *to_ptr = kmap(bvec.bv_page) + bvec.bv_offset;
|
pascal@23761
|
666 while(len > 0)
|
pascal@23761
|
667 {
|
pascal@23761
|
668 u_int32_t length_in_buffer;
|
pascal@23761
|
669 @@ -308,7 +413,7 @@
|
pascal@23761
|
670 /* puts the result in the first argument, i.e. block_offset */
|
pascal@23761
|
671 /* becomes the blocknumber to load, and offset_in_buffer the */
|
pascal@23761
|
672 /* position in the buffer */
|
pascal@23761
|
673 - offset_in_buffer = do_div(block_offset, ntohl(clo->head.block_size));
|
pascal@23761
|
674 + offset_in_buffer = do_div(block_offset, clo->head.block_size);
|
pascal@23761
|
675 /* Lookup preload cache */
|
pascal@23761
|
676 if(block_offset < clo->preload_size && clo->preload_cache != NULL &&
|
pascal@23761
|
677 clo->preload_cache[block_offset] != NULL)
|
pascal@23761
|
678 @@ -325,7 +430,7 @@
|
pascal@23761
|
679 from_ptr = clo->buffer[buffered_blocknum];
|
pascal@23761
|
680 }
|
pascal@23761
|
681 /* Now, at least part of what we want will be in the buffer. */
|
pascal@23761
|
682 - length_in_buffer = ntohl(clo->head.block_size) - offset_in_buffer;
|
pascal@23761
|
683 + length_in_buffer = clo->head.block_size - offset_in_buffer;
|
pascal@23761
|
684 if(length_in_buffer > len)
|
pascal@23761
|
685 {
|
pascal@23761
|
686 /* DEBUGP("Warning: length_in_buffer=%u > len=%u\n",
|
pascal@23761
|
687 @@ -337,18 +442,19 @@
|
pascal@23761
|
688 len -= length_in_buffer;
|
pascal@23761
|
689 offset += length_in_buffer;
|
pascal@23761
|
690 } /* while inner loop */
|
pascal@23761
|
691 - kunmap(bvec->bv_page);
|
pascal@23761
|
692 + kunmap(bvec.bv_page);
|
pascal@23761
|
693 + cond_resched();
|
pascal@23761
|
694 } /* end rq_for_each_segment*/
|
pascal@23761
|
695 return ((buffered_blocknum!=-1) || preloaded);
|
pascal@23761
|
696 }
|
pascal@23761
|
697
|
pascal@23761
|
698 /* Adopted from loop.c, a kernel thread to handle physical reads and
|
pascal@23761
|
699 - * decompression. */
|
pascal@23761
|
700 + decompression. */
|
pascal@23761
|
701 static int cloop_thread(void *data)
|
pascal@23761
|
702 {
|
pascal@23761
|
703 struct cloop_device *clo = data;
|
pascal@23761
|
704 current->flags |= PF_NOFREEZE;
|
pascal@23761
|
705 - set_user_nice(current, -15);
|
pascal@23761
|
706 + set_user_nice(current, 10);
|
pascal@23761
|
707 while (!kthread_should_stop()||!list_empty(&clo->clo_list))
|
pascal@23761
|
708 {
|
pascal@23761
|
709 int err;
|
pascal@23761
|
710 @@ -390,10 +496,18 @@
|
pascal@23761
|
711 int rw;
|
pascal@23761
|
712 /* quick sanity checks */
|
pascal@23761
|
713 /* blk_fs_request() was removed in 2.6.36 */
|
pascal@23761
|
714 - if (unlikely(req == NULL || (req->cmd_type != REQ_TYPE_FS)))
|
pascal@23761
|
715 + if (unlikely(req == NULL
|
pascal@23761
|
716 +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) /* field removed */
|
pascal@23761
|
717 + || (req->cmd_type != REQ_TYPE_FS)
|
pascal@23761
|
718 +#endif
|
pascal@23761
|
719 + ))
|
pascal@23761
|
720 goto error_continue;
|
pascal@23761
|
721 rw = rq_data_dir(req);
|
pascal@23761
|
722 - if (unlikely(rw != READ && rw != READA))
|
pascal@23761
|
723 + if (unlikely(rw != READ
|
pascal@23761
|
724 +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
|
pascal@23761
|
725 + && rw != READA
|
pascal@23761
|
726 +#endif
|
pascal@23761
|
727 + ))
|
pascal@23761
|
728 {
|
pascal@23761
|
729 DEBUGP("cloop_do_request: bad command\n");
|
pascal@23761
|
730 goto error_continue;
|
pascal@23761
|
731 @@ -409,40 +523,51 @@
|
pascal@23761
|
732 continue; /* next request */
|
pascal@23761
|
733 error_continue:
|
pascal@23761
|
734 DEBUGP(KERN_ERR "cloop_do_request: Discarding request %p.\n", req);
|
pascal@23761
|
735 +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
|
pascal@23761
|
736 req->errors++;
|
pascal@23761
|
737 +#else
|
pascal@23761
|
738 + req->error_count++;
|
pascal@23761
|
739 +#endif
|
pascal@23761
|
740 __blk_end_request_all(req, -EIO);
|
pascal@17214
|
741 }
|
pascal@23761
|
742 }
|
pascal@23761
|
743
|
pascal@23761
|
744 -/* Read header and offsets from already opened file */
|
pascal@23761
|
745 -static int cloop_set_file(int cloop_num, struct file *file, char *filename)
|
pascal@23761
|
746 +/* Read header, flags and offsets from already opened file */
|
pascal@23761
|
747 +static int cloop_set_file(int cloop_num, struct file *file)
|
pascal@23761
|
748 {
|
pascal@23761
|
749 struct cloop_device *clo = cloop_dev[cloop_num];
|
pascal@23761
|
750 struct inode *inode;
|
pascal@23761
|
751 char *bbuf=NULL;
|
pascal@23761
|
752 - unsigned int i, offsets_read, total_offsets;
|
pascal@23761
|
753 - int isblkdev;
|
pascal@23761
|
754 - int error = 0;
|
pascal@23761
|
755 + unsigned int bbuf_size = 0;
|
pascal@23761
|
756 + const unsigned int header_size = sizeof(struct cloop_head);
|
pascal@23761
|
757 + unsigned int i, total_offsets=0;
|
pascal@23761
|
758 + loff_t fs_read_position = 0, header_pos[2];
|
pascal@23761
|
759 + int flags, isblkdev, bytes_read, error = 0;
|
pascal@23761
|
760 + if (clo->suspended) return error;
|
pascal@23761
|
761 + #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)
|
pascal@23761
|
762 inode = file->f_dentry->d_inode;
|
pascal@23761
|
763 + clo->underlying_filename = kstrdup(file->f_dentry->d_name.name ? file->f_dentry->d_name.name : (const unsigned char *)"anonymous filename", GFP_KERNEL);
|
pascal@23761
|
764 + #else
|
pascal@23761
|
765 + inode = file->f_path.dentry->d_inode;
|
pascal@23761
|
766 + clo->underlying_filename = kstrdup(file->f_path.dentry->d_name.name ? file->f_path.dentry->d_name.name : (const unsigned char *)"anonymous filename", GFP_KERNEL);
|
pascal@23761
|
767 + #endif
|
pascal@23761
|
768 isblkdev=S_ISBLK(inode->i_mode)?1:0;
|
pascal@23761
|
769 if(!isblkdev&&!S_ISREG(inode->i_mode))
|
pascal@23761
|
770 {
|
pascal@23761
|
771 printk(KERN_ERR "%s: %s not a regular file or block device\n",
|
pascal@23761
|
772 - cloop_name, filename);
|
pascal@23761
|
773 + cloop_name, clo->underlying_filename);
|
pascal@23761
|
774 error=-EBADF; goto error_release;
|
pascal@23761
|
775 }
|
pascal@23761
|
776 clo->backing_file = file;
|
pascal@23761
|
777 clo->backing_inode= inode ;
|
pascal@23761
|
778 - if(!isblkdev&&inode->i_size<sizeof(struct cloop_head))
|
pascal@23761
|
779 + clo->underlying_total_size = (isblkdev) ? inode->i_bdev->bd_inode->i_size : inode->i_size;
|
pascal@23761
|
780 + if(clo->underlying_total_size < header_size)
|
pascal@23761
|
781 {
|
pascal@23761
|
782 - printk(KERN_ERR "%s: %lu bytes (must be >= %u bytes)\n",
|
pascal@23761
|
783 - cloop_name, (unsigned long)inode->i_size,
|
pascal@23761
|
784 - (unsigned)sizeof(struct cloop_head));
|
pascal@23761
|
785 + printk(KERN_ERR "%s: %llu bytes (must be >= %u bytes)\n",
|
pascal@23761
|
786 + cloop_name, clo->underlying_total_size,
|
pascal@23761
|
787 + (unsigned int)header_size);
|
pascal@23761
|
788 error=-EBADF; goto error_release;
|
pascal@23761
|
789 }
|
pascal@23761
|
790 - /* In suspended mode, we have done all checks necessary - FF */
|
pascal@23761
|
791 - if (clo->suspended)
|
pascal@23761
|
792 - return error;
|
pascal@23761
|
793 if(isblkdev)
|
pascal@23761
|
794 {
|
pascal@23761
|
795 struct request_queue *q = bdev_get_queue(inode->i_bdev);
|
pascal@23761
|
796 @@ -451,104 +576,225 @@
|
pascal@23761
|
797 /* blk_queue_max_hw_segments(clo->clo_queue, queue_max_hw_segments(q)); */ /* Removed in 2.6.34 */
|
pascal@23761
|
798 blk_queue_max_segment_size(clo->clo_queue, queue_max_segment_size(q));
|
pascal@23761
|
799 blk_queue_segment_boundary(clo->clo_queue, queue_segment_boundary(q));
|
pascal@23761
|
800 +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0)
|
pascal@23761
|
801 blk_queue_merge_bvec(clo->clo_queue, q->merge_bvec_fn);
|
pascal@23761
|
802 +#endif
|
pascal@23761
|
803 clo->underlying_blksize = block_size(inode->i_bdev);
|
pascal@23761
|
804 }
|
pascal@23761
|
805 else
|
pascal@23761
|
806 clo->underlying_blksize = PAGE_SIZE;
|
pascal@23761
|
807 - DEBUGP("Underlying blocksize is %u\n", clo->underlying_blksize);
|
pascal@23761
|
808 - bbuf = cloop_malloc(clo->underlying_blksize);
|
pascal@23761
|
809 +
|
pascal@23761
|
810 + DEBUGP(KERN_INFO "Underlying blocksize of %s is %u\n", clo->underlying_filename, clo->underlying_blksize);
|
pascal@23761
|
811 + DEBUGP(KERN_INFO "Underlying total size of %s is %llu\n", clo->underlying_filename, clo->underlying_total_size);
|
pascal@23761
|
812 +
|
pascal@23761
|
813 + /* clo->underlying_blksize should be larger than header_size, even if it's only PAGE_SIZE */
|
pascal@23761
|
814 + bbuf_size = clo->underlying_blksize;
|
pascal@23761
|
815 + bbuf = cloop_malloc(bbuf_size);
|
pascal@23761
|
816 if(!bbuf)
|
pascal@23761
|
817 {
|
pascal@23761
|
818 - printk(KERN_ERR "%s: out of kernel mem for block buffer (%lu bytes)\n",
|
pascal@23761
|
819 - cloop_name, (unsigned long)clo->underlying_blksize);
|
pascal@23761
|
820 + printk(KERN_ERR "%s: out of kernel mem for buffer (%u bytes)\n",
|
pascal@23761
|
821 + cloop_name, (unsigned int) bbuf_size);
|
pascal@23761
|
822 + error=-ENOMEM; goto error_release;
|
pascal@23761
|
823 + }
|
pascal@23761
|
824 +
|
pascal@23761
|
825 + header_pos[0] = 0; /* header first */
|
pascal@23761
|
826 + header_pos[1] = clo->underlying_total_size - sizeof(struct cloop_head); /* header last */
|
pascal@23761
|
827 + for(i=0; i<2; i++)
|
pascal@23761
|
828 + {
|
pascal@23761
|
829 + /* Check for header */
|
pascal@23761
|
830 + size_t bytes_readable = MIN(clo->underlying_blksize, clo->underlying_total_size - header_pos[i]);
|
pascal@23761
|
831 + size_t bytes_read = cloop_read_from_file(clo, file, bbuf, header_pos[i], bytes_readable);
|
pascal@23761
|
832 + if(bytes_read != bytes_readable)
|
pascal@23761
|
833 + {
|
pascal@23761
|
834 + printk(KERN_ERR "%s: Bad file %s, read() of %s %u bytes returned %d.\n",
|
pascal@23761
|
835 + cloop_name, clo->underlying_filename, (i==0)?"first":"last",
|
pascal@23761
|
836 + (unsigned int)header_size, (int)bytes_read);
|
pascal@23761
|
837 + error=-EBADF;
|
pascal@23761
|
838 + goto error_release;
|
pascal@23761
|
839 + }
|
pascal@23761
|
840 + memcpy(&clo->head, bbuf, header_size);
|
pascal@23761
|
841 + if (strncmp(bbuf+CLOOP_SIGNATURE_OFFSET, CLOOP_SIGNATURE, CLOOP_SIGNATURE_SIZE)==0)
|
pascal@23761
|
842 + {
|
pascal@23761
|
843 + clo->file_format++;
|
pascal@23761
|
844 + clo->head.block_size=ntohl(clo->head.block_size);
|
pascal@23761
|
845 + clo->head.num_blocks=ntohl(clo->head.num_blocks);
|
pascal@23761
|
846 + clo->header_first = (i==0) ? 1 : 0;
|
pascal@23761
|
847 + printk(KERN_INFO "%s: file %s, %d blocks of %d bytes, header %s.\n", cloop_name, clo->underlying_filename, clo->head.num_blocks, clo->head.block_size, (i==0)?"first":"last");
|
pascal@23761
|
848 + break;
|
pascal@23761
|
849 + }
|
pascal@23761
|
850 + }
|
pascal@23761
|
851 + if (clo->file_format == 0)
|
pascal@23761
|
852 + {
|
pascal@23761
|
853 + printk(KERN_ERR "%s: Cannot detect %s format.\n",
|
pascal@23761
|
854 + cloop_name, cloop_name);
|
pascal@23761
|
855 + error=-EBADF; goto error_release;
|
pascal@23761
|
856 + }
|
pascal@23761
|
857 + if (clo->head.block_size % 512 != 0)
|
pascal@23761
|
858 + {
|
pascal@23761
|
859 + printk(KERN_ERR "%s: blocksize %u not multiple of 512\n",
|
pascal@23761
|
860 + cloop_name, clo->head.block_size);
|
pascal@23761
|
861 + error=-EBADF; goto error_release;
|
pascal@23761
|
862 + }
|
pascal@23761
|
863 + total_offsets=clo->head.num_blocks;
|
pascal@23761
|
864 + if (!isblkdev && (sizeof(struct cloop_head)+sizeof(struct block_info)*
|
pascal@23761
|
865 + total_offsets > inode->i_size))
|
pascal@23761
|
866 + {
|
pascal@23761
|
867 + printk(KERN_ERR "%s: file %s too small for %u blocks\n",
|
pascal@23761
|
868 + cloop_name, clo->underlying_filename, clo->head.num_blocks);
|
pascal@23761
|
869 + error=-EBADF; goto error_release;
|
pascal@23761
|
870 + }
|
pascal@23761
|
871 + /* Allocate Memory for decompressors */
|
pascal@23761
|
872 +#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE))
|
pascal@23761
|
873 + clo->zstream.workspace = cloop_malloc(zlib_inflate_workspacesize());
|
pascal@23761
|
874 + if(!clo->zstream.workspace)
|
pascal@23761
|
875 + {
|
pascal@23761
|
876 + printk(KERN_ERR "%s: out of mem for zlib working area %u\n",
|
pascal@23761
|
877 + cloop_name, zlib_inflate_workspacesize());
|
pascal@23761
|
878 error=-ENOMEM; goto error_release;
|
pascal@23761
|
879 }
|
pascal@23761
|
880 - total_offsets = 1; /* Dummy total_offsets: will be filled in first time around */
|
pascal@23761
|
881 - for (i = 0, offsets_read = 0; offsets_read < total_offsets; i++)
|
pascal@23761
|
882 + zlib_inflateInit(&clo->zstream);
|
pascal@23761
|
883 +#endif
|
pascal@23761
|
884 +#if (defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE))
|
pascal@23761
|
885 +#if XZ_INTERNAL_CRC32
|
pascal@23761
|
886 + /* This must be called before any other xz_* function to initialize the CRC32 lookup table. */
|
pascal@23761
|
887 + xz_crc32_init(void);
|
pascal@23761
|
888 +#endif
|
pascal@23761
|
889 + clo->xzdecoderstate = xz_dec_init(XZ_SINGLE, 0);
|
pascal@23761
|
890 +#endif
|
pascal@23761
|
891 + if (total_offsets + 1 == 0) /* Version 3 */
|
pascal@23761
|
892 {
|
pascal@23761
|
893 - unsigned int offset = 0, num_readable;
|
pascal@23761
|
894 - size_t bytes_read = cloop_read_from_file(clo, file, bbuf,
|
pascal@23761
|
895 - i*clo->underlying_blksize,
|
pascal@23761
|
896 - clo->underlying_blksize);
|
pascal@23761
|
897 - if(bytes_read != clo->underlying_blksize)
|
pascal@23761
|
898 + struct cloop_tail tail;
|
pascal@23761
|
899 + if (isblkdev)
|
pascal@23761
|
900 {
|
pascal@23761
|
901 - printk(KERN_ERR "%s: Bad file, read() of first %lu bytes returned %d.\n",
|
pascal@23761
|
902 - cloop_name, (unsigned long)clo->underlying_blksize, (int)bytes_read);
|
pascal@23761
|
903 - error=-EBADF;
|
pascal@23761
|
904 - goto error_release;
|
pascal@23761
|
905 + /* No end of file: can't find index */
|
pascal@23761
|
906 + printk(KERN_ERR "%s: no V3 support for block device\n",
|
pascal@23761
|
907 + cloop_name);
|
pascal@23761
|
908 + error=-EBADF; goto error_release;
|
pascal@23761
|
909 }
|
pascal@23761
|
910 - /* Header will be in block zero */
|
pascal@23761
|
911 - if(i==0)
|
pascal@23761
|
912 + bytes_read = cloop_read_from_file(clo, file, (void *) &tail,
|
pascal@23761
|
913 + inode->i_size - sizeof(struct cloop_tail),
|
pascal@23761
|
914 + sizeof(struct cloop_tail));
|
pascal@23761
|
915 + if (bytes_read == sizeof(struct cloop_tail))
|
pascal@23761
|
916 {
|
pascal@23761
|
917 - memcpy(&clo->head, bbuf, sizeof(struct cloop_head));
|
pascal@23761
|
918 - offset = sizeof(struct cloop_head);
|
pascal@23761
|
919 - if (ntohl(clo->head.block_size) % 512 != 0)
|
pascal@23761
|
920 + unsigned long len, zlen;
|
pascal@23761
|
921 + int ret;
|
pascal@23761
|
922 + void *zbuf;
|
pascal@23761
|
923 + clo->head.num_blocks = ntohl(tail.num_blocks);
|
pascal@23761
|
924 + total_offsets = clo->head.num_blocks;
|
pascal@23761
|
925 + clo->block_ptrs = cloop_malloc(sizeof(struct block_info) * total_offsets);
|
pascal@23761
|
926 + zlen = ntohl(tail.table_size);
|
pascal@23761
|
927 + zbuf = cloop_malloc(zlen);
|
pascal@23761
|
928 + if (!clo->block_ptrs || !zbuf)
|
pascal@23761
|
929 {
|
pascal@23761
|
930 - printk(KERN_ERR "%s: blocksize %u not multiple of 512\n",
|
pascal@23761
|
931 - cloop_name, ntohl(clo->head.block_size));
|
pascal@23761
|
932 - error=-EBADF; goto error_release;
|
pascal@23761
|
933 - }
|
pascal@17214
|
934 - if (clo->head.preamble[0x0B]!='V'||clo->head.preamble[0x0C]<'1')
|
pascal@17214
|
935 - {
|
pascal@17214
|
936 - printk(KERN_ERR "%s: Cannot read old 32-bit (version 0.68) images, "
|
pascal@17214
|
937 - "please use an older version of %s for this file.\n",
|
pascal@17214
|
938 - cloop_name, cloop_name);
|
pascal@17214
|
939 - error=-EBADF; goto error_release;
|
pascal@23761
|
940 + printk(KERN_ERR "%s: out of kernel mem for index\n", cloop_name);
|
pascal@23761
|
941 + error=-ENOMEM; goto error_release;
|
pascal@23761
|
942 }
|
pascal@17214
|
943 - if (clo->head.preamble[0x0C]<'2')
|
pascal@23761
|
944 + bytes_read = cloop_read_from_file(clo, file, zbuf,
|
pascal@23761
|
945 + inode->i_size - zlen - sizeof(struct cloop_tail),
|
pascal@23761
|
946 + zlen);
|
pascal@23761
|
947 + if (bytes_read != zlen)
|
pascal@23761
|
948 {
|
pascal@17214
|
949 - printk(KERN_ERR "%s: Cannot read old architecture-dependent "
|
pascal@17214
|
950 - "(format <= 1.0) images, please use an older "
|
pascal@17214
|
951 - "version of %s for this file.\n",
|
pascal@17214
|
952 - cloop_name, cloop_name);
|
pascal@23761
|
953 + printk(KERN_ERR "%s: can't read index\n", cloop_name);
|
pascal@23761
|
954 error=-EBADF; goto error_release;
|
pascal@23761
|
955 }
|
pascal@17214
|
956 - total_offsets=ntohl(clo->head.num_blocks)+1;
|
pascal@17214
|
957 - if (!isblkdev && (sizeof(struct cloop_head)+sizeof(loff_t)*
|
pascal@23761
|
958 - total_offsets > inode->i_size))
|
pascal@23761
|
959 + len = CLOOP3_INDEX_SIZE(ntohl(tail.index_size)) * total_offsets;
|
pascal@23761
|
960 + flags = CLOOP3_BLOCKS_FLAGS(ntohl(tail.index_size));
|
pascal@23761
|
961 +// May 3 19:45:20 (none) user.info kernel: cloop: uncompress(clo=e0a78000, block_ptrs=e0c9c000, &len(1440)=ddc05e6c, zbuf=e0c9f000, zlen=43, flag=0)
|
pascal@23761
|
962 +printk(KERN_INFO "%s: uncompress(clo=%p, block_ptrs=%p, &len(%ld)=%p, zbuf=%p, zlen=%ld, flag=%d)\n", cloop_name,
|
pascal@23761
|
963 + clo, clo->block_ptrs, len, &len, zbuf, zlen, flags);
|
pascal@23761
|
964 + ret = uncompress(clo, (void *) clo->block_ptrs, &len, zbuf, zlen, flags);
|
pascal@23761
|
965 +// May 3 19:45:20 (none) user.alert kernel: BUG: unable to handle kernel NULL pointer dereference at (null)
|
pascal@23761
|
966 +printk(KERN_INFO "%s: uncompressed !\n", cloop_name);
|
pascal@23761
|
967 + cloop_free(zbuf, zlen);
|
pascal@23761
|
968 + if (ret != 0)
|
pascal@17214
|
969 {
|
pascal@23761
|
970 - printk(KERN_ERR "%s: file too small for %u blocks\n",
|
pascal@23761
|
971 - cloop_name, ntohl(clo->head.num_blocks));
|
pascal@23761
|
972 + printk(KERN_ERR "%s: decompression error %i uncompressing index, flags %u\n",
|
pascal@23761
|
973 + cloop_name, ret, flags);
|
pascal@17214
|
974 error=-EBADF; goto error_release;
|
pascal@17214
|
975 }
|
pascal@17214
|
976 - clo->offsets = cloop_malloc(sizeof(loff_t) * total_offsets);
|
pascal@23761
|
977 - if (!clo->offsets)
|
pascal@23761
|
978 - {
|
pascal@23761
|
979 - printk(KERN_ERR "%s: out of kernel mem for offsets\n", cloop_name);
|
pascal@23761
|
980 - error=-ENOMEM; goto error_release;
|
pascal@23761
|
981 - }
|
pascal@17214
|
982 }
|
pascal@23761
|
983 - num_readable = MIN(total_offsets - offsets_read,
|
pascal@23761
|
984 - (clo->underlying_blksize - offset)
|
pascal@17214
|
985 - / sizeof(loff_t));
|
pascal@17214
|
986 - memcpy(&clo->offsets[offsets_read], bbuf+offset, num_readable * sizeof(loff_t));
|
pascal@23761
|
987 - offsets_read += num_readable;
|
pascal@23761
|
988 - }
|
pascal@23761
|
989 - { /* Search for largest block rather than estimate. KK. */
|
pascal@23761
|
990 - int i;
|
pascal@17214
|
991 - for(i=0;i<total_offsets-1;i++)
|
pascal@23761
|
992 + else
|
pascal@23761
|
993 + {
|
pascal@23761
|
994 + printk(KERN_ERR "%s: can't find index\n", cloop_name);
|
pascal@23761
|
995 + error=-ENOMEM; goto error_release;
|
pascal@23761
|
996 + }
|
pascal@23761
|
997 + }
|
pascal@23761
|
998 + else
|
pascal@23761
|
999 + {
|
pascal@23761
|
1000 + unsigned int n, total_bytes;
|
pascal@23761
|
1001 + flags = 0;
|
pascal@23761
|
1002 + clo->block_ptrs = cloop_malloc(sizeof(struct block_info) * total_offsets);
|
pascal@23761
|
1003 + if (!clo->block_ptrs)
|
pascal@23761
|
1004 + {
|
pascal@23761
|
1005 + printk(KERN_ERR "%s: out of kernel mem for offsets\n", cloop_name);
|
pascal@23761
|
1006 + error=-ENOMEM; goto error_release;
|
pascal@23761
|
1007 + }
|
pascal@23761
|
1008 + /* Read them offsets! */
|
pascal@23761
|
1009 + if(clo->header_first)
|
pascal@23761
|
1010 + {
|
pascal@23761
|
1011 + total_bytes = total_offsets * sizeof(struct block_info);
|
pascal@23761
|
1012 + fs_read_position = sizeof(struct cloop_head);
|
pascal@23761
|
1013 + }
|
pascal@23761
|
1014 + else
|
pascal@17214
|
1015 {
|
pascal@17214
|
1016 - loff_t d=be64_to_cpu(clo->offsets[i+1]) - be64_to_cpu(clo->offsets[i]);
|
pascal@17214
|
1017 - clo->largest_block=MAX(clo->largest_block,d);
|
pascal@23761
|
1018 + total_bytes = total_offsets * sizeof(loff_t);
|
pascal@23761
|
1019 + fs_read_position = clo->underlying_total_size - sizeof(struct cloop_head) - total_bytes;
|
pascal@23761
|
1020 + }
|
pascal@23761
|
1021 + for(n=0;n<total_bytes;)
|
pascal@23761
|
1022 + {
|
pascal@23761
|
1023 + size_t bytes_readable;
|
pascal@23761
|
1024 + bytes_readable = MIN(bbuf_size, clo->underlying_total_size - fs_read_position);
|
pascal@23761
|
1025 + if(bytes_readable <= 0) break; /* Done */
|
pascal@23761
|
1026 + bytes_read = cloop_read_from_file(clo, file, bbuf, fs_read_position, bytes_readable);
|
pascal@23761
|
1027 + if(bytes_read != bytes_readable)
|
pascal@23761
|
1028 + {
|
pascal@23761
|
1029 + printk(KERN_ERR "%s: Bad file %s, read() %lu bytes @ %llu returned %d.\n",
|
pascal@23761
|
1030 + cloop_name, clo->underlying_filename, (unsigned long)clo->underlying_blksize, fs_read_position, (int)bytes_read);
|
pascal@23761
|
1031 + error=-EBADF;
|
pascal@23761
|
1032 + goto error_release;
|
pascal@23761
|
1033 + }
|
pascal@23761
|
1034 + memcpy(((char *)clo->block_ptrs) + n, bbuf, bytes_read);
|
pascal@23761
|
1035 + /* remember where to read the next blk from file */
|
pascal@23761
|
1036 + fs_read_position += bytes_read;
|
pascal@23761
|
1037 + n += bytes_read;
|
pascal@17214
|
1038 }
|
pascal@17214
|
1039 - printk(KERN_INFO "%s: %s: %u blocks, %u bytes/block, largest block is %lu bytes.\n",
|
pascal@17214
|
1040 - cloop_name, filename, ntohl(clo->head.num_blocks),
|
pascal@23761
|
1041 - ntohl(clo->head.block_size), clo->largest_block);
|
pascal@17214
|
1042 }
|
pascal@23761
|
1043 -/* Combo kmalloc used too large chunks (>130000). */
|
pascal@23761
|
1044 {
|
pascal@23761
|
1045 int i;
|
pascal@23761
|
1046 - for(i=0;i<BUFFERED_BLOCKS;i++)
|
pascal@23761
|
1047 - {
|
pascal@23761
|
1048 - clo->buffer[i] = cloop_malloc(ntohl(clo->head.block_size));
|
pascal@23761
|
1049 - if(!clo->buffer[i])
|
pascal@23761
|
1050 - {
|
pascal@23761
|
1051 - printk(KERN_ERR "%s: out of memory for buffer %lu\n",
|
pascal@23761
|
1052 - cloop_name, (unsigned long) ntohl(clo->head.block_size));
|
pascal@23761
|
1053 - error=-ENOMEM; goto error_release_free;
|
pascal@23761
|
1054 - }
|
pascal@23761
|
1055 - }
|
pascal@23761
|
1056 + char *version = build_index(clo->block_ptrs, clo->head.num_blocks, clo->head.block_size, flags);
|
pascal@23761
|
1057 + clo->largest_block = 0;
|
pascal@23761
|
1058 + for (i = 0; i < clo->head.num_blocks; i++)
|
pascal@23761
|
1059 + if (clo->block_ptrs[i].size > clo->largest_block)
|
pascal@23761
|
1060 + clo->largest_block = clo->block_ptrs[i].size;
|
pascal@23761
|
1061 + printk(KERN_INFO "%s: %s: %s: %u blocks, %u bytes/block, largest block is %lu bytes.\n",
|
pascal@23761
|
1062 + cloop_name, clo->underlying_filename, version, clo->head.num_blocks,
|
pascal@23761
|
1063 + clo->head.block_size, clo->largest_block);
|
pascal@23761
|
1064 + }
|
pascal@23761
|
1065 + {
|
pascal@23761
|
1066 + int i;
|
pascal@23761
|
1067 + clo->num_buffered_blocks = (buffers > 0 && clo->head.block_size >= 512) ?
|
pascal@23761
|
1068 + (buffers / clo->head.block_size) : 1;
|
pascal@23761
|
1069 + clo->buffered_blocknum = cloop_malloc(clo->num_buffered_blocks * sizeof (u_int32_t));
|
pascal@23761
|
1070 + clo->buffer = cloop_malloc(clo->num_buffered_blocks * sizeof (char*));
|
pascal@23761
|
1071 + if (!clo->buffered_blocknum || !clo->buffer)
|
pascal@23761
|
1072 + {
|
pascal@23761
|
1073 + printk(KERN_ERR "%s: out of memory for index of cache buffer (%lu bytes)\n",
|
pascal@23761
|
1074 + cloop_name, (unsigned long)clo->num_buffered_blocks * sizeof (u_int32_t) + sizeof(char*) );
|
pascal@23761
|
1075 + error=-ENOMEM; goto error_release;
|
pascal@23761
|
1076 + }
|
pascal@23761
|
1077 + memset(clo->buffer, 0, clo->num_buffered_blocks * sizeof (char*));
|
pascal@23761
|
1078 + for(i=0;i<clo->num_buffered_blocks;i++)
|
pascal@23761
|
1079 + {
|
pascal@23761
|
1080 + clo->buffered_blocknum[i] = -1;
|
pascal@23761
|
1081 + clo->buffer[i] = cloop_malloc(clo->head.block_size);
|
pascal@23761
|
1082 + if(!clo->buffer[i])
|
pascal@23761
|
1083 + {
|
pascal@23761
|
1084 + printk(KERN_ERR "%s: out of memory for cache buffer %lu\n",
|
pascal@23761
|
1085 + cloop_name, (unsigned long) clo->head.block_size);
|
pascal@23761
|
1086 + error=-ENOMEM; goto error_release_free;
|
pascal@23761
|
1087 + }
|
pascal@23761
|
1088 + }
|
pascal@23761
|
1089 + clo->current_bufnum = 0;
|
pascal@23761
|
1090 }
|
pascal@23761
|
1091 clo->compressed_buffer = cloop_malloc(clo->largest_block);
|
pascal@23761
|
1092 if(!clo->compressed_buffer)
|
pascal@23761
|
1093 @@ -557,31 +803,7 @@
|
pascal@23761
|
1094 cloop_name, clo->largest_block);
|
pascal@23761
|
1095 error=-ENOMEM; goto error_release_free_buffer;
|
pascal@17214
|
1096 }
|
pascal@23761
|
1097 - clo->zstream.workspace = cloop_malloc(zlib_inflate_workspacesize());
|
pascal@23761
|
1098 - if(!clo->zstream.workspace)
|
pascal@23761
|
1099 - {
|
pascal@23761
|
1100 - printk(KERN_ERR "%s: out of mem for zlib working area %u\n",
|
pascal@23761
|
1101 - cloop_name, zlib_inflate_workspacesize());
|
pascal@23761
|
1102 - error=-ENOMEM; goto error_release_free_all;
|
pascal@23761
|
1103 - }
|
pascal@23761
|
1104 - zlib_inflateInit(&clo->zstream);
|
pascal@17214
|
1105 - if(!isblkdev &&
|
pascal@17214
|
1106 - be64_to_cpu(clo->offsets[ntohl(clo->head.num_blocks)]) != inode->i_size)
|
pascal@17214
|
1107 - {
|
pascal@17214
|
1108 - printk(KERN_ERR "%s: final offset wrong (%Lu not %Lu)\n",
|
pascal@17214
|
1109 - cloop_name,
|
pascal@17214
|
1110 - be64_to_cpu(clo->offsets[ntohl(clo->head.num_blocks)]),
|
pascal@17214
|
1111 - inode->i_size);
|
pascal@17214
|
1112 - cloop_free(clo->zstream.workspace, zlib_inflate_workspacesize()); clo->zstream.workspace=NULL;
|
pascal@17214
|
1113 - goto error_release_free_all;
|
pascal@17214
|
1114 - }
|
pascal@23761
|
1115 - {
|
pascal@23761
|
1116 - int i;
|
pascal@23761
|
1117 - for(i=0; i<BUFFERED_BLOCKS; i++) clo->buffered_blocknum[i] = -1;
|
pascal@23761
|
1118 - clo->current_bufnum=0;
|
pascal@23761
|
1119 - }
|
pascal@23761
|
1120 - set_capacity(clo->clo_disk, (sector_t)(ntohl(clo->head.num_blocks)*
|
pascal@23761
|
1121 - (ntohl(clo->head.block_size)>>9)));
|
pascal@23761
|
1122 + set_capacity(clo->clo_disk, (sector_t)(clo->head.num_blocks*(clo->head.block_size>>9)));
|
pascal@23761
|
1123 clo->clo_thread = kthread_create(cloop_thread, clo, "cloop%d", cloop_num);
|
pascal@23761
|
1124 if(IS_ERR(clo->clo_thread))
|
pascal@23761
|
1125 {
|
pascal@23761
|
1126 @@ -591,17 +813,17 @@
|
pascal@23761
|
1127 }
|
pascal@23761
|
1128 if(preload > 0)
|
pascal@23761
|
1129 {
|
pascal@23761
|
1130 - clo->preload_array_size = ((preload<=ntohl(clo->head.num_blocks))?preload:ntohl(clo->head.num_blocks));
|
pascal@23761
|
1131 + clo->preload_array_size = ((preload<=clo->head.num_blocks)?preload:clo->head.num_blocks);
|
pascal@23761
|
1132 clo->preload_size = 0;
|
pascal@23761
|
1133 if((clo->preload_cache = cloop_malloc(clo->preload_array_size * sizeof(char *))) != NULL)
|
pascal@23761
|
1134 {
|
pascal@23761
|
1135 int i;
|
pascal@23761
|
1136 for(i=0; i<clo->preload_array_size; i++)
|
pascal@23761
|
1137 {
|
pascal@23761
|
1138 - if((clo->preload_cache[i] = cloop_malloc(ntohl(clo->head.block_size))) == NULL)
|
pascal@23761
|
1139 + if((clo->preload_cache[i] = cloop_malloc(clo->head.block_size)) == NULL)
|
pascal@23761
|
1140 { /* Out of memory */
|
pascal@23761
|
1141 printk(KERN_WARNING "%s: cloop_malloc(%d) failed for preload_cache[%d] (ignored).\n",
|
pascal@23761
|
1142 - cloop_name, ntohl(clo->head.block_size), i);
|
pascal@23761
|
1143 + cloop_name, clo->head.block_size, i);
|
pascal@23761
|
1144 break;
|
pascal@23761
|
1145 }
|
pascal@23761
|
1146 }
|
pascal@23761
|
1147 @@ -612,13 +834,13 @@
|
pascal@23761
|
1148 if(buffered_blocknum >= 0)
|
pascal@23761
|
1149 {
|
pascal@23761
|
1150 memcpy(clo->preload_cache[i], clo->buffer[buffered_blocknum],
|
pascal@23761
|
1151 - ntohl(clo->head.block_size));
|
pascal@23761
|
1152 + clo->head.block_size);
|
pascal@23761
|
1153 }
|
pascal@23761
|
1154 else
|
pascal@23761
|
1155 {
|
pascal@23761
|
1156 printk(KERN_WARNING "%s: can't read block %d into preload cache, set to zero.\n",
|
pascal@23761
|
1157 cloop_name, i);
|
pascal@23761
|
1158 - memset(clo->preload_cache[i], 0, ntohl(clo->head.block_size));
|
pascal@23761
|
1159 + memset(clo->preload_cache[i], 0, clo->head.block_size);
|
pascal@23761
|
1160 }
|
pascal@23761
|
1161 }
|
pascal@23761
|
1162 printk(KERN_INFO "%s: preloaded %d blocks into cache.\n", cloop_name,
|
pascal@23761
|
1163 @@ -641,22 +863,19 @@
|
pascal@23761
|
1164 cloop_free(clo->compressed_buffer, clo->largest_block);
|
pascal@23761
|
1165 clo->compressed_buffer=NULL;
|
pascal@23761
|
1166 error_release_free_buffer:
|
pascal@23761
|
1167 + if(clo->buffer)
|
pascal@17214
|
1168 {
|
pascal@17214
|
1169 int i;
|
pascal@23761
|
1170 - for(i=0; i<BUFFERED_BLOCKS; i++)
|
pascal@23761
|
1171 - {
|
pascal@23761
|
1172 - if(clo->buffer[i])
|
pascal@23761
|
1173 - {
|
pascal@23761
|
1174 - cloop_free(clo->buffer[i], ntohl(clo->head.block_size));
|
pascal@23761
|
1175 - clo->buffer[i]=NULL;
|
pascal@23761
|
1176 - }
|
pascal@23761
|
1177 - }
|
pascal@23761
|
1178 + for(i=0; i<clo->num_buffered_blocks; i++) { if(clo->buffer[i]) { cloop_free(clo->buffer[i], clo->head.block_size); clo->buffer[i]=NULL; }}
|
pascal@23761
|
1179 + cloop_free(clo->buffer, clo->num_buffered_blocks*sizeof(char*)); clo->buffer=NULL;
|
pascal@17214
|
1180 }
|
pascal@23761
|
1181 + if (clo->buffered_blocknum) { cloop_free(clo->buffered_blocknum, sizeof(int)*clo->num_buffered_blocks); clo->buffered_blocknum=NULL; }
|
pascal@17214
|
1182 error_release_free:
|
pascal@17214
|
1183 - cloop_free(clo->offsets, sizeof(loff_t) * total_offsets);
|
pascal@23761
|
1184 - clo->offsets=NULL;
|
pascal@23761
|
1185 + cloop_free(clo->block_ptrs, sizeof(struct block_info) * total_offsets);
|
pascal@23761
|
1186 + clo->block_ptrs=NULL;
|
pascal@17214
|
1187 error_release:
|
pascal@17214
|
1188 if(bbuf) cloop_free(bbuf, clo->underlying_blksize);
|
pascal@23761
|
1189 + if(clo->underlying_filename) { kfree(clo->underlying_filename); clo->underlying_filename=NULL; }
|
pascal@23761
|
1190 clo->backing_file=NULL;
|
pascal@23761
|
1191 return error;
|
pascal@23761
|
1192 }
|
pascal@23761
|
1193 @@ -673,7 +892,7 @@
|
pascal@23761
|
1194 if(clo->backing_file) return -EBUSY;
|
pascal@23761
|
1195 file = fget(arg); /* get filp struct from ioctl arg fd */
|
pascal@23761
|
1196 if(!file) return -EBADF;
|
pascal@23761
|
1197 - error=cloop_set_file(cloop_num,file,"losetup_file");
|
pascal@23761
|
1198 + error=cloop_set_file(cloop_num,file);
|
pascal@23761
|
1199 set_device_ro(bdev, 1);
|
pascal@23761
|
1200 if(error) fput(file);
|
pascal@23761
|
1201 return error;
|
pascal@23761
|
1202 @@ -684,29 +903,48 @@
|
pascal@23761
|
1203 {
|
pascal@23761
|
1204 struct cloop_device *clo = cloop_dev[cloop_num];
|
pascal@23761
|
1205 struct file *filp = clo->backing_file;
|
pascal@23761
|
1206 - int i;
|
pascal@23761
|
1207 if(clo->refcnt > 1) /* we needed one fd for the ioctl */
|
pascal@23761
|
1208 return -EBUSY;
|
pascal@23761
|
1209 if(filp==NULL) return -EINVAL;
|
pascal@23761
|
1210 if(clo->clo_thread) { kthread_stop(clo->clo_thread); clo->clo_thread=NULL; }
|
pascal@23761
|
1211 - if(filp!=initial_file) fput(filp);
|
pascal@23761
|
1212 - else { filp_close(initial_file,0); initial_file=NULL; }
|
pascal@23761
|
1213 + if(filp!=initial_file)
|
pascal@23761
|
1214 + fput(filp);
|
pascal@23761
|
1215 + else
|
pascal@23761
|
1216 + {
|
pascal@23761
|
1217 + filp_close(initial_file,0);
|
pascal@23761
|
1218 + initial_file=NULL;
|
pascal@23761
|
1219 + }
|
pascal@23761
|
1220 clo->backing_file = NULL;
|
pascal@23761
|
1221 clo->backing_inode = NULL;
|
pascal@23761
|
1222 - if(clo->offsets) { cloop_free(clo->offsets, clo->underlying_blksize); clo->offsets = NULL; }
|
pascal@23761
|
1223 + if(clo->underlying_filename) { kfree(clo->underlying_filename); clo->underlying_filename=NULL; }
|
pascal@23761
|
1224 + if(clo->block_ptrs) { cloop_free(clo->block_ptrs, clo->head.num_blocks); clo->block_ptrs = NULL; }
|
pascal@23761
|
1225 if(clo->preload_cache)
|
pascal@23761
|
1226 - {
|
pascal@23761
|
1227 - for(i=0; i < clo->preload_size; i++)
|
pascal@23761
|
1228 - cloop_free(clo->preload_cache[i], ntohl(clo->head.block_size));
|
pascal@23761
|
1229 - cloop_free(clo->preload_cache, clo->preload_array_size * sizeof(char *));
|
pascal@23761
|
1230 - clo->preload_cache = NULL;
|
pascal@23761
|
1231 - clo->preload_size = clo->preload_array_size = 0;
|
pascal@23761
|
1232 - }
|
pascal@23761
|
1233 - for(i=0; i<BUFFERED_BLOCKS; i++)
|
pascal@23761
|
1234 - if(clo->buffer[i]) { cloop_free(clo->buffer[i], ntohl(clo->head.block_size)); clo->buffer[i]=NULL; }
|
pascal@23761
|
1235 + {
|
pascal@23761
|
1236 + int i;
|
pascal@23761
|
1237 + for(i=0; i < clo->preload_size; i++)
|
pascal@23761
|
1238 + cloop_free(clo->preload_cache[i], clo->head.block_size);
|
pascal@23761
|
1239 + cloop_free(clo->preload_cache, clo->preload_array_size * sizeof(char *));
|
pascal@23761
|
1240 + clo->preload_cache = NULL;
|
pascal@23761
|
1241 + clo->preload_size = clo->preload_array_size = 0;
|
pascal@23761
|
1242 + }
|
pascal@23761
|
1243 + if (clo->buffered_blocknum)
|
pascal@23761
|
1244 + {
|
pascal@23761
|
1245 + cloop_free(clo->buffered_blocknum, sizeof(int) * clo->num_buffered_blocks); clo->buffered_blocknum = NULL;
|
pascal@23761
|
1246 + }
|
pascal@23761
|
1247 + if (clo->buffer)
|
pascal@23761
|
1248 + {
|
pascal@23761
|
1249 + int i;
|
pascal@23761
|
1250 + for(i=0; i<clo->num_buffered_blocks; i++) { if(clo->buffer[i]) cloop_free(clo->buffer[i], clo->head.block_size); }
|
pascal@23761
|
1251 + cloop_free(clo->buffer, sizeof(char*) * clo->num_buffered_blocks); clo->buffer = NULL;
|
pascal@23761
|
1252 + }
|
pascal@23761
|
1253 if(clo->compressed_buffer) { cloop_free(clo->compressed_buffer, clo->largest_block); clo->compressed_buffer = NULL; }
|
pascal@23761
|
1254 +#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE))
|
pascal@23761
|
1255 zlib_inflateEnd(&clo->zstream);
|
pascal@23761
|
1256 if(clo->zstream.workspace) { cloop_free(clo->zstream.workspace, zlib_inflate_workspacesize()); clo->zstream.workspace = NULL; }
|
pascal@23761
|
1257 +#endif
|
pascal@23761
|
1258 +#if (defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE))
|
pascal@23761
|
1259 + xz_dec_end(clo->xzdecoderstate);
|
pascal@23761
|
1260 +#endif
|
pascal@23761
|
1261 if(bdev) invalidate_bdev(bdev);
|
pascal@23761
|
1262 if(clo->clo_disk) set_capacity(clo->clo_disk, 0);
|
pascal@23761
|
1263 return 0;
|
pascal@23761
|
1264 @@ -731,8 +969,8 @@
|
pascal@23761
|
1265 const struct loop_info64 *info)
|
pascal@23761
|
1266 {
|
pascal@23761
|
1267 if (!clo->backing_file) return -ENXIO;
|
pascal@23761
|
1268 - memcpy(clo->clo_file_name, info->lo_file_name, LO_NAME_SIZE);
|
pascal@23761
|
1269 - clo->clo_file_name[LO_NAME_SIZE-1] = 0;
|
pascal@23761
|
1270 + if(clo->underlying_filename) kfree(clo->underlying_filename);
|
pascal@23761
|
1271 + clo->underlying_filename = kstrdup(info->lo_file_name, GFP_KERNEL);
|
pascal@23761
|
1272 return 0;
|
pascal@23761
|
1273 }
|
pascal@23761
|
1274
|
pascal@23761
|
1275 @@ -743,7 +981,11 @@
|
pascal@23761
|
1276 struct kstat stat;
|
pascal@23761
|
1277 int err;
|
pascal@23761
|
1278 if (!file) return -ENXIO;
|
pascal@23761
|
1279 - err = vfs_getattr(file->f_path.mnt, file->f_path.dentry, &stat);
|
pascal@23761
|
1280 +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
|
pascal@23761
|
1281 + err = vfs_getattr(&file->f_path, &stat);
|
pascal@23761
|
1282 +#else
|
pascal@23761
|
1283 + err = vfs_getattr(&file->f_path, &stat, STATX_INO, AT_STATX_SYNC_AS_STAT);
|
pascal@23761
|
1284 +#endif
|
pascal@23761
|
1285 if (err) return err;
|
pascal@23761
|
1286 memset(info, 0, sizeof(*info));
|
pascal@23761
|
1287 info->lo_number = clo->clo_number;
|
pascal@23761
|
1288 @@ -753,7 +995,8 @@
|
pascal@23761
|
1289 info->lo_offset = 0;
|
pascal@23761
|
1290 info->lo_sizelimit = 0;
|
pascal@23761
|
1291 info->lo_flags = 0;
|
pascal@23761
|
1292 - memcpy(info->lo_file_name, clo->clo_file_name, LO_NAME_SIZE);
|
pascal@23761
|
1293 + strncpy(info->lo_file_name, clo->underlying_filename, LO_NAME_SIZE);
|
pascal@23761
|
1294 + info->lo_file_name[LO_NAME_SIZE-1]=0;
|
pascal@23761
|
1295 return 0;
|
pascal@23761
|
1296 }
|
pascal@23761
|
1297
|
pascal@23761
|
1298 @@ -833,8 +1076,6 @@
|
pascal@23761
|
1299 if (!err && copy_to_user(arg, &info64, sizeof(info64))) err = -EFAULT;
|
pascal@23761
|
1300 return err;
|
pascal@23761
|
1301 }
|
pascal@23761
|
1302 -/* EOF get/set_status */
|
pascal@23761
|
1303 -
|
pascal@23761
|
1304
|
pascal@23761
|
1305 static int cloop_ioctl(struct block_device *bdev, fmode_t mode,
|
pascal@23761
|
1306 unsigned int cmd, unsigned long arg)
|
pascal@23761
|
1307 @@ -914,21 +1155,20 @@
|
pascal@23761
|
1308 /* losetup uses write-open and flags=0x8002 to set a new file */
|
pascal@23761
|
1309 if(mode & FMODE_WRITE)
|
pascal@23761
|
1310 {
|
pascal@23761
|
1311 - printk(KERN_WARNING "%s: Can't open device read-write in mode 0x%x\n", cloop_name, mode);
|
pascal@23761
|
1312 + printk(KERN_INFO "%s: Open in read-write mode 0x%x requested, ignored.\n", cloop_name, mode);
|
pascal@23761
|
1313 return -EROFS;
|
pascal@23761
|
1314 }
|
pascal@23761
|
1315 cloop_dev[cloop_num]->refcnt+=1;
|
pascal@23761
|
1316 return 0;
|
pascal@23761
|
1317 }
|
pascal@23761
|
1318
|
pascal@23761
|
1319 -static int cloop_close(struct gendisk *disk, fmode_t mode)
|
pascal@23761
|
1320 +static void cloop_close(struct gendisk *disk, fmode_t mode)
|
pascal@23761
|
1321 {
|
pascal@23761
|
1322 - int cloop_num, err=0;
|
pascal@23761
|
1323 - if(!disk) return 0;
|
pascal@23761
|
1324 + int cloop_num;
|
pascal@23761
|
1325 + if(!disk) return;
|
pascal@23761
|
1326 cloop_num=((struct cloop_device *)disk->private_data)->clo_number;
|
pascal@23761
|
1327 - if(cloop_num < 0 || cloop_num > (cloop_count-1)) return 0;
|
pascal@23761
|
1328 + if(cloop_num < 0 || cloop_num > (cloop_count-1)) return;
|
pascal@23761
|
1329 cloop_dev[cloop_num]->refcnt-=1;
|
pascal@23761
|
1330 - return err;
|
pascal@23761
|
1331 }
|
pascal@23761
|
1332
|
pascal@23761
|
1333 static struct block_device_operations clo_fops =
|
pascal@23761
|
1334 @@ -973,6 +1213,10 @@
|
pascal@23761
|
1335 goto error_out;
|
pascal@23761
|
1336 }
|
pascal@23761
|
1337 clo->clo_queue->queuedata = clo;
|
pascal@23761
|
1338 +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
|
pascal@23761
|
1339 + queue_flag_set_unlocked(QUEUE_FLAG_NONROT, clo->clo_queue);
|
pascal@23761
|
1340 + queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, clo->clo_queue);
|
pascal@23761
|
1341 +#endif
|
pascal@23761
|
1342 clo->clo_disk = alloc_disk(1);
|
pascal@23761
|
1343 if(!clo->clo_disk)
|
pascal@23761
|
1344 {
|
pascal@23761
|
1345 @@ -1004,6 +1248,11 @@
|
pascal@23761
|
1346 cloop_dev[cloop_num] = NULL;
|
pascal@23761
|
1347 }
|
pascal@23761
|
1348
|
pascal@23761
|
1349 +/* LZ4 Stuff */
|
pascal@23761
|
1350 +#if (defined USE_LZ4_INTERNAL)
|
pascal@23761
|
1351 +#include "lz4_kmod.c"
|
pascal@23761
|
1352 +#endif
|
pascal@23761
|
1353 +
|
pascal@23761
|
1354 static int __init cloop_init(void)
|
pascal@23761
|
1355 {
|
pascal@23761
|
1356 int error=0;
|
pascal@23761
|
1357 @@ -1044,7 +1293,7 @@
|
pascal@23761
|
1358 initial_file=NULL; /* if IS_ERR, it's NOT open. */
|
pascal@23761
|
1359 }
|
pascal@23761
|
1360 else
|
pascal@23761
|
1361 - error=cloop_set_file(0,initial_file,file);
|
pascal@23761
|
1362 + error=cloop_set_file(0,initial_file);
|
pascal@23761
|
1363 if(error)
|
pascal@23761
|
1364 {
|
pascal@23761
|
1365 printk(KERN_ERR
|
pascal@23761
|
1366 @@ -1052,9 +1301,6 @@
|
pascal@23761
|
1367 cloop_name, file, error);
|
pascal@23761
|
1368 goto init_out_dealloc;
|
pascal@23761
|
1369 }
|
pascal@23761
|
1370 - if(namelen >= LO_NAME_SIZE) namelen = LO_NAME_SIZE-1;
|
pascal@23761
|
1371 - memcpy(cloop_dev[0]->clo_file_name, file, namelen);
|
pascal@23761
|
1372 - cloop_dev[0]->clo_file_name[namelen] = 0;
|
pascal@23761
|
1373 }
|
pascal@23761
|
1374 return 0;
|
pascal@23761
|
1375 init_out_dealloc:
|
pascal@23762
|
1376 --- cloop.h
|
pascal@23762
|
1377 +++ cloop.h
|
pascal@23762
|
1378 @@ -86,11 +86,8 @@
|
pascal@23762
|
1379 struct cloop_tail
|
pascal@23762
|
1380 {
|
pascal@23762
|
1381 u_int32_t table_size;
|
pascal@23762
|
1382 - u_int32_t index_size; /* size:4 comp:3 ctrl-c:1 lastlen:24 */
|
pascal@23762
|
1383 + u_int32_t index_size; /* size:4 unused:3 ctrl-c:1 lastlen:24 */
|
pascal@23762
|
1384 #define CLOOP3_INDEX_SIZE(x) ((unsigned int)((x) & 0xF))
|
pascal@23762
|
1385 -#define CLOOP3_BLOCKS_FLAGS(x) ((unsigned int)((x) & 0x70) >> 4)
|
pascal@23762
|
1386 -#define CLOOP3_TRUNCATED(x) ((unsigned int)((x) & 0x80) >> 7)
|
pascal@23762
|
1387 -#define CLOOP3_LASTLEN(x) (unsigned int)((x) >> 8)
|
pascal@23762
|
1388 u_int32_t num_blocks;
|
pascal@23762
|
1389 };
|
pascal@23762
|
1390
|
pascal@23762
|
1391 @@ -104,8 +101,10 @@
|
pascal@23762
|
1392 };
|
pascal@23762
|
1393
|
pascal@23762
|
1394 static inline char *build_index(struct block_info *offsets, unsigned long n,
|
pascal@23762
|
1395 - unsigned long block_size, unsigned global_flags)
|
pascal@23762
|
1396 + unsigned long block_size)
|
pascal@23762
|
1397 {
|
pascal@23762
|
1398 + static char v[11];
|
pascal@23762
|
1399 + u_int32_t flags = 0;
|
pascal@23762
|
1400 u_int32_t *ofs32 = (u_int32_t *) offsets;
|
pascal@23762
|
1401 loff_t *ofs64 = (loff_t *) offsets;
|
pascal@23762
|
1402
|
pascal@23762
|
1403 @@ -130,8 +129,6 @@
|
pascal@23762
|
1404 }
|
pascal@23762
|
1405 else { /* V2.0/V4.0 */
|
pascal@23762
|
1406 loff_t last = CLOOP_BLOCK_OFFSET(__be64_to_cpu(ofs64[n]));
|
pascal@23762
|
1407 - u_int32_t flags;
|
pascal@23762
|
1408 - static char v4[11];
|
pascal@23762
|
1409 unsigned long i = n;
|
pascal@23762
|
1410
|
pascal@23762
|
1411 for (flags = 0; n-- ;) {
|
pascal@23762
|
1412 @@ -149,12 +146,7 @@
|
pascal@23762
|
1413 offsets[i] = offsets[offsets[i].offset];
|
pascal@23762
|
1414 }
|
pascal@23762
|
1415 }
|
pascal@23762
|
1416 - strcpy(v4, (char *) "64BE v4.0a");
|
pascal@23762
|
1417 - v4[10] = 'a' + ((flags-1) & 0xF); // compressors used
|
pascal@23762
|
1418 - if (flags > 0x10) { // with links ?
|
pascal@23762
|
1419 - v4[10] += 'A' - 'a';
|
pascal@23762
|
1420 - }
|
pascal@23762
|
1421 - return v4;
|
pascal@23762
|
1422 + strcpy(v, (char *) "64BE v4.0a");
|
pascal@23762
|
1423 }
|
pascal@23762
|
1424 }
|
pascal@23762
|
1425 else if (ofs32[1] == 0 && v3_64 == 0) { /* V1.0 */
|
pascal@23762
|
1426 @@ -170,7 +162,6 @@
|
pascal@23762
|
1427 else { /* V3.0 or V0.68 */
|
pascal@23762
|
1428 unsigned long i;
|
pascal@23762
|
1429 loff_t j;
|
pascal@23762
|
1430 - static char v3[11];
|
pascal@23762
|
1431
|
pascal@23762
|
1432 for (i = 0; i < n && ntohl(ofs32[i]) < ntohl(ofs32[i+1]); i++);
|
pascal@23762
|
1433 if (i == n && ntohl(ofs32[0]) == (4*n) + 0x8C) { /* V0.68 */
|
pascal@23762
|
1434 @@ -185,28 +176,33 @@
|
pascal@23762
|
1435 }
|
pascal@23762
|
1436
|
pascal@23762
|
1437 v3_64 = (ofs32[1] == 0);
|
pascal@23762
|
1438 - for (i = n; i-- != 0; )
|
pascal@23762
|
1439 + for (i = n; i-- != 0; ) {
|
pascal@23762
|
1440 offsets[i].size = ntohl(ofs32[i << v3_64]);
|
pascal@23762
|
1441 - for (i = 0, j = sizeof(struct cloop_head); i < n; i++) {
|
pascal@23762
|
1442 - offsets[i].offset = j;
|
pascal@23762
|
1443 - offsets[i].flags = global_flags;
|
pascal@23762
|
1444 if (offsets[i].size == 0xFFFFFFFF) {
|
pascal@23762
|
1445 - offsets[i].flags = CLOOP_COMPRESSOR_NONE;
|
pascal@23762
|
1446 - offsets[i].size = block_size;
|
pascal@23762
|
1447 + offsets[i].size = 0x10000000 | block_size;
|
pascal@23762
|
1448 }
|
pascal@23762
|
1449 - if ((offsets[i].size & 0x80000000) == 0) {
|
pascal@23762
|
1450 + offsets[i].flags = (offsets[i].size >> 28);
|
pascal@23762
|
1451 + offsets[i].size &= 0x0FFFFFFF;
|
pascal@23762
|
1452 + }
|
pascal@23762
|
1453 + for (i = 0, j = sizeof(struct cloop_head); i < n; i++) {
|
pascal@23762
|
1454 + offsets[i].offset = j;
|
pascal@23762
|
1455 + if (offsets[i].flags < 8) {
|
pascal@23762
|
1456 j += offsets[i].size;
|
pascal@23762
|
1457 }
|
pascal@23762
|
1458 }
|
pascal@23762
|
1459 for (i = 0; i < n; i++) {
|
pascal@23762
|
1460 - if (offsets[i].size & 0x80000000) {
|
pascal@23762
|
1461 - offsets[i] = offsets[offsets[i].size & 0x7FFFFFFF];
|
pascal@23762
|
1462 + flags |= 1 << offsets[i].flags;
|
pascal@23762
|
1463 + if (offsets[i].flags >= 8) {
|
pascal@23762
|
1464 + offsets[i] = offsets[offsets[i].size];
|
pascal@23762
|
1465 }
|
pascal@23762
|
1466 }
|
pascal@23762
|
1467 - strcpy(v3, (char *) (v3_64) ? "64BE v3.0a" : "32BE v3.0a");
|
pascal@23762
|
1468 - v3[10] += global_flags;
|
pascal@23762
|
1469 - return v3;
|
pascal@23762
|
1470 + strcpy(v, (char *) (v3_64) ? "64BE v3.0a" : "32BE v3.0a");
|
pascal@23762
|
1471 + }
|
pascal@23762
|
1472 + v[10] = 'a' + ((flags-1) & 0xF); // compressors used
|
pascal@23762
|
1473 + if (flags > 0x10) { // with links ?
|
pascal@23762
|
1474 + v[10] += 'A' - 'a';
|
pascal@23762
|
1475 }
|
pascal@23762
|
1476 + return v;
|
pascal@23762
|
1477 }
|
pascal@23762
|
1478
|
pascal@23762
|
1479 /* Cloop suspend IOCTL */
|
pascal@23762
|
1480 --- cloop.c
|
pascal@23762
|
1481 +++ cloop.c
|
pascal@23762
|
1482 @@ -542,7 +542,7 @@
|
pascal@23762
|
1483 const unsigned int header_size = sizeof(struct cloop_head);
|
pascal@23762
|
1484 unsigned int i, total_offsets=0;
|
pascal@23762
|
1485 loff_t fs_read_position = 0, header_pos[2];
|
pascal@23762
|
1486 - int flags, isblkdev, bytes_read, error = 0;
|
pascal@23762
|
1487 + int isblkdev, bytes_read, error = 0;
|
pascal@23762
|
1488 if (clo->suspended) return error;
|
pascal@23762
|
1489 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)
|
pascal@23762
|
1490 inode = file->f_dentry->d_inode;
|
pascal@23762
|
1491 @@ -698,18 +698,12 @@
|
pascal@23762
|
1492 error=-EBADF; goto error_release;
|
pascal@23762
|
1493 }
|
pascal@23762
|
1494 len = CLOOP3_INDEX_SIZE(ntohl(tail.index_size)) * total_offsets;
|
pascal@23762
|
1495 - flags = CLOOP3_BLOCKS_FLAGS(ntohl(tail.index_size));
|
pascal@23762
|
1496 -// May 3 19:45:20 (none) user.info kernel: cloop: uncompress(clo=e0a78000, block_ptrs=e0c9c000, &len(1440)=ddc05e6c, zbuf=e0c9f000, zlen=43, flag=0)
|
pascal@23762
|
1497 -printk(KERN_INFO "%s: uncompress(clo=%p, block_ptrs=%p, &len(%ld)=%p, zbuf=%p, zlen=%ld, flag=%d)\n", cloop_name,
|
pascal@23762
|
1498 - clo, clo->block_ptrs, len, &len, zbuf, zlen, flags);
|
pascal@23762
|
1499 - ret = uncompress(clo, (void *) clo->block_ptrs, &len, zbuf, zlen, flags);
|
pascal@23762
|
1500 -// May 3 19:45:20 (none) user.alert kernel: BUG: unable to handle kernel NULL pointer dereference at (null)
|
pascal@23762
|
1501 -printk(KERN_INFO "%s: uncompressed !\n", cloop_name);
|
pascal@23762
|
1502 + ret = uncompress(clo, (void *) clo->block_ptrs, &len, zbuf, zlen, CLOOP_COMPRESSOR_ZLIB);
|
pascal@23762
|
1503 cloop_free(zbuf, zlen);
|
pascal@23762
|
1504 if (ret != 0)
|
pascal@23762
|
1505 {
|
pascal@23762
|
1506 - printk(KERN_ERR "%s: decompression error %i uncompressing index, flags %u\n",
|
pascal@23762
|
1507 - cloop_name, ret, flags);
|
pascal@23762
|
1508 + printk(KERN_ERR "%s: decompression error %i uncompressing index\n",
|
pascal@23762
|
1509 + cloop_name, ret);
|
pascal@23762
|
1510 error=-EBADF; goto error_release;
|
pascal@23762
|
1511 }
|
pascal@23762
|
1512 }
|
pascal@23762
|
1513 @@ -722,7 +716,6 @@
|
pascal@23762
|
1514 else
|
pascal@23762
|
1515 {
|
pascal@23762
|
1516 unsigned int n, total_bytes;
|
pascal@23762
|
1517 - flags = 0;
|
pascal@23762
|
1518 clo->block_ptrs = cloop_malloc(sizeof(struct block_info) * total_offsets);
|
pascal@23762
|
1519 if (!clo->block_ptrs)
|
pascal@23762
|
1520 {
|
pascal@23762
|
1521 @@ -761,7 +754,7 @@
|
pascal@23762
|
1522 }
|
pascal@23762
|
1523 {
|
pascal@23762
|
1524 int i;
|
pascal@23762
|
1525 - char *version = build_index(clo->block_ptrs, clo->head.num_blocks, clo->head.block_size, flags);
|
pascal@23762
|
1526 + char *version = build_index(clo->block_ptrs, clo->head.num_blocks, clo->head.block_size);
|
pascal@23762
|
1527 clo->largest_block = 0;
|
pascal@23762
|
1528 for (i = 0; i < clo->head.num_blocks; i++)
|
pascal@23762
|
1529 if (clo->block_ptrs[i].size > clo->largest_block)
|
pascal@23762
|
1530 @@ -769,9 +762,6 @@
|
pascal@23762
|
1531 printk(KERN_INFO "%s: %s: %s: %u blocks, %u bytes/block, largest block is %lu bytes.\n",
|
pascal@23762
|
1532 cloop_name, clo->underlying_filename, version, clo->head.num_blocks,
|
pascal@23762
|
1533 clo->head.block_size, clo->largest_block);
|
pascal@23762
|
1534 - }
|
pascal@23762
|
1535 - {
|
pascal@23762
|
1536 - int i;
|
pascal@23762
|
1537 clo->num_buffered_blocks = (buffers > 0 && clo->head.block_size >= 512) ?
|
pascal@23762
|
1538 (buffers / clo->head.block_size) : 1;
|
pascal@23762
|
1539 clo->buffered_blocknum = cloop_malloc(clo->num_buffered_blocks * sizeof (u_int32_t));
|
pascal@23762
|
1540 @@ -874,6 +864,10 @@
|
pascal@23762
|
1541 cloop_free(clo->block_ptrs, sizeof(struct block_info) * total_offsets);
|
pascal@23762
|
1542 clo->block_ptrs=NULL;
|
pascal@23762
|
1543 error_release:
|
pascal@23762
|
1544 +#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE))
|
pascal@23762
|
1545 + zlib_inflateEnd(&clo->zstream);
|
pascal@23762
|
1546 + if(clo->zstream.workspace) { cloop_free(clo->zstream.workspace, zlib_inflate_workspacesize()); clo->zstream.workspace = NULL; }
|
pascal@23762
|
1547 +#endif
|
pascal@23762
|
1548 if(bbuf) cloop_free(bbuf, clo->underlying_blksize);
|
pascal@23762
|
1549 if(clo->underlying_filename) { kfree(clo->underlying_filename); clo->underlying_filename=NULL; }
|
pascal@23762
|
1550 clo->backing_file=NULL;
|