diff options
-rw-r--r-- | Documentation/filesystems/squashfs.txt | 8 | ||||
-rw-r--r-- | fs/squashfs/Kconfig | 15 | ||||
-rw-r--r-- | fs/squashfs/Makefile | 1 | ||||
-rw-r--r-- | fs/squashfs/decompressor.c | 7 | ||||
-rw-r--r-- | fs/squashfs/decompressor.h | 4 | ||||
-rw-r--r-- | fs/squashfs/lz4_wrapper.c | 142 | ||||
-rw-r--r-- | fs/squashfs/squashfs_fs.h | 1 |
7 files changed, 174 insertions, 4 deletions
diff --git a/Documentation/filesystems/squashfs.txt b/Documentation/filesystems/squashfs.txt index 403c090aca39..e5274f84dc56 100644 --- a/Documentation/filesystems/squashfs.txt +++ b/Documentation/filesystems/squashfs.txt | |||
@@ -2,10 +2,10 @@ SQUASHFS 4.0 FILESYSTEM | |||
2 | ======================= | 2 | ======================= |
3 | 3 | ||
4 | Squashfs is a compressed read-only filesystem for Linux. | 4 | Squashfs is a compressed read-only filesystem for Linux. |
5 | It uses zlib/lzo/xz compression to compress files, inodes and directories. | 5 | It uses zlib, lz4, lzo, or xz compression to compress files, inodes and |
6 | Inodes in the system are very small and all blocks are packed to minimise | 6 | directories. Inodes in the system are very small and all blocks are packed to |
7 | data overhead. Block sizes greater than 4K are supported up to a maximum | 7 | minimise data overhead. Block sizes greater than 4K are supported up to a |
8 | of 1Mbytes (default block size 128K). | 8 | maximum of 1Mbytes (default block size 128K). |
9 | 9 | ||
10 | Squashfs is intended for general read-only filesystem use, for archival | 10 | Squashfs is intended for general read-only filesystem use, for archival |
11 | use (i.e. in cases where a .tar.gz file may be used), and in constrained | 11 | use (i.e. in cases where a .tar.gz file may be used), and in constrained |
diff --git a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig index b6fa8657dcbc..ffb093e72b6c 100644 --- a/fs/squashfs/Kconfig +++ b/fs/squashfs/Kconfig | |||
@@ -120,6 +120,21 @@ config SQUASHFS_ZLIB | |||
120 | 120 | ||
121 | If unsure, say Y. | 121 | If unsure, say Y. |
122 | 122 | ||
123 | config SQUASHFS_LZ4 | ||
124 | bool "Include support for LZ4 compressed file systems" | ||
125 | depends on SQUASHFS | ||
126 | select LZ4_DECOMPRESS | ||
127 | help | ||
128 | Saying Y here includes support for reading Squashfs file systems | ||
129 | compressed with LZ4 compression. LZ4 compression is mainly | ||
130 | aimed at embedded systems with slower CPUs where the overheads | ||
131 | of zlib are too high. | ||
132 | |||
133 | LZ4 is not the standard compression used in Squashfs and so most | ||
134 | file systems will be readable without selecting this option. | ||
135 | |||
136 | If unsure, say N. | ||
137 | |||
123 | config SQUASHFS_LZO | 138 | config SQUASHFS_LZO |
124 | bool "Include support for LZO compressed file systems" | 139 | bool "Include support for LZO compressed file systems" |
125 | depends on SQUASHFS | 140 | depends on SQUASHFS |
diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile index 4132520b4ff2..246a6f329d89 100644 --- a/fs/squashfs/Makefile +++ b/fs/squashfs/Makefile | |||
@@ -11,6 +11,7 @@ squashfs-$(CONFIG_SQUASHFS_DECOMP_SINGLE) += decompressor_single.o | |||
11 | squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI) += decompressor_multi.o | 11 | squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI) += decompressor_multi.o |
12 | squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU) += decompressor_multi_percpu.o | 12 | squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU) += decompressor_multi_percpu.o |
13 | squashfs-$(CONFIG_SQUASHFS_XATTR) += xattr.o xattr_id.o | 13 | squashfs-$(CONFIG_SQUASHFS_XATTR) += xattr.o xattr_id.o |
14 | squashfs-$(CONFIG_SQUASHFS_LZ4) += lz4_wrapper.o | ||
14 | squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o | 15 | squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o |
15 | squashfs-$(CONFIG_SQUASHFS_XZ) += xz_wrapper.o | 16 | squashfs-$(CONFIG_SQUASHFS_XZ) += xz_wrapper.o |
16 | squashfs-$(CONFIG_SQUASHFS_ZLIB) += zlib_wrapper.o | 17 | squashfs-$(CONFIG_SQUASHFS_ZLIB) += zlib_wrapper.o |
diff --git a/fs/squashfs/decompressor.c b/fs/squashfs/decompressor.c index ac22fe73b0ad..e9034bf6e5ae 100644 --- a/fs/squashfs/decompressor.c +++ b/fs/squashfs/decompressor.c | |||
@@ -41,6 +41,12 @@ static const struct squashfs_decompressor squashfs_lzma_unsupported_comp_ops = { | |||
41 | NULL, NULL, NULL, NULL, LZMA_COMPRESSION, "lzma", 0 | 41 | NULL, NULL, NULL, NULL, LZMA_COMPRESSION, "lzma", 0 |
42 | }; | 42 | }; |
43 | 43 | ||
44 | #ifndef CONFIG_SQUASHFS_LZ4 | ||
45 | static const struct squashfs_decompressor squashfs_lz4_comp_ops = { | ||
46 | NULL, NULL, NULL, NULL, LZ4_COMPRESSION, "lz4", 0 | ||
47 | }; | ||
48 | #endif | ||
49 | |||
44 | #ifndef CONFIG_SQUASHFS_LZO | 50 | #ifndef CONFIG_SQUASHFS_LZO |
45 | static const struct squashfs_decompressor squashfs_lzo_comp_ops = { | 51 | static const struct squashfs_decompressor squashfs_lzo_comp_ops = { |
46 | NULL, NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0 | 52 | NULL, NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0 |
@@ -65,6 +71,7 @@ static const struct squashfs_decompressor squashfs_unknown_comp_ops = { | |||
65 | 71 | ||
66 | static const struct squashfs_decompressor *decompressor[] = { | 72 | static const struct squashfs_decompressor *decompressor[] = { |
67 | &squashfs_zlib_comp_ops, | 73 | &squashfs_zlib_comp_ops, |
74 | &squashfs_lz4_comp_ops, | ||
68 | &squashfs_lzo_comp_ops, | 75 | &squashfs_lzo_comp_ops, |
69 | &squashfs_xz_comp_ops, | 76 | &squashfs_xz_comp_ops, |
70 | &squashfs_lzma_unsupported_comp_ops, | 77 | &squashfs_lzma_unsupported_comp_ops, |
diff --git a/fs/squashfs/decompressor.h b/fs/squashfs/decompressor.h index af0985321808..a25713c031a5 100644 --- a/fs/squashfs/decompressor.h +++ b/fs/squashfs/decompressor.h | |||
@@ -46,6 +46,10 @@ static inline void *squashfs_comp_opts(struct squashfs_sb_info *msblk, | |||
46 | extern const struct squashfs_decompressor squashfs_xz_comp_ops; | 46 | extern const struct squashfs_decompressor squashfs_xz_comp_ops; |
47 | #endif | 47 | #endif |
48 | 48 | ||
49 | #ifdef CONFIG_SQUASHFS_LZ4 | ||
50 | extern const struct squashfs_decompressor squashfs_lz4_comp_ops; | ||
51 | #endif | ||
52 | |||
49 | #ifdef CONFIG_SQUASHFS_LZO | 53 | #ifdef CONFIG_SQUASHFS_LZO |
50 | extern const struct squashfs_decompressor squashfs_lzo_comp_ops; | 54 | extern const struct squashfs_decompressor squashfs_lzo_comp_ops; |
51 | #endif | 55 | #endif |
diff --git a/fs/squashfs/lz4_wrapper.c b/fs/squashfs/lz4_wrapper.c new file mode 100644 index 000000000000..c31e2bc9c081 --- /dev/null +++ b/fs/squashfs/lz4_wrapper.c | |||
@@ -0,0 +1,142 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013, 2014 | ||
3 | * Phillip Lougher <phillip@squashfs.org.uk> | ||
4 | * | ||
5 | * This work is licensed under the terms of the GNU GPL, version 2. See | ||
6 | * the COPYING file in the top-level directory. | ||
7 | */ | ||
8 | |||
9 | #include <linux/buffer_head.h> | ||
10 | #include <linux/mutex.h> | ||
11 | #include <linux/slab.h> | ||
12 | #include <linux/vmalloc.h> | ||
13 | #include <linux/lz4.h> | ||
14 | |||
15 | #include "squashfs_fs.h" | ||
16 | #include "squashfs_fs_sb.h" | ||
17 | #include "squashfs.h" | ||
18 | #include "decompressor.h" | ||
19 | #include "page_actor.h" | ||
20 | |||
21 | #define LZ4_LEGACY 1 | ||
22 | |||
23 | struct lz4_comp_opts { | ||
24 | __le32 version; | ||
25 | __le32 flags; | ||
26 | }; | ||
27 | |||
28 | struct squashfs_lz4 { | ||
29 | void *input; | ||
30 | void *output; | ||
31 | }; | ||
32 | |||
33 | |||
34 | static void *lz4_comp_opts(struct squashfs_sb_info *msblk, | ||
35 | void *buff, int len) | ||
36 | { | ||
37 | struct lz4_comp_opts *comp_opts = buff; | ||
38 | |||
39 | /* LZ4 compressed filesystems always have compression options */ | ||
40 | if (comp_opts == NULL || len < sizeof(*comp_opts)) | ||
41 | return ERR_PTR(-EIO); | ||
42 | |||
43 | if (le32_to_cpu(comp_opts->version) != LZ4_LEGACY) { | ||
44 | /* LZ4 format currently used by the kernel is the 'legacy' | ||
45 | * format */ | ||
46 | ERROR("Unknown LZ4 version\n"); | ||
47 | return ERR_PTR(-EINVAL); | ||
48 | } | ||
49 | |||
50 | return NULL; | ||
51 | } | ||
52 | |||
53 | |||
54 | static void *lz4_init(struct squashfs_sb_info *msblk, void *buff) | ||
55 | { | ||
56 | int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); | ||
57 | struct squashfs_lz4 *stream; | ||
58 | |||
59 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | ||
60 | if (stream == NULL) | ||
61 | goto failed; | ||
62 | stream->input = vmalloc(block_size); | ||
63 | if (stream->input == NULL) | ||
64 | goto failed2; | ||
65 | stream->output = vmalloc(block_size); | ||
66 | if (stream->output == NULL) | ||
67 | goto failed3; | ||
68 | |||
69 | return stream; | ||
70 | |||
71 | failed3: | ||
72 | vfree(stream->input); | ||
73 | failed2: | ||
74 | kfree(stream); | ||
75 | failed: | ||
76 | ERROR("Failed to initialise LZ4 decompressor\n"); | ||
77 | return ERR_PTR(-ENOMEM); | ||
78 | } | ||
79 | |||
80 | |||
81 | static void lz4_free(void *strm) | ||
82 | { | ||
83 | struct squashfs_lz4 *stream = strm; | ||
84 | |||
85 | if (stream) { | ||
86 | vfree(stream->input); | ||
87 | vfree(stream->output); | ||
88 | } | ||
89 | kfree(stream); | ||
90 | } | ||
91 | |||
92 | |||
93 | static int lz4_uncompress(struct squashfs_sb_info *msblk, void *strm, | ||
94 | struct buffer_head **bh, int b, int offset, int length, | ||
95 | struct squashfs_page_actor *output) | ||
96 | { | ||
97 | struct squashfs_lz4 *stream = strm; | ||
98 | void *buff = stream->input, *data; | ||
99 | int avail, i, bytes = length, res; | ||
100 | size_t dest_len = output->length; | ||
101 | |||
102 | for (i = 0; i < b; i++) { | ||
103 | avail = min(bytes, msblk->devblksize - offset); | ||
104 | memcpy(buff, bh[i]->b_data + offset, avail); | ||
105 | buff += avail; | ||
106 | bytes -= avail; | ||
107 | offset = 0; | ||
108 | put_bh(bh[i]); | ||
109 | } | ||
110 | |||
111 | res = lz4_decompress_unknownoutputsize(stream->input, length, | ||
112 | stream->output, &dest_len); | ||
113 | if (res) | ||
114 | return -EIO; | ||
115 | |||
116 | bytes = dest_len; | ||
117 | data = squashfs_first_page(output); | ||
118 | buff = stream->output; | ||
119 | while (data) { | ||
120 | if (bytes <= PAGE_CACHE_SIZE) { | ||
121 | memcpy(data, buff, bytes); | ||
122 | break; | ||
123 | } | ||
124 | memcpy(data, buff, PAGE_CACHE_SIZE); | ||
125 | buff += PAGE_CACHE_SIZE; | ||
126 | bytes -= PAGE_CACHE_SIZE; | ||
127 | data = squashfs_next_page(output); | ||
128 | } | ||
129 | squashfs_finish_page(output); | ||
130 | |||
131 | return dest_len; | ||
132 | } | ||
133 | |||
134 | const struct squashfs_decompressor squashfs_lz4_comp_ops = { | ||
135 | .init = lz4_init, | ||
136 | .comp_opts = lz4_comp_opts, | ||
137 | .free = lz4_free, | ||
138 | .decompress = lz4_uncompress, | ||
139 | .id = LZ4_COMPRESSION, | ||
140 | .name = "lz4", | ||
141 | .supported = 1 | ||
142 | }; | ||
diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h index 4b2beda49498..506f4ba5b983 100644 --- a/fs/squashfs/squashfs_fs.h +++ b/fs/squashfs/squashfs_fs.h | |||
@@ -240,6 +240,7 @@ struct meta_index { | |||
240 | #define LZMA_COMPRESSION 2 | 240 | #define LZMA_COMPRESSION 2 |
241 | #define LZO_COMPRESSION 3 | 241 | #define LZO_COMPRESSION 3 |
242 | #define XZ_COMPRESSION 4 | 242 | #define XZ_COMPRESSION 4 |
243 | #define LZ4_COMPRESSION 5 | ||
243 | 244 | ||
244 | struct squashfs_super_block { | 245 | struct squashfs_super_block { |
245 | __le32 s_magic; | 246 | __le32 s_magic; |