diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-24 11:02:21 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-24 11:02:21 -0400 |
commit | 5818fcc8bd1b27af4d40b8357b91a56cc3fae6a4 (patch) | |
tree | c2f266e82306fa98c78130b0dc79ef9716d3c9c7 | |
parent | 0625bef6060fab4aab0e484130b59af5e9ac81bc (diff) | |
parent | 117a91e0f25fd7698e20ac3dfa62086be3dc82a3 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pkl/squashfs-linus
* git://git.kernel.org/pub/scm/linux/kernel/git/pkl/squashfs-linus:
Squashfs: Use vmalloc rather than kmalloc for zlib workspace
Squashfs: handle corruption of directory structure
Squashfs: wrap squashfs_mount() definition
Squashfs: xz_wrapper doesn't need to include squashfs_fs_i.h anymore
Squashfs: Update documentation to include compression options
Squashfs: Update Kconfig help text to include xz compression
Squashfs: add compression options support to xz decompressor
Squashfs: extend decompressor framework to handle compression options
-rw-r--r-- | Documentation/filesystems/squashfs.txt | 28 | ||||
-rw-r--r-- | fs/squashfs/Kconfig | 12 | ||||
-rw-r--r-- | fs/squashfs/decompressor.c | 34 | ||||
-rw-r--r-- | fs/squashfs/decompressor.h | 7 | ||||
-rw-r--r-- | fs/squashfs/dir.c | 9 | ||||
-rw-r--r-- | fs/squashfs/lzo_wrapper.c | 4 | ||||
-rw-r--r-- | fs/squashfs/namei.c | 12 | ||||
-rw-r--r-- | fs/squashfs/squashfs.h | 1 | ||||
-rw-r--r-- | fs/squashfs/squashfs_fs.h | 4 | ||||
-rw-r--r-- | fs/squashfs/super.c | 15 | ||||
-rw-r--r-- | fs/squashfs/xz_wrapper.c | 53 | ||||
-rw-r--r-- | fs/squashfs/zlib_wrapper.c | 10 |
12 files changed, 145 insertions, 44 deletions
diff --git a/Documentation/filesystems/squashfs.txt b/Documentation/filesystems/squashfs.txt index 66699afd66ca..2d78f1911844 100644 --- a/Documentation/filesystems/squashfs.txt +++ b/Documentation/filesystems/squashfs.txt | |||
@@ -59,12 +59,15 @@ obtained from this site also. | |||
59 | 3. SQUASHFS FILESYSTEM DESIGN | 59 | 3. SQUASHFS FILESYSTEM DESIGN |
60 | ----------------------------- | 60 | ----------------------------- |
61 | 61 | ||
62 | A squashfs filesystem consists of a maximum of eight parts, packed together on a byte | 62 | A squashfs filesystem consists of a maximum of nine parts, packed together on a |
63 | alignment: | 63 | byte alignment: |
64 | 64 | ||
65 | --------------- | 65 | --------------- |
66 | | superblock | | 66 | | superblock | |
67 | |---------------| | 67 | |---------------| |
68 | | compression | | ||
69 | | options | | ||
70 | |---------------| | ||
68 | | datablocks | | 71 | | datablocks | |
69 | | & fragments | | 72 | | & fragments | |
70 | |---------------| | 73 | |---------------| |
@@ -91,7 +94,14 @@ the source directory, and checked for duplicates. Once all file data has been | |||
91 | written the completed inode, directory, fragment, export and uid/gid lookup | 94 | written the completed inode, directory, fragment, export and uid/gid lookup |
92 | tables are written. | 95 | tables are written. |
93 | 96 | ||
94 | 3.1 Inodes | 97 | 3.1 Compression options |
98 | ----------------------- | ||
99 | |||
100 | Compressors can optionally support compression specific options (e.g. | ||
101 | dictionary size). If non-default compression options have been used, then | ||
102 | these are stored here. | ||
103 | |||
104 | 3.2 Inodes | ||
95 | ---------- | 105 | ---------- |
96 | 106 | ||
97 | Metadata (inodes and directories) are compressed in 8Kbyte blocks. Each | 107 | Metadata (inodes and directories) are compressed in 8Kbyte blocks. Each |
@@ -114,7 +124,7 @@ directory inode are defined: inodes optimised for frequently occurring | |||
114 | regular files and directories, and extended types where extra | 124 | regular files and directories, and extended types where extra |
115 | information has to be stored. | 125 | information has to be stored. |
116 | 126 | ||
117 | 3.2 Directories | 127 | 3.3 Directories |
118 | --------------- | 128 | --------------- |
119 | 129 | ||
120 | Like inodes, directories are packed into compressed metadata blocks, stored | 130 | Like inodes, directories are packed into compressed metadata blocks, stored |
@@ -144,7 +154,7 @@ decompressed to do a lookup irrespective of the length of the directory. | |||
144 | This scheme has the advantage that it doesn't require extra memory overhead | 154 | This scheme has the advantage that it doesn't require extra memory overhead |
145 | and doesn't require much extra storage on disk. | 155 | and doesn't require much extra storage on disk. |
146 | 156 | ||
147 | 3.3 File data | 157 | 3.4 File data |
148 | ------------- | 158 | ------------- |
149 | 159 | ||
150 | Regular files consist of a sequence of contiguous compressed blocks, and/or a | 160 | Regular files consist of a sequence of contiguous compressed blocks, and/or a |
@@ -163,7 +173,7 @@ Larger files use multiple slots, with 1.75 TiB files using all 8 slots. | |||
163 | The index cache is designed to be memory efficient, and by default uses | 173 | The index cache is designed to be memory efficient, and by default uses |
164 | 16 KiB. | 174 | 16 KiB. |
165 | 175 | ||
166 | 3.4 Fragment lookup table | 176 | 3.5 Fragment lookup table |
167 | ------------------------- | 177 | ------------------------- |
168 | 178 | ||
169 | Regular files can contain a fragment index which is mapped to a fragment | 179 | Regular files can contain a fragment index which is mapped to a fragment |
@@ -173,7 +183,7 @@ A second index table is used to locate these. This second index table for | |||
173 | speed of access (and because it is small) is read at mount time and cached | 183 | speed of access (and because it is small) is read at mount time and cached |
174 | in memory. | 184 | in memory. |
175 | 185 | ||
176 | 3.5 Uid/gid lookup table | 186 | 3.6 Uid/gid lookup table |
177 | ------------------------ | 187 | ------------------------ |
178 | 188 | ||
179 | For space efficiency regular files store uid and gid indexes, which are | 189 | For space efficiency regular files store uid and gid indexes, which are |
@@ -182,7 +192,7 @@ stored compressed into metadata blocks. A second index table is used to | |||
182 | locate these. This second index table for speed of access (and because it | 192 | locate these. This second index table for speed of access (and because it |
183 | is small) is read at mount time and cached in memory. | 193 | is small) is read at mount time and cached in memory. |
184 | 194 | ||
185 | 3.6 Export table | 195 | 3.7 Export table |
186 | ---------------- | 196 | ---------------- |
187 | 197 | ||
188 | To enable Squashfs filesystems to be exportable (via NFS etc.) filesystems | 198 | To enable Squashfs filesystems to be exportable (via NFS etc.) filesystems |
@@ -196,7 +206,7 @@ This table is stored compressed into metadata blocks. A second index table is | |||
196 | used to locate these. This second index table for speed of access (and because | 206 | used to locate these. This second index table for speed of access (and because |
197 | it is small) is read at mount time and cached in memory. | 207 | it is small) is read at mount time and cached in memory. |
198 | 208 | ||
199 | 3.7 Xattr table | 209 | 3.8 Xattr table |
200 | --------------- | 210 | --------------- |
201 | 211 | ||
202 | The xattr table contains extended attributes for each inode. The xattrs | 212 | The xattr table contains extended attributes for each inode. The xattrs |
diff --git a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig index aa68a8a31518..efc309fa3035 100644 --- a/fs/squashfs/Kconfig +++ b/fs/squashfs/Kconfig | |||
@@ -5,12 +5,12 @@ config SQUASHFS | |||
5 | help | 5 | help |
6 | Saying Y here includes support for SquashFS 4.0 (a Compressed | 6 | Saying Y here includes support for SquashFS 4.0 (a Compressed |
7 | Read-Only File System). Squashfs is a highly compressed read-only | 7 | Read-Only File System). Squashfs is a highly compressed read-only |
8 | filesystem for Linux. It uses zlib/lzo compression to compress both | 8 | filesystem for Linux. It uses zlib, lzo or xz compression to |
9 | files, inodes and directories. Inodes in the system are very small | 9 | compress both files, inodes and directories. Inodes in the system |
10 | and all blocks are packed to minimise data overhead. Block sizes | 10 | are very small and all blocks are packed to minimise data overhead. |
11 | greater than 4K are supported up to a maximum of 1 Mbytes (default | 11 | Block sizes greater than 4K are supported up to a maximum of 1 Mbytes |
12 | block size 128K). SquashFS 4.0 supports 64 bit filesystems and files | 12 | (default block size 128K). SquashFS 4.0 supports 64 bit filesystems |
13 | (larger than 4GB), full uid/gid information, hard links and | 13 | and files (larger than 4GB), full uid/gid information, hard links and |
14 | timestamps. | 14 | timestamps. |
15 | 15 | ||
16 | Squashfs is intended for general read-only filesystem use, for | 16 | Squashfs is intended for general read-only filesystem use, for |
diff --git a/fs/squashfs/decompressor.c b/fs/squashfs/decompressor.c index a5940e54c4dd..e921bd213738 100644 --- a/fs/squashfs/decompressor.c +++ b/fs/squashfs/decompressor.c | |||
@@ -23,6 +23,7 @@ | |||
23 | 23 | ||
24 | #include <linux/types.h> | 24 | #include <linux/types.h> |
25 | #include <linux/mutex.h> | 25 | #include <linux/mutex.h> |
26 | #include <linux/slab.h> | ||
26 | #include <linux/buffer_head.h> | 27 | #include <linux/buffer_head.h> |
27 | 28 | ||
28 | #include "squashfs_fs.h" | 29 | #include "squashfs_fs.h" |
@@ -74,3 +75,36 @@ const struct squashfs_decompressor *squashfs_lookup_decompressor(int id) | |||
74 | 75 | ||
75 | return decompressor[i]; | 76 | return decompressor[i]; |
76 | } | 77 | } |
78 | |||
79 | |||
80 | void *squashfs_decompressor_init(struct super_block *sb, unsigned short flags) | ||
81 | { | ||
82 | struct squashfs_sb_info *msblk = sb->s_fs_info; | ||
83 | void *strm, *buffer = NULL; | ||
84 | int length = 0; | ||
85 | |||
86 | /* | ||
87 | * Read decompressor specific options from file system if present | ||
88 | */ | ||
89 | if (SQUASHFS_COMP_OPTS(flags)) { | ||
90 | buffer = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL); | ||
91 | if (buffer == NULL) | ||
92 | return ERR_PTR(-ENOMEM); | ||
93 | |||
94 | length = squashfs_read_data(sb, &buffer, | ||
95 | sizeof(struct squashfs_super_block), 0, NULL, | ||
96 | PAGE_CACHE_SIZE, 1); | ||
97 | |||
98 | if (length < 0) { | ||
99 | strm = ERR_PTR(length); | ||
100 | goto finished; | ||
101 | } | ||
102 | } | ||
103 | |||
104 | strm = msblk->decompressor->init(msblk, buffer, length); | ||
105 | |||
106 | finished: | ||
107 | kfree(buffer); | ||
108 | |||
109 | return strm; | ||
110 | } | ||
diff --git a/fs/squashfs/decompressor.h b/fs/squashfs/decompressor.h index 3b305a70f7aa..099745ad5691 100644 --- a/fs/squashfs/decompressor.h +++ b/fs/squashfs/decompressor.h | |||
@@ -24,7 +24,7 @@ | |||
24 | */ | 24 | */ |
25 | 25 | ||
26 | struct squashfs_decompressor { | 26 | struct squashfs_decompressor { |
27 | void *(*init)(struct squashfs_sb_info *); | 27 | void *(*init)(struct squashfs_sb_info *, void *, int); |
28 | void (*free)(void *); | 28 | void (*free)(void *); |
29 | int (*decompress)(struct squashfs_sb_info *, void **, | 29 | int (*decompress)(struct squashfs_sb_info *, void **, |
30 | struct buffer_head **, int, int, int, int, int); | 30 | struct buffer_head **, int, int, int, int, int); |
@@ -33,11 +33,6 @@ struct squashfs_decompressor { | |||
33 | int supported; | 33 | int supported; |
34 | }; | 34 | }; |
35 | 35 | ||
36 | static inline void *squashfs_decompressor_init(struct squashfs_sb_info *msblk) | ||
37 | { | ||
38 | return msblk->decompressor->init(msblk); | ||
39 | } | ||
40 | |||
41 | static inline void squashfs_decompressor_free(struct squashfs_sb_info *msblk, | 36 | static inline void squashfs_decompressor_free(struct squashfs_sb_info *msblk, |
42 | void *s) | 37 | void *s) |
43 | { | 38 | { |
diff --git a/fs/squashfs/dir.c b/fs/squashfs/dir.c index 0dc340aa2be9..3f79cd1d0c19 100644 --- a/fs/squashfs/dir.c +++ b/fs/squashfs/dir.c | |||
@@ -172,6 +172,11 @@ static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir) | |||
172 | length += sizeof(dirh); | 172 | length += sizeof(dirh); |
173 | 173 | ||
174 | dir_count = le32_to_cpu(dirh.count) + 1; | 174 | dir_count = le32_to_cpu(dirh.count) + 1; |
175 | |||
176 | /* dir_count should never be larger than 256 */ | ||
177 | if (dir_count > 256) | ||
178 | goto failed_read; | ||
179 | |||
175 | while (dir_count--) { | 180 | while (dir_count--) { |
176 | /* | 181 | /* |
177 | * Read directory entry. | 182 | * Read directory entry. |
@@ -183,6 +188,10 @@ static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir) | |||
183 | 188 | ||
184 | size = le16_to_cpu(dire->size) + 1; | 189 | size = le16_to_cpu(dire->size) + 1; |
185 | 190 | ||
191 | /* size should never be larger than SQUASHFS_NAME_LEN */ | ||
192 | if (size > SQUASHFS_NAME_LEN) | ||
193 | goto failed_read; | ||
194 | |||
186 | err = squashfs_read_metadata(inode->i_sb, dire->name, | 195 | err = squashfs_read_metadata(inode->i_sb, dire->name, |
187 | &block, &offset, size); | 196 | &block, &offset, size); |
188 | if (err < 0) | 197 | if (err < 0) |
diff --git a/fs/squashfs/lzo_wrapper.c b/fs/squashfs/lzo_wrapper.c index 7da759e34c52..00f4dfc5f088 100644 --- a/fs/squashfs/lzo_wrapper.c +++ b/fs/squashfs/lzo_wrapper.c | |||
@@ -37,7 +37,7 @@ struct squashfs_lzo { | |||
37 | void *output; | 37 | void *output; |
38 | }; | 38 | }; |
39 | 39 | ||
40 | static void *lzo_init(struct squashfs_sb_info *msblk) | 40 | static void *lzo_init(struct squashfs_sb_info *msblk, void *buff, int len) |
41 | { | 41 | { |
42 | int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); | 42 | int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); |
43 | 43 | ||
@@ -58,7 +58,7 @@ failed2: | |||
58 | failed: | 58 | failed: |
59 | ERROR("Failed to allocate lzo workspace\n"); | 59 | ERROR("Failed to allocate lzo workspace\n"); |
60 | kfree(stream); | 60 | kfree(stream); |
61 | return NULL; | 61 | return ERR_PTR(-ENOMEM); |
62 | } | 62 | } |
63 | 63 | ||
64 | 64 | ||
diff --git a/fs/squashfs/namei.c b/fs/squashfs/namei.c index 7a9464d08cf6..5d922a6701ab 100644 --- a/fs/squashfs/namei.c +++ b/fs/squashfs/namei.c | |||
@@ -176,6 +176,11 @@ static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry, | |||
176 | length += sizeof(dirh); | 176 | length += sizeof(dirh); |
177 | 177 | ||
178 | dir_count = le32_to_cpu(dirh.count) + 1; | 178 | dir_count = le32_to_cpu(dirh.count) + 1; |
179 | |||
180 | /* dir_count should never be larger than 256 */ | ||
181 | if (dir_count > 256) | ||
182 | goto data_error; | ||
183 | |||
179 | while (dir_count--) { | 184 | while (dir_count--) { |
180 | /* | 185 | /* |
181 | * Read directory entry. | 186 | * Read directory entry. |
@@ -187,6 +192,10 @@ static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry, | |||
187 | 192 | ||
188 | size = le16_to_cpu(dire->size) + 1; | 193 | size = le16_to_cpu(dire->size) + 1; |
189 | 194 | ||
195 | /* size should never be larger than SQUASHFS_NAME_LEN */ | ||
196 | if (size > SQUASHFS_NAME_LEN) | ||
197 | goto data_error; | ||
198 | |||
190 | err = squashfs_read_metadata(dir->i_sb, dire->name, | 199 | err = squashfs_read_metadata(dir->i_sb, dire->name, |
191 | &block, &offset, size); | 200 | &block, &offset, size); |
192 | if (err < 0) | 201 | if (err < 0) |
@@ -228,6 +237,9 @@ exit_lookup: | |||
228 | d_add(dentry, inode); | 237 | d_add(dentry, inode); |
229 | return ERR_PTR(0); | 238 | return ERR_PTR(0); |
230 | 239 | ||
240 | data_error: | ||
241 | err = -EIO; | ||
242 | |||
231 | read_failure: | 243 | read_failure: |
232 | ERROR("Unable to read directory block [%llx:%x]\n", | 244 | ERROR("Unable to read directory block [%llx:%x]\n", |
233 | squashfs_i(dir)->start + msblk->directory_table, | 245 | squashfs_i(dir)->start + msblk->directory_table, |
diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index ba729d808876..1f2e608b8785 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h | |||
@@ -48,6 +48,7 @@ extern int squashfs_read_table(struct super_block *, void *, u64, int); | |||
48 | 48 | ||
49 | /* decompressor.c */ | 49 | /* decompressor.c */ |
50 | extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int); | 50 | extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int); |
51 | extern void *squashfs_decompressor_init(struct super_block *, unsigned short); | ||
51 | 52 | ||
52 | /* export.c */ | 53 | /* export.c */ |
53 | extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, | 54 | extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, |
diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h index 39533feffd6d..4582c568ef4d 100644 --- a/fs/squashfs/squashfs_fs.h +++ b/fs/squashfs/squashfs_fs.h | |||
@@ -57,6 +57,7 @@ | |||
57 | #define SQUASHFS_ALWAYS_FRAG 5 | 57 | #define SQUASHFS_ALWAYS_FRAG 5 |
58 | #define SQUASHFS_DUPLICATE 6 | 58 | #define SQUASHFS_DUPLICATE 6 |
59 | #define SQUASHFS_EXPORT 7 | 59 | #define SQUASHFS_EXPORT 7 |
60 | #define SQUASHFS_COMP_OPT 10 | ||
60 | 61 | ||
61 | #define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1) | 62 | #define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1) |
62 | 63 | ||
@@ -81,6 +82,9 @@ | |||
81 | #define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \ | 82 | #define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \ |
82 | SQUASHFS_EXPORT) | 83 | SQUASHFS_EXPORT) |
83 | 84 | ||
85 | #define SQUASHFS_COMP_OPTS(flags) SQUASHFS_BIT(flags, \ | ||
86 | SQUASHFS_COMP_OPT) | ||
87 | |||
84 | /* Max number of types and file types */ | 88 | /* Max number of types and file types */ |
85 | #define SQUASHFS_DIR_TYPE 1 | 89 | #define SQUASHFS_DIR_TYPE 1 |
86 | #define SQUASHFS_REG_TYPE 2 | 90 | #define SQUASHFS_REG_TYPE 2 |
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 20700b9f2b4c..5c8184c061a4 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c | |||
@@ -199,10 +199,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
199 | 199 | ||
200 | err = -ENOMEM; | 200 | err = -ENOMEM; |
201 | 201 | ||
202 | msblk->stream = squashfs_decompressor_init(msblk); | ||
203 | if (msblk->stream == NULL) | ||
204 | goto failed_mount; | ||
205 | |||
206 | msblk->block_cache = squashfs_cache_init("metadata", | 202 | msblk->block_cache = squashfs_cache_init("metadata", |
207 | SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE); | 203 | SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE); |
208 | if (msblk->block_cache == NULL) | 204 | if (msblk->block_cache == NULL) |
@@ -215,6 +211,13 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
215 | goto failed_mount; | 211 | goto failed_mount; |
216 | } | 212 | } |
217 | 213 | ||
214 | msblk->stream = squashfs_decompressor_init(sb, flags); | ||
215 | if (IS_ERR(msblk->stream)) { | ||
216 | err = PTR_ERR(msblk->stream); | ||
217 | msblk->stream = NULL; | ||
218 | goto failed_mount; | ||
219 | } | ||
220 | |||
218 | /* Allocate and read id index table */ | 221 | /* Allocate and read id index table */ |
219 | msblk->id_table = squashfs_read_id_index_table(sb, | 222 | msblk->id_table = squashfs_read_id_index_table(sb, |
220 | le64_to_cpu(sblk->id_table_start), le16_to_cpu(sblk->no_ids)); | 223 | le64_to_cpu(sblk->id_table_start), le16_to_cpu(sblk->no_ids)); |
@@ -370,8 +373,8 @@ static void squashfs_put_super(struct super_block *sb) | |||
370 | } | 373 | } |
371 | 374 | ||
372 | 375 | ||
373 | static struct dentry *squashfs_mount(struct file_system_type *fs_type, int flags, | 376 | static struct dentry *squashfs_mount(struct file_system_type *fs_type, |
374 | const char *dev_name, void *data) | 377 | int flags, const char *dev_name, void *data) |
375 | { | 378 | { |
376 | return mount_bdev(fs_type, flags, dev_name, data, squashfs_fill_super); | 379 | return mount_bdev(fs_type, flags, dev_name, data, squashfs_fill_super); |
377 | } | 380 | } |
diff --git a/fs/squashfs/xz_wrapper.c b/fs/squashfs/xz_wrapper.c index c4eb40018256..aa47a286d1f8 100644 --- a/fs/squashfs/xz_wrapper.c +++ b/fs/squashfs/xz_wrapper.c | |||
@@ -26,10 +26,10 @@ | |||
26 | #include <linux/buffer_head.h> | 26 | #include <linux/buffer_head.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/xz.h> | 28 | #include <linux/xz.h> |
29 | #include <linux/bitops.h> | ||
29 | 30 | ||
30 | #include "squashfs_fs.h" | 31 | #include "squashfs_fs.h" |
31 | #include "squashfs_fs_sb.h" | 32 | #include "squashfs_fs_sb.h" |
32 | #include "squashfs_fs_i.h" | ||
33 | #include "squashfs.h" | 33 | #include "squashfs.h" |
34 | #include "decompressor.h" | 34 | #include "decompressor.h" |
35 | 35 | ||
@@ -38,24 +38,57 @@ struct squashfs_xz { | |||
38 | struct xz_buf buf; | 38 | struct xz_buf buf; |
39 | }; | 39 | }; |
40 | 40 | ||
41 | static void *squashfs_xz_init(struct squashfs_sb_info *msblk) | 41 | struct comp_opts { |
42 | __le32 dictionary_size; | ||
43 | __le32 flags; | ||
44 | }; | ||
45 | |||
46 | static void *squashfs_xz_init(struct squashfs_sb_info *msblk, void *buff, | ||
47 | int len) | ||
42 | { | 48 | { |
43 | int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); | 49 | struct comp_opts *comp_opts = buff; |
50 | struct squashfs_xz *stream; | ||
51 | int dict_size = msblk->block_size; | ||
52 | int err, n; | ||
53 | |||
54 | if (comp_opts) { | ||
55 | /* check compressor options are the expected length */ | ||
56 | if (len < sizeof(*comp_opts)) { | ||
57 | err = -EIO; | ||
58 | goto failed; | ||
59 | } | ||
44 | 60 | ||
45 | struct squashfs_xz *stream = kmalloc(sizeof(*stream), GFP_KERNEL); | 61 | dict_size = le32_to_cpu(comp_opts->dictionary_size); |
46 | if (stream == NULL) | 62 | |
63 | /* the dictionary size should be 2^n or 2^n+2^(n+1) */ | ||
64 | n = ffs(dict_size) - 1; | ||
65 | if (dict_size != (1 << n) && dict_size != (1 << n) + | ||
66 | (1 << (n + 1))) { | ||
67 | err = -EIO; | ||
68 | goto failed; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | dict_size = max_t(int, dict_size, SQUASHFS_METADATA_SIZE); | ||
73 | |||
74 | stream = kmalloc(sizeof(*stream), GFP_KERNEL); | ||
75 | if (stream == NULL) { | ||
76 | err = -ENOMEM; | ||
47 | goto failed; | 77 | goto failed; |
78 | } | ||
48 | 79 | ||
49 | stream->state = xz_dec_init(XZ_PREALLOC, block_size); | 80 | stream->state = xz_dec_init(XZ_PREALLOC, dict_size); |
50 | if (stream->state == NULL) | 81 | if (stream->state == NULL) { |
82 | kfree(stream); | ||
83 | err = -ENOMEM; | ||
51 | goto failed; | 84 | goto failed; |
85 | } | ||
52 | 86 | ||
53 | return stream; | 87 | return stream; |
54 | 88 | ||
55 | failed: | 89 | failed: |
56 | ERROR("Failed to allocate xz workspace\n"); | 90 | ERROR("Failed to initialise xz decompressor\n"); |
57 | kfree(stream); | 91 | return ERR_PTR(err); |
58 | return NULL; | ||
59 | } | 92 | } |
60 | 93 | ||
61 | 94 | ||
diff --git a/fs/squashfs/zlib_wrapper.c b/fs/squashfs/zlib_wrapper.c index 4661ae2b1cec..517688b32ffa 100644 --- a/fs/squashfs/zlib_wrapper.c +++ b/fs/squashfs/zlib_wrapper.c | |||
@@ -26,19 +26,19 @@ | |||
26 | #include <linux/buffer_head.h> | 26 | #include <linux/buffer_head.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/zlib.h> | 28 | #include <linux/zlib.h> |
29 | #include <linux/vmalloc.h> | ||
29 | 30 | ||
30 | #include "squashfs_fs.h" | 31 | #include "squashfs_fs.h" |
31 | #include "squashfs_fs_sb.h" | 32 | #include "squashfs_fs_sb.h" |
32 | #include "squashfs.h" | 33 | #include "squashfs.h" |
33 | #include "decompressor.h" | 34 | #include "decompressor.h" |
34 | 35 | ||
35 | static void *zlib_init(struct squashfs_sb_info *dummy) | 36 | static void *zlib_init(struct squashfs_sb_info *dummy, void *buff, int len) |
36 | { | 37 | { |
37 | z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL); | 38 | z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL); |
38 | if (stream == NULL) | 39 | if (stream == NULL) |
39 | goto failed; | 40 | goto failed; |
40 | stream->workspace = kmalloc(zlib_inflate_workspacesize(), | 41 | stream->workspace = vmalloc(zlib_inflate_workspacesize()); |
41 | GFP_KERNEL); | ||
42 | if (stream->workspace == NULL) | 42 | if (stream->workspace == NULL) |
43 | goto failed; | 43 | goto failed; |
44 | 44 | ||
@@ -47,7 +47,7 @@ static void *zlib_init(struct squashfs_sb_info *dummy) | |||
47 | failed: | 47 | failed: |
48 | ERROR("Failed to allocate zlib workspace\n"); | 48 | ERROR("Failed to allocate zlib workspace\n"); |
49 | kfree(stream); | 49 | kfree(stream); |
50 | return NULL; | 50 | return ERR_PTR(-ENOMEM); |
51 | } | 51 | } |
52 | 52 | ||
53 | 53 | ||
@@ -56,7 +56,7 @@ static void zlib_free(void *strm) | |||
56 | z_stream *stream = strm; | 56 | z_stream *stream = strm; |
57 | 57 | ||
58 | if (stream) | 58 | if (stream) |
59 | kfree(stream->workspace); | 59 | vfree(stream->workspace); |
60 | kfree(stream); | 60 | kfree(stream); |
61 | } | 61 | } |
62 | 62 | ||