aboutsummaryrefslogtreecommitdiffstats
path: root/fs/squashfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/squashfs')
-rw-r--r--fs/squashfs/Kconfig32
-rw-r--r--fs/squashfs/Makefile1
-rw-r--r--fs/squashfs/block.c11
-rw-r--r--fs/squashfs/cache.c38
-rw-r--r--fs/squashfs/decompressor.c52
-rw-r--r--fs/squashfs/decompressor.h18
-rw-r--r--fs/squashfs/dir.c14
-rw-r--r--fs/squashfs/export.c42
-rw-r--r--fs/squashfs/file.c2
-rw-r--r--fs/squashfs/fragment.c38
-rw-r--r--fs/squashfs/id.c43
-rw-r--r--fs/squashfs/inode.c2
-rw-r--r--fs/squashfs/lzo_wrapper.c5
-rw-r--r--fs/squashfs/namei.c14
-rw-r--r--fs/squashfs/squashfs.h19
-rw-r--r--fs/squashfs/squashfs_fs.h7
-rw-r--r--fs/squashfs/squashfs_fs_i.h8
-rw-r--r--fs/squashfs/squashfs_fs_sb.h2
-rw-r--r--fs/squashfs/super.c147
-rw-r--r--fs/squashfs/symlink.c2
-rw-r--r--fs/squashfs/xattr.c11
-rw-r--r--fs/squashfs/xattr.h7
-rw-r--r--fs/squashfs/xattr_id.c49
-rw-r--r--fs/squashfs/xz_wrapper.c180
-rw-r--r--fs/squashfs/zlib_wrapper.c33
25 files changed, 546 insertions, 231 deletions
diff --git a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig
index e5f63da64d04..7797218d0b30 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
@@ -29,7 +29,6 @@ config SQUASHFS
29config SQUASHFS_XATTR 29config SQUASHFS_XATTR
30 bool "Squashfs XATTR support" 30 bool "Squashfs XATTR support"
31 depends on SQUASHFS 31 depends on SQUASHFS
32 default n
33 help 32 help
34 Saying Y here includes support for extended attributes (xattrs). 33 Saying Y here includes support for extended attributes (xattrs).
35 Xattrs are name:value pairs associated with inodes by 34 Xattrs are name:value pairs associated with inodes by
@@ -40,11 +39,10 @@ config SQUASHFS_XATTR
40config SQUASHFS_LZO 39config SQUASHFS_LZO
41 bool "Include support for LZO compressed file systems" 40 bool "Include support for LZO compressed file systems"
42 depends on SQUASHFS 41 depends on SQUASHFS
43 default n
44 select LZO_DECOMPRESS 42 select LZO_DECOMPRESS
45 help 43 help
46 Saying Y here includes support for reading Squashfs file systems 44 Saying Y here includes support for reading Squashfs file systems
47 compressed with LZO compresssion. LZO compression is mainly 45 compressed with LZO compression. LZO compression is mainly
48 aimed at embedded systems with slower CPUs where the overheads 46 aimed at embedded systems with slower CPUs where the overheads
49 of zlib are too high. 47 of zlib are too high.
50 48
@@ -53,10 +51,24 @@ config SQUASHFS_LZO
53 51
54 If unsure, say N. 52 If unsure, say N.
55 53
54config SQUASHFS_XZ
55 bool "Include support for XZ compressed file systems"
56 depends on SQUASHFS
57 select XZ_DEC
58 help
59 Saying Y here includes support for reading Squashfs file systems
60 compressed with XZ compression. XZ gives better compression than
61 the default zlib compression, at the expense of greater CPU and
62 memory overhead.
63
64 XZ is not the standard compression used in Squashfs and so most
65 file systems will be readable without selecting this option.
66
67 If unsure, say N.
68
56config SQUASHFS_EMBEDDED 69config SQUASHFS_EMBEDDED
57 bool "Additional option for memory-constrained systems" 70 bool "Additional option for memory-constrained systems"
58 depends on SQUASHFS 71 depends on SQUASHFS
59 default n
60 help 72 help
61 Saying Y here allows you to specify cache size. 73 Saying Y here allows you to specify cache size.
62 74
diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile
index 7672bac8d328..cecf2bea07af 100644
--- a/fs/squashfs/Makefile
+++ b/fs/squashfs/Makefile
@@ -7,3 +7,4 @@ squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o
7squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o 7squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o
8squashfs-$(CONFIG_SQUASHFS_XATTR) += xattr.o xattr_id.o 8squashfs-$(CONFIG_SQUASHFS_XATTR) += xattr.o xattr_id.o
9squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o 9squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o
10squashfs-$(CONFIG_SQUASHFS_XZ) += xz_wrapper.o
diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c
index 653c030eb840..ed0eb2a921f4 100644
--- a/fs/squashfs/block.c
+++ b/fs/squashfs/block.c
@@ -2,7 +2,7 @@
2 * Squashfs - a compressed read only filesystem for Linux 2 * Squashfs - a compressed read only filesystem for Linux
3 * 3 *
4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
5 * Phillip Lougher <phillip@lougher.demon.co.uk> 5 * Phillip Lougher <phillip@squashfs.org.uk>
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
@@ -34,7 +34,6 @@
34 34
35#include "squashfs_fs.h" 35#include "squashfs_fs.h"
36#include "squashfs_fs_sb.h" 36#include "squashfs_fs_sb.h"
37#include "squashfs_fs_i.h"
38#include "squashfs.h" 37#include "squashfs.h"
39#include "decompressor.h" 38#include "decompressor.h"
40 39
@@ -64,6 +63,14 @@ static struct buffer_head *get_block_length(struct super_block *sb,
64 *length = (unsigned char) bh->b_data[*offset] | 63 *length = (unsigned char) bh->b_data[*offset] |
65 (unsigned char) bh->b_data[*offset + 1] << 8; 64 (unsigned char) bh->b_data[*offset + 1] << 8;
66 *offset += 2; 65 *offset += 2;
66
67 if (*offset == msblk->devblksize) {
68 put_bh(bh);
69 bh = sb_bread(sb, ++(*cur_index));
70 if (bh == NULL)
71 return NULL;
72 *offset = 0;
73 }
67 } 74 }
68 75
69 return bh; 76 return bh;
diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c
index 57314bee9059..f744be98cd5a 100644
--- a/fs/squashfs/cache.c
+++ b/fs/squashfs/cache.c
@@ -2,7 +2,7 @@
2 * Squashfs - a compressed read only filesystem for Linux 2 * Squashfs - a compressed read only filesystem for Linux
3 * 3 *
4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
5 * Phillip Lougher <phillip@lougher.demon.co.uk> 5 * Phillip Lougher <phillip@squashfs.org.uk>
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
@@ -29,7 +29,7 @@
29 * plus functions layered ontop of the generic cache implementation to 29 * plus functions layered ontop of the generic cache implementation to
30 * access the metadata and fragment caches. 30 * access the metadata and fragment caches.
31 * 31 *
32 * To avoid out of memory and fragmentation isssues with vmalloc the cache 32 * To avoid out of memory and fragmentation issues with vmalloc the cache
33 * uses sequences of kmalloced PAGE_CACHE_SIZE buffers. 33 * uses sequences of kmalloced PAGE_CACHE_SIZE buffers.
34 * 34 *
35 * It should be noted that the cache is not used for file datablocks, these 35 * It should be noted that the cache is not used for file datablocks, these
@@ -55,7 +55,6 @@
55 55
56#include "squashfs_fs.h" 56#include "squashfs_fs.h"
57#include "squashfs_fs_sb.h" 57#include "squashfs_fs_sb.h"
58#include "squashfs_fs_i.h"
59#include "squashfs.h" 58#include "squashfs.h"
60 59
61/* 60/*
@@ -105,7 +104,7 @@ struct squashfs_cache_entry *squashfs_cache_get(struct super_block *sb,
105 entry = &cache->entry[i]; 104 entry = &cache->entry[i];
106 105
107 /* 106 /*
108 * Initialise choosen cache entry, and fill it in from 107 * Initialise chosen cache entry, and fill it in from
109 * disk. 108 * disk.
110 */ 109 */
111 cache->unused--; 110 cache->unused--;
@@ -287,7 +286,7 @@ cleanup:
287 286
288 287
289/* 288/*
290 * Copy upto length bytes from cache entry to buffer starting at offset bytes 289 * Copy up to length bytes from cache entry to buffer starting at offset bytes
291 * into the cache entry. If there's not length bytes then copy the number of 290 * into the cache entry. If there's not length bytes then copy the number of
292 * bytes available. In all cases return the number of bytes copied. 291 * bytes available. In all cases return the number of bytes copied.
293 */ 292 */
@@ -394,19 +393,36 @@ struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *sb,
394/* 393/*
395 * Read a filesystem table (uncompressed sequence of bytes) from disk 394 * Read a filesystem table (uncompressed sequence of bytes) from disk
396 */ 395 */
397int squashfs_read_table(struct super_block *sb, void *buffer, u64 block, 396void *squashfs_read_table(struct super_block *sb, u64 block, int length)
398 int length)
399{ 397{
400 int pages = (length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; 398 int pages = (length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
401 int i, res; 399 int i, res;
402 void **data = kcalloc(pages, sizeof(void *), GFP_KERNEL); 400 void *table, *buffer, **data;
403 if (data == NULL) 401
404 return -ENOMEM; 402 table = buffer = kmalloc(length, GFP_KERNEL);
403 if (table == NULL)
404 return ERR_PTR(-ENOMEM);
405
406 data = kcalloc(pages, sizeof(void *), GFP_KERNEL);
407 if (data == NULL) {
408 res = -ENOMEM;
409 goto failed;
410 }
405 411
406 for (i = 0; i < pages; i++, buffer += PAGE_CACHE_SIZE) 412 for (i = 0; i < pages; i++, buffer += PAGE_CACHE_SIZE)
407 data[i] = buffer; 413 data[i] = buffer;
414
408 res = squashfs_read_data(sb, data, block, length | 415 res = squashfs_read_data(sb, data, block, length |
409 SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length, pages); 416 SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length, pages);
417
410 kfree(data); 418 kfree(data);
411 return res; 419
420 if (res < 0)
421 goto failed;
422
423 return table;
424
425failed:
426 kfree(table);
427 return ERR_PTR(res);
412} 428}
diff --git a/fs/squashfs/decompressor.c b/fs/squashfs/decompressor.c
index 24af9ce9722f..9f1b0bb96f13 100644
--- a/fs/squashfs/decompressor.c
+++ b/fs/squashfs/decompressor.c
@@ -2,7 +2,7 @@
2 * Squashfs - a compressed read only filesystem for Linux 2 * Squashfs - a compressed read only filesystem for Linux
3 * 3 *
4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
5 * Phillip Lougher <phillip@lougher.demon.co.uk> 5 * Phillip Lougher <phillip@squashfs.org.uk>
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
@@ -23,11 +23,11 @@
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"
29#include "squashfs_fs_sb.h" 30#include "squashfs_fs_sb.h"
30#include "squashfs_fs_i.h"
31#include "decompressor.h" 31#include "decompressor.h"
32#include "squashfs.h" 32#include "squashfs.h"
33 33
@@ -41,23 +41,26 @@ static const struct squashfs_decompressor squashfs_lzma_unsupported_comp_ops = {
41}; 41};
42 42
43#ifndef CONFIG_SQUASHFS_LZO 43#ifndef CONFIG_SQUASHFS_LZO
44static const struct squashfs_decompressor squashfs_lzo_unsupported_comp_ops = { 44static const struct squashfs_decompressor squashfs_lzo_comp_ops = {
45 NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0 45 NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0
46}; 46};
47#endif 47#endif
48 48
49#ifndef CONFIG_SQUASHFS_XZ
50static const struct squashfs_decompressor squashfs_xz_comp_ops = {
51 NULL, NULL, NULL, XZ_COMPRESSION, "xz", 0
52};
53#endif
54
49static const struct squashfs_decompressor squashfs_unknown_comp_ops = { 55static const struct squashfs_decompressor squashfs_unknown_comp_ops = {
50 NULL, NULL, NULL, 0, "unknown", 0 56 NULL, NULL, NULL, 0, "unknown", 0
51}; 57};
52 58
53static const struct squashfs_decompressor *decompressor[] = { 59static const struct squashfs_decompressor *decompressor[] = {
54 &squashfs_zlib_comp_ops, 60 &squashfs_zlib_comp_ops,
55 &squashfs_lzma_unsupported_comp_ops,
56#ifdef CONFIG_SQUASHFS_LZO
57 &squashfs_lzo_comp_ops, 61 &squashfs_lzo_comp_ops,
58#else 62 &squashfs_xz_comp_ops,
59 &squashfs_lzo_unsupported_comp_ops, 63 &squashfs_lzma_unsupported_comp_ops,
60#endif
61 &squashfs_unknown_comp_ops 64 &squashfs_unknown_comp_ops
62}; 65};
63 66
@@ -72,3 +75,36 @@ const struct squashfs_decompressor *squashfs_lookup_decompressor(int id)
72 75
73 return decompressor[i]; 76 return decompressor[i];
74} 77}
78
79
80void *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
106finished:
107 kfree(buffer);
108
109 return strm;
110}
diff --git a/fs/squashfs/decompressor.h b/fs/squashfs/decompressor.h
index 7425f80783f6..8ba70cff09a6 100644
--- a/fs/squashfs/decompressor.h
+++ b/fs/squashfs/decompressor.h
@@ -4,7 +4,7 @@
4 * Squashfs - a compressed read only filesystem for Linux 4 * Squashfs - a compressed read only filesystem for Linux
5 * 5 *
6 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 6 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
7 * Phillip Lougher <phillip@lougher.demon.co.uk> 7 * Phillip Lougher <phillip@squashfs.org.uk>
8 * 8 *
9 * This program is free software; you can redistribute it and/or 9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License 10 * modify it under the terms of the GNU General Public License
@@ -24,7 +24,7 @@
24 */ 24 */
25 25
26struct squashfs_decompressor { 26struct 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
36static inline void *squashfs_decompressor_init(struct squashfs_sb_info *msblk)
37{
38 return msblk->decompressor->init(msblk);
39}
40
41static inline void squashfs_decompressor_free(struct squashfs_sb_info *msblk, 36static inline void squashfs_decompressor_free(struct squashfs_sb_info *msblk,
42 void *s) 37 void *s)
43{ 38{
@@ -52,4 +47,13 @@ static inline int squashfs_decompress(struct squashfs_sb_info *msblk,
52 return msblk->decompressor->decompress(msblk, buffer, bh, b, offset, 47 return msblk->decompressor->decompress(msblk, buffer, bh, b, offset,
53 length, srclength, pages); 48 length, srclength, pages);
54} 49}
50
51#ifdef CONFIG_SQUASHFS_XZ
52extern const struct squashfs_decompressor squashfs_xz_comp_ops;
53#endif
54
55#ifdef CONFIG_SQUASHFS_LZO
56extern const struct squashfs_decompressor squashfs_lzo_comp_ops;
57#endif
58
55#endif 59#endif
diff --git a/fs/squashfs/dir.c b/fs/squashfs/dir.c
index 12b933ac6585..9dfe2ce0fb70 100644
--- a/fs/squashfs/dir.c
+++ b/fs/squashfs/dir.c
@@ -2,7 +2,7 @@
2 * Squashfs - a compressed read only filesystem for Linux 2 * Squashfs - a compressed read only filesystem for Linux
3 * 3 *
4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
5 * Phillip Lougher <phillip@lougher.demon.co.uk> 5 * Phillip Lougher <phillip@squashfs.org.uk>
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
@@ -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)
@@ -230,5 +239,6 @@ failed_read:
230 239
231const struct file_operations squashfs_dir_ops = { 240const struct file_operations squashfs_dir_ops = {
232 .read = generic_read_dir, 241 .read = generic_read_dir,
233 .readdir = squashfs_readdir 242 .readdir = squashfs_readdir,
243 .llseek = default_llseek,
234}; 244};
diff --git a/fs/squashfs/export.c b/fs/squashfs/export.c
index 7f93d5a9ee05..5e1101ff276f 100644
--- a/fs/squashfs/export.c
+++ b/fs/squashfs/export.c
@@ -2,7 +2,7 @@
2 * Squashfs - a compressed read only filesystem for Linux 2 * Squashfs - a compressed read only filesystem for Linux
3 * 3 *
4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
5 * Phillip Lougher <phillip@lougher.demon.co.uk> 5 * Phillip Lougher <phillip@squashfs.org.uk>
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
@@ -121,30 +121,38 @@ static struct dentry *squashfs_get_parent(struct dentry *child)
121 * Read uncompressed inode lookup table indexes off disk into memory 121 * Read uncompressed inode lookup table indexes off disk into memory
122 */ 122 */
123__le64 *squashfs_read_inode_lookup_table(struct super_block *sb, 123__le64 *squashfs_read_inode_lookup_table(struct super_block *sb,
124 u64 lookup_table_start, unsigned int inodes) 124 u64 lookup_table_start, u64 next_table, unsigned int inodes)
125{ 125{
126 unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(inodes); 126 unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(inodes);
127 __le64 *inode_lookup_table; 127 __le64 *table;
128 int err;
129 128
130 TRACE("In read_inode_lookup_table, length %d\n", length); 129 TRACE("In read_inode_lookup_table, length %d\n", length);
131 130
132 /* Allocate inode lookup table indexes */ 131 /* Sanity check values */
133 inode_lookup_table = kmalloc(length, GFP_KERNEL); 132
134 if (inode_lookup_table == NULL) { 133 /* there should always be at least one inode */
135 ERROR("Failed to allocate inode lookup table\n"); 134 if (inodes == 0)
136 return ERR_PTR(-ENOMEM); 135 return ERR_PTR(-EINVAL);
137 } 136
137 /* length bytes should not extend into the next table - this check
138 * also traps instances where lookup_table_start is incorrectly larger
139 * than the next table start
140 */
141 if (lookup_table_start + length > next_table)
142 return ERR_PTR(-EINVAL);
143
144 table = squashfs_read_table(sb, lookup_table_start, length);
138 145
139 err = squashfs_read_table(sb, inode_lookup_table, lookup_table_start, 146 /*
140 length); 147 * table[0] points to the first inode lookup table metadata block,
141 if (err < 0) { 148 * this should be less than lookup_table_start
142 ERROR("unable to read inode lookup table\n"); 149 */
143 kfree(inode_lookup_table); 150 if (!IS_ERR(table) && le64_to_cpu(table[0]) >= lookup_table_start) {
144 return ERR_PTR(err); 151 kfree(table);
152 return ERR_PTR(-EINVAL);
145 } 153 }
146 154
147 return inode_lookup_table; 155 return table;
148} 156}
149 157
150 158
diff --git a/fs/squashfs/file.c b/fs/squashfs/file.c
index a25c5060bdcb..38bb1c640559 100644
--- a/fs/squashfs/file.c
+++ b/fs/squashfs/file.c
@@ -2,7 +2,7 @@
2 * Squashfs - a compressed read only filesystem for Linux 2 * Squashfs - a compressed read only filesystem for Linux
3 * 3 *
4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
5 * Phillip Lougher <phillip@lougher.demon.co.uk> 5 * Phillip Lougher <phillip@squashfs.org.uk>
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
diff --git a/fs/squashfs/fragment.c b/fs/squashfs/fragment.c
index 7c90bbd6879d..0ed6edbc5c71 100644
--- a/fs/squashfs/fragment.c
+++ b/fs/squashfs/fragment.c
@@ -2,7 +2,7 @@
2 * Squashfs - a compressed read only filesystem for Linux 2 * Squashfs - a compressed read only filesystem for Linux
3 * 3 *
4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
5 * Phillip Lougher <phillip@lougher.demon.co.uk> 5 * Phillip Lougher <phillip@squashfs.org.uk>
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
@@ -39,7 +39,6 @@
39 39
40#include "squashfs_fs.h" 40#include "squashfs_fs.h"
41#include "squashfs_fs_sb.h" 41#include "squashfs_fs_sb.h"
42#include "squashfs_fs_i.h"
43#include "squashfs.h" 42#include "squashfs.h"
44 43
45/* 44/*
@@ -72,26 +71,29 @@ int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment,
72 * Read the uncompressed fragment lookup table indexes off disk into memory 71 * Read the uncompressed fragment lookup table indexes off disk into memory
73 */ 72 */
74__le64 *squashfs_read_fragment_index_table(struct super_block *sb, 73__le64 *squashfs_read_fragment_index_table(struct super_block *sb,
75 u64 fragment_table_start, unsigned int fragments) 74 u64 fragment_table_start, u64 next_table, unsigned int fragments)
76{ 75{
77 unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(fragments); 76 unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(fragments);
78 __le64 *fragment_index; 77 __le64 *table;
79 int err;
80 78
81 /* Allocate fragment lookup table indexes */ 79 /*
82 fragment_index = kmalloc(length, GFP_KERNEL); 80 * Sanity check, length bytes should not extend into the next table -
83 if (fragment_index == NULL) { 81 * this check also traps instances where fragment_table_start is
84 ERROR("Failed to allocate fragment index table\n"); 82 * incorrectly larger than the next table start
85 return ERR_PTR(-ENOMEM); 83 */
86 } 84 if (fragment_table_start + length > next_table)
85 return ERR_PTR(-EINVAL);
86
87 table = squashfs_read_table(sb, fragment_table_start, length);
87 88
88 err = squashfs_read_table(sb, fragment_index, fragment_table_start, 89 /*
89 length); 90 * table[0] points to the first fragment table metadata block, this
90 if (err < 0) { 91 * should be less than fragment_table_start
91 ERROR("unable to read fragment index table\n"); 92 */
92 kfree(fragment_index); 93 if (!IS_ERR(table) && le64_to_cpu(table[0]) >= fragment_table_start) {
93 return ERR_PTR(err); 94 kfree(table);
95 return ERR_PTR(-EINVAL);
94 } 96 }
95 97
96 return fragment_index; 98 return table;
97} 99}
diff --git a/fs/squashfs/id.c b/fs/squashfs/id.c
index b7f64bcd2b70..d38ea3dab951 100644
--- a/fs/squashfs/id.c
+++ b/fs/squashfs/id.c
@@ -2,7 +2,7 @@
2 * Squashfs - a compressed read only filesystem for Linux 2 * Squashfs - a compressed read only filesystem for Linux
3 * 3 *
4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
5 * Phillip Lougher <phillip@lougher.demon.co.uk> 5 * Phillip Lougher <phillip@squashfs.org.uk>
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
@@ -37,7 +37,6 @@
37 37
38#include "squashfs_fs.h" 38#include "squashfs_fs.h"
39#include "squashfs_fs_sb.h" 39#include "squashfs_fs_sb.h"
40#include "squashfs_fs_i.h"
41#include "squashfs.h" 40#include "squashfs.h"
42 41
43/* 42/*
@@ -67,27 +66,37 @@ int squashfs_get_id(struct super_block *sb, unsigned int index,
67 * Read uncompressed id lookup table indexes from disk into memory 66 * Read uncompressed id lookup table indexes from disk into memory
68 */ 67 */
69__le64 *squashfs_read_id_index_table(struct super_block *sb, 68__le64 *squashfs_read_id_index_table(struct super_block *sb,
70 u64 id_table_start, unsigned short no_ids) 69 u64 id_table_start, u64 next_table, unsigned short no_ids)
71{ 70{
72 unsigned int length = SQUASHFS_ID_BLOCK_BYTES(no_ids); 71 unsigned int length = SQUASHFS_ID_BLOCK_BYTES(no_ids);
73 __le64 *id_table; 72 __le64 *table;
74 int err;
75 73
76 TRACE("In read_id_index_table, length %d\n", length); 74 TRACE("In read_id_index_table, length %d\n", length);
77 75
78 /* Allocate id lookup table indexes */ 76 /* Sanity check values */
79 id_table = kmalloc(length, GFP_KERNEL); 77
80 if (id_table == NULL) { 78 /* there should always be at least one id */
81 ERROR("Failed to allocate id index table\n"); 79 if (no_ids == 0)
82 return ERR_PTR(-ENOMEM); 80 return ERR_PTR(-EINVAL);
83 } 81
82 /*
83 * length bytes should not extend into the next table - this check
84 * also traps instances where id_table_start is incorrectly larger
85 * than the next table start
86 */
87 if (id_table_start + length > next_table)
88 return ERR_PTR(-EINVAL);
89
90 table = squashfs_read_table(sb, id_table_start, length);
84 91
85 err = squashfs_read_table(sb, id_table, id_table_start, length); 92 /*
86 if (err < 0) { 93 * table[0] points to the first id lookup table metadata block, this
87 ERROR("unable to read id index table\n"); 94 * should be less than id_table_start
88 kfree(id_table); 95 */
89 return ERR_PTR(err); 96 if (!IS_ERR(table) && le64_to_cpu(table[0]) >= id_table_start) {
97 kfree(table);
98 return ERR_PTR(-EINVAL);
90 } 99 }
91 100
92 return id_table; 101 return table;
93} 102}
diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c
index 62e63ad25075..04bebcaa2373 100644
--- a/fs/squashfs/inode.c
+++ b/fs/squashfs/inode.c
@@ -2,7 +2,7 @@
2 * Squashfs - a compressed read only filesystem for Linux 2 * Squashfs - a compressed read only filesystem for Linux
3 * 3 *
4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
5 * Phillip Lougher <phillip@lougher.demon.co.uk> 5 * Phillip Lougher <phillip@squashfs.org.uk>
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
diff --git a/fs/squashfs/lzo_wrapper.c b/fs/squashfs/lzo_wrapper.c
index 5d87789bf1c1..00f4dfc5f088 100644
--- a/fs/squashfs/lzo_wrapper.c
+++ b/fs/squashfs/lzo_wrapper.c
@@ -29,7 +29,6 @@
29 29
30#include "squashfs_fs.h" 30#include "squashfs_fs.h"
31#include "squashfs_fs_sb.h" 31#include "squashfs_fs_sb.h"
32#include "squashfs_fs_i.h"
33#include "squashfs.h" 32#include "squashfs.h"
34#include "decompressor.h" 33#include "decompressor.h"
35 34
@@ -38,7 +37,7 @@ struct squashfs_lzo {
38 void *output; 37 void *output;
39}; 38};
40 39
41static void *lzo_init(struct squashfs_sb_info *msblk) 40static void *lzo_init(struct squashfs_sb_info *msblk, void *buff, int len)
42{ 41{
43 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);
44 43
@@ -59,7 +58,7 @@ failed2:
59failed: 58failed:
60 ERROR("Failed to allocate lzo workspace\n"); 59 ERROR("Failed to allocate lzo workspace\n");
61 kfree(stream); 60 kfree(stream);
62 return NULL; 61 return ERR_PTR(-ENOMEM);
63} 62}
64 63
65 64
diff --git a/fs/squashfs/namei.c b/fs/squashfs/namei.c
index 7a9464d08cf6..4bc63ac64bc0 100644
--- a/fs/squashfs/namei.c
+++ b/fs/squashfs/namei.c
@@ -2,7 +2,7 @@
2 * Squashfs - a compressed read only filesystem for Linux 2 * Squashfs - a compressed read only filesystem for Linux
3 * 3 *
4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
5 * Phillip Lougher <phillip@lougher.demon.co.uk> 5 * Phillip Lougher <phillip@squashfs.org.uk>
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
@@ -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
240data_error:
241 err = -EIO;
242
231read_failure: 243read_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 5d45569d5f72..e3be6a71cfa7 100644
--- a/fs/squashfs/squashfs.h
+++ b/fs/squashfs/squashfs.h
@@ -2,7 +2,7 @@
2 * Squashfs - a compressed read only filesystem for Linux 2 * Squashfs - a compressed read only filesystem for Linux
3 * 3 *
4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
5 * Phillip Lougher <phillip@lougher.demon.co.uk> 5 * Phillip Lougher <phillip@squashfs.org.uk>
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
@@ -27,11 +27,6 @@
27 27
28#define WARNING(s, args...) pr_warning("SQUASHFS: "s, ## args) 28#define WARNING(s, args...) pr_warning("SQUASHFS: "s, ## args)
29 29
30static inline struct squashfs_inode_info *squashfs_i(struct inode *inode)
31{
32 return list_entry(inode, struct squashfs_inode_info, vfs_inode);
33}
34
35/* block.c */ 30/* block.c */
36extern int squashfs_read_data(struct super_block *, void **, u64, int, u64 *, 31extern int squashfs_read_data(struct super_block *, void **, u64, int, u64 *,
37 int, int); 32 int, int);
@@ -49,23 +44,24 @@ extern struct squashfs_cache_entry *squashfs_get_fragment(struct super_block *,
49 u64, int); 44 u64, int);
50extern struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *, 45extern struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *,
51 u64, int); 46 u64, int);
52extern int squashfs_read_table(struct super_block *, void *, u64, int); 47extern void *squashfs_read_table(struct super_block *, u64, int);
53 48
54/* decompressor.c */ 49/* decompressor.c */
55extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int); 50extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int);
51extern void *squashfs_decompressor_init(struct super_block *, unsigned short);
56 52
57/* export.c */ 53/* export.c */
58extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, 54extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, u64,
59 unsigned int); 55 unsigned int);
60 56
61/* fragment.c */ 57/* fragment.c */
62extern int squashfs_frag_lookup(struct super_block *, unsigned int, u64 *); 58extern int squashfs_frag_lookup(struct super_block *, unsigned int, u64 *);
63extern __le64 *squashfs_read_fragment_index_table(struct super_block *, 59extern __le64 *squashfs_read_fragment_index_table(struct super_block *,
64 u64, unsigned int); 60 u64, u64, unsigned int);
65 61
66/* id.c */ 62/* id.c */
67extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *); 63extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *);
68extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, 64extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, u64,
69 unsigned short); 65 unsigned short);
70 66
71/* inode.c */ 67/* inode.c */
@@ -104,6 +100,3 @@ extern const struct xattr_handler *squashfs_xattr_handlers[];
104 100
105/* zlib_wrapper.c */ 101/* zlib_wrapper.c */
106extern const struct squashfs_decompressor squashfs_zlib_comp_ops; 102extern const struct squashfs_decompressor squashfs_zlib_comp_ops;
107
108/* lzo_wrapper.c */
109extern const struct squashfs_decompressor squashfs_lzo_comp_ops;
diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h
index c5137fc9ab11..b4a4e539a08c 100644
--- a/fs/squashfs/squashfs_fs.h
+++ b/fs/squashfs/squashfs_fs.h
@@ -4,7 +4,7 @@
4 * Squashfs 4 * Squashfs
5 * 5 *
6 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 6 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
7 * Phillip Lougher <phillip@lougher.demon.co.uk> 7 * Phillip Lougher <phillip@squashfs.org.uk>
8 * 8 *
9 * This program is free software; you can redistribute it and/or 9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License 10 * modify it under the terms of the GNU General Public License
@@ -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
@@ -238,6 +242,7 @@ struct meta_index {
238#define ZLIB_COMPRESSION 1 242#define ZLIB_COMPRESSION 1
239#define LZMA_COMPRESSION 2 243#define LZMA_COMPRESSION 2
240#define LZO_COMPRESSION 3 244#define LZO_COMPRESSION 3
245#define XZ_COMPRESSION 4
241 246
242struct squashfs_super_block { 247struct squashfs_super_block {
243 __le32 s_magic; 248 __le32 s_magic;
diff --git a/fs/squashfs/squashfs_fs_i.h b/fs/squashfs/squashfs_fs_i.h
index d3e3a37f28a1..73588e7700ed 100644
--- a/fs/squashfs/squashfs_fs_i.h
+++ b/fs/squashfs/squashfs_fs_i.h
@@ -4,7 +4,7 @@
4 * Squashfs 4 * Squashfs
5 * 5 *
6 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 6 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
7 * Phillip Lougher <phillip@lougher.demon.co.uk> 7 * Phillip Lougher <phillip@squashfs.org.uk>
8 * 8 *
9 * This program is free software; you can redistribute it and/or 9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License 10 * modify it under the terms of the GNU General Public License
@@ -45,4 +45,10 @@ struct squashfs_inode_info {
45 }; 45 };
46 struct inode vfs_inode; 46 struct inode vfs_inode;
47}; 47};
48
49
50static inline struct squashfs_inode_info *squashfs_i(struct inode *inode)
51{
52 return list_entry(inode, struct squashfs_inode_info, vfs_inode);
53}
48#endif 54#endif
diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h
index d9037a5215f0..651f0b31d296 100644
--- a/fs/squashfs/squashfs_fs_sb.h
+++ b/fs/squashfs/squashfs_fs_sb.h
@@ -4,7 +4,7 @@
4 * Squashfs 4 * Squashfs
5 * 5 *
6 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 6 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
7 * Phillip Lougher <phillip@lougher.demon.co.uk> 7 * Phillip Lougher <phillip@squashfs.org.uk>
8 * 8 *
9 * This program is free software; you can redistribute it and/or 9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License 10 * modify it under the terms of the GNU General Public License
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c
index 88b4f8606652..7438850c62d0 100644
--- a/fs/squashfs/super.c
+++ b/fs/squashfs/super.c
@@ -2,7 +2,7 @@
2 * Squashfs - a compressed read only filesystem for Linux 2 * Squashfs - a compressed read only filesystem for Linux
3 * 3 *
4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
5 * Phillip Lougher <phillip@lougher.demon.co.uk> 5 * Phillip Lougher <phillip@squashfs.org.uk>
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
@@ -30,7 +30,6 @@
30#include <linux/fs.h> 30#include <linux/fs.h>
31#include <linux/vfs.h> 31#include <linux/vfs.h>
32#include <linux/slab.h> 32#include <linux/slab.h>
33#include <linux/smp_lock.h>
34#include <linux/mutex.h> 33#include <linux/mutex.h>
35#include <linux/pagemap.h> 34#include <linux/pagemap.h>
36#include <linux/init.h> 35#include <linux/init.h>
@@ -84,7 +83,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
84 long long root_inode; 83 long long root_inode;
85 unsigned short flags; 84 unsigned short flags;
86 unsigned int fragments; 85 unsigned int fragments;
87 u64 lookup_table_start, xattr_id_table_start; 86 u64 lookup_table_start, xattr_id_table_start, next_table;
88 int err; 87 int err;
89 88
90 TRACE("Entered squashfs_fill_superblock\n"); 89 TRACE("Entered squashfs_fill_superblock\n");
@@ -96,12 +95,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
96 } 95 }
97 msblk = sb->s_fs_info; 96 msblk = sb->s_fs_info;
98 97
99 sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
100 if (sblk == NULL) {
101 ERROR("Failed to allocate squashfs_super_block\n");
102 goto failure;
103 }
104
105 msblk->devblksize = sb_min_blocksize(sb, BLOCK_SIZE); 98 msblk->devblksize = sb_min_blocksize(sb, BLOCK_SIZE);
106 msblk->devblksize_log2 = ffz(~msblk->devblksize); 99 msblk->devblksize_log2 = ffz(~msblk->devblksize);
107 100
@@ -115,10 +108,12 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
115 * of bytes_used) we need to set it to an initial sensible dummy value 108 * of bytes_used) we need to set it to an initial sensible dummy value
116 */ 109 */
117 msblk->bytes_used = sizeof(*sblk); 110 msblk->bytes_used = sizeof(*sblk);
118 err = squashfs_read_table(sb, sblk, SQUASHFS_START, sizeof(*sblk)); 111 sblk = squashfs_read_table(sb, SQUASHFS_START, sizeof(*sblk));
119 112
120 if (err < 0) { 113 if (IS_ERR(sblk)) {
121 ERROR("unable to read squashfs_super_block\n"); 114 ERROR("unable to read squashfs_super_block\n");
115 err = PTR_ERR(sblk);
116 sblk = NULL;
122 goto failed_mount; 117 goto failed_mount;
123 } 118 }
124 119
@@ -200,10 +195,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
200 195
201 err = -ENOMEM; 196 err = -ENOMEM;
202 197
203 msblk->stream = squashfs_decompressor_init(msblk);
204 if (msblk->stream == NULL)
205 goto failed_mount;
206
207 msblk->block_cache = squashfs_cache_init("metadata", 198 msblk->block_cache = squashfs_cache_init("metadata",
208 SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE); 199 SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE);
209 if (msblk->block_cache == NULL) 200 if (msblk->block_cache == NULL)
@@ -216,18 +207,68 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
216 goto failed_mount; 207 goto failed_mount;
217 } 208 }
218 209
210 msblk->stream = squashfs_decompressor_init(sb, flags);
211 if (IS_ERR(msblk->stream)) {
212 err = PTR_ERR(msblk->stream);
213 msblk->stream = NULL;
214 goto failed_mount;
215 }
216
217 /* Handle xattrs */
218 sb->s_xattr = squashfs_xattr_handlers;
219 xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start);
220 if (xattr_id_table_start == SQUASHFS_INVALID_BLK) {
221 next_table = msblk->bytes_used;
222 goto allocate_id_index_table;
223 }
224
225 /* Allocate and read xattr id lookup table */
226 msblk->xattr_id_table = squashfs_read_xattr_id_table(sb,
227 xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids);
228 if (IS_ERR(msblk->xattr_id_table)) {
229 ERROR("unable to read xattr id index table\n");
230 err = PTR_ERR(msblk->xattr_id_table);
231 msblk->xattr_id_table = NULL;
232 if (err != -ENOTSUPP)
233 goto failed_mount;
234 }
235 next_table = msblk->xattr_table;
236
237allocate_id_index_table:
219 /* Allocate and read id index table */ 238 /* Allocate and read id index table */
220 msblk->id_table = squashfs_read_id_index_table(sb, 239 msblk->id_table = squashfs_read_id_index_table(sb,
221 le64_to_cpu(sblk->id_table_start), le16_to_cpu(sblk->no_ids)); 240 le64_to_cpu(sblk->id_table_start), next_table,
241 le16_to_cpu(sblk->no_ids));
222 if (IS_ERR(msblk->id_table)) { 242 if (IS_ERR(msblk->id_table)) {
243 ERROR("unable to read id index table\n");
223 err = PTR_ERR(msblk->id_table); 244 err = PTR_ERR(msblk->id_table);
224 msblk->id_table = NULL; 245 msblk->id_table = NULL;
225 goto failed_mount; 246 goto failed_mount;
226 } 247 }
248 next_table = le64_to_cpu(msblk->id_table[0]);
249
250 /* Handle inode lookup table */
251 lookup_table_start = le64_to_cpu(sblk->lookup_table_start);
252 if (lookup_table_start == SQUASHFS_INVALID_BLK)
253 goto handle_fragments;
254
255 /* Allocate and read inode lookup table */
256 msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb,
257 lookup_table_start, next_table, msblk->inodes);
258 if (IS_ERR(msblk->inode_lookup_table)) {
259 ERROR("unable to read inode lookup table\n");
260 err = PTR_ERR(msblk->inode_lookup_table);
261 msblk->inode_lookup_table = NULL;
262 goto failed_mount;
263 }
264 next_table = le64_to_cpu(msblk->inode_lookup_table[0]);
265
266 sb->s_export_op = &squashfs_export_ops;
227 267
268handle_fragments:
228 fragments = le32_to_cpu(sblk->fragments); 269 fragments = le32_to_cpu(sblk->fragments);
229 if (fragments == 0) 270 if (fragments == 0)
230 goto allocate_lookup_table; 271 goto check_directory_table;
231 272
232 msblk->fragment_cache = squashfs_cache_init("fragment", 273 msblk->fragment_cache = squashfs_cache_init("fragment",
233 SQUASHFS_CACHED_FRAGMENTS, msblk->block_size); 274 SQUASHFS_CACHED_FRAGMENTS, msblk->block_size);
@@ -238,45 +279,29 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
238 279
239 /* Allocate and read fragment index table */ 280 /* Allocate and read fragment index table */
240 msblk->fragment_index = squashfs_read_fragment_index_table(sb, 281 msblk->fragment_index = squashfs_read_fragment_index_table(sb,
241 le64_to_cpu(sblk->fragment_table_start), fragments); 282 le64_to_cpu(sblk->fragment_table_start), next_table, fragments);
242 if (IS_ERR(msblk->fragment_index)) { 283 if (IS_ERR(msblk->fragment_index)) {
284 ERROR("unable to read fragment index table\n");
243 err = PTR_ERR(msblk->fragment_index); 285 err = PTR_ERR(msblk->fragment_index);
244 msblk->fragment_index = NULL; 286 msblk->fragment_index = NULL;
245 goto failed_mount; 287 goto failed_mount;
246 } 288 }
289 next_table = le64_to_cpu(msblk->fragment_index[0]);
247 290
248allocate_lookup_table: 291check_directory_table:
249 lookup_table_start = le64_to_cpu(sblk->lookup_table_start); 292 /* Sanity check directory_table */
250 if (lookup_table_start == SQUASHFS_INVALID_BLK) 293 if (msblk->directory_table >= next_table) {
251 goto allocate_xattr_table; 294 err = -EINVAL;
252
253 /* Allocate and read inode lookup table */
254 msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb,
255 lookup_table_start, msblk->inodes);
256 if (IS_ERR(msblk->inode_lookup_table)) {
257 err = PTR_ERR(msblk->inode_lookup_table);
258 msblk->inode_lookup_table = NULL;
259 goto failed_mount; 295 goto failed_mount;
260 } 296 }
261 297
262 sb->s_export_op = &squashfs_export_ops; 298 /* Sanity check inode_table */
263 299 if (msblk->inode_table >= msblk->directory_table) {
264allocate_xattr_table: 300 err = -EINVAL;
265 sb->s_xattr = squashfs_xattr_handlers; 301 goto failed_mount;
266 xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start);
267 if (xattr_id_table_start == SQUASHFS_INVALID_BLK)
268 goto allocate_root;
269
270 /* Allocate and read xattr id lookup table */
271 msblk->xattr_id_table = squashfs_read_xattr_id_table(sb,
272 xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids);
273 if (IS_ERR(msblk->xattr_id_table)) {
274 err = PTR_ERR(msblk->xattr_id_table);
275 msblk->xattr_id_table = NULL;
276 if (err != -ENOTSUPP)
277 goto failed_mount;
278 } 302 }
279allocate_root: 303
304 /* allocate root */
280 root = new_inode(sb); 305 root = new_inode(sb);
281 if (!root) { 306 if (!root) {
282 err = -ENOMEM; 307 err = -ENOMEM;
@@ -316,11 +341,6 @@ failed_mount:
316 sb->s_fs_info = NULL; 341 sb->s_fs_info = NULL;
317 kfree(sblk); 342 kfree(sblk);
318 return err; 343 return err;
319
320failure:
321 kfree(sb->s_fs_info);
322 sb->s_fs_info = NULL;
323 return -ENOMEM;
324} 344}
325 345
326 346
@@ -354,8 +374,6 @@ static int squashfs_remount(struct super_block *sb, int *flags, char *data)
354 374
355static void squashfs_put_super(struct super_block *sb) 375static void squashfs_put_super(struct super_block *sb)
356{ 376{
357 lock_kernel();
358
359 if (sb->s_fs_info) { 377 if (sb->s_fs_info) {
360 struct squashfs_sb_info *sbi = sb->s_fs_info; 378 struct squashfs_sb_info *sbi = sb->s_fs_info;
361 squashfs_cache_delete(sbi->block_cache); 379 squashfs_cache_delete(sbi->block_cache);
@@ -370,17 +388,13 @@ static void squashfs_put_super(struct super_block *sb)
370 kfree(sb->s_fs_info); 388 kfree(sb->s_fs_info);
371 sb->s_fs_info = NULL; 389 sb->s_fs_info = NULL;
372 } 390 }
373
374 unlock_kernel();
375} 391}
376 392
377 393
378static int squashfs_get_sb(struct file_system_type *fs_type, int flags, 394static struct dentry *squashfs_mount(struct file_system_type *fs_type,
379 const char *dev_name, void *data, 395 int flags, const char *dev_name, void *data)
380 struct vfsmount *mnt)
381{ 396{
382 return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super, 397 return mount_bdev(fs_type, flags, dev_name, data, squashfs_fill_super);
383 mnt);
384} 398}
385 399
386 400
@@ -447,16 +461,23 @@ static struct inode *squashfs_alloc_inode(struct super_block *sb)
447} 461}
448 462
449 463
450static void squashfs_destroy_inode(struct inode *inode) 464static void squashfs_i_callback(struct rcu_head *head)
451{ 465{
466 struct inode *inode = container_of(head, struct inode, i_rcu);
467 INIT_LIST_HEAD(&inode->i_dentry);
452 kmem_cache_free(squashfs_inode_cachep, squashfs_i(inode)); 468 kmem_cache_free(squashfs_inode_cachep, squashfs_i(inode));
453} 469}
454 470
471static void squashfs_destroy_inode(struct inode *inode)
472{
473 call_rcu(&inode->i_rcu, squashfs_i_callback);
474}
475
455 476
456static struct file_system_type squashfs_fs_type = { 477static struct file_system_type squashfs_fs_type = {
457 .owner = THIS_MODULE, 478 .owner = THIS_MODULE,
458 .name = "squashfs", 479 .name = "squashfs",
459 .get_sb = squashfs_get_sb, 480 .mount = squashfs_mount,
460 .kill_sb = kill_block_super, 481 .kill_sb = kill_block_super,
461 .fs_flags = FS_REQUIRES_DEV 482 .fs_flags = FS_REQUIRES_DEV
462}; 483};
@@ -472,5 +493,5 @@ static const struct super_operations squashfs_super_ops = {
472module_init(init_squashfs_fs); 493module_init(init_squashfs_fs);
473module_exit(exit_squashfs_fs); 494module_exit(exit_squashfs_fs);
474MODULE_DESCRIPTION("squashfs 4.0, a compressed read-only filesystem"); 495MODULE_DESCRIPTION("squashfs 4.0, a compressed read-only filesystem");
475MODULE_AUTHOR("Phillip Lougher <phillip@lougher.demon.co.uk>"); 496MODULE_AUTHOR("Phillip Lougher <phillip@squashfs.org.uk>");
476MODULE_LICENSE("GPL"); 497MODULE_LICENSE("GPL");
diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c
index ec86434921e1..1191817264cc 100644
--- a/fs/squashfs/symlink.c
+++ b/fs/squashfs/symlink.c
@@ -2,7 +2,7 @@
2 * Squashfs - a compressed read only filesystem for Linux 2 * Squashfs - a compressed read only filesystem for Linux
3 * 3 *
4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
5 * Phillip Lougher <phillip@lougher.demon.co.uk> 5 * Phillip Lougher <phillip@squashfs.org.uk>
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
diff --git a/fs/squashfs/xattr.c b/fs/squashfs/xattr.c
index 652b8541f9c6..92fcde7b4d61 100644
--- a/fs/squashfs/xattr.c
+++ b/fs/squashfs/xattr.c
@@ -2,7 +2,7 @@
2 * Squashfs - a compressed read only filesystem for Linux 2 * Squashfs - a compressed read only filesystem for Linux
3 * 3 *
4 * Copyright (c) 2010 4 * Copyright (c) 2010
5 * Phillip Lougher <phillip@lougher.demon.co.uk> 5 * Phillip Lougher <phillip@squashfs.org.uk>
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
@@ -158,17 +158,18 @@ static int squashfs_xattr_get(struct inode *inode, int name_index,
158 strncmp(target, name, name_size) == 0) { 158 strncmp(target, name, name_size) == 0) {
159 /* found xattr */ 159 /* found xattr */
160 if (type & SQUASHFS_XATTR_VALUE_OOL) { 160 if (type & SQUASHFS_XATTR_VALUE_OOL) {
161 __le64 xattr; 161 __le64 xattr_val;
162 u64 xattr;
162 /* val is a reference to the real location */ 163 /* val is a reference to the real location */
163 err = squashfs_read_metadata(sb, &val, &start, 164 err = squashfs_read_metadata(sb, &val, &start,
164 &offset, sizeof(val)); 165 &offset, sizeof(val));
165 if (err < 0) 166 if (err < 0)
166 goto failed; 167 goto failed;
167 err = squashfs_read_metadata(sb, &xattr, &start, 168 err = squashfs_read_metadata(sb, &xattr_val,
168 &offset, sizeof(xattr)); 169 &start, &offset, sizeof(xattr_val));
169 if (err < 0) 170 if (err < 0)
170 goto failed; 171 goto failed;
171 xattr = le64_to_cpu(xattr); 172 xattr = le64_to_cpu(xattr_val);
172 start = SQUASHFS_XATTR_BLK(xattr) + 173 start = SQUASHFS_XATTR_BLK(xattr) +
173 msblk->xattr_table; 174 msblk->xattr_table;
174 offset = SQUASHFS_XATTR_OFFSET(xattr); 175 offset = SQUASHFS_XATTR_OFFSET(xattr);
diff --git a/fs/squashfs/xattr.h b/fs/squashfs/xattr.h
index 49fe0d719fbf..c83f5d9ec125 100644
--- a/fs/squashfs/xattr.h
+++ b/fs/squashfs/xattr.h
@@ -2,7 +2,7 @@
2 * Squashfs - a compressed read only filesystem for Linux 2 * Squashfs - a compressed read only filesystem for Linux
3 * 3 *
4 * Copyright (c) 2010 4 * Copyright (c) 2010
5 * Phillip Lougher <phillip@lougher.demon.co.uk> 5 * Phillip Lougher <phillip@squashfs.org.uk>
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
@@ -25,17 +25,18 @@
25extern __le64 *squashfs_read_xattr_id_table(struct super_block *, u64, 25extern __le64 *squashfs_read_xattr_id_table(struct super_block *, u64,
26 u64 *, int *); 26 u64 *, int *);
27extern int squashfs_xattr_lookup(struct super_block *, unsigned int, int *, 27extern int squashfs_xattr_lookup(struct super_block *, unsigned int, int *,
28 int *, unsigned long long *); 28 unsigned int *, unsigned long long *);
29#else 29#else
30static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb, 30static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb,
31 u64 start, u64 *xattr_table_start, int *xattr_ids) 31 u64 start, u64 *xattr_table_start, int *xattr_ids)
32{ 32{
33 ERROR("Xattrs in filesystem, these will be ignored\n"); 33 ERROR("Xattrs in filesystem, these will be ignored\n");
34 *xattr_table_start = start;
34 return ERR_PTR(-ENOTSUPP); 35 return ERR_PTR(-ENOTSUPP);
35} 36}
36 37
37static inline int squashfs_xattr_lookup(struct super_block *sb, 38static inline int squashfs_xattr_lookup(struct super_block *sb,
38 unsigned int index, int *count, int *size, 39 unsigned int index, int *count, unsigned int *size,
39 unsigned long long *xattr) 40 unsigned long long *xattr)
40{ 41{
41 return 0; 42 return 0;
diff --git a/fs/squashfs/xattr_id.c b/fs/squashfs/xattr_id.c
index cfb41106098f..c89607d690c4 100644
--- a/fs/squashfs/xattr_id.c
+++ b/fs/squashfs/xattr_id.c
@@ -2,7 +2,7 @@
2 * Squashfs - a compressed read only filesystem for Linux 2 * Squashfs - a compressed read only filesystem for Linux
3 * 3 *
4 * Copyright (c) 2010 4 * Copyright (c) 2010
5 * Phillip Lougher <phillip@lougher.demon.co.uk> 5 * Phillip Lougher <phillip@squashfs.org.uk>
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
@@ -32,8 +32,8 @@
32 32
33#include "squashfs_fs.h" 33#include "squashfs_fs.h"
34#include "squashfs_fs_sb.h" 34#include "squashfs_fs_sb.h"
35#include "squashfs_fs_i.h"
36#include "squashfs.h" 35#include "squashfs.h"
36#include "xattr.h"
37 37
38/* 38/*
39 * Map xattr id using the xattr id look up table 39 * Map xattr id using the xattr id look up table
@@ -67,34 +67,29 @@ __le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start,
67 u64 *xattr_table_start, int *xattr_ids) 67 u64 *xattr_table_start, int *xattr_ids)
68{ 68{
69 unsigned int len; 69 unsigned int len;
70 __le64 *xid_table; 70 struct squashfs_xattr_id_table *id_table;
71 struct squashfs_xattr_id_table id_table; 71
72 int err; 72 id_table = squashfs_read_table(sb, start, sizeof(*id_table));
73 if (IS_ERR(id_table))
74 return (__le64 *) id_table;
75
76 *xattr_table_start = le64_to_cpu(id_table->xattr_table_start);
77 *xattr_ids = le32_to_cpu(id_table->xattr_ids);
78 kfree(id_table);
79
80 /* Sanity check values */
81
82 /* there is always at least one xattr id */
83 if (*xattr_ids == 0)
84 return ERR_PTR(-EINVAL);
85
86 /* xattr_table should be less than start */
87 if (*xattr_table_start >= start)
88 return ERR_PTR(-EINVAL);
73 89
74 err = squashfs_read_table(sb, &id_table, start, sizeof(id_table));
75 if (err < 0) {
76 ERROR("unable to read xattr id table\n");
77 return ERR_PTR(err);
78 }
79 *xattr_table_start = le64_to_cpu(id_table.xattr_table_start);
80 *xattr_ids = le32_to_cpu(id_table.xattr_ids);
81 len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids); 90 len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids);
82 91
83 TRACE("In read_xattr_index_table, length %d\n", len); 92 TRACE("In read_xattr_index_table, length %d\n", len);
84 93
85 /* Allocate xattr id lookup table indexes */ 94 return squashfs_read_table(sb, start + sizeof(*id_table), len);
86 xid_table = kmalloc(len, GFP_KERNEL);
87 if (xid_table == NULL) {
88 ERROR("Failed to allocate xattr id index table\n");
89 return ERR_PTR(-ENOMEM);
90 }
91
92 err = squashfs_read_table(sb, xid_table, start + sizeof(id_table), len);
93 if (err < 0) {
94 ERROR("unable to read xattr id index table\n");
95 kfree(xid_table);
96 return ERR_PTR(err);
97 }
98
99 return xid_table;
100} 95}
diff --git a/fs/squashfs/xz_wrapper.c b/fs/squashfs/xz_wrapper.c
new file mode 100644
index 000000000000..1760b7d108f6
--- /dev/null
+++ b/fs/squashfs/xz_wrapper.c
@@ -0,0 +1,180 @@
1/*
2 * Squashfs - a compressed read only filesystem for Linux
3 *
4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
5 * Phillip Lougher <phillip@squashfs.org.uk>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2,
10 * or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 * xz_wrapper.c
22 */
23
24
25#include <linux/mutex.h>
26#include <linux/buffer_head.h>
27#include <linux/slab.h>
28#include <linux/xz.h>
29#include <linux/bitops.h>
30
31#include "squashfs_fs.h"
32#include "squashfs_fs_sb.h"
33#include "squashfs.h"
34#include "decompressor.h"
35
36struct squashfs_xz {
37 struct xz_dec *state;
38 struct xz_buf buf;
39};
40
41struct comp_opts {
42 __le32 dictionary_size;
43 __le32 flags;
44};
45
46static void *squashfs_xz_init(struct squashfs_sb_info *msblk, void *buff,
47 int len)
48{
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 }
60
61 dict_size = le32_to_cpu(comp_opts->dictionary_size);
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;
77 goto failed;
78 }
79
80 stream->state = xz_dec_init(XZ_PREALLOC, dict_size);
81 if (stream->state == NULL) {
82 kfree(stream);
83 err = -ENOMEM;
84 goto failed;
85 }
86
87 return stream;
88
89failed:
90 ERROR("Failed to initialise xz decompressor\n");
91 return ERR_PTR(err);
92}
93
94
95static void squashfs_xz_free(void *strm)
96{
97 struct squashfs_xz *stream = strm;
98
99 if (stream) {
100 xz_dec_end(stream->state);
101 kfree(stream);
102 }
103}
104
105
106static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void **buffer,
107 struct buffer_head **bh, int b, int offset, int length, int srclength,
108 int pages)
109{
110 enum xz_ret xz_err;
111 int avail, total = 0, k = 0, page = 0;
112 struct squashfs_xz *stream = msblk->stream;
113
114 mutex_lock(&msblk->read_data_mutex);
115
116 xz_dec_reset(stream->state);
117 stream->buf.in_pos = 0;
118 stream->buf.in_size = 0;
119 stream->buf.out_pos = 0;
120 stream->buf.out_size = PAGE_CACHE_SIZE;
121 stream->buf.out = buffer[page++];
122
123 do {
124 if (stream->buf.in_pos == stream->buf.in_size && k < b) {
125 avail = min(length, msblk->devblksize - offset);
126 length -= avail;
127 wait_on_buffer(bh[k]);
128 if (!buffer_uptodate(bh[k]))
129 goto release_mutex;
130
131 stream->buf.in = bh[k]->b_data + offset;
132 stream->buf.in_size = avail;
133 stream->buf.in_pos = 0;
134 offset = 0;
135 }
136
137 if (stream->buf.out_pos == stream->buf.out_size
138 && page < pages) {
139 stream->buf.out = buffer[page++];
140 stream->buf.out_pos = 0;
141 total += PAGE_CACHE_SIZE;
142 }
143
144 xz_err = xz_dec_run(stream->state, &stream->buf);
145
146 if (stream->buf.in_pos == stream->buf.in_size && k < b)
147 put_bh(bh[k++]);
148 } while (xz_err == XZ_OK);
149
150 if (xz_err != XZ_STREAM_END) {
151 ERROR("xz_dec_run error, data probably corrupt\n");
152 goto release_mutex;
153 }
154
155 if (k < b) {
156 ERROR("xz_uncompress error, input remaining\n");
157 goto release_mutex;
158 }
159
160 total += stream->buf.out_pos;
161 mutex_unlock(&msblk->read_data_mutex);
162 return total;
163
164release_mutex:
165 mutex_unlock(&msblk->read_data_mutex);
166
167 for (; k < b; k++)
168 put_bh(bh[k]);
169
170 return -EIO;
171}
172
173const struct squashfs_decompressor squashfs_xz_comp_ops = {
174 .init = squashfs_xz_init,
175 .free = squashfs_xz_free,
176 .decompress = squashfs_xz_uncompress,
177 .id = XZ_COMPRESSION,
178 .name = "xz",
179 .supported = 1
180};
diff --git a/fs/squashfs/zlib_wrapper.c b/fs/squashfs/zlib_wrapper.c
index 7a603874e483..55d918fd2d86 100644
--- a/fs/squashfs/zlib_wrapper.c
+++ b/fs/squashfs/zlib_wrapper.c
@@ -2,7 +2,7 @@
2 * Squashfs - a compressed read only filesystem for Linux 2 * Squashfs - a compressed read only filesystem for Linux
3 * 3 *
4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
5 * Phillip Lougher <phillip@lougher.demon.co.uk> 5 * Phillip Lougher <phillip@squashfs.org.uk>
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
@@ -26,20 +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_fs_i.h"
33#include "squashfs.h" 33#include "squashfs.h"
34#include "decompressor.h" 34#include "decompressor.h"
35 35
36static void *zlib_init(struct squashfs_sb_info *dummy) 36static void *zlib_init(struct squashfs_sb_info *dummy, void *buff, int len)
37{ 37{
38 z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL); 38 z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL);
39 if (stream == NULL) 39 if (stream == NULL)
40 goto failed; 40 goto failed;
41 stream->workspace = kmalloc(zlib_inflate_workspacesize(), 41 stream->workspace = vmalloc(zlib_inflate_workspacesize());
42 GFP_KERNEL);
43 if (stream->workspace == NULL) 42 if (stream->workspace == NULL)
44 goto failed; 43 goto failed;
45 44
@@ -48,7 +47,7 @@ static void *zlib_init(struct squashfs_sb_info *dummy)
48failed: 47failed:
49 ERROR("Failed to allocate zlib workspace\n"); 48 ERROR("Failed to allocate zlib workspace\n");
50 kfree(stream); 49 kfree(stream);
51 return NULL; 50 return ERR_PTR(-ENOMEM);
52} 51}
53 52
54 53
@@ -57,7 +56,7 @@ static void zlib_free(void *strm)
57 z_stream *stream = strm; 56 z_stream *stream = strm;
58 57
59 if (stream) 58 if (stream)
60 kfree(stream->workspace); 59 vfree(stream->workspace);
61 kfree(stream); 60 kfree(stream);
62} 61}
63 62
@@ -66,8 +65,8 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
66 struct buffer_head **bh, int b, int offset, int length, int srclength, 65 struct buffer_head **bh, int b, int offset, int length, int srclength,
67 int pages) 66 int pages)
68{ 67{
69 int zlib_err = 0, zlib_init = 0; 68 int zlib_err, zlib_init = 0;
70 int avail, bytes, k = 0, page = 0; 69 int k = 0, page = 0;
71 z_stream *stream = msblk->stream; 70 z_stream *stream = msblk->stream;
72 71
73 mutex_lock(&msblk->read_data_mutex); 72 mutex_lock(&msblk->read_data_mutex);
@@ -75,21 +74,14 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
75 stream->avail_out = 0; 74 stream->avail_out = 0;
76 stream->avail_in = 0; 75 stream->avail_in = 0;
77 76
78 bytes = length;
79 do { 77 do {
80 if (stream->avail_in == 0 && k < b) { 78 if (stream->avail_in == 0 && k < b) {
81 avail = min(bytes, msblk->devblksize - offset); 79 int avail = min(length, msblk->devblksize - offset);
82 bytes -= avail; 80 length -= avail;
83 wait_on_buffer(bh[k]); 81 wait_on_buffer(bh[k]);
84 if (!buffer_uptodate(bh[k])) 82 if (!buffer_uptodate(bh[k]))
85 goto release_mutex; 83 goto release_mutex;
86 84
87 if (avail == 0) {
88 offset = 0;
89 put_bh(bh[k++]);
90 continue;
91 }
92
93 stream->next_in = bh[k]->b_data + offset; 85 stream->next_in = bh[k]->b_data + offset;
94 stream->avail_in = avail; 86 stream->avail_in = avail;
95 offset = 0; 87 offset = 0;
@@ -128,6 +120,11 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
128 goto release_mutex; 120 goto release_mutex;
129 } 121 }
130 122
123 if (k < b) {
124 ERROR("zlib_uncompress error, data remaining\n");
125 goto release_mutex;
126 }
127
131 length = stream->total_out; 128 length = stream->total_out;
132 mutex_unlock(&msblk->read_data_mutex); 129 mutex_unlock(&msblk->read_data_mutex);
133 return length; 130 return length;