aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorPhillip Lougher <phillip@lougher.demon.co.uk>2009-10-05 23:04:15 -0400
committerPhillip Lougher <phillip@lougher.demon.co.uk>2010-01-20 16:47:47 -0500
commit4c0f0bb2351bee3de8dd7715ee199454a59f1230 (patch)
treec552993587a8e87f7ebc0fe0955efdde94cc8884 /fs
parentf1a40359f8d8ba073257ed31a513e492621bcbc5 (diff)
Squashfs: add a decompressor framework
This adds a decompressor framework which allows multiple compression algorithms to be cleanly supported. Also update zlib wrapper and other code to use the new framework. Signed-off-by: Phillip Lougher <phillip@lougher.demon.co.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/squashfs/Makefile2
-rw-r--r--fs/squashfs/block.c3
-rw-r--r--fs/squashfs/decompressor.c58
-rw-r--r--fs/squashfs/decompressor.h55
-rw-r--r--fs/squashfs/squashfs.h14
-rw-r--r--fs/squashfs/squashfs_fs_sb.h41
-rw-r--r--fs/squashfs/super.c45
-rw-r--r--fs/squashfs/zlib_wrapper.c17
8 files changed, 184 insertions, 51 deletions
diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile
index a397e6f12ab5..df8a19ef870d 100644
--- a/fs/squashfs/Makefile
+++ b/fs/squashfs/Makefile
@@ -4,4 +4,4 @@
4 4
5obj-$(CONFIG_SQUASHFS) += squashfs.o 5obj-$(CONFIG_SQUASHFS) += squashfs.o
6squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o 6squashfs-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 7squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o
diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c
index 3f836e181eb8..1cb0d81b164b 100644
--- a/fs/squashfs/block.c
+++ b/fs/squashfs/block.c
@@ -36,6 +36,7 @@
36#include "squashfs_fs_sb.h" 36#include "squashfs_fs_sb.h"
37#include "squashfs_fs_i.h" 37#include "squashfs_fs_i.h"
38#include "squashfs.h" 38#include "squashfs.h"
39#include "decompressor.h"
39 40
40/* 41/*
41 * Read the metadata block length, this is stored in the first two 42 * Read the metadata block length, this is stored in the first two
@@ -151,7 +152,7 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
151 } 152 }
152 153
153 if (compressed) { 154 if (compressed) {
154 length = squashfs_zlib_uncompress(msblk, buffer, bh, b, offset, 155 length = squashfs_decompress(msblk, buffer, bh, b, offset,
155 length, srclength, pages); 156 length, srclength, pages);
156 if (length < 0) 157 if (length < 0)
157 goto read_failure; 158 goto read_failure;
diff --git a/fs/squashfs/decompressor.c b/fs/squashfs/decompressor.c
new file mode 100644
index 000000000000..0072ccdac1e2
--- /dev/null
+++ b/fs/squashfs/decompressor.c
@@ -0,0 +1,58 @@
1/*
2 * Squashfs - a compressed read only filesystem for Linux
3 *
4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
5 * Phillip Lougher <phillip@lougher.demon.co.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 * decompressor.c
22 */
23
24#include <linux/types.h>
25#include <linux/mutex.h>
26#include <linux/buffer_head.h>
27
28#include "squashfs_fs.h"
29#include "squashfs_fs_sb.h"
30#include "squashfs_fs_i.h"
31#include "decompressor.h"
32#include "squashfs.h"
33
34/*
35 * This file (and decompressor.h) implements a decompressor framework for
36 * Squashfs, allowing multiple decompressors to be easily supported
37 */
38
39static const struct squashfs_decompressor squashfs_unknown_comp_ops = {
40 NULL, NULL, NULL, 0, "unknown", 0
41};
42
43static const struct squashfs_decompressor *decompressor[] = {
44 &squashfs_zlib_comp_ops,
45 &squashfs_unknown_comp_ops
46};
47
48
49const struct squashfs_decompressor *squashfs_lookup_decompressor(int id)
50{
51 int i;
52
53 for (i = 0; decompressor[i]->id; i++)
54 if (id == decompressor[i]->id)
55 break;
56
57 return decompressor[i];
58}
diff --git a/fs/squashfs/decompressor.h b/fs/squashfs/decompressor.h
new file mode 100644
index 000000000000..7425f80783f6
--- /dev/null
+++ b/fs/squashfs/decompressor.h
@@ -0,0 +1,55 @@
1#ifndef DECOMPRESSOR_H
2#define DECOMPRESSOR_H
3/*
4 * Squashfs - a compressed read only filesystem for Linux
5 *
6 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
7 * Phillip Lougher <phillip@lougher.demon.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2,
12 * or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 *
23 * decompressor.h
24 */
25
26struct squashfs_decompressor {
27 void *(*init)(struct squashfs_sb_info *);
28 void (*free)(void *);
29 int (*decompress)(struct squashfs_sb_info *, void **,
30 struct buffer_head **, int, int, int, int, int);
31 int id;
32 char *name;
33 int supported;
34};
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,
42 void *s)
43{
44 if (msblk->decompressor)
45 msblk->decompressor->free(s);
46}
47
48static inline int squashfs_decompress(struct squashfs_sb_info *msblk,
49 void **buffer, struct buffer_head **bh, int b, int offset, int length,
50 int srclength, int pages)
51{
52 return msblk->decompressor->decompress(msblk, buffer, bh, b, offset,
53 length, srclength, pages);
54}
55#endif
diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h
index 9c2f76a1c50b..fe2587af5512 100644
--- a/fs/squashfs/squashfs.h
+++ b/fs/squashfs/squashfs.h
@@ -51,6 +51,9 @@ extern struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *,
51 u64, int); 51 u64, int);
52extern int squashfs_read_table(struct super_block *, void *, u64, int); 52extern int squashfs_read_table(struct super_block *, void *, u64, int);
53 53
54/* decompressor.c */
55extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int);
56
54/* export.c */ 57/* export.c */
55extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, 58extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64,
56 unsigned int); 59 unsigned int);
@@ -70,14 +73,8 @@ extern struct inode *squashfs_iget(struct super_block *, long long,
70 unsigned int); 73 unsigned int);
71extern int squashfs_read_inode(struct inode *, long long); 74extern int squashfs_read_inode(struct inode *, long long);
72 75
73/* zlib_wrapper.c */
74extern void *squashfs_zlib_init(void);
75extern void squashfs_zlib_free(void *);
76extern int squashfs_zlib_uncompress(struct squashfs_sb_info *, void **,
77 struct buffer_head **, int, int, int, int, int);
78
79/* 76/*
80 * Inodes and files operations 77 * Inodes, files and decompressor operations
81 */ 78 */
82 79
83/* dir.c */ 80/* dir.c */
@@ -94,3 +91,6 @@ extern const struct inode_operations squashfs_dir_inode_ops;
94 91
95/* symlink.c */ 92/* symlink.c */
96extern const struct address_space_operations squashfs_symlink_aops; 93extern const struct address_space_operations squashfs_symlink_aops;
94
95/* zlib_wrapper.c */
96extern const struct squashfs_decompressor squashfs_zlib_comp_ops;
diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h
index 23a67fa40b03..753335085e41 100644
--- a/fs/squashfs/squashfs_fs_sb.h
+++ b/fs/squashfs/squashfs_fs_sb.h
@@ -52,25 +52,26 @@ struct squashfs_cache_entry {
52}; 52};
53 53
54struct squashfs_sb_info { 54struct squashfs_sb_info {
55 int devblksize; 55 const struct squashfs_decompressor *decompressor;
56 int devblksize_log2; 56 int devblksize;
57 struct squashfs_cache *block_cache; 57 int devblksize_log2;
58 struct squashfs_cache *fragment_cache; 58 struct squashfs_cache *block_cache;
59 struct squashfs_cache *read_page; 59 struct squashfs_cache *fragment_cache;
60 int next_meta_index; 60 struct squashfs_cache *read_page;
61 __le64 *id_table; 61 int next_meta_index;
62 __le64 *fragment_index; 62 __le64 *id_table;
63 unsigned int *fragment_index_2; 63 __le64 *fragment_index;
64 struct mutex read_data_mutex; 64 unsigned int *fragment_index_2;
65 struct mutex meta_index_mutex; 65 struct mutex read_data_mutex;
66 struct meta_index *meta_index; 66 struct mutex meta_index_mutex;
67 void *stream; 67 struct meta_index *meta_index;
68 __le64 *inode_lookup_table; 68 void *stream;
69 u64 inode_table; 69 __le64 *inode_lookup_table;
70 u64 directory_table; 70 u64 inode_table;
71 unsigned int block_size; 71 u64 directory_table;
72 unsigned short block_log; 72 unsigned int block_size;
73 long long bytes_used; 73 unsigned short block_log;
74 unsigned int inodes; 74 long long bytes_used;
75 unsigned int inodes;
75}; 76};
76#endif 77#endif
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c
index b9f8c6a92d6a..3550aec2f655 100644
--- a/fs/squashfs/super.c
+++ b/fs/squashfs/super.c
@@ -41,27 +41,35 @@
41#include "squashfs_fs_sb.h" 41#include "squashfs_fs_sb.h"
42#include "squashfs_fs_i.h" 42#include "squashfs_fs_i.h"
43#include "squashfs.h" 43#include "squashfs.h"
44#include "decompressor.h"
44 45
45static struct file_system_type squashfs_fs_type; 46static struct file_system_type squashfs_fs_type;
46static const struct super_operations squashfs_super_ops; 47static const struct super_operations squashfs_super_ops;
47 48
48static int supported_squashfs_filesystem(short major, short minor, short comp) 49static const struct squashfs_decompressor *supported_squashfs_filesystem(short
50 major, short minor, short id)
49{ 51{
52 const struct squashfs_decompressor *decompressor;
53
50 if (major < SQUASHFS_MAJOR) { 54 if (major < SQUASHFS_MAJOR) {
51 ERROR("Major/Minor mismatch, older Squashfs %d.%d " 55 ERROR("Major/Minor mismatch, older Squashfs %d.%d "
52 "filesystems are unsupported\n", major, minor); 56 "filesystems are unsupported\n", major, minor);
53 return -EINVAL; 57 return NULL;
54 } else if (major > SQUASHFS_MAJOR || minor > SQUASHFS_MINOR) { 58 } else if (major > SQUASHFS_MAJOR || minor > SQUASHFS_MINOR) {
55 ERROR("Major/Minor mismatch, trying to mount newer " 59 ERROR("Major/Minor mismatch, trying to mount newer "
56 "%d.%d filesystem\n", major, minor); 60 "%d.%d filesystem\n", major, minor);
57 ERROR("Please update your kernel\n"); 61 ERROR("Please update your kernel\n");
58 return -EINVAL; 62 return NULL;
59 } 63 }
60 64
61 if (comp != ZLIB_COMPRESSION) 65 decompressor = squashfs_lookup_decompressor(id);
62 return -EINVAL; 66 if (!decompressor->supported) {
67 ERROR("Filesystem uses \"%s\" compression. This is not "
68 "supported\n", decompressor->name);
69 return NULL;
70 }
63 71
64 return 0; 72 return decompressor;
65} 73}
66 74
67 75
@@ -86,10 +94,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
86 } 94 }
87 msblk = sb->s_fs_info; 95 msblk = sb->s_fs_info;
88 96
89 msblk->stream = squashfs_zlib_init();
90 if (msblk->stream == NULL)
91 goto failure;
92
93 sblk = kzalloc(sizeof(*sblk), GFP_KERNEL); 97 sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
94 if (sblk == NULL) { 98 if (sblk == NULL) {
95 ERROR("Failed to allocate squashfs_super_block\n"); 99 ERROR("Failed to allocate squashfs_super_block\n");
@@ -116,25 +120,25 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
116 goto failed_mount; 120 goto failed_mount;
117 } 121 }
118 122
123 err = -EINVAL;
124
119 /* Check it is a SQUASHFS superblock */ 125 /* Check it is a SQUASHFS superblock */
120 sb->s_magic = le32_to_cpu(sblk->s_magic); 126 sb->s_magic = le32_to_cpu(sblk->s_magic);
121 if (sb->s_magic != SQUASHFS_MAGIC) { 127 if (sb->s_magic != SQUASHFS_MAGIC) {
122 if (!silent) 128 if (!silent)
123 ERROR("Can't find a SQUASHFS superblock on %s\n", 129 ERROR("Can't find a SQUASHFS superblock on %s\n",
124 bdevname(sb->s_bdev, b)); 130 bdevname(sb->s_bdev, b));
125 err = -EINVAL;
126 goto failed_mount; 131 goto failed_mount;
127 } 132 }
128 133
129 /* Check the MAJOR & MINOR versions and compression type */ 134 /* Check the MAJOR & MINOR versions and lookup compression type */
130 err = supported_squashfs_filesystem(le16_to_cpu(sblk->s_major), 135 msblk->decompressor = supported_squashfs_filesystem(
136 le16_to_cpu(sblk->s_major),
131 le16_to_cpu(sblk->s_minor), 137 le16_to_cpu(sblk->s_minor),
132 le16_to_cpu(sblk->compression)); 138 le16_to_cpu(sblk->compression));
133 if (err < 0) 139 if (msblk->decompressor == NULL)
134 goto failed_mount; 140 goto failed_mount;
135 141
136 err = -EINVAL;
137
138 /* 142 /*
139 * Check if there's xattrs in the filesystem. These are not 143 * Check if there's xattrs in the filesystem. These are not
140 * supported in this version, so warn that they will be ignored. 144 * supported in this version, so warn that they will be ignored.
@@ -201,6 +205,10 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
201 205
202 err = -ENOMEM; 206 err = -ENOMEM;
203 207
208 msblk->stream = squashfs_decompressor_init(msblk);
209 if (msblk->stream == NULL)
210 goto failed_mount;
211
204 msblk->block_cache = squashfs_cache_init("metadata", 212 msblk->block_cache = squashfs_cache_init("metadata",
205 SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE); 213 SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE);
206 if (msblk->block_cache == NULL) 214 if (msblk->block_cache == NULL)
@@ -288,7 +296,7 @@ failed_mount:
288 squashfs_cache_delete(msblk->block_cache); 296 squashfs_cache_delete(msblk->block_cache);
289 squashfs_cache_delete(msblk->fragment_cache); 297 squashfs_cache_delete(msblk->fragment_cache);
290 squashfs_cache_delete(msblk->read_page); 298 squashfs_cache_delete(msblk->read_page);
291 squashfs_zlib_free(msblk->stream); 299 squashfs_decompressor_free(msblk, msblk->stream);
292 kfree(msblk->inode_lookup_table); 300 kfree(msblk->inode_lookup_table);
293 kfree(msblk->fragment_index); 301 kfree(msblk->fragment_index);
294 kfree(msblk->id_table); 302 kfree(msblk->id_table);
@@ -298,7 +306,6 @@ failed_mount:
298 return err; 306 return err;
299 307
300failure: 308failure:
301 squashfs_zlib_free(msblk->stream);
302 kfree(sb->s_fs_info); 309 kfree(sb->s_fs_info);
303 sb->s_fs_info = NULL; 310 sb->s_fs_info = NULL;
304 return -ENOMEM; 311 return -ENOMEM;
@@ -342,7 +349,7 @@ static void squashfs_put_super(struct super_block *sb)
342 squashfs_cache_delete(sbi->block_cache); 349 squashfs_cache_delete(sbi->block_cache);
343 squashfs_cache_delete(sbi->fragment_cache); 350 squashfs_cache_delete(sbi->fragment_cache);
344 squashfs_cache_delete(sbi->read_page); 351 squashfs_cache_delete(sbi->read_page);
345 squashfs_zlib_free(sbi->stream); 352 squashfs_decompressor_free(sbi, sbi->stream);
346 kfree(sbi->id_table); 353 kfree(sbi->id_table);
347 kfree(sbi->fragment_index); 354 kfree(sbi->fragment_index);
348 kfree(sbi->meta_index); 355 kfree(sbi->meta_index);
diff --git a/fs/squashfs/zlib_wrapper.c b/fs/squashfs/zlib_wrapper.c
index c814594d522e..4dd70e04333b 100644
--- a/fs/squashfs/zlib_wrapper.c
+++ b/fs/squashfs/zlib_wrapper.c
@@ -30,8 +30,9 @@
30#include "squashfs_fs_sb.h" 30#include "squashfs_fs_sb.h"
31#include "squashfs_fs_i.h" 31#include "squashfs_fs_i.h"
32#include "squashfs.h" 32#include "squashfs.h"
33#include "decompressor.h"
33 34
34void *squashfs_zlib_init() 35static void *zlib_init(struct squashfs_sb_info *dummy)
35{ 36{
36 z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL); 37 z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL);
37 if (stream == NULL) 38 if (stream == NULL)
@@ -50,7 +51,7 @@ failed:
50} 51}
51 52
52 53
53void squashfs_zlib_free(void *strm) 54static void zlib_free(void *strm)
54{ 55{
55 z_stream *stream = strm; 56 z_stream *stream = strm;
56 57
@@ -60,7 +61,7 @@ void squashfs_zlib_free(void *strm)
60} 61}
61 62
62 63
63int squashfs_zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer, 64static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
64 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,
65 int pages) 66 int pages)
66{ 67{
@@ -137,3 +138,13 @@ release_mutex:
137 138
138 return -EIO; 139 return -EIO;
139} 140}
141
142const struct squashfs_decompressor squashfs_zlib_comp_ops = {
143 .init = zlib_init,
144 .free = zlib_free,
145 .decompress = zlib_uncompress,
146 .id = ZLIB_COMPRESSION,
147 .name = "zlib",
148 .supported = 1
149};
150