# HG changeset patch # User Pascal Bellard # Date 1652028321 0 # Node ID 5a92a26adcc13c0af9267ce8d812f4930a127f7e # Parent 0f92b8cc80862d6d0c09947304687cff1e0c0eae Up xcursor-comix (0.9.2) diff -r 0f92b8cc8086 -r 5a92a26adcc1 linux-cloop/receipt --- a/linux-cloop/receipt Sun May 08 13:06:36 2022 +0000 +++ b/linux-cloop/receipt Sun May 08 16:45:21 2022 +0000 @@ -2,16 +2,15 @@ PACKAGE="linux-cloop" SOURCE="cloop" -_VERSION="2.639-2" -#VERSION="$(sed '/+#define CLOOP_VERSION/!d;s|.* "\(.*\)"|\1|' stuff/cloop.u)" +_VERSION="3.14.1.3" VERSION="4.12" CATEGORY="base-system" MAINTAINER="pascal.bellard@slitaz.org" LICENSE="GPL2" SHORT_DESC="The read-only compressed loop device kernel module." WEB_SITE="http://knoppix.net/wiki/Cloop" -TARBALL="${SOURCE}_${_VERSION}.tar.gz" -WGET_URL="http://debian-knoppix.alioth.debian.org/packages/$SOURCE/$TARBALL" +TARBALL="${SOURCE}_${_VERSION}.tar.xz" +WGET_URL="http://deb.debian.org/debian/pool/main/c/$SOURCE/$TARBALL" DEPENDS="linux" BUILD_DEPENDS="linux-module-headers xz" @@ -23,6 +22,7 @@ { patch -p0 < $stuff/cloop.u make ARCH=i386 KERNEL_DIR="/usr/src/linux" cloop.ko && xz cloop.ko + make cloop_suspend } # Rules to gen a SliTaz package suitable for Tazpkg. diff -r 0f92b8cc8086 -r 5a92a26adcc1 linux-cloop/stuff/cloop.u --- a/linux-cloop/stuff/cloop.u Sun May 08 13:06:36 2022 +0000 +++ b/linux-cloop/stuff/cloop.u Sun May 08 16:45:21 2022 +0000 @@ -1,6 +1,6 @@ --- cloop.h +++ cloop.h -@@ -1,15 +1,50 @@ +@@ -1,3 +1,7 @@ +#define CLOOP_SIGNATURE "#!/bin/sh" /* @ offset 0 */ +#define CLOOP_SIGNATURE_SIZE 9 +#define CLOOP_SIGNATURE_OFFSET 0x0 @@ -8,99 +8,46 @@ #ifndef _COMPRESSED_LOOP_H #define _COMPRESSED_LOOP_H --#define CLOOP_HEADROOM 128 -+/*************************************************************************\ -+* Starting with Format V4.0 (cloop version 4.x), cloop can now have two * -+* alternative structures: * -+* * -+* 1. Header first: "robust" format, handles missing blocks well * -+* 2. Footer (header last): "streaming" format, easier to create * -+* * -+* The cloop kernel module autodetects both formats, and can (currently) * -+* still handle the V2.0 format as well. * -+* * -+* 1. Header first: * -+* +---------------------------- FIXED SIZE ---------------------------+ * -+* |Signature (128 bytes) | * -+* |block_size (32bit number, network order) | * -+* |num_blocks (32bit number, network order) | * -+* +--------------------------- VARIABLE SIZE -------------------------+ * -+* |num_blocks * FlagsOffset (upper 4 bits flags, lower 64 bits offset)| * -+* |compressed data blocks of variable size ... | * -+* +-------------------------------------------------------------------+ * -+* * -+* 2. Footer (header last): * -+* +--------------------------- VARIABLE SIZE -------------------------+ * -+* |compressed data blocks of variable size ... | * -+* |num_blocks * FlagsOffset (upper 4 bits flags, lower 64 bits offset)| * -+* +---------------------------- FIXED SIZE ---------------------------+ * -+* |Signature (128 bytes) | * -+* |block_size (32bit number, network order) | * -+* |num_blocks (32bit number, network order) | * -+* +-------------------------------------------------------------------+ * -+* * -+* Offsets are always relative to beginning of file, in all formats. * -+* The block index contains num_blocks+1 offsets, followed (1) or * -+* preceded (2) by the compressed blocks. * -+\*************************************************************************/ +@@ -38,10 +42,6 @@ --/* The cloop header usually looks like this: */ --/* #!/bin/sh */ --/* #V2.00 Format */ --/* ...padding up to CLOOP_HEADROOM... */ --/* block_size (32bit number, network order) */ --/* num_blocks (32bit number, network order) */ -+#include /* u_int32_t */ -+ -+#define CLOOP_HEADROOM 128 + #include /* u_int32_t */ -+/* Header of fixed length, can be located at beginning or end of file */ - struct cloop_head - { - char preamble[CLOOP_HEADROOM]; -@@ -17,9 +52,163 @@ +-#ifndef __KERNEL__ +-#include /* regular uint64_t */ +-#endif +- + #define CLOOP_HEADROOM 128 + + /* Header of fixed length, can be located at beginning or end of file */ +@@ -52,13 +52,6 @@ u_int32_t num_blocks; }; -+/************************************************************************\ -+* CLOOP4 flags for each compressed block * -+* Value Meaning * -+* 0 GZIP/7ZIP compression (compatible with V2.0 Format) * -+* 1 no compression (incompressible data) * -+* 2 xz compression (currently best space saver) * -+* 3 lz4 compression * -+* 4 lzo compression (fastest) * -+\************************************************************************/ -+ -+typedef uint64_t cloop_block_ptr; -+ -+/* Get value of first 4 bits */ -+#define CLOOP_BLOCK_FLAGS(x) ((unsigned int)(((x) & 0xf000000000000000LLU) >> 60)) -+/* Get value of last 60 bits */ -+#define CLOOP_BLOCK_OFFSET(x) ((x) & 0x0fffffffffffffffLLU) -+ -+#define CLOOP_COMPRESSOR_ZLIB 0x0 -+#define CLOOP_COMPRESSOR_NONE 0x1 -+#define CLOOP_COMPRESSOR_XZ 0x2 -+#define CLOOP_COMPRESSOR_LZ4 0x3 -+#define CLOOP_COMPRESSOR_LZO1X 0x4 -+ -+#define CLOOP_COMPRESSOR_VALID(x) ((x) >= CLOOP_COMPRESSOR_ZLIB && (x) <= CLOOP_COMPRESSOR_LZO1X) -+ +-#define CLOOP2_SIGNATURE "V2.0" /* @ offset 0x0b */ +-#define CLOOP2_SIGNATURE_SIZE 4 +-#define CLOOP2_SIGNATURE_OFFSET 0x0b +-#define CLOOP4_SIGNATURE "V4.0" /* @ offset 0x0b */ +-#define CLOOP4_SIGNATURE_SIZE 4 +-#define CLOOP4_SIGNATURE_OFFSET 0x0b +- + /************************************************************************\ + * CLOOP4 flags for each compressed block * + * Value Meaning * +@@ -84,6 +77,134 @@ + + #define CLOOP_COMPRESSOR_VALID(x) ((x) >= CLOOP_COMPRESSOR_ZLIB && (x) <= CLOOP_COMPRESSOR_LZO1X) + +#define CLOOP_COMPRESSOR_LINK 0xF + + - /* data_index (num_blocks 64bit pointers, network order)... */ - /* compressed data (gzip block compressed format)... */ - ++/* data_index (num_blocks 64bit pointers, network order)... */ ++/* compressed data (gzip block compressed format)... */ ++ +struct cloop_tail +{ + u_int32_t table_size; -+ u_int32_t index_size; /* size:4 comp:3 ctrl-c:1 lastlen:24 */ ++ u_int32_t index_size; /* size:4 unused:3 ctrl-c:1 lastlen:24 */ +#define CLOOP3_INDEX_SIZE(x) ((unsigned int)((x) & 0xF)) -+#define CLOOP3_BLOCKS_FLAGS(x) ((unsigned int)((x) & 0x70) >> 4) -+#define CLOOP3_TRUNCATED(x) ((unsigned int)((x) & 0x80) >> 7) -+#define CLOOP3_LASTLEN(x) (unsigned int)((x) >> 8) + u_int32_t num_blocks; +}; + @@ -114,8 +61,10 @@ +}; + +static inline char *build_index(struct block_info *offsets, unsigned long n, -+ unsigned long block_size, unsigned global_flags) ++ unsigned long block_size) +{ ++ static char v[11]; ++ u_int32_t flags = 0; + u_int32_t *ofs32 = (u_int32_t *) offsets; + loff_t *ofs64 = (loff_t *) offsets; + @@ -140,8 +89,6 @@ + } + else { /* V2.0/V4.0 */ + loff_t last = CLOOP_BLOCK_OFFSET(__be64_to_cpu(ofs64[n])); -+ u_int32_t flags; -+ static char v4[11]; + unsigned long i = n; + + for (flags = 0; n-- ;) { @@ -159,12 +106,7 @@ + offsets[i] = offsets[offsets[i].offset]; + } + } -+ strcpy(v4, (char *) "64BE v4.0a"); -+ v4[10] = 'a' + ((flags-1) & 0xF); // compressors used -+ if (flags > 0x10) { // with links ? -+ v4[10] += 'A' - 'a'; -+ } -+ return v4; ++ strcpy(v, (char *) "64BE v4.0a"); + } + } + else if (ofs32[1] == 0 && v3_64 == 0) { /* V1.0 */ @@ -180,7 +122,6 @@ + else { /* V3.0 or V0.68 */ + unsigned long i; + loff_t j; -+ static char v3[11]; + + for (i = 0; i < n && ntohl(ofs32[i]) < ntohl(ofs32[i+1]); i++); + if (i == n && ntohl(ofs32[0]) == (4*n) + 0x8C) { /* V0.68 */ @@ -195,28 +136,33 @@ + } + + v3_64 = (ofs32[1] == 0); -+ for (i = n; i-- != 0; ) ++ for (i = n; i-- != 0; ) { + offsets[i].size = ntohl(ofs32[i << v3_64]); ++ if (offsets[i].size == 0xFFFFFFFF) { ++ offsets[i].size = 0x10000000 | block_size; ++ } ++ offsets[i].flags = (offsets[i].size >> 28); ++ offsets[i].size &= 0x0FFFFFFF; ++ } + for (i = 0, j = sizeof(struct cloop_head); i < n; i++) { + offsets[i].offset = j; -+ offsets[i].flags = global_flags; -+ if (offsets[i].size == 0xFFFFFFFF) { -+ offsets[i].flags = CLOOP_COMPRESSOR_NONE; -+ offsets[i].size = block_size; -+ } -+ if ((offsets[i].size & 0x80000000) == 0) { ++ if (offsets[i].flags < 8) { + j += offsets[i].size; + } + } + for (i = 0; i < n; i++) { -+ if (offsets[i].size & 0x80000000) { -+ offsets[i] = offsets[offsets[i].size & 0x7FFFFFFF]; ++ flags |= 1 << offsets[i].flags; ++ if (offsets[i].flags >= 8) { ++ offsets[i] = offsets[offsets[i].size]; + } + } -+ strcpy(v3, (char *) (v3_64) ? "64BE v3.0a" : "32BE v3.0a"); -+ v3[10] += global_flags; -+ return v3; ++ strcpy(v, (char *) (v3_64) ? "64BE v3.0a" : "32BE v3.0a"); + } ++ v[10] = 'a' + ((flags-1) & 0xF); // compressors used ++ if (flags > 0x10) { // with links ? ++ v[10] += 'A' - 'a'; ++ } ++ return v; +} + /* Cloop suspend IOCTL */ @@ -224,661 +170,538 @@ --- cloop.c +++ cloop.c -@@ -1,26 +1,23 @@ --/* -- * compressed_loop.c: Read-only compressed loop blockdevice -- * hacked up by Rusty in 1999, extended and maintained by Klaus Knopper -- * -- * A cloop file looks like this: -- * [32-bit uncompressed block size: network order] -- * [32-bit number of blocks (n_blocks): network order] -- * [64-bit file offsets of start of blocks: network order] -- * ... -- * (n_blocks + 1). -- * n_blocks consisting of: -- * [compressed block] -- * -- * Every version greatly inspired by code seen in loop.c -- * by Theodore Ts'o, 3/29/93. -- * -- * Copyright 1999-2009 by Paul `Rusty' Russell & Klaus Knopper. -- * Redistribution of this file is permitted under the GNU Public License. -- * -- */ -+/************************************************************************\ -+* cloop.c: Read-only compressed loop blockdevice * -+* hacked up by Rusty in 1999, extended and maintained by Klaus Knopper * -+* * -+* For all supported cloop file formats, please check the file "cloop.h" * -+* New in Version 4: * -+* - Header can be first or last in cloop file, * -+* - Different compression algorithms supported (compression type * -+* encoded in first 4 bytes of block offset address) * -+* * -+* Every version greatly inspired by code seen in loop.c * -+* by Theodore Ts'o, 3/29/93. * -+* * -+* Copyright 1999-2009 by Paul `Rusty' Russell & Klaus Knopper. * -+* Redistribution of this file is permitted under the GNU Public License * -+* V2. * -+\************************************************************************/ +@@ -17,7 +17,7 @@ + \************************************************************************/ #define CLOOP_NAME "cloop" --#define CLOOP_VERSION "2.639" +-#define CLOOP_VERSION "5.3" +#define CLOOP_VERSION "4.12" #define CLOOP_MAX 8 #ifndef KBUILD_MODNAME -@@ -47,8 +44,27 @@ - #include /* do_div() for 64bit division */ - #include - #include --/* Use zlib_inflate from lib/zlib_inflate */ -+/* Check for ZLIB, LZO1X, LZ4 decompression algorithms in kernel. */ -+#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE)) - #include -+#endif -+#if (defined(CONFIG_LZO_DECOMPRESS) || defined(CONFIG_LZO_DECOMPRESS_MODULE)) -+#include -+#endif -+#if (defined(CONFIG_DECOMPRESS_LZ4) || defined(CONFIG_DECOMPRESS_LZ4_MODULE)) -+#include -+#endif -+#if (defined(CONFIG_DECOMPRESS_LZMA) || defined(CONFIG_DECOMPRESS_LZMA_MODULE)) -+#include -+#endif -+#if (defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE)) -+#include -+#endif -+ -+#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))) -+#error "No decompression library selected in kernel config!" -+#endif -+ +@@ -68,7 +68,6 @@ #include #include #include -@@ -92,47 +108,64 @@ - #define DEBUGP(format, x...) - #endif +-#include /* new multiqueue infrastructure */ + #include "cloop.h" -+/* Default size of buffer to keep some decompressed blocks in memory to speed up access */ -+#define BLOCK_BUFFER_MEM (16*65536) -+ - /* One file can be opened at module insertion time */ - /* insmod cloop file=/path/to/file */ - static char *file=NULL; - static unsigned int preload=0; - static unsigned int cloop_max=CLOOP_MAX; -+static unsigned int buffers=BLOCK_BUFFER_MEM; - module_param(file, charp, 0); - module_param(preload, uint, 0); - module_param(cloop_max, uint, 0); - MODULE_PARM_DESC(file, "Initial cloop image file (full path) for /dev/cloop"); - MODULE_PARM_DESC(preload, "Preload n blocks of cloop data into memory"); - MODULE_PARM_DESC(cloop_max, "Maximum number of cloop devices (default 8)"); -+MODULE_PARM_DESC(buffers, "Size of buffer to keep uncompressed blocks in memory in MiB (default 1)"); + /* New License scheme */ +@@ -93,10 +92,7 @@ + /* Use experimental major for now */ + #define MAJOR_NR 240 - static struct file *initial_file=NULL; - static int cloop_major=MAJOR_NR; +-#ifndef DEVICE_NAME +-#define DEVICE_NAME CLOOP_NAME +-#endif +- ++/* #define DEVICE_NAME CLOOP_NAME */ + /* #define DEVICE_NR(device) (MINOR(device)) */ + /* #define DEVICE_ON(device) */ + /* #define DEVICE_OFF(device) */ +@@ -143,7 +139,7 @@ + u_int32_t allflags; --/* Number of buffered decompressed blocks */ --#define BUFFERED_BLOCKS 8 - struct cloop_device - { -- /* Copied straight from the file */ -+ /* Header filled from the file */ - struct cloop_head head; -+ int header_first; -+ int file_format; - -- /* An array of offsets of compressed blocks within the file */ -- loff_t *offsets; -+ /* An or'd sum of all flags of each compressed block (v3) */ -+ u_int32_t allflags; -+ -+ /* An array of cloop_ptr flags/offset for compressed blocks within the file */ + /* An array of cloop_ptr flags/offset for compressed blocks within the file */ +- cloop_block_ptr *block_ptrs; + struct block_info *block_ptrs; /* We buffer some uncompressed blocks for performance */ -- int buffered_blocknum[BUFFERED_BLOCKS]; -- int current_bufnum; -- void *buffer[BUFFERED_BLOCKS]; -- void *compressed_buffer; -- size_t preload_array_size; /* Size of pointer array in blocks */ -- size_t preload_size; /* Number of successfully allocated blocks */ -- char **preload_cache; /* Pointers to preloaded blocks */ -+ size_t num_buffered_blocks; /* how many uncompressed blocks buffered for performance */ -+ int *buffered_blocknum; /* list of numbers of uncompressed blocks in buffer */ -+ int current_bufnum; /* which block is current */ -+ unsigned char **buffer; /* cache space for num_buffered_blocks uncompressed blocks */ -+ void *compressed_buffer; /* space for the largest compressed block */ -+ size_t preload_array_size; /* Size of pointer array in blocks */ -+ size_t preload_size; /* Number of successfully allocated blocks */ -+ char **preload_cache; /* Pointers to preloaded blocks */ - -+#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE)) - z_stream zstream; -+#endif -+#if (defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE)) -+ struct xz_dec *xzdecoderstate; -+ struct xz_buf xz_buffer; -+#endif - - struct file *backing_file; /* associated file */ - struct inode *backing_inode; /* for bmap */ - -+ unsigned char *underlying_filename; - unsigned long largest_block; - unsigned int underlying_blksize; -+ loff_t underlying_total_size; - int clo_number; - int refcnt; - struct block_device *bdev; -@@ -147,7 +180,6 @@ + size_t num_buffered_blocks; /* how many uncompressed blocks buffered for performance */ +@@ -178,14 +174,16 @@ + spinlock_t queue_lock; + /* mutex for ioctl() */ + struct mutex clo_ctl_mutex; +- /* mutex for request */ +- struct mutex clo_rq_mutex; ++ struct list_head clo_list; ++ struct task_struct *clo_thread; ++ wait_queue_head_t clo_event; struct request_queue *clo_queue; struct gendisk *clo_disk; +- struct blk_mq_tag_set tag_set; int suspended; -- char clo_file_name[LO_NAME_SIZE]; }; - /* Changed in 2.639: cloop_dev is now a an array of cloop_dev pointers, -@@ -156,52 +188,113 @@ ++/* Changed in 2.639: cloop_dev is now a an array of cloop_dev pointers, ++ so we can specify how many devices we need via parameters. */ + static struct cloop_device **cloop_dev; static const char *cloop_name=CLOOP_NAME; static int cloop_count = 0; - --#if (!(defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE))) /* Must be compiled into kernel. */ --#error "Invalid Kernel configuration. CONFIG_ZLIB_INFLATE support is needed for cloop." --#endif -- --/* Use __get_free_pages instead of vmalloc, allows up to 32 pages, -- * 2MB in one piece */ - static void *cloop_malloc(size_t size) - { -- int order = get_order(size); -- if(order <= KMALLOC_MAX_ORDER) -- return (void *)kmalloc(size, GFP_KERNEL); -- else if(order < MAX_ORDER) -- return (void *)__get_free_pages(GFP_KERNEL, order); -+ /* kmalloc will fail after the system is running for a while, */ -+ /* when large orders can't return contiguous memory. */ -+ /* Let's just use vmalloc for now. :-/ */ -+ /* int order = get_order(size); */ -+ /* if(order <= KMALLOC_MAX_ORDER) */ -+ /* return (void *)kmalloc(size, GFP_KERNEL); */ -+ /* else if(order < MAX_ORDER) */ -+ /* return (void *)__get_free_pages(GFP_KERNEL, order); */ - return (void *)vmalloc(size); +@@ -214,24 +212,21 @@ + vfree(mem); } - static void cloop_free(void *mem, size_t size) - { -- int order = get_order(size); -- if(order <= KMALLOC_MAX_ORDER) -- kfree(mem); -- else if(order < MAX_ORDER) -- free_pages((unsigned long)mem, order); -- else vfree(mem); -+ /* int order = get_order(size); */ -+ /* if(order <= KMALLOC_MAX_ORDER) */ -+ /* kfree(mem); */ -+ /* else if(order < MAX_ORDER) */ -+ /* free_pages((unsigned long)mem, order); */ -+ /* else */ -+ vfree(mem); - } - --static int uncompress(struct cloop_device *clo, -- unsigned char *dest, unsigned long *destLen, -- unsigned char *source, unsigned long sourceLen) +-/* static int uncompress(struct cloop_device *clo, unsigned char *dest, unsigned long *destLen, unsigned char *source, unsigned long sourceLen) */ +-static int uncompress(struct cloop_device *clo, u_int32_t block_num, u_int32_t compressed_length, unsigned long *uncompressed_length) +static int uncompress(struct cloop_device *clo, unsigned char *dest, unsigned long *destLen, unsigned char *source, unsigned long sourceLen, int flags) { -- /* Most of this code can be found in fs/cramfs/uncompress.c */ -- int err; -- clo->zstream.next_in = source; -- clo->zstream.avail_in = sourceLen; -- clo->zstream.next_out = dest; -- clo->zstream.avail_out = *destLen; -- err = zlib_inflateReset(&clo->zstream); -- if (err != Z_OK) -- { -- printk(KERN_ERR "%s: zlib_inflateReset error %d\n", cloop_name, err); -- zlib_inflateEnd(&clo->zstream); zlib_inflateInit(&clo->zstream); -- } -- err = zlib_inflate(&clo->zstream, Z_FINISH); -- *destLen = clo->zstream.total_out; -- if (err != Z_STREAM_END) return err; -- return Z_OK; -+ int err = -1; -+ switch(flags) -+ { -+ case CLOOP_COMPRESSOR_NONE: + int err = -1; +- int flags = CLOOP_BLOCK_FLAGS(clo->block_ptrs[block_num]); + switch(flags) + { + case CLOOP_COMPRESSOR_NONE: +- /* block is umcompressed, swap pointers only! */ +- { char *tmp = clo->compressed_buffer; clo->compressed_buffer = clo->buffer[clo->current_bufnum]; clo->buffer[clo->current_bufnum] = tmp; } +- DEBUGP("cloop: block %d is uncompressed (flags=%d), just swapping %u bytes\n", block_num, flags, compressed_length); + memcpy(dest, source, *destLen = sourceLen); + err = Z_OK; -+ break; -+#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE)) -+ case CLOOP_COMPRESSOR_ZLIB: + break; + #if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE)) + case CLOOP_COMPRESSOR_ZLIB: +- clo->zstream.next_in = clo->compressed_buffer; +- clo->zstream.avail_in = compressed_length; +- clo->zstream.next_out = clo->buffer[clo->current_bufnum]; +- clo->zstream.avail_out = clo->head.block_size; + clo->zstream.next_in = source; + clo->zstream.avail_in = sourceLen; + clo->zstream.next_out = dest; + clo->zstream.avail_out = *destLen; -+ err = zlib_inflateReset(&clo->zstream); -+ if (err != Z_OK) -+ { -+ printk(KERN_ERR "%s: zlib_inflateReset error %d\n", cloop_name, err); -+ zlib_inflateEnd(&clo->zstream); zlib_inflateInit(&clo->zstream); -+ } -+ err = zlib_inflate(&clo->zstream, Z_FINISH); + err = zlib_inflateReset(&clo->zstream); + if (err != Z_OK) + { +@@ -239,50 +234,50 @@ + zlib_inflateEnd(&clo->zstream); zlib_inflateInit(&clo->zstream); + } + err = zlib_inflate(&clo->zstream, Z_FINISH); +- *uncompressed_length = clo->zstream.total_out; + *destLen = clo->zstream.total_out; -+ if (err == Z_STREAM_END) err = 0; + if (err == Z_STREAM_END) err = 0; +- DEBUGP("cloop: zlib decompression done, ret =%d, size =%lu\n", err, *uncompressed_length); + DEBUGP("cloop: zlib decompression done, ret =%d, size =%lu\n", err, *destLen); -+ break; -+#endif -+#if (defined(CONFIG_LZO_DECOMPRESS) || defined(CONFIG_LZO_DECOMPRESS_MODULE)) -+ case CLOOP_COMPRESSOR_LZO1X: -+ { -+ size_t tmp = (size_t) clo->head.block_size; + break; + #endif + #if (defined(CONFIG_LZO_DECOMPRESS) || defined(CONFIG_LZO_DECOMPRESS_MODULE)) + case CLOOP_COMPRESSOR_LZO1X: + { + size_t tmp = (size_t) clo->head.block_size; +- err = lzo1x_decompress_safe(clo->compressed_buffer, compressed_length, +- clo->buffer[clo->current_bufnum], &tmp); +- if (err == LZO_E_OK) *uncompressed_length = (u_int32_t) tmp; + err = lzo1x_decompress_safe(source, sourceLen, + dest, &tmp); + if (err == LZO_E_OK) *destLen = (u_int32_t) tmp; -+ } -+ break; -+#endif -+#if (defined(CONFIG_DECOMPRESS_LZ4) || defined(CONFIG_DECOMPRESS_LZ4_MODULE)) -+ case CLOOP_COMPRESSOR_LZ4: -+ { + } + break; + #endif + #if (defined(CONFIG_DECOMPRESS_LZ4) || defined(CONFIG_DECOMPRESS_LZ4_MODULE)) + case CLOOP_COMPRESSOR_LZ4: + { +- size_t outputSize = clo->head.block_size; + size_t outputSize = *destLen; -+ /* We should adjust outputSize here, in case the last block is smaller than block_size */ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) /* field removed */ + /* We should adjust outputSize here, in case the last block is smaller than block_size */ + #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) /* field removed */ +- err = lz4_decompress(clo->compressed_buffer, (size_t *) &compressed_length, +- clo->buffer[clo->current_bufnum], outputSize); + err = lz4_decompress(source, (size_t *) &sourceLen, + dest, outputSize); -+#else + #else +- err = LZ4_decompress_safe(clo->compressed_buffer, +- clo->buffer[clo->current_bufnum], +- compressed_length, outputSize); + err = LZ4_decompress_safe(source, + dest, + sourceLen, outputSize); -+#endif -+ if (err >= 0) -+ { -+ err = 0; + #endif + if (err >= 0) + { + err = 0; +- *uncompressed_length = outputSize; + *destLen = outputSize; -+ } -+ } -+ break; -+#endif -+#if (defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE)) -+ case CLOOP_COMPRESSOR_XZ: + } + } + break; + #endif + #if (defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE)) + case CLOOP_COMPRESSOR_XZ: +- clo->xz_buffer.in = clo->compressed_buffer; + clo->xz_buffer.in = source; -+ clo->xz_buffer.in_pos = 0; + clo->xz_buffer.in_pos = 0; +- clo->xz_buffer.in_size = compressed_length; +- clo->xz_buffer.out = clo->buffer[clo->current_bufnum]; + clo->xz_buffer.in_size = sourceLen; + clo->xz_buffer.out = dest; -+ clo->xz_buffer.out_pos = 0; + clo->xz_buffer.out_pos = 0; +- clo->xz_buffer.out_size = clo->head.block_size; + clo->xz_buffer.out_size = *destLen; -+ xz_dec_reset(clo->xzdecoderstate); -+ err = xz_dec_run(clo->xzdecoderstate, &clo->xz_buffer); -+ if (err == XZ_STREAM_END || err == XZ_OK) -+ { -+ err = 0; -+ } -+ else -+ { -+ printk(KERN_ERR "%s: xz_dec_run error %d\n", cloop_name, err); -+ err = 1; -+ } -+ break; -+#endif -+ default: -+ printk(KERN_ERR "%s: compression method is not supported!\n", cloop_name); -+ } -+ return err; - } - - static ssize_t cloop_read_from_file(struct cloop_device *clo, struct file *f, char *buf, -@@ -220,7 +313,7 @@ + xz_dec_reset(clo->xzdecoderstate); + err = xz_dec_run(clo->xzdecoderstate, &clo->xz_buffer); + if (err == XZ_STREAM_END || err == XZ_OK) +@@ -309,16 +304,12 @@ + while (buf_done < buf_len) + { + size_t size = buf_len - buf_done, size_read; +- mm_segment_t old_fs; + /* kernel_read() only supports 32 bit offsets, so we use vfs_read() instead. */ + /* int size_read = kernel_read(f, pos, buf + buf_done, size); */ +- +- // mutex_lock(&clo->clo_rq_mutex); +- old_fs = get_fs(); +- set_fs(KERNEL_DS); ++ mm_segment_t old_fs = get_fs(); ++ set_fs(get_ds()); + size_read = vfs_read(f, (void __user *)(buf + buf_done), size, &pos); + set_fs(old_fs); +- // mutex_unlock(&clo->clo_rq_mutex); if(size_read <= 0) { -- printk(KERN_ERR "%s: Read error %d at pos %Lu in file %s, " -+ printk(KERN_ERR "%s: Read error %d at pos %llu in file %s, " - "%d bytes lost.\n", cloop_name, (int)size_read, pos, - file, (int)size); - memset(buf + buf_len - size, 0, size); -@@ -232,72 +325,84 @@ - } +@@ -358,8 +349,8 @@ + return i; + } - /* This looks more complicated than it is */ --/* Returns number of block buffer to use for this request */ -+/* Returns number of cache block buffer to use for this request */ - static int cloop_load_buffer(struct cloop_device *clo, int blocknum) - { -- unsigned int buf_done = 0; -- unsigned long buflen; -- unsigned int buf_length; -+ loff_t compressed_block_offset; -+ long compressed_block_len; -+ long uncompressed_block_len=0; - int ret; - int i; -- if(blocknum > ntohl(clo->head.num_blocks) || blocknum < 0) -- { -- printk(KERN_WARNING "%s: Invalid block number %d requested.\n", -- cloop_name, blocknum); -- return -1; -- } -+ if(blocknum > clo->head.num_blocks || blocknum < 0) -+ { -+ printk(KERN_WARNING "%s: Invalid block number %d requested.\n", -+ cloop_name, blocknum); -+ return -1; -+ } - - /* Quick return if the block we seek is already in one of the buffers. */ - /* Return number of buffer */ -- for(i=0; inum_buffered_blocks; i++) - if (blocknum == clo->buffered_blocknum[i]) -- { -- DEBUGP(KERN_INFO "cloop_load_buffer: Found buffered block %d\n", i); -- return i; -- } -- -- buf_length = be64_to_cpu(clo->offsets[blocknum+1]) - be64_to_cpu(clo->offsets[blocknum]); -- --/* Load one compressed block from the file. */ -- cloop_read_from_file(clo, clo->backing_file, (char *)clo->compressed_buffer, -- be64_to_cpu(clo->offsets[blocknum]), buf_length); -+ { -+ DEBUGP(KERN_INFO "cloop_load_buffer: Found buffered block %d\n", i); -+ return i; -+ } - -- buflen = ntohl(clo->head.block_size); +- compressed_block_offset = CLOOP_BLOCK_OFFSET(clo->block_ptrs[blocknum]); +- compressed_block_len = (long) (CLOOP_BLOCK_OFFSET(clo->block_ptrs[blocknum+1]) - compressed_block_offset) ; + compressed_block_offset = clo->block_ptrs[blocknum].offset; + compressed_block_len = (long) (clo->block_ptrs[blocknum].size) ; -- /* Go to next position in the block ring buffer */ -- clo->current_bufnum++; -- if(clo->current_bufnum >= BUFFERED_BLOCKS) clo->current_bufnum = 0; -+ /* Load one compressed block from the file. */ -+ if(compressed_block_offset > 0 && compressed_block_len >= 0) /* sanity check */ -+ { -+ size_t n = cloop_read_from_file(clo, clo->backing_file, (char *)clo->compressed_buffer, -+ compressed_block_offset, compressed_block_len); -+ if (n!= compressed_block_len) -+ { -+ printk(KERN_ERR "%s: error while reading %lu bytes @ %llu from file %s\n", + /* Load one compressed block from the file. */ + if(compressed_block_offset > 0 && compressed_block_len >= 0) /* sanity check */ +@@ -369,12 +360,12 @@ + if (n!= compressed_block_len) + { + printk(KERN_ERR "%s: error while reading %lu bytes @ %llu from file %s\n", +- cloop_name, compressed_block_len, clo->block_ptrs[blocknum], clo->underlying_filename); + cloop_name, compressed_block_len, clo->block_ptrs[blocknum].offset, clo->underlying_filename); -+ /* return -1; */ -+ } -+ } else { -+ printk(KERN_ERR "%s: invalid data block len %ld bytes @ %lld from file %s\n", + /* return -1; */ + } + } else { + printk(KERN_ERR "%s: invalid data block len %ld bytes @ %lld from file %s\n", +- cloop_name, compressed_block_len, clo->block_ptrs[blocknum], clo->underlying_filename); + cloop_name, compressed_block_len, clo->block_ptrs[blocknum].offset, clo->underlying_filename); -+ return -1; -+ } -+ -+ /* Go to next position in the cache block buffer (which is used as a cyclic buffer) */ -+ if(++clo->current_bufnum >= clo->num_buffered_blocks) clo->current_bufnum = 0; + return -1; + } + +@@ -382,14 +373,16 @@ + if(++clo->current_bufnum >= clo->num_buffered_blocks) clo->current_bufnum = 0; /* Do the uncompression */ -- ret = uncompress(clo, clo->buffer[clo->current_bufnum], &buflen, clo->compressed_buffer, -- buf_length); +- ret = uncompress(clo, blocknum, compressed_block_len, &uncompressed_block_len); + uncompressed_block_len = clo->head.block_size; + ret = uncompress(clo, clo->buffer[clo->current_bufnum], &uncompressed_block_len, + clo->compressed_buffer, compressed_block_len, clo->block_ptrs[blocknum].flags); /* DEBUGP("cloop: buflen after uncompress: %ld\n",buflen); */ if (ret != 0) -- { -- printk(KERN_ERR "%s: zlib decompression error %i uncompressing block %u %u/%lu/%u/%u " -- "%Lu-%Lu\n", cloop_name, ret, blocknum, -- ntohl(clo->head.block_size), buflen, buf_length, buf_done, -- be64_to_cpu(clo->offsets[blocknum]), be64_to_cpu(clo->offsets[blocknum+1])); -- clo->buffered_blocknum[clo->current_bufnum] = -1; -- return -1; -- } -+ { -+ printk(KERN_ERR "%s: decompression error %i uncompressing block %u %lu bytes @ %llu, flags %u\n", -+ cloop_name, ret, blocknum, + { + printk(KERN_ERR "%s: decompression error %i uncompressing block %u %lu bytes @ %llu, flags %u\n", + cloop_name, ret, blocknum, +- compressed_block_len, CLOOP_BLOCK_OFFSET(clo->block_ptrs[blocknum]), +- CLOOP_BLOCK_FLAGS(clo->block_ptrs[blocknum])); + compressed_block_len, clo->block_ptrs[blocknum].offset, + clo->block_ptrs[blocknum].flags); -+ clo->buffered_blocknum[clo->current_bufnum] = -1; -+ return -1; -+ } - clo->buffered_blocknum[clo->current_bufnum] = blocknum; + clo->buffered_blocknum[clo->current_bufnum] = -1; + return -1; + } +@@ -397,107 +390,146 @@ return clo->current_bufnum; } - /* This function does all the real work. */ --/* returns "uptodate" */ +-static blk_status_t cloop_handle_request(struct cloop_device *clo, struct request *req) ++/* This function does all the real work. */ +/* returns "uptodate" */ - static int cloop_handle_request(struct cloop_device *clo, struct request *req) ++static int cloop_handle_request(struct cloop_device *clo, struct request *req) { int buffered_blocknum = -1; int preloaded = 0; - loff_t offset = (loff_t) blk_rq_pos(req)<<9; /* req->sector<<9 */ -- struct bio_vec *bvec; -+ struct bio_vec bvec; +- loff_t offset = (loff_t) blk_rq_pos(req)<<9; ++ loff_t offset = (loff_t) blk_rq_pos(req)<<9; /* req->sector<<9 */ + struct bio_vec bvec; struct req_iterator iter; +- blk_status_t ret = BLK_STS_OK; +- +- if (unlikely(req_op(req) != REQ_OP_READ )) +- { +- blk_dump_rq_flags(req, DEVICE_NAME " bad request"); +- return BLK_STS_IOERR; +- } +- +- if (unlikely(!clo->backing_file && !clo->suspended)) +- { +- DEBUGP("cloop_handle_request: not connected to a file\n"); +- return BLK_STS_IOERR; +- } +- rq_for_each_segment(bvec, req, iter) +- { +- unsigned long len = bvec.bv_len; +- loff_t to_offset = bvec.bv_offset; +- +- while(len > 0) { -- unsigned long len = bvec->bv_len; -- char *to_ptr = kmap(bvec->bv_page) + bvec->bv_offset; +- u_int32_t length_in_buffer; +- loff_t block_offset = offset; +- u_int32_t offset_in_buffer; +- char *from_ptr, *to_ptr; +- /* do_div (div64.h) returns the 64bit division remainder and */ +- /* puts the result in the first argument, i.e. block_offset */ +- /* becomes the blocknumber to load, and offset_in_buffer the */ +- /* position in the buffer */ +- offset_in_buffer = do_div(block_offset, clo->head.block_size); +- /* Lookup preload cache */ +- if(block_offset < clo->preload_size && clo->preload_cache != NULL && clo->preload_cache[block_offset] != NULL) +- { /* Copy from cache */ +- preloaded = 1; +- from_ptr = clo->preload_cache[block_offset]; +- } +- else +- { +- preloaded = 0; +- buffered_blocknum = cloop_load_buffer(clo,block_offset); +- if(buffered_blocknum == -1) + unsigned long len = bvec.bv_len; + char *to_ptr = kmap(bvec.bv_page) + bvec.bv_offset; - while(len > 0) ++ while(len > 0) { - u_int32_t length_in_buffer; -@@ -308,7 +413,7 @@ - /* puts the result in the first argument, i.e. block_offset */ - /* becomes the blocknumber to load, and offset_in_buffer the */ - /* position in the buffer */ -- offset_in_buffer = do_div(block_offset, ntohl(clo->head.block_size)); +- ret = BLK_STS_IOERR; +- break; /* invalid data, leave inner loop */ ++ u_int32_t length_in_buffer; ++ loff_t block_offset = offset; ++ u_int32_t offset_in_buffer; ++ char *from_ptr; ++ /* do_div (div64.h) returns the 64bit division remainder and */ ++ /* puts the result in the first argument, i.e. block_offset */ ++ /* becomes the blocknumber to load, and offset_in_buffer the */ ++ /* position in the buffer */ + offset_in_buffer = do_div(block_offset, clo->head.block_size); - /* Lookup preload cache */ - if(block_offset < clo->preload_size && clo->preload_cache != NULL && - clo->preload_cache[block_offset] != NULL) -@@ -325,7 +430,7 @@ - from_ptr = clo->buffer[buffered_blocknum]; - } - /* Now, at least part of what we want will be in the buffer. */ -- length_in_buffer = ntohl(clo->head.block_size) - offset_in_buffer; ++ /* Lookup preload cache */ ++ if(block_offset < clo->preload_size && clo->preload_cache != NULL && ++ clo->preload_cache[block_offset] != NULL) ++ { /* Copy from cache */ ++ preloaded = 1; ++ from_ptr = clo->preload_cache[block_offset]; ++ } ++ else ++ { ++ preloaded = 0; ++ buffered_blocknum = cloop_load_buffer(clo,block_offset); ++ if(buffered_blocknum == -1) break; /* invalid data, leave inner loop */ ++ /* Copy from buffer */ ++ from_ptr = clo->buffer[buffered_blocknum]; ++ } ++ /* Now, at least part of what we want will be in the buffer. */ + length_in_buffer = clo->head.block_size - offset_in_buffer; - if(length_in_buffer > len) - { - /* DEBUGP("Warning: length_in_buffer=%u > len=%u\n", -@@ -337,18 +442,19 @@ - len -= length_in_buffer; - offset += length_in_buffer; - } /* while inner loop */ -- kunmap(bvec->bv_page); ++ if(length_in_buffer > len) ++ { ++/* DEBUGP("Warning: length_in_buffer=%u > len=%u\n", ++ length_in_buffer,len); */ ++ length_in_buffer = len; ++ } ++ memcpy(to_ptr, from_ptr + offset_in_buffer, length_in_buffer); ++ to_ptr += length_in_buffer; ++ len -= length_in_buffer; ++ offset += length_in_buffer; ++ } /* while inner loop */ + kunmap(bvec.bv_page); + cond_resched(); - } /* end rq_for_each_segment*/ - return ((buffered_blocknum!=-1) || preloaded); - } - - /* Adopted from loop.c, a kernel thread to handle physical reads and -- * decompression. */ ++ } /* end rq_for_each_segment*/ ++ return ((buffered_blocknum!=-1) || preloaded); ++} ++ ++/* Adopted from loop.c, a kernel thread to handle physical reads and + decompression. */ - static int cloop_thread(void *data) - { - struct cloop_device *clo = data; - current->flags |= PF_NOFREEZE; -- set_user_nice(current, -15); ++static int cloop_thread(void *data) ++{ ++ struct cloop_device *clo = data; ++ current->flags |= PF_NOFREEZE; + set_user_nice(current, 10); - while (!kthread_should_stop()||!list_empty(&clo->clo_list)) - { - int err; -@@ -390,10 +496,18 @@ - int rw; - /* quick sanity checks */ - /* blk_fs_request() was removed in 2.6.36 */ -- if (unlikely(req == NULL || (req->cmd_type != REQ_TYPE_FS))) ++ while (!kthread_should_stop()||!list_empty(&clo->clo_list)) ++ { ++ int err; ++ err = wait_event_interruptible(clo->clo_event, !list_empty(&clo->clo_list) || ++ kthread_should_stop()); ++ if(unlikely(err)) ++ { ++ DEBUGP(KERN_ERR "cloop thread activated on error!? Continuing.\n"); ++ continue; + } +- /* Copy from buffer */ +- from_ptr = clo->buffer[buffered_blocknum]; +- } +- /* Now, at least part of what we want will be in the buffer. */ +- length_in_buffer = clo->head.block_size - offset_in_buffer; +- if(length_in_buffer > len) +- { +- /* DEBUGP("Warning: length_in_buffer=%u > len=%u\n", length_in_buffer,len); */ +- length_in_buffer = len; +- } +- to_ptr = kmap_atomic(bvec.bv_page); +- memcpy(to_ptr + to_offset, from_ptr + offset_in_buffer, length_in_buffer); +- kunmap_atomic(to_ptr); +- to_offset += length_in_buffer; +- len -= length_in_buffer; +- offset += length_in_buffer; +- } /* while inner loop */ +- } /* rq_for_each_segment */ +- return ret; +-} +- +-static blk_status_t cloop_queue_rq(struct blk_mq_hw_ctx *hctx, const struct blk_mq_queue_data *bd) +-{ +-// struct request_queue *q = hctx->queue; +-// struct cloop_device *clo = q->queuedata; +- struct request *req = bd->rq; +- struct cloop_device *clo = req->rq_disk->private_data; +- blk_status_t ret = BLK_STS_OK; +- +-#if 1 /* Does it work when loading libraries? */ +- /* Since we have a buffered block list as well as data to read */ +- /* from disk (slow), and are (probably) never called from an */ +- /* interrupt, we use a simple mutex lock right here to ensure */ +- /* consistency. */ +- mutex_lock(&clo->clo_rq_mutex); +- #else +- spin_lock_irq(&clo->queue_lock); +- #endif +- blk_mq_start_request(req); +- do { +- ret = cloop_handle_request(clo, req); +- } while(blk_update_request(req, ret, blk_rq_cur_bytes(req))); +- blk_mq_end_request(req, ret); +- #if 1 /* See above */ +- mutex_unlock(&clo->clo_rq_mutex); +- #else +- spin_unlock_irq(&clo->queue_lock); +- #endif +- return ret; ++ if(!list_empty(&clo->clo_list)) ++ { ++ struct request *req; ++ unsigned long flags; ++ int uptodate; ++ spin_lock_irq(&clo->queue_lock); ++ req = list_entry(clo->clo_list.next, struct request, queuelist); ++ list_del_init(&req->queuelist); ++ spin_unlock_irq(&clo->queue_lock); ++ uptodate = cloop_handle_request(clo, req); ++ spin_lock_irqsave(&clo->queue_lock, flags); ++ __blk_end_request_all(req, uptodate ? 0 : -EIO); ++ spin_unlock_irqrestore(&clo->queue_lock, flags); ++ } ++ } ++ DEBUGP(KERN_ERR "cloop_thread exited.\n"); ++ return 0; ++} ++ ++/* This is called by the kernel block queue management every now and then, ++ * with successive read requests qeued and sorted in a (hopefully) ++ * "most efficient way". spin_lock_irq() is being held by the kernel. */ ++static void cloop_do_request(struct request_queue *q) ++{ ++ struct request *req; ++ while((req = blk_fetch_request(q)) != NULL) ++ { ++ struct cloop_device *clo; ++ int rw; ++ /* quick sanity checks */ ++ /* blk_fs_request() was removed in 2.6.36 */ + if (unlikely(req == NULL +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) /* field removed */ + || (req->cmd_type != REQ_TYPE_FS) +#endif + )) - goto error_continue; - rw = rq_data_dir(req); -- if (unlikely(rw != READ && rw != READA)) ++ goto error_continue; ++ rw = rq_data_dir(req); + if (unlikely(rw != READ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) + && rw != READA +#endif + )) - { - DEBUGP("cloop_do_request: bad command\n"); - goto error_continue; -@@ -409,40 +523,51 @@ - continue; /* next request */ - error_continue: - DEBUGP(KERN_ERR "cloop_do_request: Discarding request %p.\n", req); ++ { ++ DEBUGP("cloop_do_request: bad command\n"); ++ goto error_continue; ++ } ++ clo = req->rq_disk->private_data; ++ if (unlikely(!clo->backing_file && !clo->suspended)) ++ { ++ DEBUGP("cloop_do_request: not connected to a file\n"); ++ goto error_continue; ++ } ++ list_add_tail(&req->queuelist, &clo->clo_list); /* Add to working list for thread */ ++ wake_up(&clo->clo_event); /* Wake up cloop_thread */ ++ continue; /* next request */ ++ error_continue: ++ DEBUGP(KERN_ERR "cloop_do_request: Discarding request %p.\n", req); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) - req->errors++; ++ req->errors++; +#else + req->error_count++; +#endif - __blk_end_request_all(req, -EIO); - } ++ __blk_end_request_all(req, -EIO); ++ } } --/* Read header and offsets from already opened file */ --static int cloop_set_file(int cloop_num, struct file *file, char *filename) -+/* Read header, flags and offsets from already opened file */ -+static int cloop_set_file(int cloop_num, struct file *file) - { - struct cloop_device *clo = cloop_dev[cloop_num]; - struct inode *inode; + /* Read header, flags and offsets from already opened file */ +@@ -508,7 +540,7 @@ char *bbuf=NULL; -- unsigned int i, offsets_read, total_offsets; -- int isblkdev; -- int error = 0; -+ unsigned int bbuf_size = 0; -+ const unsigned int header_size = sizeof(struct cloop_head); + unsigned int bbuf_size = 0; + const unsigned int header_size = sizeof(struct cloop_head); +- unsigned int i, offsets_read=0, total_offsets=0; + unsigned int i, total_offsets=0; -+ loff_t fs_read_position = 0, header_pos[2]; -+ int flags, isblkdev, bytes_read, error = 0; -+ if (clo->suspended) return error; -+ #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) - inode = file->f_dentry->d_inode; -+ clo->underlying_filename = kstrdup(file->f_dentry->d_name.name ? file->f_dentry->d_name.name : (const unsigned char *)"anonymous filename", GFP_KERNEL); -+ #else -+ inode = file->f_path.dentry->d_inode; -+ 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); -+ #endif - isblkdev=S_ISBLK(inode->i_mode)?1:0; - if(!isblkdev&&!S_ISREG(inode->i_mode)) + loff_t fs_read_position = 0, header_pos[2]; + int isblkdev, bytes_read, error = 0; + if (clo->suspended) return error; +@@ -581,29 +613,19 @@ + goto error_release; + } + memcpy(&clo->head, bbuf, header_size); +- if (strncmp(bbuf+CLOOP4_SIGNATURE_OFFSET, CLOOP4_SIGNATURE, CLOOP4_SIGNATURE_SIZE)==0) ++ if (strncmp(bbuf+CLOOP_SIGNATURE_OFFSET, CLOOP_SIGNATURE, CLOOP_SIGNATURE_SIZE)==0) + { +- clo->file_format=4; ++ clo->file_format++; + clo->head.block_size=ntohl(clo->head.block_size); + clo->head.num_blocks=ntohl(clo->head.num_blocks); + clo->header_first = (i==0) ? 1 : 0; +- printk(KERN_INFO "%s: file %s version %d, %d blocks of %d bytes, header %s.\n", cloop_name, clo->underlying_filename, clo->file_format, clo->head.num_blocks, clo->head.block_size, (i==0)?"first":"last"); +- break; +- } +- else if (strncmp(bbuf+CLOOP2_SIGNATURE_OFFSET, CLOOP2_SIGNATURE, CLOOP2_SIGNATURE_SIZE)==0) +- { +- clo->file_format=2; +- clo->head.block_size=ntohl(clo->head.block_size); +- clo->head.num_blocks=ntohl(clo->head.num_blocks); +- clo->header_first = (i==0) ? 1 : 0; +- printk(KERN_INFO "%s: file %s version %d, %d blocks of %d bytes, header %s.\n", cloop_name, clo->underlying_filename, clo->file_format, clo->head.num_blocks, clo->head.block_size, (i==0)?"first":"last"); ++ 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"); + break; + } + } + if (clo->file_format == 0) { - printk(KERN_ERR "%s: %s not a regular file or block device\n", -- cloop_name, filename); -+ cloop_name, clo->underlying_filename); +- printk(KERN_ERR "%s: Cannot read old 32-bit (version 0.68) images, " +- "please use an older version of %s for this file.\n", ++ printk(KERN_ERR "%s: Cannot detect %s format.\n", + cloop_name, cloop_name); + error=-EBADF; goto error_release; + } +@@ -613,67 +635,133 @@ + cloop_name, clo->head.block_size); error=-EBADF; goto error_release; } - clo->backing_file = file; - clo->backing_inode= inode ; -- if(!isblkdev&&inode->i_sizeunderlying_total_size = (isblkdev) ? inode->i_bdev->bd_inode->i_size : inode->i_size; -+ if(clo->underlying_total_size < header_size) +- total_offsets=clo->head.num_blocks+1; +- if (!isblkdev && (sizeof(struct cloop_head)+sizeof(loff_t)* ++ total_offsets=clo->head.num_blocks; ++ if (!isblkdev && (sizeof(struct cloop_head)+sizeof(struct block_info)* + total_offsets > inode->i_size)) { -- printk(KERN_ERR "%s: %lu bytes (must be >= %u bytes)\n", -- cloop_name, (unsigned long)inode->i_size, -- (unsigned)sizeof(struct cloop_head)); -+ printk(KERN_ERR "%s: %llu bytes (must be >= %u bytes)\n", -+ cloop_name, clo->underlying_total_size, -+ (unsigned int)header_size); + printk(KERN_ERR "%s: file %s too small for %u blocks\n", + cloop_name, clo->underlying_filename, clo->head.num_blocks); error=-EBADF; goto error_release; } -- /* In suspended mode, we have done all checks necessary - FF */ -- if (clo->suspended) -- return error; - if(isblkdev) - { - struct request_queue *q = bdev_get_queue(inode->i_bdev); -@@ -451,104 +576,225 @@ - /* blk_queue_max_hw_segments(clo->clo_queue, queue_max_hw_segments(q)); */ /* Removed in 2.6.34 */ - blk_queue_max_segment_size(clo->clo_queue, queue_max_segment_size(q)); - blk_queue_segment_boundary(clo->clo_queue, queue_segment_boundary(q)); -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) - blk_queue_merge_bvec(clo->clo_queue, q->merge_bvec_fn); -+#endif - clo->underlying_blksize = block_size(inode->i_bdev); - } - else - clo->underlying_blksize = PAGE_SIZE; -- DEBUGP("Underlying blocksize is %u\n", clo->underlying_blksize); -- bbuf = cloop_malloc(clo->underlying_blksize); -+ -+ DEBUGP(KERN_INFO "Underlying blocksize of %s is %u\n", clo->underlying_filename, clo->underlying_blksize); -+ DEBUGP(KERN_INFO "Underlying total size of %s is %llu\n", clo->underlying_filename, clo->underlying_total_size); -+ -+ /* clo->underlying_blksize should be larger than header_size, even if it's only PAGE_SIZE */ -+ bbuf_size = clo->underlying_blksize; -+ bbuf = cloop_malloc(bbuf_size); - if(!bbuf) - { -- printk(KERN_ERR "%s: out of kernel mem for block buffer (%lu bytes)\n", -- cloop_name, (unsigned long)clo->underlying_blksize); -+ printk(KERN_ERR "%s: out of kernel mem for buffer (%u bytes)\n", -+ cloop_name, (unsigned int) bbuf_size); -+ error=-ENOMEM; goto error_release; -+ } -+ -+ header_pos[0] = 0; /* header first */ -+ header_pos[1] = clo->underlying_total_size - sizeof(struct cloop_head); /* header last */ -+ for(i=0; i<2; i++) -+ { -+ /* Check for header */ -+ size_t bytes_readable = MIN(clo->underlying_blksize, clo->underlying_total_size - header_pos[i]); -+ size_t bytes_read = cloop_read_from_file(clo, file, bbuf, header_pos[i], bytes_readable); -+ if(bytes_read != bytes_readable) -+ { -+ printk(KERN_ERR "%s: Bad file %s, read() of %s %u bytes returned %d.\n", -+ cloop_name, clo->underlying_filename, (i==0)?"first":"last", -+ (unsigned int)header_size, (int)bytes_read); -+ error=-EBADF; -+ goto error_release; -+ } -+ memcpy(&clo->head, bbuf, header_size); -+ if (strncmp(bbuf+CLOOP_SIGNATURE_OFFSET, CLOOP_SIGNATURE, CLOOP_SIGNATURE_SIZE)==0) -+ { -+ clo->file_format++; -+ clo->head.block_size=ntohl(clo->head.block_size); -+ clo->head.num_blocks=ntohl(clo->head.num_blocks); -+ clo->header_first = (i==0) ? 1 : 0; -+ 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"); -+ break; -+ } -+ } -+ if (clo->file_format == 0) -+ { -+ printk(KERN_ERR "%s: Cannot detect %s format.\n", -+ cloop_name, cloop_name); -+ error=-EBADF; goto error_release; -+ } -+ if (clo->head.block_size % 512 != 0) -+ { -+ printk(KERN_ERR "%s: blocksize %u not multiple of 512\n", -+ cloop_name, clo->head.block_size); -+ error=-EBADF; goto error_release; -+ } -+ total_offsets=clo->head.num_blocks; -+ if (!isblkdev && (sizeof(struct cloop_head)+sizeof(struct block_info)* -+ total_offsets > inode->i_size)) -+ { -+ printk(KERN_ERR "%s: file %s too small for %u blocks\n", -+ cloop_name, clo->underlying_filename, clo->head.num_blocks); -+ error=-EBADF; goto error_release; -+ } +- clo->block_ptrs = cloop_malloc(sizeof(cloop_block_ptr) * total_offsets); +- if (!clo->block_ptrs) + /* Allocate Memory for decompressors */ +#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE)) + clo->zstream.workspace = cloop_malloc(zlib_inflate_workspacesize()); + if(!clo->zstream.workspace) -+ { + { +- printk(KERN_ERR "%s: out of kernel mem for offsets\n", cloop_name); + printk(KERN_ERR "%s: out of mem for zlib working area %u\n", + cloop_name, zlib_inflate_workspacesize()); error=-ENOMEM; goto error_release; } -- total_offsets = 1; /* Dummy total_offsets: will be filled in first time around */ -- for (i = 0, offsets_read = 0; offsets_read < total_offsets; i++) +- /* Read them offsets! */ +- if(clo->header_first) + zlib_inflateInit(&clo->zstream); +#endif +#if (defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE)) @@ -890,33 +713,20 @@ +#endif + if (total_offsets + 1 == 0) /* Version 3 */ { -- unsigned int offset = 0, num_readable; -- size_t bytes_read = cloop_read_from_file(clo, file, bbuf, -- i*clo->underlying_blksize, -- clo->underlying_blksize); -- if(bytes_read != clo->underlying_blksize) +- fs_read_position = sizeof(struct cloop_head); + struct cloop_tail tail; + if (isblkdev) - { -- printk(KERN_ERR "%s: Bad file, read() of first %lu bytes returned %d.\n", -- cloop_name, (unsigned long)clo->underlying_blksize, (int)bytes_read); -- error=-EBADF; -- goto error_release; ++ { + /* No end of file: can't find index */ + printk(KERN_ERR "%s: no V3 support for block device\n", + cloop_name); + error=-EBADF; goto error_release; - } -- /* Header will be in block zero */ -- if(i==0) ++ } + bytes_read = cloop_read_from_file(clo, file, (void *) &tail, + inode->i_size - sizeof(struct cloop_tail), + sizeof(struct cloop_tail)); + if (bytes_read == sizeof(struct cloop_tail)) - { -- memcpy(&clo->head, bbuf, sizeof(struct cloop_head)); -- offset = sizeof(struct cloop_head); -- if (ntohl(clo->head.block_size) % 512 != 0) ++ { + unsigned long len, zlen; + int ret; + void *zbuf; @@ -926,79 +736,47 @@ + zlen = ntohl(tail.table_size); + zbuf = cloop_malloc(zlen); + if (!clo->block_ptrs || !zbuf) - { -- printk(KERN_ERR "%s: blocksize %u not multiple of 512\n", -- cloop_name, ntohl(clo->head.block_size)); -- error=-EBADF; goto error_release; -- } -- if (clo->head.preamble[0x0B]!='V'||clo->head.preamble[0x0C]<'1') -- { -- printk(KERN_ERR "%s: Cannot read old 32-bit (version 0.68) images, " -- "please use an older version of %s for this file.\n", -- cloop_name, cloop_name); -- error=-EBADF; goto error_release; ++ { + printk(KERN_ERR "%s: out of kernel mem for index\n", cloop_name); + error=-ENOMEM; goto error_release; - } -- if (clo->head.preamble[0x0C]<'2') ++ } + bytes_read = cloop_read_from_file(clo, file, zbuf, + inode->i_size - zlen - sizeof(struct cloop_tail), + zlen); + if (bytes_read != zlen) - { -- printk(KERN_ERR "%s: Cannot read old architecture-dependent " -- "(format <= 1.0) images, please use an older " -- "version of %s for this file.\n", -- cloop_name, cloop_name); ++ { + printk(KERN_ERR "%s: can't read index\n", cloop_name); - error=-EBADF; goto error_release; - } -- total_offsets=ntohl(clo->head.num_blocks)+1; -- if (!isblkdev && (sizeof(struct cloop_head)+sizeof(loff_t)* -- total_offsets > inode->i_size)) ++ error=-EBADF; goto error_release; ++ } + len = CLOOP3_INDEX_SIZE(ntohl(tail.index_size)) * total_offsets; -+ flags = CLOOP3_BLOCKS_FLAGS(ntohl(tail.index_size)); -+// 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) -+printk(KERN_INFO "%s: uncompress(clo=%p, block_ptrs=%p, &len(%ld)=%p, zbuf=%p, zlen=%ld, flag=%d)\n", cloop_name, -+ clo, clo->block_ptrs, len, &len, zbuf, zlen, flags); -+ ret = uncompress(clo, (void *) clo->block_ptrs, &len, zbuf, zlen, flags); -+// May 3 19:45:20 (none) user.alert kernel: BUG: unable to handle kernel NULL pointer dereference at (null) -+printk(KERN_INFO "%s: uncompressed !\n", cloop_name); ++ ret = uncompress(clo, (void *) clo->block_ptrs, &len, zbuf, zlen, CLOOP_COMPRESSOR_ZLIB); + cloop_free(zbuf, zlen); + if (ret != 0) - { -- printk(KERN_ERR "%s: file too small for %u blocks\n", -- cloop_name, ntohl(clo->head.num_blocks)); -+ printk(KERN_ERR "%s: decompression error %i uncompressing index, flags %u\n", -+ cloop_name, ret, flags); - error=-EBADF; goto error_release; - } -- clo->offsets = cloop_malloc(sizeof(loff_t) * total_offsets); -- if (!clo->offsets) -- { -- printk(KERN_ERR "%s: out of kernel mem for offsets\n", cloop_name); -- error=-ENOMEM; goto error_release; -- } - } -- num_readable = MIN(total_offsets - offsets_read, -- (clo->underlying_blksize - offset) -- / sizeof(loff_t)); -- memcpy(&clo->offsets[offsets_read], bbuf+offset, num_readable * sizeof(loff_t)); -- offsets_read += num_readable; -- } -- { /* Search for largest block rather than estimate. KK. */ -- int i; -- for(i=0;iunderlying_total_size - sizeof(struct cloop_head) - total_offsets * sizeof(loff_t); +- } +- for(offsets_read=0;offsets_readunderlying_total_size - fs_read_position); +- if(bytes_readable <= 0) break; /* Done */ +- bytes_read = cloop_read_from_file(clo, file, bbuf, fs_read_position, bytes_readable); +- if(bytes_read != bytes_readable) + unsigned int n, total_bytes; -+ flags = 0; + clo->block_ptrs = cloop_malloc(sizeof(struct block_info) * total_offsets); + if (!clo->block_ptrs) + { @@ -1007,14 +785,26 @@ + } + /* Read them offsets! */ + if(clo->header_first) -+ { + { +- printk(KERN_ERR "%s: Bad file %s, read() %lu bytes @ %llu returned %d.\n", +- cloop_name, clo->underlying_filename, (unsigned long)clo->underlying_blksize, fs_read_position, (int)bytes_read); +- error=-EBADF; +- goto error_release; + total_bytes = total_offsets * sizeof(struct block_info); + fs_read_position = sizeof(struct cloop_head); -+ } + } +- /* remember where to read the next blk from file */ +- fs_read_position += bytes_read; +- /* calculate how many offsets can be taken from current bbuf */ +- num_readable = MIN(total_offsets - offsets_read, +- bytes_read / sizeof(loff_t)); +- DEBUGP(KERN_INFO "cloop: parsing %d offsets %d to %d\n", num_readable, offsets_read, offsets_read+num_readable-1); +- for (i=0,offset=0; ioffsets[i+1]) - be64_to_cpu(clo->offsets[i]); -- clo->largest_block=MAX(clo->largest_block,d); +- loff_t tmp = be64_to_cpu( *(loff_t*) (bbuf+offset) ); +- if (i%50==0) DEBUGP(KERN_INFO "cloop: offset %03d: %llu\n", offsets_read, tmp); +- if(offsets_read > 0) + total_bytes = total_offsets * sizeof(loff_t); + fs_read_position = clo->underlying_total_size - sizeof(struct cloop_head) - total_bytes; + } @@ -1025,35 +815,28 @@ + if(bytes_readable <= 0) break; /* Done */ + bytes_read = cloop_read_from_file(clo, file, bbuf, fs_read_position, bytes_readable); + if(bytes_read != bytes_readable) -+ { + { +- loff_t d = CLOOP_BLOCK_OFFSET(tmp) - CLOOP_BLOCK_OFFSET(clo->block_ptrs[offsets_read-1]); +- if(d > clo->largest_block) clo->largest_block = d; + printk(KERN_ERR "%s: Bad file %s, read() %lu bytes @ %llu returned %d.\n", + cloop_name, clo->underlying_filename, (unsigned long)clo->underlying_blksize, fs_read_position, (int)bytes_read); + error=-EBADF; + goto error_release; -+ } + } +- clo->block_ptrs[offsets_read++] = tmp; +- offset += sizeof(loff_t); + memcpy(((char *)clo->block_ptrs) + n, bbuf, bytes_read); + /* remember where to read the next blk from file */ + fs_read_position += bytes_read; + n += bytes_read; } -- printk(KERN_INFO "%s: %s: %u blocks, %u bytes/block, largest block is %lu bytes.\n", -- cloop_name, filename, ntohl(clo->head.num_blocks), -- ntohl(clo->head.block_size), clo->largest_block); } --/* Combo kmalloc used too large chunks (>130000). */ +- printk(KERN_INFO "%s: %s: %u blocks, %u bytes/block, largest block is %lu bytes.\n", +- cloop_name, clo->underlying_filename, clo->head.num_blocks, +- clo->head.block_size, clo->largest_block); { int i; -- for(i=0;ibuffer[i] = cloop_malloc(ntohl(clo->head.block_size)); -- if(!clo->buffer[i]) -- { -- printk(KERN_ERR "%s: out of memory for buffer %lu\n", -- cloop_name, (unsigned long) ntohl(clo->head.block_size)); -- error=-ENOMEM; goto error_release_free; -- } -- } -+ char *version = build_index(clo->block_ptrs, clo->head.num_blocks, clo->head.block_size, flags); ++ char *version = build_index(clo->block_ptrs, clo->head.num_blocks, clo->head.block_size); + clo->largest_block = 0; + for (i = 0; i < clo->head.num_blocks; i++) + if (clo->block_ptrs[i].size > clo->largest_block) @@ -1061,39 +844,15 @@ + printk(KERN_INFO "%s: %s: %s: %u blocks, %u bytes/block, largest block is %lu bytes.\n", + cloop_name, clo->underlying_filename, version, clo->head.num_blocks, + clo->head.block_size, clo->largest_block); -+ } -+ { -+ int i; -+ clo->num_buffered_blocks = (buffers > 0 && clo->head.block_size >= 512) ? -+ (buffers / clo->head.block_size) : 1; -+ clo->buffered_blocknum = cloop_malloc(clo->num_buffered_blocks * sizeof (u_int32_t)); -+ clo->buffer = cloop_malloc(clo->num_buffered_blocks * sizeof (char*)); -+ if (!clo->buffered_blocknum || !clo->buffer) -+ { -+ printk(KERN_ERR "%s: out of memory for index of cache buffer (%lu bytes)\n", -+ cloop_name, (unsigned long)clo->num_buffered_blocks * sizeof (u_int32_t) + sizeof(char*) ); -+ error=-ENOMEM; goto error_release; -+ } -+ memset(clo->buffer, 0, clo->num_buffered_blocks * sizeof (char*)); -+ for(i=0;inum_buffered_blocks;i++) -+ { -+ clo->buffered_blocknum[i] = -1; -+ clo->buffer[i] = cloop_malloc(clo->head.block_size); -+ if(!clo->buffer[i]) -+ { -+ printk(KERN_ERR "%s: out of memory for cache buffer %lu\n", -+ cloop_name, (unsigned long) clo->head.block_size); -+ error=-ENOMEM; goto error_release_free; -+ } -+ } -+ clo->current_bufnum = 0; - } - clo->compressed_buffer = cloop_malloc(clo->largest_block); - if(!clo->compressed_buffer) -@@ -557,31 +803,7 @@ + clo->num_buffered_blocks = (buffers > 0 && clo->head.block_size >= 512) ? + (buffers / clo->head.block_size) : 1; + clo->buffered_blocknum = cloop_malloc(clo->num_buffered_blocks * sizeof (u_int32_t)); +@@ -705,36 +793,14 @@ cloop_name, clo->largest_block); error=-ENOMEM; goto error_release_free_buffer; } +- /* Allocate Memory for decompressors */ +-#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE)) - clo->zstream.workspace = cloop_malloc(zlib_inflate_workspacesize()); - if(!clo->zstream.workspace) - { @@ -1102,443 +861,48 @@ - error=-ENOMEM; goto error_release_free_all; - } - zlib_inflateInit(&clo->zstream); -- if(!isblkdev && -- be64_to_cpu(clo->offsets[ntohl(clo->head.num_blocks)]) != inode->i_size) -- { -- printk(KERN_ERR "%s: final offset wrong (%Lu not %Lu)\n", +-#endif +-#if (defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE)) +-#if XZ_INTERNAL_CRC32 +- /* This must be called before any other xz_* function to initialize the CRC32 lookup table. */ +- xz_crc32_init(void); +-#endif +- clo->xzdecoderstate = xz_dec_init(XZ_SINGLE, 0); +-#endif +- if(CLOOP_BLOCK_OFFSET(clo->block_ptrs[clo->head.num_blocks]) > clo->underlying_total_size) ++ set_capacity(clo->clo_disk, (sector_t)(clo->head.num_blocks*(clo->head.block_size>>9))); ++ clo->clo_thread = kthread_create(cloop_thread, clo, "cloop%d", cloop_num); ++ if(IS_ERR(clo->clo_thread)) + { +- printk(KERN_ERR "%s: final offset wrong (%llu > %llu)\n", - cloop_name, -- be64_to_cpu(clo->offsets[ntohl(clo->head.num_blocks)]), -- inode->i_size); +- CLOOP_BLOCK_OFFSET(clo->block_ptrs[clo->head.num_blocks]), +- clo->underlying_total_size); +-#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE)) - cloop_free(clo->zstream.workspace, zlib_inflate_workspacesize()); clo->zstream.workspace=NULL; -- goto error_release_free_all; -- } -- { -- int i; -- for(i=0; ibuffered_blocknum[i] = -1; -- clo->current_bufnum=0; -- } -- set_capacity(clo->clo_disk, (sector_t)(ntohl(clo->head.num_blocks)* -- (ntohl(clo->head.block_size)>>9))); -+ set_capacity(clo->clo_disk, (sector_t)(clo->head.num_blocks*(clo->head.block_size>>9))); - clo->clo_thread = kthread_create(cloop_thread, clo, "cloop%d", cloop_num); - if(IS_ERR(clo->clo_thread)) - { -@@ -591,17 +813,17 @@ +-#endif ++ error = PTR_ERR(clo->clo_thread); ++ clo->clo_thread=NULL; + goto error_release_free_all; } +- set_capacity(clo->clo_disk, (sector_t)(clo->head.num_blocks*(clo->head.block_size>>9))); if(preload > 0) { -- clo->preload_array_size = ((preload<=ntohl(clo->head.num_blocks))?preload:ntohl(clo->head.num_blocks)); -+ clo->preload_array_size = ((preload<=clo->head.num_blocks)?preload:clo->head.num_blocks); - clo->preload_size = 0; - if((clo->preload_cache = cloop_malloc(clo->preload_array_size * sizeof(char *))) != NULL) - { - int i; - for(i=0; ipreload_array_size; i++) - { -- if((clo->preload_cache[i] = cloop_malloc(ntohl(clo->head.block_size))) == NULL) -+ if((clo->preload_cache[i] = cloop_malloc(clo->head.block_size)) == NULL) - { /* Out of memory */ - printk(KERN_WARNING "%s: cloop_malloc(%d) failed for preload_cache[%d] (ignored).\n", -- cloop_name, ntohl(clo->head.block_size), i); -+ cloop_name, clo->head.block_size, i); - break; - } - } -@@ -612,13 +834,13 @@ - if(buffered_blocknum >= 0) - { - memcpy(clo->preload_cache[i], clo->buffer[buffered_blocknum], -- ntohl(clo->head.block_size)); -+ clo->head.block_size); - } - else - { - printk(KERN_WARNING "%s: can't read block %d into preload cache, set to zero.\n", - cloop_name, i); -- memset(clo->preload_cache[i], 0, ntohl(clo->head.block_size)); -+ memset(clo->preload_cache[i], 0, clo->head.block_size); - } - } - printk(KERN_INFO "%s: preloaded %d blocks into cache.\n", cloop_name, -@@ -641,22 +863,19 @@ - cloop_free(clo->compressed_buffer, clo->largest_block); - clo->compressed_buffer=NULL; - error_release_free_buffer: -+ if(clo->buffer) - { - int i; -- for(i=0; ibuffer[i]) -- { -- cloop_free(clo->buffer[i], ntohl(clo->head.block_size)); -- clo->buffer[i]=NULL; -- } -- } -+ for(i=0; inum_buffered_blocks; i++) { if(clo->buffer[i]) { cloop_free(clo->buffer[i], clo->head.block_size); clo->buffer[i]=NULL; }} -+ cloop_free(clo->buffer, clo->num_buffered_blocks*sizeof(char*)); clo->buffer=NULL; + clo->preload_array_size = ((preload<=clo->head.num_blocks)?preload:clo->head.num_blocks); +@@ -780,6 +846,7 @@ + clo->preload_array_size = clo->preload_size = 0; + } + } ++ wake_up_process(clo->clo_thread); + /* Uncheck */ + return error; + error_release_free_all: +@@ -794,9 +861,13 @@ } -+ if (clo->buffered_blocknum) { cloop_free(clo->buffered_blocknum, sizeof(int)*clo->num_buffered_blocks); clo->buffered_blocknum=NULL; } + if (clo->buffered_blocknum) { cloop_free(clo->buffered_blocknum, sizeof(int)*clo->num_buffered_blocks); clo->buffered_blocknum=NULL; } error_release_free: -- cloop_free(clo->offsets, sizeof(loff_t) * total_offsets); -- clo->offsets=NULL; +- cloop_free(clo->block_ptrs, sizeof(cloop_block_ptr) * total_offsets); + cloop_free(clo->block_ptrs, sizeof(struct block_info) * total_offsets); -+ clo->block_ptrs=NULL; - error_release: - if(bbuf) cloop_free(bbuf, clo->underlying_blksize); -+ if(clo->underlying_filename) { kfree(clo->underlying_filename); clo->underlying_filename=NULL; } - clo->backing_file=NULL; - return error; - } -@@ -673,7 +892,7 @@ - if(clo->backing_file) return -EBUSY; - file = fget(arg); /* get filp struct from ioctl arg fd */ - if(!file) return -EBADF; -- error=cloop_set_file(cloop_num,file,"losetup_file"); -+ error=cloop_set_file(cloop_num,file); - set_device_ro(bdev, 1); - if(error) fput(file); - return error; -@@ -684,29 +903,48 @@ - { - struct cloop_device *clo = cloop_dev[cloop_num]; - struct file *filp = clo->backing_file; -- int i; - if(clo->refcnt > 1) /* we needed one fd for the ioctl */ - return -EBUSY; - if(filp==NULL) return -EINVAL; - if(clo->clo_thread) { kthread_stop(clo->clo_thread); clo->clo_thread=NULL; } -- if(filp!=initial_file) fput(filp); -- else { filp_close(initial_file,0); initial_file=NULL; } -+ if(filp!=initial_file) -+ fput(filp); -+ else -+ { -+ filp_close(initial_file,0); -+ initial_file=NULL; -+ } - clo->backing_file = NULL; - clo->backing_inode = NULL; -- if(clo->offsets) { cloop_free(clo->offsets, clo->underlying_blksize); clo->offsets = NULL; } -+ if(clo->underlying_filename) { kfree(clo->underlying_filename); clo->underlying_filename=NULL; } -+ if(clo->block_ptrs) { cloop_free(clo->block_ptrs, clo->head.num_blocks); clo->block_ptrs = NULL; } - if(clo->preload_cache) -- { -- for(i=0; i < clo->preload_size; i++) -- cloop_free(clo->preload_cache[i], ntohl(clo->head.block_size)); -- cloop_free(clo->preload_cache, clo->preload_array_size * sizeof(char *)); -- clo->preload_cache = NULL; -- clo->preload_size = clo->preload_array_size = 0; -- } -- for(i=0; ibuffer[i]) { cloop_free(clo->buffer[i], ntohl(clo->head.block_size)); clo->buffer[i]=NULL; } -+ { -+ int i; -+ for(i=0; i < clo->preload_size; i++) -+ cloop_free(clo->preload_cache[i], clo->head.block_size); -+ cloop_free(clo->preload_cache, clo->preload_array_size * sizeof(char *)); -+ clo->preload_cache = NULL; -+ clo->preload_size = clo->preload_array_size = 0; -+ } -+ if (clo->buffered_blocknum) -+ { -+ cloop_free(clo->buffered_blocknum, sizeof(int) * clo->num_buffered_blocks); clo->buffered_blocknum = NULL; -+ } -+ if (clo->buffer) -+ { -+ int i; -+ for(i=0; inum_buffered_blocks; i++) { if(clo->buffer[i]) cloop_free(clo->buffer[i], clo->head.block_size); } -+ cloop_free(clo->buffer, sizeof(char*) * clo->num_buffered_blocks); clo->buffer = NULL; -+ } - if(clo->compressed_buffer) { cloop_free(clo->compressed_buffer, clo->largest_block); clo->compressed_buffer = NULL; } -+#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE)) - zlib_inflateEnd(&clo->zstream); - if(clo->zstream.workspace) { cloop_free(clo->zstream.workspace, zlib_inflate_workspacesize()); clo->zstream.workspace = NULL; } -+#endif -+#if (defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE)) -+ xz_dec_end(clo->xzdecoderstate); -+#endif - if(bdev) invalidate_bdev(bdev); - if(clo->clo_disk) set_capacity(clo->clo_disk, 0); - return 0; -@@ -731,8 +969,8 @@ - const struct loop_info64 *info) - { - if (!clo->backing_file) return -ENXIO; -- memcpy(clo->clo_file_name, info->lo_file_name, LO_NAME_SIZE); -- clo->clo_file_name[LO_NAME_SIZE-1] = 0; -+ if(clo->underlying_filename) kfree(clo->underlying_filename); -+ clo->underlying_filename = kstrdup(info->lo_file_name, GFP_KERNEL); - return 0; - } - -@@ -743,7 +981,11 @@ - struct kstat stat; - int err; - if (!file) return -ENXIO; -- err = vfs_getattr(file->f_path.mnt, file->f_path.dentry, &stat); -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) -+ err = vfs_getattr(&file->f_path, &stat); -+#else -+ err = vfs_getattr(&file->f_path, &stat, STATX_INO, AT_STATX_SYNC_AS_STAT); -+#endif - if (err) return err; - memset(info, 0, sizeof(*info)); - info->lo_number = clo->clo_number; -@@ -753,7 +995,8 @@ - info->lo_offset = 0; - info->lo_sizelimit = 0; - info->lo_flags = 0; -- memcpy(info->lo_file_name, clo->clo_file_name, LO_NAME_SIZE); -+ strncpy(info->lo_file_name, clo->underlying_filename, LO_NAME_SIZE); -+ info->lo_file_name[LO_NAME_SIZE-1]=0; - return 0; - } - -@@ -833,8 +1076,6 @@ - if (!err && copy_to_user(arg, &info64, sizeof(info64))) err = -EFAULT; - return err; - } --/* EOF get/set_status */ -- - - static int cloop_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -@@ -914,21 +1155,20 @@ - /* losetup uses write-open and flags=0x8002 to set a new file */ - if(mode & FMODE_WRITE) - { -- printk(KERN_WARNING "%s: Can't open device read-write in mode 0x%x\n", cloop_name, mode); -+ printk(KERN_INFO "%s: Open in read-write mode 0x%x requested, ignored.\n", cloop_name, mode); - return -EROFS; - } - cloop_dev[cloop_num]->refcnt+=1; - return 0; - } - --static int cloop_close(struct gendisk *disk, fmode_t mode) -+static void cloop_close(struct gendisk *disk, fmode_t mode) - { -- int cloop_num, err=0; -- if(!disk) return 0; -+ int cloop_num; -+ if(!disk) return; - cloop_num=((struct cloop_device *)disk->private_data)->clo_number; -- if(cloop_num < 0 || cloop_num > (cloop_count-1)) return 0; -+ if(cloop_num < 0 || cloop_num > (cloop_count-1)) return; - cloop_dev[cloop_num]->refcnt-=1; -- return err; - } - - static struct block_device_operations clo_fops = -@@ -973,6 +1213,10 @@ - goto error_out; - } - clo->clo_queue->queuedata = clo; -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) -+ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, clo->clo_queue); -+ queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, clo->clo_queue); -+#endif - clo->clo_disk = alloc_disk(1); - if(!clo->clo_disk) - { -@@ -1004,6 +1248,11 @@ - cloop_dev[cloop_num] = NULL; - } - -+/* LZ4 Stuff */ -+#if (defined USE_LZ4_INTERNAL) -+#include "lz4_kmod.c" -+#endif -+ - static int __init cloop_init(void) - { - int error=0; -@@ -1044,7 +1293,7 @@ - initial_file=NULL; /* if IS_ERR, it's NOT open. */ - } - else -- error=cloop_set_file(0,initial_file,file); -+ error=cloop_set_file(0,initial_file); - if(error) - { - printk(KERN_ERR -@@ -1052,9 +1301,6 @@ - cloop_name, file, error); - goto init_out_dealloc; - } -- if(namelen >= LO_NAME_SIZE) namelen = LO_NAME_SIZE-1; -- memcpy(cloop_dev[0]->clo_file_name, file, namelen); -- cloop_dev[0]->clo_file_name[namelen] = 0; - } - return 0; - init_out_dealloc: ---- cloop.h -+++ cloop.h -@@ -86,11 +86,8 @@ - struct cloop_tail - { - u_int32_t table_size; -- u_int32_t index_size; /* size:4 comp:3 ctrl-c:1 lastlen:24 */ -+ u_int32_t index_size; /* size:4 unused:3 ctrl-c:1 lastlen:24 */ - #define CLOOP3_INDEX_SIZE(x) ((unsigned int)((x) & 0xF)) --#define CLOOP3_BLOCKS_FLAGS(x) ((unsigned int)((x) & 0x70) >> 4) --#define CLOOP3_TRUNCATED(x) ((unsigned int)((x) & 0x80) >> 7) --#define CLOOP3_LASTLEN(x) (unsigned int)((x) >> 8) - u_int32_t num_blocks; - }; - -@@ -104,8 +101,10 @@ - }; - - static inline char *build_index(struct block_info *offsets, unsigned long n, -- unsigned long block_size, unsigned global_flags) -+ unsigned long block_size) - { -+ static char v[11]; -+ u_int32_t flags = 0; - u_int32_t *ofs32 = (u_int32_t *) offsets; - loff_t *ofs64 = (loff_t *) offsets; - -@@ -130,8 +129,6 @@ - } - else { /* V2.0/V4.0 */ - loff_t last = CLOOP_BLOCK_OFFSET(__be64_to_cpu(ofs64[n])); -- u_int32_t flags; -- static char v4[11]; - unsigned long i = n; - - for (flags = 0; n-- ;) { -@@ -149,12 +146,7 @@ - offsets[i] = offsets[offsets[i].offset]; - } - } -- strcpy(v4, (char *) "64BE v4.0a"); -- v4[10] = 'a' + ((flags-1) & 0xF); // compressors used -- if (flags > 0x10) { // with links ? -- v4[10] += 'A' - 'a'; -- } -- return v4; -+ strcpy(v, (char *) "64BE v4.0a"); - } - } - else if (ofs32[1] == 0 && v3_64 == 0) { /* V1.0 */ -@@ -170,7 +162,6 @@ - else { /* V3.0 or V0.68 */ - unsigned long i; - loff_t j; -- static char v3[11]; - - for (i = 0; i < n && ntohl(ofs32[i]) < ntohl(ofs32[i+1]); i++); - if (i == n && ntohl(ofs32[0]) == (4*n) + 0x8C) { /* V0.68 */ -@@ -185,28 +176,33 @@ - } - - v3_64 = (ofs32[1] == 0); -- for (i = n; i-- != 0; ) -+ for (i = n; i-- != 0; ) { - offsets[i].size = ntohl(ofs32[i << v3_64]); -- for (i = 0, j = sizeof(struct cloop_head); i < n; i++) { -- offsets[i].offset = j; -- offsets[i].flags = global_flags; - if (offsets[i].size == 0xFFFFFFFF) { -- offsets[i].flags = CLOOP_COMPRESSOR_NONE; -- offsets[i].size = block_size; -+ offsets[i].size = 0x10000000 | block_size; - } -- if ((offsets[i].size & 0x80000000) == 0) { -+ offsets[i].flags = (offsets[i].size >> 28); -+ offsets[i].size &= 0x0FFFFFFF; -+ } -+ for (i = 0, j = sizeof(struct cloop_head); i < n; i++) { -+ offsets[i].offset = j; -+ if (offsets[i].flags < 8) { - j += offsets[i].size; - } - } - for (i = 0; i < n; i++) { -- if (offsets[i].size & 0x80000000) { -- offsets[i] = offsets[offsets[i].size & 0x7FFFFFFF]; -+ flags |= 1 << offsets[i].flags; -+ if (offsets[i].flags >= 8) { -+ offsets[i] = offsets[offsets[i].size]; - } - } -- strcpy(v3, (char *) (v3_64) ? "64BE v3.0a" : "32BE v3.0a"); -- v3[10] += global_flags; -- return v3; -+ strcpy(v, (char *) (v3_64) ? "64BE v3.0a" : "32BE v3.0a"); -+ } -+ v[10] = 'a' + ((flags-1) & 0xF); // compressors used -+ if (flags > 0x10) { // with links ? -+ v[10] += 'A' - 'a'; - } -+ return v; - } - - /* Cloop suspend IOCTL */ ---- cloop.c -+++ cloop.c -@@ -542,7 +542,7 @@ - const unsigned int header_size = sizeof(struct cloop_head); - unsigned int i, total_offsets=0; - loff_t fs_read_position = 0, header_pos[2]; -- int flags, isblkdev, bytes_read, error = 0; -+ int isblkdev, bytes_read, error = 0; - if (clo->suspended) return error; - #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) - inode = file->f_dentry->d_inode; -@@ -698,18 +698,12 @@ - error=-EBADF; goto error_release; - } - len = CLOOP3_INDEX_SIZE(ntohl(tail.index_size)) * total_offsets; -- flags = CLOOP3_BLOCKS_FLAGS(ntohl(tail.index_size)); --// 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) --printk(KERN_INFO "%s: uncompress(clo=%p, block_ptrs=%p, &len(%ld)=%p, zbuf=%p, zlen=%ld, flag=%d)\n", cloop_name, -- clo, clo->block_ptrs, len, &len, zbuf, zlen, flags); -- ret = uncompress(clo, (void *) clo->block_ptrs, &len, zbuf, zlen, flags); --// May 3 19:45:20 (none) user.alert kernel: BUG: unable to handle kernel NULL pointer dereference at (null) --printk(KERN_INFO "%s: uncompressed !\n", cloop_name); -+ ret = uncompress(clo, (void *) clo->block_ptrs, &len, zbuf, zlen, CLOOP_COMPRESSOR_ZLIB); - cloop_free(zbuf, zlen); - if (ret != 0) - { -- printk(KERN_ERR "%s: decompression error %i uncompressing index, flags %u\n", -- cloop_name, ret, flags); -+ printk(KERN_ERR "%s: decompression error %i uncompressing index\n", -+ cloop_name, ret); - error=-EBADF; goto error_release; - } - } -@@ -722,7 +716,6 @@ - else - { - unsigned int n, total_bytes; -- flags = 0; - clo->block_ptrs = cloop_malloc(sizeof(struct block_info) * total_offsets); - if (!clo->block_ptrs) - { -@@ -761,7 +754,7 @@ - } - { - int i; -- char *version = build_index(clo->block_ptrs, clo->head.num_blocks, clo->head.block_size, flags); -+ char *version = build_index(clo->block_ptrs, clo->head.num_blocks, clo->head.block_size); - clo->largest_block = 0; - for (i = 0; i < clo->head.num_blocks; i++) - if (clo->block_ptrs[i].size > clo->largest_block) -@@ -769,9 +762,6 @@ - printk(KERN_INFO "%s: %s: %s: %u blocks, %u bytes/block, largest block is %lu bytes.\n", - cloop_name, clo->underlying_filename, version, clo->head.num_blocks, - clo->head.block_size, clo->largest_block); -- } -- { -- int i; - clo->num_buffered_blocks = (buffers > 0 && clo->head.block_size >= 512) ? - (buffers / clo->head.block_size) : 1; - clo->buffered_blocknum = cloop_malloc(clo->num_buffered_blocks * sizeof (u_int32_t)); -@@ -874,6 +864,10 @@ - cloop_free(clo->block_ptrs, sizeof(struct block_info) * total_offsets); clo->block_ptrs=NULL; error_release: +#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE)) @@ -1548,3 +912,146 @@ if(bbuf) cloop_free(bbuf, clo->underlying_blksize); if(clo->underlying_filename) { kfree(clo->underlying_filename); clo->underlying_filename=NULL; } clo->backing_file=NULL; +@@ -829,6 +900,7 @@ + if(clo->refcnt > 1) /* we needed one fd for the ioctl */ + return -EBUSY; + if(filp==NULL) return -EINVAL; ++ if(clo->clo_thread) { kthread_stop(clo->clo_thread); clo->clo_thread=NULL; } + if(filp!=initial_file) + fput(filp); + else +@@ -839,7 +911,7 @@ + clo->backing_file = NULL; + clo->backing_inode = NULL; + if(clo->underlying_filename) { kfree(clo->underlying_filename); clo->underlying_filename=NULL; } +- if(clo->block_ptrs) { cloop_free(clo->block_ptrs, clo->head.num_blocks+1); clo->block_ptrs = NULL; } ++ if(clo->block_ptrs) { cloop_free(clo->block_ptrs, clo->head.num_blocks); clo->block_ptrs = NULL; } + if(clo->preload_cache) + { + int i; +@@ -1054,15 +1126,15 @@ + case LOOP_CLR_FD: /* Change arg */ + case LOOP_GET_STATUS64: /* Change arg */ + case LOOP_SET_STATUS64: /* Change arg */ +- return cloop_ioctl(bdev, mode, cmd, (unsigned long) compat_ptr(arg)); ++ arg = (unsigned long) compat_ptr(arg); + case LOOP_SET_STATUS: /* unchanged */ + case LOOP_GET_STATUS: /* unchanged */ + case LOOP_SET_FD: /* unchanged */ + case LOOP_CHANGE_FD: /* unchanged */ +- return cloop_ioctl(bdev, mode, cmd, arg); +- default: +- return -ENOIOCTLCMD; ++ return cloop_ioctl(bdev, mode, cmd, arg); ++ break; + } ++ return -ENOIOCTLCMD; + } + #endif + +@@ -1093,7 +1165,7 @@ + cloop_dev[cloop_num]->refcnt-=1; + } + +-static const struct block_device_operations clo_fops = ++static struct block_device_operations clo_fops = + { + owner: THIS_MODULE, + open: cloop_open, +@@ -1105,12 +1177,6 @@ + /* locked_ioctl ceased to exist in 2.6.36 */ + }; + +-static const struct blk_mq_ops cloop_mq_ops = { +- .queue_rq = cloop_queue_rq, +-/* .init_request = cloop_init_request, */ +-/* .complete = cloop_complete_rq, */ +-}; +- + static int cloop_register_blkdev(int major_nr) + { + return register_blkdev(major_nr, cloop_name); +@@ -1124,37 +1190,33 @@ + + static int cloop_alloc(int cloop_num) + { +- struct cloop_device *clo = (struct cloop_device *) cloop_malloc(sizeof(struct cloop_device)); ++ struct cloop_device *clo = (struct cloop_device *) cloop_malloc(sizeof(struct cloop_device));; + if(clo == NULL) goto error_out; + cloop_dev[cloop_num] = clo; + memset(clo, 0, sizeof(struct cloop_device)); + clo->clo_number = cloop_num; +- clo->tag_set.ops = &cloop_mq_ops; +- clo->tag_set.nr_hw_queues = 1; +- clo->tag_set.queue_depth = 128; +- clo->tag_set.numa_node = NUMA_NO_NODE; +- clo->tag_set.cmd_size = 0; /* No extra data needed */ +- /* BLK_MQ_F_BLOCKING is extremely important if we want to call blocking functions like vfs_read */ +- clo->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING; +- clo->tag_set.driver_data = clo; +- if(blk_mq_alloc_tag_set(&clo->tag_set)) goto error_out_free_clo; +- clo->clo_queue = blk_mq_init_queue(&clo->tag_set); +- if(IS_ERR(clo->clo_queue)) ++ clo->clo_thread = NULL; ++ init_waitqueue_head(&clo->clo_event); ++ spin_lock_init(&clo->queue_lock); ++ mutex_init(&clo->clo_ctl_mutex); ++ INIT_LIST_HEAD(&clo->clo_list); ++ clo->clo_queue = blk_init_queue(cloop_do_request, &clo->queue_lock); ++ if(!clo->clo_queue) + { + printk(KERN_ERR "%s: Unable to alloc queue[%d]\n", cloop_name, cloop_num); +- goto error_out_free_tags; ++ goto error_out; + } + clo->clo_queue->queuedata = clo; +- blk_queue_max_hw_sectors(clo->clo_queue, BLK_DEF_MAX_SECTORS); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) ++ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, clo->clo_queue); ++ queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, clo->clo_queue); ++#endif + clo->clo_disk = alloc_disk(1); + if(!clo->clo_disk) + { + printk(KERN_ERR "%s: Unable to alloc disk[%d]\n", cloop_name, cloop_num); +- goto error_out_free_queue; ++ goto error_disk; + } +- spin_lock_init(&clo->queue_lock); +- mutex_init(&clo->clo_ctl_mutex); +- mutex_init(&clo->clo_rq_mutex); + clo->clo_disk->major = cloop_major; + clo->clo_disk->first_minor = cloop_num; + clo->clo_disk->fops = &clo_fops; +@@ -1163,12 +1225,8 @@ + sprintf(clo->clo_disk->disk_name, "%s%d", cloop_name, cloop_num); + add_disk(clo->clo_disk); + return 0; +-error_out_free_queue: ++error_disk: + blk_cleanup_queue(clo->clo_queue); +-error_out_free_tags: +- blk_mq_free_tag_set(&clo->tag_set); +-error_out_free_clo: +- cloop_free(clo, sizeof(struct cloop_device)); + error_out: + return -ENOMEM; + } +@@ -1179,7 +1237,6 @@ + if(clo == NULL) return; + del_gendisk(clo->clo_disk); + blk_cleanup_queue(clo->clo_queue); +- blk_mq_free_tag_set(&clo->tag_set); + put_disk(clo->clo_disk); + cloop_free(clo, sizeof(struct cloop_device)); + cloop_dev[cloop_num] = NULL; +--- cloop_suspend.c ++++ cloop_suspend.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + /* We don't use the structure, so that define does not hurt */ + #define dev_t int diff -r 0f92b8cc8086 -r 5a92a26adcc1 linux64-cloop/receipt --- a/linux64-cloop/receipt Sun May 08 13:06:36 2022 +0000 +++ b/linux64-cloop/receipt Sun May 08 16:45:21 2022 +0000 @@ -2,16 +2,15 @@ PACKAGE="linux64-cloop" SOURCE="cloop" -_VERSION="2.639-2" -#VERSION="$(sed '/+#define CLOOP_VERSION/!d;s|.* "\(.*\)"|\1|' stuff/cloop.u)" +_VERSION="3.14.1.3" VERSION="4.12" CATEGORY="base-system" MAINTAINER="pascal.bellard@slitaz.org" LICENSE="GPL2" SHORT_DESC="The read-only compressed loop device kernel module." WEB_SITE="http://knoppix.net/wiki/Cloop" -TARBALL="${SOURCE}_${_VERSION}.tar.gz" -WGET_URL="http://debian-knoppix.alioth.debian.org/packages/$SOURCE/$TARBALL" +TARBALL="${SOURCE}_${_VERSION}.tar.xz" +WGET_URL="http://deb.debian.org/debian/pool/main/c/$SOURCE/$TARBALL" PROVIDE="linux-cloop:linux64" DEPENDS="linux64" @@ -26,6 +25,7 @@ { patch -p0 < $stuff/cloop.u make ARCH=x86_64 KERNEL_DIR="/usr/src/linux" cloop.ko && xz cloop.ko + make cloop_suspend } # Rules to gen a SliTaz package suitable for Tazpkg. diff -r 0f92b8cc8086 -r 5a92a26adcc1 linux64-cloop/stuff/cloop.u --- a/linux64-cloop/stuff/cloop.u Sun May 08 13:06:36 2022 +0000 +++ b/linux64-cloop/stuff/cloop.u Sun May 08 16:45:21 2022 +0000 @@ -1,6 +1,6 @@ --- cloop.h +++ cloop.h -@@ -1,15 +1,50 @@ +@@ -1,3 +1,7 @@ +#define CLOOP_SIGNATURE "#!/bin/sh" /* @ offset 0 */ +#define CLOOP_SIGNATURE_SIZE 9 +#define CLOOP_SIGNATURE_OFFSET 0x0 @@ -8,99 +8,46 @@ #ifndef _COMPRESSED_LOOP_H #define _COMPRESSED_LOOP_H --#define CLOOP_HEADROOM 128 -+/*************************************************************************\ -+* Starting with Format V4.0 (cloop version 4.x), cloop can now have two * -+* alternative structures: * -+* * -+* 1. Header first: "robust" format, handles missing blocks well * -+* 2. Footer (header last): "streaming" format, easier to create * -+* * -+* The cloop kernel module autodetects both formats, and can (currently) * -+* still handle the V2.0 format as well. * -+* * -+* 1. Header first: * -+* +---------------------------- FIXED SIZE ---------------------------+ * -+* |Signature (128 bytes) | * -+* |block_size (32bit number, network order) | * -+* |num_blocks (32bit number, network order) | * -+* +--------------------------- VARIABLE SIZE -------------------------+ * -+* |num_blocks * FlagsOffset (upper 4 bits flags, lower 64 bits offset)| * -+* |compressed data blocks of variable size ... | * -+* +-------------------------------------------------------------------+ * -+* * -+* 2. Footer (header last): * -+* +--------------------------- VARIABLE SIZE -------------------------+ * -+* |compressed data blocks of variable size ... | * -+* |num_blocks * FlagsOffset (upper 4 bits flags, lower 64 bits offset)| * -+* +---------------------------- FIXED SIZE ---------------------------+ * -+* |Signature (128 bytes) | * -+* |block_size (32bit number, network order) | * -+* |num_blocks (32bit number, network order) | * -+* +-------------------------------------------------------------------+ * -+* * -+* Offsets are always relative to beginning of file, in all formats. * -+* The block index contains num_blocks+1 offsets, followed (1) or * -+* preceded (2) by the compressed blocks. * -+\*************************************************************************/ +@@ -38,10 +42,6 @@ --/* The cloop header usually looks like this: */ --/* #!/bin/sh */ --/* #V2.00 Format */ --/* ...padding up to CLOOP_HEADROOM... */ --/* block_size (32bit number, network order) */ --/* num_blocks (32bit number, network order) */ -+#include /* u_int32_t */ -+ -+#define CLOOP_HEADROOM 128 + #include /* u_int32_t */ -+/* Header of fixed length, can be located at beginning or end of file */ - struct cloop_head - { - char preamble[CLOOP_HEADROOM]; -@@ -17,9 +52,163 @@ +-#ifndef __KERNEL__ +-#include /* regular uint64_t */ +-#endif +- + #define CLOOP_HEADROOM 128 + + /* Header of fixed length, can be located at beginning or end of file */ +@@ -52,13 +52,6 @@ u_int32_t num_blocks; }; -+/************************************************************************\ -+* CLOOP4 flags for each compressed block * -+* Value Meaning * -+* 0 GZIP/7ZIP compression (compatible with V2.0 Format) * -+* 1 no compression (incompressible data) * -+* 2 xz compression (currently best space saver) * -+* 3 lz4 compression * -+* 4 lzo compression (fastest) * -+\************************************************************************/ -+ -+typedef uint64_t cloop_block_ptr; -+ -+/* Get value of first 4 bits */ -+#define CLOOP_BLOCK_FLAGS(x) ((unsigned int)(((x) & 0xf000000000000000LLU) >> 60)) -+/* Get value of last 60 bits */ -+#define CLOOP_BLOCK_OFFSET(x) ((x) & 0x0fffffffffffffffLLU) -+ -+#define CLOOP_COMPRESSOR_ZLIB 0x0 -+#define CLOOP_COMPRESSOR_NONE 0x1 -+#define CLOOP_COMPRESSOR_XZ 0x2 -+#define CLOOP_COMPRESSOR_LZ4 0x3 -+#define CLOOP_COMPRESSOR_LZO1X 0x4 -+ -+#define CLOOP_COMPRESSOR_VALID(x) ((x) >= CLOOP_COMPRESSOR_ZLIB && (x) <= CLOOP_COMPRESSOR_LZO1X) -+ +-#define CLOOP2_SIGNATURE "V2.0" /* @ offset 0x0b */ +-#define CLOOP2_SIGNATURE_SIZE 4 +-#define CLOOP2_SIGNATURE_OFFSET 0x0b +-#define CLOOP4_SIGNATURE "V4.0" /* @ offset 0x0b */ +-#define CLOOP4_SIGNATURE_SIZE 4 +-#define CLOOP4_SIGNATURE_OFFSET 0x0b +- + /************************************************************************\ + * CLOOP4 flags for each compressed block * + * Value Meaning * +@@ -84,6 +77,134 @@ + + #define CLOOP_COMPRESSOR_VALID(x) ((x) >= CLOOP_COMPRESSOR_ZLIB && (x) <= CLOOP_COMPRESSOR_LZO1X) + +#define CLOOP_COMPRESSOR_LINK 0xF + + - /* data_index (num_blocks 64bit pointers, network order)... */ - /* compressed data (gzip block compressed format)... */ - ++/* data_index (num_blocks 64bit pointers, network order)... */ ++/* compressed data (gzip block compressed format)... */ ++ +struct cloop_tail +{ + u_int32_t table_size; -+ u_int32_t index_size; /* size:4 comp:3 ctrl-c:1 lastlen:24 */ ++ u_int32_t index_size; /* size:4 unused:3 ctrl-c:1 lastlen:24 */ +#define CLOOP3_INDEX_SIZE(x) ((unsigned int)((x) & 0xF)) -+#define CLOOP3_BLOCKS_FLAGS(x) ((unsigned int)((x) & 0x70) >> 4) -+#define CLOOP3_TRUNCATED(x) ((unsigned int)((x) & 0x80) >> 7) -+#define CLOOP3_LASTLEN(x) (unsigned int)((x) >> 8) + u_int32_t num_blocks; +}; + @@ -114,8 +61,10 @@ +}; + +static inline char *build_index(struct block_info *offsets, unsigned long n, -+ unsigned long block_size, unsigned global_flags) ++ unsigned long block_size) +{ ++ static char v[11]; ++ u_int32_t flags = 0; + u_int32_t *ofs32 = (u_int32_t *) offsets; + loff_t *ofs64 = (loff_t *) offsets; + @@ -140,8 +89,6 @@ + } + else { /* V2.0/V4.0 */ + loff_t last = CLOOP_BLOCK_OFFSET(__be64_to_cpu(ofs64[n])); -+ u_int32_t flags; -+ static char v4[11]; + unsigned long i = n; + + for (flags = 0; n-- ;) { @@ -159,12 +106,7 @@ + offsets[i] = offsets[offsets[i].offset]; + } + } -+ strcpy(v4, (char *) "64BE v4.0a"); -+ v4[10] = 'a' + ((flags-1) & 0xF); // compressors used -+ if (flags > 0x10) { // with links ? -+ v4[10] += 'A' - 'a'; -+ } -+ return v4; ++ strcpy(v, (char *) "64BE v4.0a"); + } + } + else if (ofs32[1] == 0 && v3_64 == 0) { /* V1.0 */ @@ -180,7 +122,6 @@ + else { /* V3.0 or V0.68 */ + unsigned long i; + loff_t j; -+ static char v3[11]; + + for (i = 0; i < n && ntohl(ofs32[i]) < ntohl(ofs32[i+1]); i++); + if (i == n && ntohl(ofs32[0]) == (4*n) + 0x8C) { /* V0.68 */ @@ -195,28 +136,33 @@ + } + + v3_64 = (ofs32[1] == 0); -+ for (i = n; i-- != 0; ) ++ for (i = n; i-- != 0; ) { + offsets[i].size = ntohl(ofs32[i << v3_64]); ++ if (offsets[i].size == 0xFFFFFFFF) { ++ offsets[i].size = 0x10000000 | block_size; ++ } ++ offsets[i].flags = (offsets[i].size >> 28); ++ offsets[i].size &= 0x0FFFFFFF; ++ } + for (i = 0, j = sizeof(struct cloop_head); i < n; i++) { + offsets[i].offset = j; -+ offsets[i].flags = global_flags; -+ if (offsets[i].size == 0xFFFFFFFF) { -+ offsets[i].flags = CLOOP_COMPRESSOR_NONE; -+ offsets[i].size = block_size; -+ } -+ if ((offsets[i].size & 0x80000000) == 0) { ++ if (offsets[i].flags < 8) { + j += offsets[i].size; + } + } + for (i = 0; i < n; i++) { -+ if (offsets[i].size & 0x80000000) { -+ offsets[i] = offsets[offsets[i].size & 0x7FFFFFFF]; ++ flags |= 1 << offsets[i].flags; ++ if (offsets[i].flags >= 8) { ++ offsets[i] = offsets[offsets[i].size]; + } + } -+ strcpy(v3, (char *) (v3_64) ? "64BE v3.0a" : "32BE v3.0a"); -+ v3[10] += global_flags; -+ return v3; ++ strcpy(v, (char *) (v3_64) ? "64BE v3.0a" : "32BE v3.0a"); + } ++ v[10] = 'a' + ((flags-1) & 0xF); // compressors used ++ if (flags > 0x10) { // with links ? ++ v[10] += 'A' - 'a'; ++ } ++ return v; +} + /* Cloop suspend IOCTL */ @@ -224,661 +170,538 @@ --- cloop.c +++ cloop.c -@@ -1,26 +1,23 @@ --/* -- * compressed_loop.c: Read-only compressed loop blockdevice -- * hacked up by Rusty in 1999, extended and maintained by Klaus Knopper -- * -- * A cloop file looks like this: -- * [32-bit uncompressed block size: network order] -- * [32-bit number of blocks (n_blocks): network order] -- * [64-bit file offsets of start of blocks: network order] -- * ... -- * (n_blocks + 1). -- * n_blocks consisting of: -- * [compressed block] -- * -- * Every version greatly inspired by code seen in loop.c -- * by Theodore Ts'o, 3/29/93. -- * -- * Copyright 1999-2009 by Paul `Rusty' Russell & Klaus Knopper. -- * Redistribution of this file is permitted under the GNU Public License. -- * -- */ -+/************************************************************************\ -+* cloop.c: Read-only compressed loop blockdevice * -+* hacked up by Rusty in 1999, extended and maintained by Klaus Knopper * -+* * -+* For all supported cloop file formats, please check the file "cloop.h" * -+* New in Version 4: * -+* - Header can be first or last in cloop file, * -+* - Different compression algorithms supported (compression type * -+* encoded in first 4 bytes of block offset address) * -+* * -+* Every version greatly inspired by code seen in loop.c * -+* by Theodore Ts'o, 3/29/93. * -+* * -+* Copyright 1999-2009 by Paul `Rusty' Russell & Klaus Knopper. * -+* Redistribution of this file is permitted under the GNU Public License * -+* V2. * -+\************************************************************************/ +@@ -17,7 +17,7 @@ + \************************************************************************/ #define CLOOP_NAME "cloop" --#define CLOOP_VERSION "2.639" +-#define CLOOP_VERSION "5.3" +#define CLOOP_VERSION "4.12" #define CLOOP_MAX 8 #ifndef KBUILD_MODNAME -@@ -47,8 +44,27 @@ - #include /* do_div() for 64bit division */ - #include - #include --/* Use zlib_inflate from lib/zlib_inflate */ -+/* Check for ZLIB, LZO1X, LZ4 decompression algorithms in kernel. */ -+#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE)) - #include -+#endif -+#if (defined(CONFIG_LZO_DECOMPRESS) || defined(CONFIG_LZO_DECOMPRESS_MODULE)) -+#include -+#endif -+#if (defined(CONFIG_DECOMPRESS_LZ4) || defined(CONFIG_DECOMPRESS_LZ4_MODULE)) -+#include -+#endif -+#if (defined(CONFIG_DECOMPRESS_LZMA) || defined(CONFIG_DECOMPRESS_LZMA_MODULE)) -+#include -+#endif -+#if (defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE)) -+#include -+#endif -+ -+#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))) -+#error "No decompression library selected in kernel config!" -+#endif -+ +@@ -68,7 +68,6 @@ #include #include #include -@@ -92,47 +108,64 @@ - #define DEBUGP(format, x...) - #endif +-#include /* new multiqueue infrastructure */ + #include "cloop.h" -+/* Default size of buffer to keep some decompressed blocks in memory to speed up access */ -+#define BLOCK_BUFFER_MEM (16*65536) -+ - /* One file can be opened at module insertion time */ - /* insmod cloop file=/path/to/file */ - static char *file=NULL; - static unsigned int preload=0; - static unsigned int cloop_max=CLOOP_MAX; -+static unsigned int buffers=BLOCK_BUFFER_MEM; - module_param(file, charp, 0); - module_param(preload, uint, 0); - module_param(cloop_max, uint, 0); - MODULE_PARM_DESC(file, "Initial cloop image file (full path) for /dev/cloop"); - MODULE_PARM_DESC(preload, "Preload n blocks of cloop data into memory"); - MODULE_PARM_DESC(cloop_max, "Maximum number of cloop devices (default 8)"); -+MODULE_PARM_DESC(buffers, "Size of buffer to keep uncompressed blocks in memory in MiB (default 1)"); + /* New License scheme */ +@@ -93,10 +92,7 @@ + /* Use experimental major for now */ + #define MAJOR_NR 240 - static struct file *initial_file=NULL; - static int cloop_major=MAJOR_NR; +-#ifndef DEVICE_NAME +-#define DEVICE_NAME CLOOP_NAME +-#endif +- ++/* #define DEVICE_NAME CLOOP_NAME */ + /* #define DEVICE_NR(device) (MINOR(device)) */ + /* #define DEVICE_ON(device) */ + /* #define DEVICE_OFF(device) */ +@@ -143,7 +139,7 @@ + u_int32_t allflags; --/* Number of buffered decompressed blocks */ --#define BUFFERED_BLOCKS 8 - struct cloop_device - { -- /* Copied straight from the file */ -+ /* Header filled from the file */ - struct cloop_head head; -+ int header_first; -+ int file_format; - -- /* An array of offsets of compressed blocks within the file */ -- loff_t *offsets; -+ /* An or'd sum of all flags of each compressed block (v3) */ -+ u_int32_t allflags; -+ -+ /* An array of cloop_ptr flags/offset for compressed blocks within the file */ + /* An array of cloop_ptr flags/offset for compressed blocks within the file */ +- cloop_block_ptr *block_ptrs; + struct block_info *block_ptrs; /* We buffer some uncompressed blocks for performance */ -- int buffered_blocknum[BUFFERED_BLOCKS]; -- int current_bufnum; -- void *buffer[BUFFERED_BLOCKS]; -- void *compressed_buffer; -- size_t preload_array_size; /* Size of pointer array in blocks */ -- size_t preload_size; /* Number of successfully allocated blocks */ -- char **preload_cache; /* Pointers to preloaded blocks */ -+ size_t num_buffered_blocks; /* how many uncompressed blocks buffered for performance */ -+ int *buffered_blocknum; /* list of numbers of uncompressed blocks in buffer */ -+ int current_bufnum; /* which block is current */ -+ unsigned char **buffer; /* cache space for num_buffered_blocks uncompressed blocks */ -+ void *compressed_buffer; /* space for the largest compressed block */ -+ size_t preload_array_size; /* Size of pointer array in blocks */ -+ size_t preload_size; /* Number of successfully allocated blocks */ -+ char **preload_cache; /* Pointers to preloaded blocks */ - -+#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE)) - z_stream zstream; -+#endif -+#if (defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE)) -+ struct xz_dec *xzdecoderstate; -+ struct xz_buf xz_buffer; -+#endif - - struct file *backing_file; /* associated file */ - struct inode *backing_inode; /* for bmap */ - -+ unsigned char *underlying_filename; - unsigned long largest_block; - unsigned int underlying_blksize; -+ loff_t underlying_total_size; - int clo_number; - int refcnt; - struct block_device *bdev; -@@ -147,7 +180,6 @@ + size_t num_buffered_blocks; /* how many uncompressed blocks buffered for performance */ +@@ -178,14 +174,16 @@ + spinlock_t queue_lock; + /* mutex for ioctl() */ + struct mutex clo_ctl_mutex; +- /* mutex for request */ +- struct mutex clo_rq_mutex; ++ struct list_head clo_list; ++ struct task_struct *clo_thread; ++ wait_queue_head_t clo_event; struct request_queue *clo_queue; struct gendisk *clo_disk; +- struct blk_mq_tag_set tag_set; int suspended; -- char clo_file_name[LO_NAME_SIZE]; }; - /* Changed in 2.639: cloop_dev is now a an array of cloop_dev pointers, -@@ -156,52 +188,113 @@ ++/* Changed in 2.639: cloop_dev is now a an array of cloop_dev pointers, ++ so we can specify how many devices we need via parameters. */ + static struct cloop_device **cloop_dev; static const char *cloop_name=CLOOP_NAME; static int cloop_count = 0; - --#if (!(defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE))) /* Must be compiled into kernel. */ --#error "Invalid Kernel configuration. CONFIG_ZLIB_INFLATE support is needed for cloop." --#endif -- --/* Use __get_free_pages instead of vmalloc, allows up to 32 pages, -- * 2MB in one piece */ - static void *cloop_malloc(size_t size) - { -- int order = get_order(size); -- if(order <= KMALLOC_MAX_ORDER) -- return (void *)kmalloc(size, GFP_KERNEL); -- else if(order < MAX_ORDER) -- return (void *)__get_free_pages(GFP_KERNEL, order); -+ /* kmalloc will fail after the system is running for a while, */ -+ /* when large orders can't return contiguous memory. */ -+ /* Let's just use vmalloc for now. :-/ */ -+ /* int order = get_order(size); */ -+ /* if(order <= KMALLOC_MAX_ORDER) */ -+ /* return (void *)kmalloc(size, GFP_KERNEL); */ -+ /* else if(order < MAX_ORDER) */ -+ /* return (void *)__get_free_pages(GFP_KERNEL, order); */ - return (void *)vmalloc(size); +@@ -214,24 +212,21 @@ + vfree(mem); } - static void cloop_free(void *mem, size_t size) - { -- int order = get_order(size); -- if(order <= KMALLOC_MAX_ORDER) -- kfree(mem); -- else if(order < MAX_ORDER) -- free_pages((unsigned long)mem, order); -- else vfree(mem); -+ /* int order = get_order(size); */ -+ /* if(order <= KMALLOC_MAX_ORDER) */ -+ /* kfree(mem); */ -+ /* else if(order < MAX_ORDER) */ -+ /* free_pages((unsigned long)mem, order); */ -+ /* else */ -+ vfree(mem); - } - --static int uncompress(struct cloop_device *clo, -- unsigned char *dest, unsigned long *destLen, -- unsigned char *source, unsigned long sourceLen) +-/* static int uncompress(struct cloop_device *clo, unsigned char *dest, unsigned long *destLen, unsigned char *source, unsigned long sourceLen) */ +-static int uncompress(struct cloop_device *clo, u_int32_t block_num, u_int32_t compressed_length, unsigned long *uncompressed_length) +static int uncompress(struct cloop_device *clo, unsigned char *dest, unsigned long *destLen, unsigned char *source, unsigned long sourceLen, int flags) { -- /* Most of this code can be found in fs/cramfs/uncompress.c */ -- int err; -- clo->zstream.next_in = source; -- clo->zstream.avail_in = sourceLen; -- clo->zstream.next_out = dest; -- clo->zstream.avail_out = *destLen; -- err = zlib_inflateReset(&clo->zstream); -- if (err != Z_OK) -- { -- printk(KERN_ERR "%s: zlib_inflateReset error %d\n", cloop_name, err); -- zlib_inflateEnd(&clo->zstream); zlib_inflateInit(&clo->zstream); -- } -- err = zlib_inflate(&clo->zstream, Z_FINISH); -- *destLen = clo->zstream.total_out; -- if (err != Z_STREAM_END) return err; -- return Z_OK; -+ int err = -1; -+ switch(flags) -+ { -+ case CLOOP_COMPRESSOR_NONE: + int err = -1; +- int flags = CLOOP_BLOCK_FLAGS(clo->block_ptrs[block_num]); + switch(flags) + { + case CLOOP_COMPRESSOR_NONE: +- /* block is umcompressed, swap pointers only! */ +- { char *tmp = clo->compressed_buffer; clo->compressed_buffer = clo->buffer[clo->current_bufnum]; clo->buffer[clo->current_bufnum] = tmp; } +- DEBUGP("cloop: block %d is uncompressed (flags=%d), just swapping %u bytes\n", block_num, flags, compressed_length); + memcpy(dest, source, *destLen = sourceLen); + err = Z_OK; -+ break; -+#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE)) -+ case CLOOP_COMPRESSOR_ZLIB: + break; + #if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE)) + case CLOOP_COMPRESSOR_ZLIB: +- clo->zstream.next_in = clo->compressed_buffer; +- clo->zstream.avail_in = compressed_length; +- clo->zstream.next_out = clo->buffer[clo->current_bufnum]; +- clo->zstream.avail_out = clo->head.block_size; + clo->zstream.next_in = source; + clo->zstream.avail_in = sourceLen; + clo->zstream.next_out = dest; + clo->zstream.avail_out = *destLen; -+ err = zlib_inflateReset(&clo->zstream); -+ if (err != Z_OK) -+ { -+ printk(KERN_ERR "%s: zlib_inflateReset error %d\n", cloop_name, err); -+ zlib_inflateEnd(&clo->zstream); zlib_inflateInit(&clo->zstream); -+ } -+ err = zlib_inflate(&clo->zstream, Z_FINISH); + err = zlib_inflateReset(&clo->zstream); + if (err != Z_OK) + { +@@ -239,50 +234,50 @@ + zlib_inflateEnd(&clo->zstream); zlib_inflateInit(&clo->zstream); + } + err = zlib_inflate(&clo->zstream, Z_FINISH); +- *uncompressed_length = clo->zstream.total_out; + *destLen = clo->zstream.total_out; -+ if (err == Z_STREAM_END) err = 0; + if (err == Z_STREAM_END) err = 0; +- DEBUGP("cloop: zlib decompression done, ret =%d, size =%lu\n", err, *uncompressed_length); + DEBUGP("cloop: zlib decompression done, ret =%d, size =%lu\n", err, *destLen); -+ break; -+#endif -+#if (defined(CONFIG_LZO_DECOMPRESS) || defined(CONFIG_LZO_DECOMPRESS_MODULE)) -+ case CLOOP_COMPRESSOR_LZO1X: -+ { -+ size_t tmp = (size_t) clo->head.block_size; + break; + #endif + #if (defined(CONFIG_LZO_DECOMPRESS) || defined(CONFIG_LZO_DECOMPRESS_MODULE)) + case CLOOP_COMPRESSOR_LZO1X: + { + size_t tmp = (size_t) clo->head.block_size; +- err = lzo1x_decompress_safe(clo->compressed_buffer, compressed_length, +- clo->buffer[clo->current_bufnum], &tmp); +- if (err == LZO_E_OK) *uncompressed_length = (u_int32_t) tmp; + err = lzo1x_decompress_safe(source, sourceLen, + dest, &tmp); + if (err == LZO_E_OK) *destLen = (u_int32_t) tmp; -+ } -+ break; -+#endif -+#if (defined(CONFIG_DECOMPRESS_LZ4) || defined(CONFIG_DECOMPRESS_LZ4_MODULE)) -+ case CLOOP_COMPRESSOR_LZ4: -+ { + } + break; + #endif + #if (defined(CONFIG_DECOMPRESS_LZ4) || defined(CONFIG_DECOMPRESS_LZ4_MODULE)) + case CLOOP_COMPRESSOR_LZ4: + { +- size_t outputSize = clo->head.block_size; + size_t outputSize = *destLen; -+ /* We should adjust outputSize here, in case the last block is smaller than block_size */ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) /* field removed */ + /* We should adjust outputSize here, in case the last block is smaller than block_size */ + #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) /* field removed */ +- err = lz4_decompress(clo->compressed_buffer, (size_t *) &compressed_length, +- clo->buffer[clo->current_bufnum], outputSize); + err = lz4_decompress(source, (size_t *) &sourceLen, + dest, outputSize); -+#else + #else +- err = LZ4_decompress_safe(clo->compressed_buffer, +- clo->buffer[clo->current_bufnum], +- compressed_length, outputSize); + err = LZ4_decompress_safe(source, + dest, + sourceLen, outputSize); -+#endif -+ if (err >= 0) -+ { -+ err = 0; + #endif + if (err >= 0) + { + err = 0; +- *uncompressed_length = outputSize; + *destLen = outputSize; -+ } -+ } -+ break; -+#endif -+#if (defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE)) -+ case CLOOP_COMPRESSOR_XZ: + } + } + break; + #endif + #if (defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE)) + case CLOOP_COMPRESSOR_XZ: +- clo->xz_buffer.in = clo->compressed_buffer; + clo->xz_buffer.in = source; -+ clo->xz_buffer.in_pos = 0; + clo->xz_buffer.in_pos = 0; +- clo->xz_buffer.in_size = compressed_length; +- clo->xz_buffer.out = clo->buffer[clo->current_bufnum]; + clo->xz_buffer.in_size = sourceLen; + clo->xz_buffer.out = dest; -+ clo->xz_buffer.out_pos = 0; + clo->xz_buffer.out_pos = 0; +- clo->xz_buffer.out_size = clo->head.block_size; + clo->xz_buffer.out_size = *destLen; -+ xz_dec_reset(clo->xzdecoderstate); -+ err = xz_dec_run(clo->xzdecoderstate, &clo->xz_buffer); -+ if (err == XZ_STREAM_END || err == XZ_OK) -+ { -+ err = 0; -+ } -+ else -+ { -+ printk(KERN_ERR "%s: xz_dec_run error %d\n", cloop_name, err); -+ err = 1; -+ } -+ break; -+#endif -+ default: -+ printk(KERN_ERR "%s: compression method is not supported!\n", cloop_name); -+ } -+ return err; - } - - static ssize_t cloop_read_from_file(struct cloop_device *clo, struct file *f, char *buf, -@@ -220,7 +313,7 @@ + xz_dec_reset(clo->xzdecoderstate); + err = xz_dec_run(clo->xzdecoderstate, &clo->xz_buffer); + if (err == XZ_STREAM_END || err == XZ_OK) +@@ -309,16 +304,12 @@ + while (buf_done < buf_len) + { + size_t size = buf_len - buf_done, size_read; +- mm_segment_t old_fs; + /* kernel_read() only supports 32 bit offsets, so we use vfs_read() instead. */ + /* int size_read = kernel_read(f, pos, buf + buf_done, size); */ +- +- // mutex_lock(&clo->clo_rq_mutex); +- old_fs = get_fs(); +- set_fs(KERNEL_DS); ++ mm_segment_t old_fs = get_fs(); ++ set_fs(get_ds()); + size_read = vfs_read(f, (void __user *)(buf + buf_done), size, &pos); + set_fs(old_fs); +- // mutex_unlock(&clo->clo_rq_mutex); if(size_read <= 0) { -- printk(KERN_ERR "%s: Read error %d at pos %Lu in file %s, " -+ printk(KERN_ERR "%s: Read error %d at pos %llu in file %s, " - "%d bytes lost.\n", cloop_name, (int)size_read, pos, - file, (int)size); - memset(buf + buf_len - size, 0, size); -@@ -232,72 +325,84 @@ - } +@@ -358,8 +349,8 @@ + return i; + } - /* This looks more complicated than it is */ --/* Returns number of block buffer to use for this request */ -+/* Returns number of cache block buffer to use for this request */ - static int cloop_load_buffer(struct cloop_device *clo, int blocknum) - { -- unsigned int buf_done = 0; -- unsigned long buflen; -- unsigned int buf_length; -+ loff_t compressed_block_offset; -+ long compressed_block_len; -+ long uncompressed_block_len=0; - int ret; - int i; -- if(blocknum > ntohl(clo->head.num_blocks) || blocknum < 0) -- { -- printk(KERN_WARNING "%s: Invalid block number %d requested.\n", -- cloop_name, blocknum); -- return -1; -- } -+ if(blocknum > clo->head.num_blocks || blocknum < 0) -+ { -+ printk(KERN_WARNING "%s: Invalid block number %d requested.\n", -+ cloop_name, blocknum); -+ return -1; -+ } - - /* Quick return if the block we seek is already in one of the buffers. */ - /* Return number of buffer */ -- for(i=0; inum_buffered_blocks; i++) - if (blocknum == clo->buffered_blocknum[i]) -- { -- DEBUGP(KERN_INFO "cloop_load_buffer: Found buffered block %d\n", i); -- return i; -- } -- -- buf_length = be64_to_cpu(clo->offsets[blocknum+1]) - be64_to_cpu(clo->offsets[blocknum]); -- --/* Load one compressed block from the file. */ -- cloop_read_from_file(clo, clo->backing_file, (char *)clo->compressed_buffer, -- be64_to_cpu(clo->offsets[blocknum]), buf_length); -+ { -+ DEBUGP(KERN_INFO "cloop_load_buffer: Found buffered block %d\n", i); -+ return i; -+ } - -- buflen = ntohl(clo->head.block_size); +- compressed_block_offset = CLOOP_BLOCK_OFFSET(clo->block_ptrs[blocknum]); +- compressed_block_len = (long) (CLOOP_BLOCK_OFFSET(clo->block_ptrs[blocknum+1]) - compressed_block_offset) ; + compressed_block_offset = clo->block_ptrs[blocknum].offset; + compressed_block_len = (long) (clo->block_ptrs[blocknum].size) ; -- /* Go to next position in the block ring buffer */ -- clo->current_bufnum++; -- if(clo->current_bufnum >= BUFFERED_BLOCKS) clo->current_bufnum = 0; -+ /* Load one compressed block from the file. */ -+ if(compressed_block_offset > 0 && compressed_block_len >= 0) /* sanity check */ -+ { -+ size_t n = cloop_read_from_file(clo, clo->backing_file, (char *)clo->compressed_buffer, -+ compressed_block_offset, compressed_block_len); -+ if (n!= compressed_block_len) -+ { -+ printk(KERN_ERR "%s: error while reading %lu bytes @ %llu from file %s\n", + /* Load one compressed block from the file. */ + if(compressed_block_offset > 0 && compressed_block_len >= 0) /* sanity check */ +@@ -369,12 +360,12 @@ + if (n!= compressed_block_len) + { + printk(KERN_ERR "%s: error while reading %lu bytes @ %llu from file %s\n", +- cloop_name, compressed_block_len, clo->block_ptrs[blocknum], clo->underlying_filename); + cloop_name, compressed_block_len, clo->block_ptrs[blocknum].offset, clo->underlying_filename); -+ /* return -1; */ -+ } -+ } else { -+ printk(KERN_ERR "%s: invalid data block len %ld bytes @ %lld from file %s\n", + /* return -1; */ + } + } else { + printk(KERN_ERR "%s: invalid data block len %ld bytes @ %lld from file %s\n", +- cloop_name, compressed_block_len, clo->block_ptrs[blocknum], clo->underlying_filename); + cloop_name, compressed_block_len, clo->block_ptrs[blocknum].offset, clo->underlying_filename); -+ return -1; -+ } -+ -+ /* Go to next position in the cache block buffer (which is used as a cyclic buffer) */ -+ if(++clo->current_bufnum >= clo->num_buffered_blocks) clo->current_bufnum = 0; + return -1; + } + +@@ -382,14 +373,16 @@ + if(++clo->current_bufnum >= clo->num_buffered_blocks) clo->current_bufnum = 0; /* Do the uncompression */ -- ret = uncompress(clo, clo->buffer[clo->current_bufnum], &buflen, clo->compressed_buffer, -- buf_length); +- ret = uncompress(clo, blocknum, compressed_block_len, &uncompressed_block_len); + uncompressed_block_len = clo->head.block_size; + ret = uncompress(clo, clo->buffer[clo->current_bufnum], &uncompressed_block_len, + clo->compressed_buffer, compressed_block_len, clo->block_ptrs[blocknum].flags); /* DEBUGP("cloop: buflen after uncompress: %ld\n",buflen); */ if (ret != 0) -- { -- printk(KERN_ERR "%s: zlib decompression error %i uncompressing block %u %u/%lu/%u/%u " -- "%Lu-%Lu\n", cloop_name, ret, blocknum, -- ntohl(clo->head.block_size), buflen, buf_length, buf_done, -- be64_to_cpu(clo->offsets[blocknum]), be64_to_cpu(clo->offsets[blocknum+1])); -- clo->buffered_blocknum[clo->current_bufnum] = -1; -- return -1; -- } -+ { -+ printk(KERN_ERR "%s: decompression error %i uncompressing block %u %lu bytes @ %llu, flags %u\n", -+ cloop_name, ret, blocknum, + { + printk(KERN_ERR "%s: decompression error %i uncompressing block %u %lu bytes @ %llu, flags %u\n", + cloop_name, ret, blocknum, +- compressed_block_len, CLOOP_BLOCK_OFFSET(clo->block_ptrs[blocknum]), +- CLOOP_BLOCK_FLAGS(clo->block_ptrs[blocknum])); + compressed_block_len, clo->block_ptrs[blocknum].offset, + clo->block_ptrs[blocknum].flags); -+ clo->buffered_blocknum[clo->current_bufnum] = -1; -+ return -1; -+ } - clo->buffered_blocknum[clo->current_bufnum] = blocknum; + clo->buffered_blocknum[clo->current_bufnum] = -1; + return -1; + } +@@ -397,107 +390,146 @@ return clo->current_bufnum; } - /* This function does all the real work. */ --/* returns "uptodate" */ +-static blk_status_t cloop_handle_request(struct cloop_device *clo, struct request *req) ++/* This function does all the real work. */ +/* returns "uptodate" */ - static int cloop_handle_request(struct cloop_device *clo, struct request *req) ++static int cloop_handle_request(struct cloop_device *clo, struct request *req) { int buffered_blocknum = -1; int preloaded = 0; - loff_t offset = (loff_t) blk_rq_pos(req)<<9; /* req->sector<<9 */ -- struct bio_vec *bvec; -+ struct bio_vec bvec; +- loff_t offset = (loff_t) blk_rq_pos(req)<<9; ++ loff_t offset = (loff_t) blk_rq_pos(req)<<9; /* req->sector<<9 */ + struct bio_vec bvec; struct req_iterator iter; +- blk_status_t ret = BLK_STS_OK; +- +- if (unlikely(req_op(req) != REQ_OP_READ )) +- { +- blk_dump_rq_flags(req, DEVICE_NAME " bad request"); +- return BLK_STS_IOERR; +- } +- +- if (unlikely(!clo->backing_file && !clo->suspended)) +- { +- DEBUGP("cloop_handle_request: not connected to a file\n"); +- return BLK_STS_IOERR; +- } +- rq_for_each_segment(bvec, req, iter) +- { +- unsigned long len = bvec.bv_len; +- loff_t to_offset = bvec.bv_offset; +- +- while(len > 0) { -- unsigned long len = bvec->bv_len; -- char *to_ptr = kmap(bvec->bv_page) + bvec->bv_offset; +- u_int32_t length_in_buffer; +- loff_t block_offset = offset; +- u_int32_t offset_in_buffer; +- char *from_ptr, *to_ptr; +- /* do_div (div64.h) returns the 64bit division remainder and */ +- /* puts the result in the first argument, i.e. block_offset */ +- /* becomes the blocknumber to load, and offset_in_buffer the */ +- /* position in the buffer */ +- offset_in_buffer = do_div(block_offset, clo->head.block_size); +- /* Lookup preload cache */ +- if(block_offset < clo->preload_size && clo->preload_cache != NULL && clo->preload_cache[block_offset] != NULL) +- { /* Copy from cache */ +- preloaded = 1; +- from_ptr = clo->preload_cache[block_offset]; +- } +- else +- { +- preloaded = 0; +- buffered_blocknum = cloop_load_buffer(clo,block_offset); +- if(buffered_blocknum == -1) + unsigned long len = bvec.bv_len; + char *to_ptr = kmap(bvec.bv_page) + bvec.bv_offset; - while(len > 0) ++ while(len > 0) { - u_int32_t length_in_buffer; -@@ -308,7 +413,7 @@ - /* puts the result in the first argument, i.e. block_offset */ - /* becomes the blocknumber to load, and offset_in_buffer the */ - /* position in the buffer */ -- offset_in_buffer = do_div(block_offset, ntohl(clo->head.block_size)); +- ret = BLK_STS_IOERR; +- break; /* invalid data, leave inner loop */ ++ u_int32_t length_in_buffer; ++ loff_t block_offset = offset; ++ u_int32_t offset_in_buffer; ++ char *from_ptr; ++ /* do_div (div64.h) returns the 64bit division remainder and */ ++ /* puts the result in the first argument, i.e. block_offset */ ++ /* becomes the blocknumber to load, and offset_in_buffer the */ ++ /* position in the buffer */ + offset_in_buffer = do_div(block_offset, clo->head.block_size); - /* Lookup preload cache */ - if(block_offset < clo->preload_size && clo->preload_cache != NULL && - clo->preload_cache[block_offset] != NULL) -@@ -325,7 +430,7 @@ - from_ptr = clo->buffer[buffered_blocknum]; - } - /* Now, at least part of what we want will be in the buffer. */ -- length_in_buffer = ntohl(clo->head.block_size) - offset_in_buffer; ++ /* Lookup preload cache */ ++ if(block_offset < clo->preload_size && clo->preload_cache != NULL && ++ clo->preload_cache[block_offset] != NULL) ++ { /* Copy from cache */ ++ preloaded = 1; ++ from_ptr = clo->preload_cache[block_offset]; ++ } ++ else ++ { ++ preloaded = 0; ++ buffered_blocknum = cloop_load_buffer(clo,block_offset); ++ if(buffered_blocknum == -1) break; /* invalid data, leave inner loop */ ++ /* Copy from buffer */ ++ from_ptr = clo->buffer[buffered_blocknum]; ++ } ++ /* Now, at least part of what we want will be in the buffer. */ + length_in_buffer = clo->head.block_size - offset_in_buffer; - if(length_in_buffer > len) - { - /* DEBUGP("Warning: length_in_buffer=%u > len=%u\n", -@@ -337,18 +442,19 @@ - len -= length_in_buffer; - offset += length_in_buffer; - } /* while inner loop */ -- kunmap(bvec->bv_page); ++ if(length_in_buffer > len) ++ { ++/* DEBUGP("Warning: length_in_buffer=%u > len=%u\n", ++ length_in_buffer,len); */ ++ length_in_buffer = len; ++ } ++ memcpy(to_ptr, from_ptr + offset_in_buffer, length_in_buffer); ++ to_ptr += length_in_buffer; ++ len -= length_in_buffer; ++ offset += length_in_buffer; ++ } /* while inner loop */ + kunmap(bvec.bv_page); + cond_resched(); - } /* end rq_for_each_segment*/ - return ((buffered_blocknum!=-1) || preloaded); - } - - /* Adopted from loop.c, a kernel thread to handle physical reads and -- * decompression. */ ++ } /* end rq_for_each_segment*/ ++ return ((buffered_blocknum!=-1) || preloaded); ++} ++ ++/* Adopted from loop.c, a kernel thread to handle physical reads and + decompression. */ - static int cloop_thread(void *data) - { - struct cloop_device *clo = data; - current->flags |= PF_NOFREEZE; -- set_user_nice(current, -15); ++static int cloop_thread(void *data) ++{ ++ struct cloop_device *clo = data; ++ current->flags |= PF_NOFREEZE; + set_user_nice(current, 10); - while (!kthread_should_stop()||!list_empty(&clo->clo_list)) - { - int err; -@@ -390,10 +496,18 @@ - int rw; - /* quick sanity checks */ - /* blk_fs_request() was removed in 2.6.36 */ -- if (unlikely(req == NULL || (req->cmd_type != REQ_TYPE_FS))) ++ while (!kthread_should_stop()||!list_empty(&clo->clo_list)) ++ { ++ int err; ++ err = wait_event_interruptible(clo->clo_event, !list_empty(&clo->clo_list) || ++ kthread_should_stop()); ++ if(unlikely(err)) ++ { ++ DEBUGP(KERN_ERR "cloop thread activated on error!? Continuing.\n"); ++ continue; + } +- /* Copy from buffer */ +- from_ptr = clo->buffer[buffered_blocknum]; +- } +- /* Now, at least part of what we want will be in the buffer. */ +- length_in_buffer = clo->head.block_size - offset_in_buffer; +- if(length_in_buffer > len) +- { +- /* DEBUGP("Warning: length_in_buffer=%u > len=%u\n", length_in_buffer,len); */ +- length_in_buffer = len; +- } +- to_ptr = kmap_atomic(bvec.bv_page); +- memcpy(to_ptr + to_offset, from_ptr + offset_in_buffer, length_in_buffer); +- kunmap_atomic(to_ptr); +- to_offset += length_in_buffer; +- len -= length_in_buffer; +- offset += length_in_buffer; +- } /* while inner loop */ +- } /* rq_for_each_segment */ +- return ret; +-} +- +-static blk_status_t cloop_queue_rq(struct blk_mq_hw_ctx *hctx, const struct blk_mq_queue_data *bd) +-{ +-// struct request_queue *q = hctx->queue; +-// struct cloop_device *clo = q->queuedata; +- struct request *req = bd->rq; +- struct cloop_device *clo = req->rq_disk->private_data; +- blk_status_t ret = BLK_STS_OK; +- +-#if 1 /* Does it work when loading libraries? */ +- /* Since we have a buffered block list as well as data to read */ +- /* from disk (slow), and are (probably) never called from an */ +- /* interrupt, we use a simple mutex lock right here to ensure */ +- /* consistency. */ +- mutex_lock(&clo->clo_rq_mutex); +- #else +- spin_lock_irq(&clo->queue_lock); +- #endif +- blk_mq_start_request(req); +- do { +- ret = cloop_handle_request(clo, req); +- } while(blk_update_request(req, ret, blk_rq_cur_bytes(req))); +- blk_mq_end_request(req, ret); +- #if 1 /* See above */ +- mutex_unlock(&clo->clo_rq_mutex); +- #else +- spin_unlock_irq(&clo->queue_lock); +- #endif +- return ret; ++ if(!list_empty(&clo->clo_list)) ++ { ++ struct request *req; ++ unsigned long flags; ++ int uptodate; ++ spin_lock_irq(&clo->queue_lock); ++ req = list_entry(clo->clo_list.next, struct request, queuelist); ++ list_del_init(&req->queuelist); ++ spin_unlock_irq(&clo->queue_lock); ++ uptodate = cloop_handle_request(clo, req); ++ spin_lock_irqsave(&clo->queue_lock, flags); ++ __blk_end_request_all(req, uptodate ? 0 : -EIO); ++ spin_unlock_irqrestore(&clo->queue_lock, flags); ++ } ++ } ++ DEBUGP(KERN_ERR "cloop_thread exited.\n"); ++ return 0; ++} ++ ++/* This is called by the kernel block queue management every now and then, ++ * with successive read requests qeued and sorted in a (hopefully) ++ * "most efficient way". spin_lock_irq() is being held by the kernel. */ ++static void cloop_do_request(struct request_queue *q) ++{ ++ struct request *req; ++ while((req = blk_fetch_request(q)) != NULL) ++ { ++ struct cloop_device *clo; ++ int rw; ++ /* quick sanity checks */ ++ /* blk_fs_request() was removed in 2.6.36 */ + if (unlikely(req == NULL +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) /* field removed */ + || (req->cmd_type != REQ_TYPE_FS) +#endif + )) - goto error_continue; - rw = rq_data_dir(req); -- if (unlikely(rw != READ && rw != READA)) ++ goto error_continue; ++ rw = rq_data_dir(req); + if (unlikely(rw != READ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) + && rw != READA +#endif + )) - { - DEBUGP("cloop_do_request: bad command\n"); - goto error_continue; -@@ -409,40 +523,51 @@ - continue; /* next request */ - error_continue: - DEBUGP(KERN_ERR "cloop_do_request: Discarding request %p.\n", req); ++ { ++ DEBUGP("cloop_do_request: bad command\n"); ++ goto error_continue; ++ } ++ clo = req->rq_disk->private_data; ++ if (unlikely(!clo->backing_file && !clo->suspended)) ++ { ++ DEBUGP("cloop_do_request: not connected to a file\n"); ++ goto error_continue; ++ } ++ list_add_tail(&req->queuelist, &clo->clo_list); /* Add to working list for thread */ ++ wake_up(&clo->clo_event); /* Wake up cloop_thread */ ++ continue; /* next request */ ++ error_continue: ++ DEBUGP(KERN_ERR "cloop_do_request: Discarding request %p.\n", req); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) - req->errors++; ++ req->errors++; +#else + req->error_count++; +#endif - __blk_end_request_all(req, -EIO); - } ++ __blk_end_request_all(req, -EIO); ++ } } --/* Read header and offsets from already opened file */ --static int cloop_set_file(int cloop_num, struct file *file, char *filename) -+/* Read header, flags and offsets from already opened file */ -+static int cloop_set_file(int cloop_num, struct file *file) - { - struct cloop_device *clo = cloop_dev[cloop_num]; - struct inode *inode; + /* Read header, flags and offsets from already opened file */ +@@ -508,7 +540,7 @@ char *bbuf=NULL; -- unsigned int i, offsets_read, total_offsets; -- int isblkdev; -- int error = 0; -+ unsigned int bbuf_size = 0; -+ const unsigned int header_size = sizeof(struct cloop_head); + unsigned int bbuf_size = 0; + const unsigned int header_size = sizeof(struct cloop_head); +- unsigned int i, offsets_read=0, total_offsets=0; + unsigned int i, total_offsets=0; -+ loff_t fs_read_position = 0, header_pos[2]; -+ int flags, isblkdev, bytes_read, error = 0; -+ if (clo->suspended) return error; -+ #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) - inode = file->f_dentry->d_inode; -+ clo->underlying_filename = kstrdup(file->f_dentry->d_name.name ? file->f_dentry->d_name.name : (const unsigned char *)"anonymous filename", GFP_KERNEL); -+ #else -+ inode = file->f_path.dentry->d_inode; -+ 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); -+ #endif - isblkdev=S_ISBLK(inode->i_mode)?1:0; - if(!isblkdev&&!S_ISREG(inode->i_mode)) + loff_t fs_read_position = 0, header_pos[2]; + int isblkdev, bytes_read, error = 0; + if (clo->suspended) return error; +@@ -581,29 +613,19 @@ + goto error_release; + } + memcpy(&clo->head, bbuf, header_size); +- if (strncmp(bbuf+CLOOP4_SIGNATURE_OFFSET, CLOOP4_SIGNATURE, CLOOP4_SIGNATURE_SIZE)==0) ++ if (strncmp(bbuf+CLOOP_SIGNATURE_OFFSET, CLOOP_SIGNATURE, CLOOP_SIGNATURE_SIZE)==0) + { +- clo->file_format=4; ++ clo->file_format++; + clo->head.block_size=ntohl(clo->head.block_size); + clo->head.num_blocks=ntohl(clo->head.num_blocks); + clo->header_first = (i==0) ? 1 : 0; +- printk(KERN_INFO "%s: file %s version %d, %d blocks of %d bytes, header %s.\n", cloop_name, clo->underlying_filename, clo->file_format, clo->head.num_blocks, clo->head.block_size, (i==0)?"first":"last"); +- break; +- } +- else if (strncmp(bbuf+CLOOP2_SIGNATURE_OFFSET, CLOOP2_SIGNATURE, CLOOP2_SIGNATURE_SIZE)==0) +- { +- clo->file_format=2; +- clo->head.block_size=ntohl(clo->head.block_size); +- clo->head.num_blocks=ntohl(clo->head.num_blocks); +- clo->header_first = (i==0) ? 1 : 0; +- printk(KERN_INFO "%s: file %s version %d, %d blocks of %d bytes, header %s.\n", cloop_name, clo->underlying_filename, clo->file_format, clo->head.num_blocks, clo->head.block_size, (i==0)?"first":"last"); ++ 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"); + break; + } + } + if (clo->file_format == 0) { - printk(KERN_ERR "%s: %s not a regular file or block device\n", -- cloop_name, filename); -+ cloop_name, clo->underlying_filename); +- printk(KERN_ERR "%s: Cannot read old 32-bit (version 0.68) images, " +- "please use an older version of %s for this file.\n", ++ printk(KERN_ERR "%s: Cannot detect %s format.\n", + cloop_name, cloop_name); + error=-EBADF; goto error_release; + } +@@ -613,67 +635,133 @@ + cloop_name, clo->head.block_size); error=-EBADF; goto error_release; } - clo->backing_file = file; - clo->backing_inode= inode ; -- if(!isblkdev&&inode->i_sizeunderlying_total_size = (isblkdev) ? inode->i_bdev->bd_inode->i_size : inode->i_size; -+ if(clo->underlying_total_size < header_size) +- total_offsets=clo->head.num_blocks+1; +- if (!isblkdev && (sizeof(struct cloop_head)+sizeof(loff_t)* ++ total_offsets=clo->head.num_blocks; ++ if (!isblkdev && (sizeof(struct cloop_head)+sizeof(struct block_info)* + total_offsets > inode->i_size)) { -- printk(KERN_ERR "%s: %lu bytes (must be >= %u bytes)\n", -- cloop_name, (unsigned long)inode->i_size, -- (unsigned)sizeof(struct cloop_head)); -+ printk(KERN_ERR "%s: %llu bytes (must be >= %u bytes)\n", -+ cloop_name, clo->underlying_total_size, -+ (unsigned int)header_size); + printk(KERN_ERR "%s: file %s too small for %u blocks\n", + cloop_name, clo->underlying_filename, clo->head.num_blocks); error=-EBADF; goto error_release; } -- /* In suspended mode, we have done all checks necessary - FF */ -- if (clo->suspended) -- return error; - if(isblkdev) - { - struct request_queue *q = bdev_get_queue(inode->i_bdev); -@@ -451,104 +576,225 @@ - /* blk_queue_max_hw_segments(clo->clo_queue, queue_max_hw_segments(q)); */ /* Removed in 2.6.34 */ - blk_queue_max_segment_size(clo->clo_queue, queue_max_segment_size(q)); - blk_queue_segment_boundary(clo->clo_queue, queue_segment_boundary(q)); -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) - blk_queue_merge_bvec(clo->clo_queue, q->merge_bvec_fn); -+#endif - clo->underlying_blksize = block_size(inode->i_bdev); - } - else - clo->underlying_blksize = PAGE_SIZE; -- DEBUGP("Underlying blocksize is %u\n", clo->underlying_blksize); -- bbuf = cloop_malloc(clo->underlying_blksize); -+ -+ DEBUGP(KERN_INFO "Underlying blocksize of %s is %u\n", clo->underlying_filename, clo->underlying_blksize); -+ DEBUGP(KERN_INFO "Underlying total size of %s is %llu\n", clo->underlying_filename, clo->underlying_total_size); -+ -+ /* clo->underlying_blksize should be larger than header_size, even if it's only PAGE_SIZE */ -+ bbuf_size = clo->underlying_blksize; -+ bbuf = cloop_malloc(bbuf_size); - if(!bbuf) - { -- printk(KERN_ERR "%s: out of kernel mem for block buffer (%lu bytes)\n", -- cloop_name, (unsigned long)clo->underlying_blksize); -+ printk(KERN_ERR "%s: out of kernel mem for buffer (%u bytes)\n", -+ cloop_name, (unsigned int) bbuf_size); -+ error=-ENOMEM; goto error_release; -+ } -+ -+ header_pos[0] = 0; /* header first */ -+ header_pos[1] = clo->underlying_total_size - sizeof(struct cloop_head); /* header last */ -+ for(i=0; i<2; i++) -+ { -+ /* Check for header */ -+ size_t bytes_readable = MIN(clo->underlying_blksize, clo->underlying_total_size - header_pos[i]); -+ size_t bytes_read = cloop_read_from_file(clo, file, bbuf, header_pos[i], bytes_readable); -+ if(bytes_read != bytes_readable) -+ { -+ printk(KERN_ERR "%s: Bad file %s, read() of %s %u bytes returned %d.\n", -+ cloop_name, clo->underlying_filename, (i==0)?"first":"last", -+ (unsigned int)header_size, (int)bytes_read); -+ error=-EBADF; -+ goto error_release; -+ } -+ memcpy(&clo->head, bbuf, header_size); -+ if (strncmp(bbuf+CLOOP_SIGNATURE_OFFSET, CLOOP_SIGNATURE, CLOOP_SIGNATURE_SIZE)==0) -+ { -+ clo->file_format++; -+ clo->head.block_size=ntohl(clo->head.block_size); -+ clo->head.num_blocks=ntohl(clo->head.num_blocks); -+ clo->header_first = (i==0) ? 1 : 0; -+ 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"); -+ break; -+ } -+ } -+ if (clo->file_format == 0) -+ { -+ printk(KERN_ERR "%s: Cannot detect %s format.\n", -+ cloop_name, cloop_name); -+ error=-EBADF; goto error_release; -+ } -+ if (clo->head.block_size % 512 != 0) -+ { -+ printk(KERN_ERR "%s: blocksize %u not multiple of 512\n", -+ cloop_name, clo->head.block_size); -+ error=-EBADF; goto error_release; -+ } -+ total_offsets=clo->head.num_blocks; -+ if (!isblkdev && (sizeof(struct cloop_head)+sizeof(struct block_info)* -+ total_offsets > inode->i_size)) -+ { -+ printk(KERN_ERR "%s: file %s too small for %u blocks\n", -+ cloop_name, clo->underlying_filename, clo->head.num_blocks); -+ error=-EBADF; goto error_release; -+ } +- clo->block_ptrs = cloop_malloc(sizeof(cloop_block_ptr) * total_offsets); +- if (!clo->block_ptrs) + /* Allocate Memory for decompressors */ +#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE)) + clo->zstream.workspace = cloop_malloc(zlib_inflate_workspacesize()); + if(!clo->zstream.workspace) -+ { + { +- printk(KERN_ERR "%s: out of kernel mem for offsets\n", cloop_name); + printk(KERN_ERR "%s: out of mem for zlib working area %u\n", + cloop_name, zlib_inflate_workspacesize()); error=-ENOMEM; goto error_release; } -- total_offsets = 1; /* Dummy total_offsets: will be filled in first time around */ -- for (i = 0, offsets_read = 0; offsets_read < total_offsets; i++) +- /* Read them offsets! */ +- if(clo->header_first) + zlib_inflateInit(&clo->zstream); +#endif +#if (defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE)) @@ -890,33 +713,20 @@ +#endif + if (total_offsets + 1 == 0) /* Version 3 */ { -- unsigned int offset = 0, num_readable; -- size_t bytes_read = cloop_read_from_file(clo, file, bbuf, -- i*clo->underlying_blksize, -- clo->underlying_blksize); -- if(bytes_read != clo->underlying_blksize) +- fs_read_position = sizeof(struct cloop_head); + struct cloop_tail tail; + if (isblkdev) - { -- printk(KERN_ERR "%s: Bad file, read() of first %lu bytes returned %d.\n", -- cloop_name, (unsigned long)clo->underlying_blksize, (int)bytes_read); -- error=-EBADF; -- goto error_release; ++ { + /* No end of file: can't find index */ + printk(KERN_ERR "%s: no V3 support for block device\n", + cloop_name); + error=-EBADF; goto error_release; - } -- /* Header will be in block zero */ -- if(i==0) ++ } + bytes_read = cloop_read_from_file(clo, file, (void *) &tail, + inode->i_size - sizeof(struct cloop_tail), + sizeof(struct cloop_tail)); + if (bytes_read == sizeof(struct cloop_tail)) - { -- memcpy(&clo->head, bbuf, sizeof(struct cloop_head)); -- offset = sizeof(struct cloop_head); -- if (ntohl(clo->head.block_size) % 512 != 0) ++ { + unsigned long len, zlen; + int ret; + void *zbuf; @@ -926,79 +736,47 @@ + zlen = ntohl(tail.table_size); + zbuf = cloop_malloc(zlen); + if (!clo->block_ptrs || !zbuf) - { -- printk(KERN_ERR "%s: blocksize %u not multiple of 512\n", -- cloop_name, ntohl(clo->head.block_size)); -- error=-EBADF; goto error_release; -- } -- if (clo->head.preamble[0x0B]!='V'||clo->head.preamble[0x0C]<'1') -- { -- printk(KERN_ERR "%s: Cannot read old 32-bit (version 0.68) images, " -- "please use an older version of %s for this file.\n", -- cloop_name, cloop_name); -- error=-EBADF; goto error_release; ++ { + printk(KERN_ERR "%s: out of kernel mem for index\n", cloop_name); + error=-ENOMEM; goto error_release; - } -- if (clo->head.preamble[0x0C]<'2') ++ } + bytes_read = cloop_read_from_file(clo, file, zbuf, + inode->i_size - zlen - sizeof(struct cloop_tail), + zlen); + if (bytes_read != zlen) - { -- printk(KERN_ERR "%s: Cannot read old architecture-dependent " -- "(format <= 1.0) images, please use an older " -- "version of %s for this file.\n", -- cloop_name, cloop_name); ++ { + printk(KERN_ERR "%s: can't read index\n", cloop_name); - error=-EBADF; goto error_release; - } -- total_offsets=ntohl(clo->head.num_blocks)+1; -- if (!isblkdev && (sizeof(struct cloop_head)+sizeof(loff_t)* -- total_offsets > inode->i_size)) ++ error=-EBADF; goto error_release; ++ } + len = CLOOP3_INDEX_SIZE(ntohl(tail.index_size)) * total_offsets; -+ flags = CLOOP3_BLOCKS_FLAGS(ntohl(tail.index_size)); -+// 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) -+printk(KERN_INFO "%s: uncompress(clo=%p, block_ptrs=%p, &len(%ld)=%p, zbuf=%p, zlen=%ld, flag=%d)\n", cloop_name, -+ clo, clo->block_ptrs, len, &len, zbuf, zlen, flags); -+ ret = uncompress(clo, (void *) clo->block_ptrs, &len, zbuf, zlen, flags); -+// May 3 19:45:20 (none) user.alert kernel: BUG: unable to handle kernel NULL pointer dereference at (null) -+printk(KERN_INFO "%s: uncompressed !\n", cloop_name); ++ ret = uncompress(clo, (void *) clo->block_ptrs, &len, zbuf, zlen, CLOOP_COMPRESSOR_ZLIB); + cloop_free(zbuf, zlen); + if (ret != 0) - { -- printk(KERN_ERR "%s: file too small for %u blocks\n", -- cloop_name, ntohl(clo->head.num_blocks)); -+ printk(KERN_ERR "%s: decompression error %i uncompressing index, flags %u\n", -+ cloop_name, ret, flags); - error=-EBADF; goto error_release; - } -- clo->offsets = cloop_malloc(sizeof(loff_t) * total_offsets); -- if (!clo->offsets) -- { -- printk(KERN_ERR "%s: out of kernel mem for offsets\n", cloop_name); -- error=-ENOMEM; goto error_release; -- } - } -- num_readable = MIN(total_offsets - offsets_read, -- (clo->underlying_blksize - offset) -- / sizeof(loff_t)); -- memcpy(&clo->offsets[offsets_read], bbuf+offset, num_readable * sizeof(loff_t)); -- offsets_read += num_readable; -- } -- { /* Search for largest block rather than estimate. KK. */ -- int i; -- for(i=0;iunderlying_total_size - sizeof(struct cloop_head) - total_offsets * sizeof(loff_t); +- } +- for(offsets_read=0;offsets_readunderlying_total_size - fs_read_position); +- if(bytes_readable <= 0) break; /* Done */ +- bytes_read = cloop_read_from_file(clo, file, bbuf, fs_read_position, bytes_readable); +- if(bytes_read != bytes_readable) + unsigned int n, total_bytes; -+ flags = 0; + clo->block_ptrs = cloop_malloc(sizeof(struct block_info) * total_offsets); + if (!clo->block_ptrs) + { @@ -1007,14 +785,26 @@ + } + /* Read them offsets! */ + if(clo->header_first) -+ { + { +- printk(KERN_ERR "%s: Bad file %s, read() %lu bytes @ %llu returned %d.\n", +- cloop_name, clo->underlying_filename, (unsigned long)clo->underlying_blksize, fs_read_position, (int)bytes_read); +- error=-EBADF; +- goto error_release; + total_bytes = total_offsets * sizeof(struct block_info); + fs_read_position = sizeof(struct cloop_head); -+ } + } +- /* remember where to read the next blk from file */ +- fs_read_position += bytes_read; +- /* calculate how many offsets can be taken from current bbuf */ +- num_readable = MIN(total_offsets - offsets_read, +- bytes_read / sizeof(loff_t)); +- DEBUGP(KERN_INFO "cloop: parsing %d offsets %d to %d\n", num_readable, offsets_read, offsets_read+num_readable-1); +- for (i=0,offset=0; ioffsets[i+1]) - be64_to_cpu(clo->offsets[i]); -- clo->largest_block=MAX(clo->largest_block,d); +- loff_t tmp = be64_to_cpu( *(loff_t*) (bbuf+offset) ); +- if (i%50==0) DEBUGP(KERN_INFO "cloop: offset %03d: %llu\n", offsets_read, tmp); +- if(offsets_read > 0) + total_bytes = total_offsets * sizeof(loff_t); + fs_read_position = clo->underlying_total_size - sizeof(struct cloop_head) - total_bytes; + } @@ -1025,35 +815,28 @@ + if(bytes_readable <= 0) break; /* Done */ + bytes_read = cloop_read_from_file(clo, file, bbuf, fs_read_position, bytes_readable); + if(bytes_read != bytes_readable) -+ { + { +- loff_t d = CLOOP_BLOCK_OFFSET(tmp) - CLOOP_BLOCK_OFFSET(clo->block_ptrs[offsets_read-1]); +- if(d > clo->largest_block) clo->largest_block = d; + printk(KERN_ERR "%s: Bad file %s, read() %lu bytes @ %llu returned %d.\n", + cloop_name, clo->underlying_filename, (unsigned long)clo->underlying_blksize, fs_read_position, (int)bytes_read); + error=-EBADF; + goto error_release; -+ } + } +- clo->block_ptrs[offsets_read++] = tmp; +- offset += sizeof(loff_t); + memcpy(((char *)clo->block_ptrs) + n, bbuf, bytes_read); + /* remember where to read the next blk from file */ + fs_read_position += bytes_read; + n += bytes_read; } -- printk(KERN_INFO "%s: %s: %u blocks, %u bytes/block, largest block is %lu bytes.\n", -- cloop_name, filename, ntohl(clo->head.num_blocks), -- ntohl(clo->head.block_size), clo->largest_block); } --/* Combo kmalloc used too large chunks (>130000). */ +- printk(KERN_INFO "%s: %s: %u blocks, %u bytes/block, largest block is %lu bytes.\n", +- cloop_name, clo->underlying_filename, clo->head.num_blocks, +- clo->head.block_size, clo->largest_block); { int i; -- for(i=0;ibuffer[i] = cloop_malloc(ntohl(clo->head.block_size)); -- if(!clo->buffer[i]) -- { -- printk(KERN_ERR "%s: out of memory for buffer %lu\n", -- cloop_name, (unsigned long) ntohl(clo->head.block_size)); -- error=-ENOMEM; goto error_release_free; -- } -- } -+ char *version = build_index(clo->block_ptrs, clo->head.num_blocks, clo->head.block_size, flags); ++ char *version = build_index(clo->block_ptrs, clo->head.num_blocks, clo->head.block_size); + clo->largest_block = 0; + for (i = 0; i < clo->head.num_blocks; i++) + if (clo->block_ptrs[i].size > clo->largest_block) @@ -1061,39 +844,15 @@ + printk(KERN_INFO "%s: %s: %s: %u blocks, %u bytes/block, largest block is %lu bytes.\n", + cloop_name, clo->underlying_filename, version, clo->head.num_blocks, + clo->head.block_size, clo->largest_block); -+ } -+ { -+ int i; -+ clo->num_buffered_blocks = (buffers > 0 && clo->head.block_size >= 512) ? -+ (buffers / clo->head.block_size) : 1; -+ clo->buffered_blocknum = cloop_malloc(clo->num_buffered_blocks * sizeof (u_int32_t)); -+ clo->buffer = cloop_malloc(clo->num_buffered_blocks * sizeof (char*)); -+ if (!clo->buffered_blocknum || !clo->buffer) -+ { -+ printk(KERN_ERR "%s: out of memory for index of cache buffer (%lu bytes)\n", -+ cloop_name, (unsigned long)clo->num_buffered_blocks * sizeof (u_int32_t) + sizeof(char*) ); -+ error=-ENOMEM; goto error_release; -+ } -+ memset(clo->buffer, 0, clo->num_buffered_blocks * sizeof (char*)); -+ for(i=0;inum_buffered_blocks;i++) -+ { -+ clo->buffered_blocknum[i] = -1; -+ clo->buffer[i] = cloop_malloc(clo->head.block_size); -+ if(!clo->buffer[i]) -+ { -+ printk(KERN_ERR "%s: out of memory for cache buffer %lu\n", -+ cloop_name, (unsigned long) clo->head.block_size); -+ error=-ENOMEM; goto error_release_free; -+ } -+ } -+ clo->current_bufnum = 0; - } - clo->compressed_buffer = cloop_malloc(clo->largest_block); - if(!clo->compressed_buffer) -@@ -557,31 +803,7 @@ + clo->num_buffered_blocks = (buffers > 0 && clo->head.block_size >= 512) ? + (buffers / clo->head.block_size) : 1; + clo->buffered_blocknum = cloop_malloc(clo->num_buffered_blocks * sizeof (u_int32_t)); +@@ -705,36 +793,14 @@ cloop_name, clo->largest_block); error=-ENOMEM; goto error_release_free_buffer; } +- /* Allocate Memory for decompressors */ +-#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE)) - clo->zstream.workspace = cloop_malloc(zlib_inflate_workspacesize()); - if(!clo->zstream.workspace) - { @@ -1102,443 +861,48 @@ - error=-ENOMEM; goto error_release_free_all; - } - zlib_inflateInit(&clo->zstream); -- if(!isblkdev && -- be64_to_cpu(clo->offsets[ntohl(clo->head.num_blocks)]) != inode->i_size) -- { -- printk(KERN_ERR "%s: final offset wrong (%Lu not %Lu)\n", +-#endif +-#if (defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE)) +-#if XZ_INTERNAL_CRC32 +- /* This must be called before any other xz_* function to initialize the CRC32 lookup table. */ +- xz_crc32_init(void); +-#endif +- clo->xzdecoderstate = xz_dec_init(XZ_SINGLE, 0); +-#endif +- if(CLOOP_BLOCK_OFFSET(clo->block_ptrs[clo->head.num_blocks]) > clo->underlying_total_size) ++ set_capacity(clo->clo_disk, (sector_t)(clo->head.num_blocks*(clo->head.block_size>>9))); ++ clo->clo_thread = kthread_create(cloop_thread, clo, "cloop%d", cloop_num); ++ if(IS_ERR(clo->clo_thread)) + { +- printk(KERN_ERR "%s: final offset wrong (%llu > %llu)\n", - cloop_name, -- be64_to_cpu(clo->offsets[ntohl(clo->head.num_blocks)]), -- inode->i_size); +- CLOOP_BLOCK_OFFSET(clo->block_ptrs[clo->head.num_blocks]), +- clo->underlying_total_size); +-#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE)) - cloop_free(clo->zstream.workspace, zlib_inflate_workspacesize()); clo->zstream.workspace=NULL; -- goto error_release_free_all; -- } -- { -- int i; -- for(i=0; ibuffered_blocknum[i] = -1; -- clo->current_bufnum=0; -- } -- set_capacity(clo->clo_disk, (sector_t)(ntohl(clo->head.num_blocks)* -- (ntohl(clo->head.block_size)>>9))); -+ set_capacity(clo->clo_disk, (sector_t)(clo->head.num_blocks*(clo->head.block_size>>9))); - clo->clo_thread = kthread_create(cloop_thread, clo, "cloop%d", cloop_num); - if(IS_ERR(clo->clo_thread)) - { -@@ -591,17 +813,17 @@ +-#endif ++ error = PTR_ERR(clo->clo_thread); ++ clo->clo_thread=NULL; + goto error_release_free_all; } +- set_capacity(clo->clo_disk, (sector_t)(clo->head.num_blocks*(clo->head.block_size>>9))); if(preload > 0) { -- clo->preload_array_size = ((preload<=ntohl(clo->head.num_blocks))?preload:ntohl(clo->head.num_blocks)); -+ clo->preload_array_size = ((preload<=clo->head.num_blocks)?preload:clo->head.num_blocks); - clo->preload_size = 0; - if((clo->preload_cache = cloop_malloc(clo->preload_array_size * sizeof(char *))) != NULL) - { - int i; - for(i=0; ipreload_array_size; i++) - { -- if((clo->preload_cache[i] = cloop_malloc(ntohl(clo->head.block_size))) == NULL) -+ if((clo->preload_cache[i] = cloop_malloc(clo->head.block_size)) == NULL) - { /* Out of memory */ - printk(KERN_WARNING "%s: cloop_malloc(%d) failed for preload_cache[%d] (ignored).\n", -- cloop_name, ntohl(clo->head.block_size), i); -+ cloop_name, clo->head.block_size, i); - break; - } - } -@@ -612,13 +834,13 @@ - if(buffered_blocknum >= 0) - { - memcpy(clo->preload_cache[i], clo->buffer[buffered_blocknum], -- ntohl(clo->head.block_size)); -+ clo->head.block_size); - } - else - { - printk(KERN_WARNING "%s: can't read block %d into preload cache, set to zero.\n", - cloop_name, i); -- memset(clo->preload_cache[i], 0, ntohl(clo->head.block_size)); -+ memset(clo->preload_cache[i], 0, clo->head.block_size); - } - } - printk(KERN_INFO "%s: preloaded %d blocks into cache.\n", cloop_name, -@@ -641,22 +863,19 @@ - cloop_free(clo->compressed_buffer, clo->largest_block); - clo->compressed_buffer=NULL; - error_release_free_buffer: -+ if(clo->buffer) - { - int i; -- for(i=0; ibuffer[i]) -- { -- cloop_free(clo->buffer[i], ntohl(clo->head.block_size)); -- clo->buffer[i]=NULL; -- } -- } -+ for(i=0; inum_buffered_blocks; i++) { if(clo->buffer[i]) { cloop_free(clo->buffer[i], clo->head.block_size); clo->buffer[i]=NULL; }} -+ cloop_free(clo->buffer, clo->num_buffered_blocks*sizeof(char*)); clo->buffer=NULL; + clo->preload_array_size = ((preload<=clo->head.num_blocks)?preload:clo->head.num_blocks); +@@ -780,6 +846,7 @@ + clo->preload_array_size = clo->preload_size = 0; + } + } ++ wake_up_process(clo->clo_thread); + /* Uncheck */ + return error; + error_release_free_all: +@@ -794,9 +861,13 @@ } -+ if (clo->buffered_blocknum) { cloop_free(clo->buffered_blocknum, sizeof(int)*clo->num_buffered_blocks); clo->buffered_blocknum=NULL; } + if (clo->buffered_blocknum) { cloop_free(clo->buffered_blocknum, sizeof(int)*clo->num_buffered_blocks); clo->buffered_blocknum=NULL; } error_release_free: -- cloop_free(clo->offsets, sizeof(loff_t) * total_offsets); -- clo->offsets=NULL; +- cloop_free(clo->block_ptrs, sizeof(cloop_block_ptr) * total_offsets); + cloop_free(clo->block_ptrs, sizeof(struct block_info) * total_offsets); -+ clo->block_ptrs=NULL; - error_release: - if(bbuf) cloop_free(bbuf, clo->underlying_blksize); -+ if(clo->underlying_filename) { kfree(clo->underlying_filename); clo->underlying_filename=NULL; } - clo->backing_file=NULL; - return error; - } -@@ -673,7 +892,7 @@ - if(clo->backing_file) return -EBUSY; - file = fget(arg); /* get filp struct from ioctl arg fd */ - if(!file) return -EBADF; -- error=cloop_set_file(cloop_num,file,"losetup_file"); -+ error=cloop_set_file(cloop_num,file); - set_device_ro(bdev, 1); - if(error) fput(file); - return error; -@@ -684,29 +903,48 @@ - { - struct cloop_device *clo = cloop_dev[cloop_num]; - struct file *filp = clo->backing_file; -- int i; - if(clo->refcnt > 1) /* we needed one fd for the ioctl */ - return -EBUSY; - if(filp==NULL) return -EINVAL; - if(clo->clo_thread) { kthread_stop(clo->clo_thread); clo->clo_thread=NULL; } -- if(filp!=initial_file) fput(filp); -- else { filp_close(initial_file,0); initial_file=NULL; } -+ if(filp!=initial_file) -+ fput(filp); -+ else -+ { -+ filp_close(initial_file,0); -+ initial_file=NULL; -+ } - clo->backing_file = NULL; - clo->backing_inode = NULL; -- if(clo->offsets) { cloop_free(clo->offsets, clo->underlying_blksize); clo->offsets = NULL; } -+ if(clo->underlying_filename) { kfree(clo->underlying_filename); clo->underlying_filename=NULL; } -+ if(clo->block_ptrs) { cloop_free(clo->block_ptrs, clo->head.num_blocks); clo->block_ptrs = NULL; } - if(clo->preload_cache) -- { -- for(i=0; i < clo->preload_size; i++) -- cloop_free(clo->preload_cache[i], ntohl(clo->head.block_size)); -- cloop_free(clo->preload_cache, clo->preload_array_size * sizeof(char *)); -- clo->preload_cache = NULL; -- clo->preload_size = clo->preload_array_size = 0; -- } -- for(i=0; ibuffer[i]) { cloop_free(clo->buffer[i], ntohl(clo->head.block_size)); clo->buffer[i]=NULL; } -+ { -+ int i; -+ for(i=0; i < clo->preload_size; i++) -+ cloop_free(clo->preload_cache[i], clo->head.block_size); -+ cloop_free(clo->preload_cache, clo->preload_array_size * sizeof(char *)); -+ clo->preload_cache = NULL; -+ clo->preload_size = clo->preload_array_size = 0; -+ } -+ if (clo->buffered_blocknum) -+ { -+ cloop_free(clo->buffered_blocknum, sizeof(int) * clo->num_buffered_blocks); clo->buffered_blocknum = NULL; -+ } -+ if (clo->buffer) -+ { -+ int i; -+ for(i=0; inum_buffered_blocks; i++) { if(clo->buffer[i]) cloop_free(clo->buffer[i], clo->head.block_size); } -+ cloop_free(clo->buffer, sizeof(char*) * clo->num_buffered_blocks); clo->buffer = NULL; -+ } - if(clo->compressed_buffer) { cloop_free(clo->compressed_buffer, clo->largest_block); clo->compressed_buffer = NULL; } -+#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE)) - zlib_inflateEnd(&clo->zstream); - if(clo->zstream.workspace) { cloop_free(clo->zstream.workspace, zlib_inflate_workspacesize()); clo->zstream.workspace = NULL; } -+#endif -+#if (defined(CONFIG_DECOMPRESS_XZ) || defined(CONFIG_DECOMPRESS_XZ_MODULE)) -+ xz_dec_end(clo->xzdecoderstate); -+#endif - if(bdev) invalidate_bdev(bdev); - if(clo->clo_disk) set_capacity(clo->clo_disk, 0); - return 0; -@@ -731,8 +969,8 @@ - const struct loop_info64 *info) - { - if (!clo->backing_file) return -ENXIO; -- memcpy(clo->clo_file_name, info->lo_file_name, LO_NAME_SIZE); -- clo->clo_file_name[LO_NAME_SIZE-1] = 0; -+ if(clo->underlying_filename) kfree(clo->underlying_filename); -+ clo->underlying_filename = kstrdup(info->lo_file_name, GFP_KERNEL); - return 0; - } - -@@ -743,7 +981,11 @@ - struct kstat stat; - int err; - if (!file) return -ENXIO; -- err = vfs_getattr(file->f_path.mnt, file->f_path.dentry, &stat); -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) -+ err = vfs_getattr(&file->f_path, &stat); -+#else -+ err = vfs_getattr(&file->f_path, &stat, STATX_INO, AT_STATX_SYNC_AS_STAT); -+#endif - if (err) return err; - memset(info, 0, sizeof(*info)); - info->lo_number = clo->clo_number; -@@ -753,7 +995,8 @@ - info->lo_offset = 0; - info->lo_sizelimit = 0; - info->lo_flags = 0; -- memcpy(info->lo_file_name, clo->clo_file_name, LO_NAME_SIZE); -+ strncpy(info->lo_file_name, clo->underlying_filename, LO_NAME_SIZE); -+ info->lo_file_name[LO_NAME_SIZE-1]=0; - return 0; - } - -@@ -833,8 +1076,6 @@ - if (!err && copy_to_user(arg, &info64, sizeof(info64))) err = -EFAULT; - return err; - } --/* EOF get/set_status */ -- - - static int cloop_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -@@ -914,21 +1155,20 @@ - /* losetup uses write-open and flags=0x8002 to set a new file */ - if(mode & FMODE_WRITE) - { -- printk(KERN_WARNING "%s: Can't open device read-write in mode 0x%x\n", cloop_name, mode); -+ printk(KERN_INFO "%s: Open in read-write mode 0x%x requested, ignored.\n", cloop_name, mode); - return -EROFS; - } - cloop_dev[cloop_num]->refcnt+=1; - return 0; - } - --static int cloop_close(struct gendisk *disk, fmode_t mode) -+static void cloop_close(struct gendisk *disk, fmode_t mode) - { -- int cloop_num, err=0; -- if(!disk) return 0; -+ int cloop_num; -+ if(!disk) return; - cloop_num=((struct cloop_device *)disk->private_data)->clo_number; -- if(cloop_num < 0 || cloop_num > (cloop_count-1)) return 0; -+ if(cloop_num < 0 || cloop_num > (cloop_count-1)) return; - cloop_dev[cloop_num]->refcnt-=1; -- return err; - } - - static struct block_device_operations clo_fops = -@@ -973,6 +1213,10 @@ - goto error_out; - } - clo->clo_queue->queuedata = clo; -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) -+ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, clo->clo_queue); -+ queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, clo->clo_queue); -+#endif - clo->clo_disk = alloc_disk(1); - if(!clo->clo_disk) - { -@@ -1004,6 +1248,11 @@ - cloop_dev[cloop_num] = NULL; - } - -+/* LZ4 Stuff */ -+#if (defined USE_LZ4_INTERNAL) -+#include "lz4_kmod.c" -+#endif -+ - static int __init cloop_init(void) - { - int error=0; -@@ -1044,7 +1293,7 @@ - initial_file=NULL; /* if IS_ERR, it's NOT open. */ - } - else -- error=cloop_set_file(0,initial_file,file); -+ error=cloop_set_file(0,initial_file); - if(error) - { - printk(KERN_ERR -@@ -1052,9 +1301,6 @@ - cloop_name, file, error); - goto init_out_dealloc; - } -- if(namelen >= LO_NAME_SIZE) namelen = LO_NAME_SIZE-1; -- memcpy(cloop_dev[0]->clo_file_name, file, namelen); -- cloop_dev[0]->clo_file_name[namelen] = 0; - } - return 0; - init_out_dealloc: ---- cloop.h -+++ cloop.h -@@ -86,11 +86,8 @@ - struct cloop_tail - { - u_int32_t table_size; -- u_int32_t index_size; /* size:4 comp:3 ctrl-c:1 lastlen:24 */ -+ u_int32_t index_size; /* size:4 unused:3 ctrl-c:1 lastlen:24 */ - #define CLOOP3_INDEX_SIZE(x) ((unsigned int)((x) & 0xF)) --#define CLOOP3_BLOCKS_FLAGS(x) ((unsigned int)((x) & 0x70) >> 4) --#define CLOOP3_TRUNCATED(x) ((unsigned int)((x) & 0x80) >> 7) --#define CLOOP3_LASTLEN(x) (unsigned int)((x) >> 8) - u_int32_t num_blocks; - }; - -@@ -104,8 +101,10 @@ - }; - - static inline char *build_index(struct block_info *offsets, unsigned long n, -- unsigned long block_size, unsigned global_flags) -+ unsigned long block_size) - { -+ static char v[11]; -+ u_int32_t flags = 0; - u_int32_t *ofs32 = (u_int32_t *) offsets; - loff_t *ofs64 = (loff_t *) offsets; - -@@ -130,8 +129,6 @@ - } - else { /* V2.0/V4.0 */ - loff_t last = CLOOP_BLOCK_OFFSET(__be64_to_cpu(ofs64[n])); -- u_int32_t flags; -- static char v4[11]; - unsigned long i = n; - - for (flags = 0; n-- ;) { -@@ -149,12 +146,7 @@ - offsets[i] = offsets[offsets[i].offset]; - } - } -- strcpy(v4, (char *) "64BE v4.0a"); -- v4[10] = 'a' + ((flags-1) & 0xF); // compressors used -- if (flags > 0x10) { // with links ? -- v4[10] += 'A' - 'a'; -- } -- return v4; -+ strcpy(v, (char *) "64BE v4.0a"); - } - } - else if (ofs32[1] == 0 && v3_64 == 0) { /* V1.0 */ -@@ -170,7 +162,6 @@ - else { /* V3.0 or V0.68 */ - unsigned long i; - loff_t j; -- static char v3[11]; - - for (i = 0; i < n && ntohl(ofs32[i]) < ntohl(ofs32[i+1]); i++); - if (i == n && ntohl(ofs32[0]) == (4*n) + 0x8C) { /* V0.68 */ -@@ -185,28 +176,33 @@ - } - - v3_64 = (ofs32[1] == 0); -- for (i = n; i-- != 0; ) -+ for (i = n; i-- != 0; ) { - offsets[i].size = ntohl(ofs32[i << v3_64]); -- for (i = 0, j = sizeof(struct cloop_head); i < n; i++) { -- offsets[i].offset = j; -- offsets[i].flags = global_flags; - if (offsets[i].size == 0xFFFFFFFF) { -- offsets[i].flags = CLOOP_COMPRESSOR_NONE; -- offsets[i].size = block_size; -+ offsets[i].size = 0x10000000 | block_size; - } -- if ((offsets[i].size & 0x80000000) == 0) { -+ offsets[i].flags = (offsets[i].size >> 28); -+ offsets[i].size &= 0x0FFFFFFF; -+ } -+ for (i = 0, j = sizeof(struct cloop_head); i < n; i++) { -+ offsets[i].offset = j; -+ if (offsets[i].flags < 8) { - j += offsets[i].size; - } - } - for (i = 0; i < n; i++) { -- if (offsets[i].size & 0x80000000) { -- offsets[i] = offsets[offsets[i].size & 0x7FFFFFFF]; -+ flags |= 1 << offsets[i].flags; -+ if (offsets[i].flags >= 8) { -+ offsets[i] = offsets[offsets[i].size]; - } - } -- strcpy(v3, (char *) (v3_64) ? "64BE v3.0a" : "32BE v3.0a"); -- v3[10] += global_flags; -- return v3; -+ strcpy(v, (char *) (v3_64) ? "64BE v3.0a" : "32BE v3.0a"); -+ } -+ v[10] = 'a' + ((flags-1) & 0xF); // compressors used -+ if (flags > 0x10) { // with links ? -+ v[10] += 'A' - 'a'; - } -+ return v; - } - - /* Cloop suspend IOCTL */ ---- cloop.c -+++ cloop.c -@@ -542,7 +542,7 @@ - const unsigned int header_size = sizeof(struct cloop_head); - unsigned int i, total_offsets=0; - loff_t fs_read_position = 0, header_pos[2]; -- int flags, isblkdev, bytes_read, error = 0; -+ int isblkdev, bytes_read, error = 0; - if (clo->suspended) return error; - #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) - inode = file->f_dentry->d_inode; -@@ -698,18 +698,12 @@ - error=-EBADF; goto error_release; - } - len = CLOOP3_INDEX_SIZE(ntohl(tail.index_size)) * total_offsets; -- flags = CLOOP3_BLOCKS_FLAGS(ntohl(tail.index_size)); --// 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) --printk(KERN_INFO "%s: uncompress(clo=%p, block_ptrs=%p, &len(%ld)=%p, zbuf=%p, zlen=%ld, flag=%d)\n", cloop_name, -- clo, clo->block_ptrs, len, &len, zbuf, zlen, flags); -- ret = uncompress(clo, (void *) clo->block_ptrs, &len, zbuf, zlen, flags); --// May 3 19:45:20 (none) user.alert kernel: BUG: unable to handle kernel NULL pointer dereference at (null) --printk(KERN_INFO "%s: uncompressed !\n", cloop_name); -+ ret = uncompress(clo, (void *) clo->block_ptrs, &len, zbuf, zlen, CLOOP_COMPRESSOR_ZLIB); - cloop_free(zbuf, zlen); - if (ret != 0) - { -- printk(KERN_ERR "%s: decompression error %i uncompressing index, flags %u\n", -- cloop_name, ret, flags); -+ printk(KERN_ERR "%s: decompression error %i uncompressing index\n", -+ cloop_name, ret); - error=-EBADF; goto error_release; - } - } -@@ -722,7 +716,6 @@ - else - { - unsigned int n, total_bytes; -- flags = 0; - clo->block_ptrs = cloop_malloc(sizeof(struct block_info) * total_offsets); - if (!clo->block_ptrs) - { -@@ -761,7 +754,7 @@ - } - { - int i; -- char *version = build_index(clo->block_ptrs, clo->head.num_blocks, clo->head.block_size, flags); -+ char *version = build_index(clo->block_ptrs, clo->head.num_blocks, clo->head.block_size); - clo->largest_block = 0; - for (i = 0; i < clo->head.num_blocks; i++) - if (clo->block_ptrs[i].size > clo->largest_block) -@@ -769,9 +762,6 @@ - printk(KERN_INFO "%s: %s: %s: %u blocks, %u bytes/block, largest block is %lu bytes.\n", - cloop_name, clo->underlying_filename, version, clo->head.num_blocks, - clo->head.block_size, clo->largest_block); -- } -- { -- int i; - clo->num_buffered_blocks = (buffers > 0 && clo->head.block_size >= 512) ? - (buffers / clo->head.block_size) : 1; - clo->buffered_blocknum = cloop_malloc(clo->num_buffered_blocks * sizeof (u_int32_t)); -@@ -874,6 +864,10 @@ - cloop_free(clo->block_ptrs, sizeof(struct block_info) * total_offsets); clo->block_ptrs=NULL; error_release: +#if (defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE)) @@ -1548,3 +912,146 @@ if(bbuf) cloop_free(bbuf, clo->underlying_blksize); if(clo->underlying_filename) { kfree(clo->underlying_filename); clo->underlying_filename=NULL; } clo->backing_file=NULL; +@@ -829,6 +900,7 @@ + if(clo->refcnt > 1) /* we needed one fd for the ioctl */ + return -EBUSY; + if(filp==NULL) return -EINVAL; ++ if(clo->clo_thread) { kthread_stop(clo->clo_thread); clo->clo_thread=NULL; } + if(filp!=initial_file) + fput(filp); + else +@@ -839,7 +911,7 @@ + clo->backing_file = NULL; + clo->backing_inode = NULL; + if(clo->underlying_filename) { kfree(clo->underlying_filename); clo->underlying_filename=NULL; } +- if(clo->block_ptrs) { cloop_free(clo->block_ptrs, clo->head.num_blocks+1); clo->block_ptrs = NULL; } ++ if(clo->block_ptrs) { cloop_free(clo->block_ptrs, clo->head.num_blocks); clo->block_ptrs = NULL; } + if(clo->preload_cache) + { + int i; +@@ -1054,15 +1126,15 @@ + case LOOP_CLR_FD: /* Change arg */ + case LOOP_GET_STATUS64: /* Change arg */ + case LOOP_SET_STATUS64: /* Change arg */ +- return cloop_ioctl(bdev, mode, cmd, (unsigned long) compat_ptr(arg)); ++ arg = (unsigned long) compat_ptr(arg); + case LOOP_SET_STATUS: /* unchanged */ + case LOOP_GET_STATUS: /* unchanged */ + case LOOP_SET_FD: /* unchanged */ + case LOOP_CHANGE_FD: /* unchanged */ +- return cloop_ioctl(bdev, mode, cmd, arg); +- default: +- return -ENOIOCTLCMD; ++ return cloop_ioctl(bdev, mode, cmd, arg); ++ break; + } ++ return -ENOIOCTLCMD; + } + #endif + +@@ -1093,7 +1165,7 @@ + cloop_dev[cloop_num]->refcnt-=1; + } + +-static const struct block_device_operations clo_fops = ++static struct block_device_operations clo_fops = + { + owner: THIS_MODULE, + open: cloop_open, +@@ -1105,12 +1177,6 @@ + /* locked_ioctl ceased to exist in 2.6.36 */ + }; + +-static const struct blk_mq_ops cloop_mq_ops = { +- .queue_rq = cloop_queue_rq, +-/* .init_request = cloop_init_request, */ +-/* .complete = cloop_complete_rq, */ +-}; +- + static int cloop_register_blkdev(int major_nr) + { + return register_blkdev(major_nr, cloop_name); +@@ -1124,37 +1190,33 @@ + + static int cloop_alloc(int cloop_num) + { +- struct cloop_device *clo = (struct cloop_device *) cloop_malloc(sizeof(struct cloop_device)); ++ struct cloop_device *clo = (struct cloop_device *) cloop_malloc(sizeof(struct cloop_device));; + if(clo == NULL) goto error_out; + cloop_dev[cloop_num] = clo; + memset(clo, 0, sizeof(struct cloop_device)); + clo->clo_number = cloop_num; +- clo->tag_set.ops = &cloop_mq_ops; +- clo->tag_set.nr_hw_queues = 1; +- clo->tag_set.queue_depth = 128; +- clo->tag_set.numa_node = NUMA_NO_NODE; +- clo->tag_set.cmd_size = 0; /* No extra data needed */ +- /* BLK_MQ_F_BLOCKING is extremely important if we want to call blocking functions like vfs_read */ +- clo->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING; +- clo->tag_set.driver_data = clo; +- if(blk_mq_alloc_tag_set(&clo->tag_set)) goto error_out_free_clo; +- clo->clo_queue = blk_mq_init_queue(&clo->tag_set); +- if(IS_ERR(clo->clo_queue)) ++ clo->clo_thread = NULL; ++ init_waitqueue_head(&clo->clo_event); ++ spin_lock_init(&clo->queue_lock); ++ mutex_init(&clo->clo_ctl_mutex); ++ INIT_LIST_HEAD(&clo->clo_list); ++ clo->clo_queue = blk_init_queue(cloop_do_request, &clo->queue_lock); ++ if(!clo->clo_queue) + { + printk(KERN_ERR "%s: Unable to alloc queue[%d]\n", cloop_name, cloop_num); +- goto error_out_free_tags; ++ goto error_out; + } + clo->clo_queue->queuedata = clo; +- blk_queue_max_hw_sectors(clo->clo_queue, BLK_DEF_MAX_SECTORS); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) ++ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, clo->clo_queue); ++ queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, clo->clo_queue); ++#endif + clo->clo_disk = alloc_disk(1); + if(!clo->clo_disk) + { + printk(KERN_ERR "%s: Unable to alloc disk[%d]\n", cloop_name, cloop_num); +- goto error_out_free_queue; ++ goto error_disk; + } +- spin_lock_init(&clo->queue_lock); +- mutex_init(&clo->clo_ctl_mutex); +- mutex_init(&clo->clo_rq_mutex); + clo->clo_disk->major = cloop_major; + clo->clo_disk->first_minor = cloop_num; + clo->clo_disk->fops = &clo_fops; +@@ -1163,12 +1225,8 @@ + sprintf(clo->clo_disk->disk_name, "%s%d", cloop_name, cloop_num); + add_disk(clo->clo_disk); + return 0; +-error_out_free_queue: ++error_disk: + blk_cleanup_queue(clo->clo_queue); +-error_out_free_tags: +- blk_mq_free_tag_set(&clo->tag_set); +-error_out_free_clo: +- cloop_free(clo, sizeof(struct cloop_device)); + error_out: + return -ENOMEM; + } +@@ -1179,7 +1237,6 @@ + if(clo == NULL) return; + del_gendisk(clo->clo_disk); + blk_cleanup_queue(clo->clo_queue); +- blk_mq_free_tag_set(&clo->tag_set); + put_disk(clo->clo_disk); + cloop_free(clo, sizeof(struct cloop_device)); + cloop_dev[cloop_num] = NULL; +--- cloop_suspend.c ++++ cloop_suspend.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + /* We don't use the structure, so that define does not hurt */ + #define dev_t int diff -r 0f92b8cc8086 -r 5a92a26adcc1 wbar/receipt --- a/wbar/receipt Sun May 08 13:06:36 2022 +0000 +++ b/wbar/receipt Sun May 08 16:45:21 2022 +0000 @@ -8,7 +8,7 @@ LICENSE="GPL" TARBALL="$PACKAGE-$VERSION.tbz2" WEB_SITE="https://github.com/rodolf0/wbar" -WGET_URL="http://www.tecapli.com.ar/warlock/$TARBALL" +WGET_URL="https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/$PACKAGE/$TARBALL" CONFIG_FILES="/etc/wbar/dot.wbar" TAGS="desktop launchbar" diff -r 0f92b8cc8086 -r 5a92a26adcc1 xa/receipt --- a/xa/receipt Sun May 08 13:06:36 2022 +0000 +++ b/xa/receipt Sun May 08 16:45:21 2022 +0000 @@ -10,7 +10,7 @@ WEB_SITE="https://www.floodgap.com/retrotech/xa/" TARBALL="$PACKAGE-$VERSION.tar.gz" -WGET_URL="${WEB_SITE}dists/$TARBALL" +WGET_URL="${WEB_SITE}dists/unsupported/$TARBALL" # What is the latest version available today? current_version() diff -r 0f92b8cc8086 -r 5a92a26adcc1 xautomation/receipt --- a/xautomation/receipt Sun May 08 13:06:36 2022 +0000 +++ b/xautomation/receipt Sun May 08 16:45:21 2022 +0000 @@ -7,9 +7,8 @@ MAINTAINER="pankso@slitaz.org" LICENSE="GPL2" TARBALL="$PACKAGE-$VERSION.tar.gz" -#WEB_SITE="http://hoopajoo.net/projects/xautomation.html" -WEB_SITE="https://sourceforge.net/projects/xautomation/" -WGET_URL="http://hoopajoo.net/static/projects/$TARBALL" +WEB_SITE="https://www.hoopajoo.net/projects/xautomation.html" +WGET_URL="https://www.hoopajoo.net/static/projects/$TARBALL" #HOST_ARCH="i486 arm" DEPENDS="xorg-libX11 libpng" diff -r 0f92b8cc8086 -r 5a92a26adcc1 xcursor-aero/receipt --- a/xcursor-aero/receipt Sun May 08 13:06:36 2022 +0000 +++ b/xcursor-aero/receipt Sun May 08 16:45:21 2022 +0000 @@ -8,7 +8,7 @@ LICENSE="GPL" WEB_SITE="https://www.gnome-look.org/p/999972/" TARBALL="$PACKAGE-$VERSION.tar.gz" -WGET_URL="http://www.infinality.net/files/aero.tar.gz" +WGET_URL="https://github.com/Infinality/mouse-cursors/raw/master/aero.tar.gz" TAGS="cursor-theme" DEPENDS="xorg-libXcursor" diff -r 0f92b8cc8086 -r 5a92a26adcc1 xcursor-comix/receipt --- a/xcursor-comix/receipt Sun May 08 13:06:36 2022 +0000 +++ b/xcursor-comix/receipt Sun May 08 16:45:21 2022 +0000 @@ -1,7 +1,7 @@ # SliTaz package receipt. PACKAGE="xcursor-comix" -VERSION="0.9.1" +VERSION="0.9.2" CATEGORY="customization" TAGS="cursor-theme" SHORT_DESC="Comix cursor theme." @@ -10,6 +10,7 @@ WEB_SITE="https://limitland.de/comixcursors" TARBALL="ComixCursors-$VERSION.tar.bz2" +#WGET_URL="https://gitlab.com/limitland/comixcursors/-/archive/$VERSION/comixcursors-$VERSION.tar.bz2" WGET_URL="https://limitland.gitlab.io/comixcursors/$TARBALL" DEPENDS="xorg-libXcursor"