Commit 4c0f0bb2351bee3de8dd7715ee199454a59f1230

Authored by Phillip Lougher
1 parent f1a40359f8

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>

Showing 8 changed files with 184 additions and 51 deletions Side-by-side Diff

fs/squashfs/Makefile
... ... @@ -4,5 +4,5 @@
4 4  
5 5 obj-$(CONFIG_SQUASHFS) += squashfs.o
6 6 squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o
7   -squashfs-y += namei.o super.o symlink.o zlib_wrapper.o
  7 +squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o
... ... @@ -36,6 +36,7 @@
36 36 #include "squashfs_fs_sb.h"
37 37 #include "squashfs_fs_i.h"
38 38 #include "squashfs.h"
  39 +#include "decompressor.h"
39 40  
40 41 /*
41 42 * Read the metadata block length, this is stored in the first two
... ... @@ -151,7 +152,7 @@
151 152 }
152 153  
153 154 if (compressed) {
154   - length = squashfs_zlib_uncompress(msblk, buffer, bh, b, offset,
  155 + length = squashfs_decompress(msblk, buffer, bh, b, offset,
155 156 length, srclength, pages);
156 157 if (length < 0)
157 158 goto read_failure;
fs/squashfs/decompressor.c
  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 +
  39 +static const struct squashfs_decompressor squashfs_unknown_comp_ops = {
  40 + NULL, NULL, NULL, 0, "unknown", 0
  41 +};
  42 +
  43 +static const struct squashfs_decompressor *decompressor[] = {
  44 + &squashfs_zlib_comp_ops,
  45 + &squashfs_unknown_comp_ops
  46 +};
  47 +
  48 +
  49 +const 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 +}
fs/squashfs/decompressor.h
  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 +
  26 +struct 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 +
  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,
  42 + void *s)
  43 +{
  44 + if (msblk->decompressor)
  45 + msblk->decompressor->free(s);
  46 +}
  47 +
  48 +static 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
fs/squashfs/squashfs.h
... ... @@ -51,6 +51,9 @@
51 51 u64, int);
52 52 extern int squashfs_read_table(struct super_block *, void *, u64, int);
53 53  
  54 +/* decompressor.c */
  55 +extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int);
  56 +
54 57 /* export.c */
55 58 extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64,
56 59 unsigned int);
57 60  
... ... @@ -70,14 +73,8 @@
70 73 unsigned int);
71 74 extern int squashfs_read_inode(struct inode *, long long);
72 75  
73   -/* zlib_wrapper.c */
74   -extern void *squashfs_zlib_init(void);
75   -extern void squashfs_zlib_free(void *);
76   -extern 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 80 /* dir.c */
... ... @@ -94,4 +91,7 @@
94 91  
95 92 /* symlink.c */
96 93 extern const struct address_space_operations squashfs_symlink_aops;
  94 +
  95 +/* zlib_wrapper.c */
  96 +extern const struct squashfs_decompressor squashfs_zlib_comp_ops;
fs/squashfs/squashfs_fs_sb.h
... ... @@ -52,26 +52,27 @@
52 52 };
53 53  
54 54 struct squashfs_sb_info {
55   - int devblksize;
56   - int devblksize_log2;
57   - struct squashfs_cache *block_cache;
58   - struct squashfs_cache *fragment_cache;
59   - struct squashfs_cache *read_page;
60   - int next_meta_index;
61   - __le64 *id_table;
62   - __le64 *fragment_index;
63   - unsigned int *fragment_index_2;
64   - struct mutex read_data_mutex;
65   - struct mutex meta_index_mutex;
66   - struct meta_index *meta_index;
67   - void *stream;
68   - __le64 *inode_lookup_table;
69   - u64 inode_table;
70   - u64 directory_table;
71   - unsigned int block_size;
72   - unsigned short block_log;
73   - long long bytes_used;
74   - unsigned int inodes;
  55 + const struct squashfs_decompressor *decompressor;
  56 + int devblksize;
  57 + int devblksize_log2;
  58 + struct squashfs_cache *block_cache;
  59 + struct squashfs_cache *fragment_cache;
  60 + struct squashfs_cache *read_page;
  61 + int next_meta_index;
  62 + __le64 *id_table;
  63 + __le64 *fragment_index;
  64 + unsigned int *fragment_index_2;
  65 + struct mutex read_data_mutex;
  66 + struct mutex meta_index_mutex;
  67 + struct meta_index *meta_index;
  68 + void *stream;
  69 + __le64 *inode_lookup_table;
  70 + u64 inode_table;
  71 + u64 directory_table;
  72 + unsigned int block_size;
  73 + unsigned short block_log;
  74 + long long bytes_used;
  75 + unsigned int inodes;
75 76 };
76 77 #endif
... ... @@ -41,27 +41,35 @@
41 41 #include "squashfs_fs_sb.h"
42 42 #include "squashfs_fs_i.h"
43 43 #include "squashfs.h"
  44 +#include "decompressor.h"
44 45  
45 46 static struct file_system_type squashfs_fs_type;
46 47 static const struct super_operations squashfs_super_ops;
47 48  
48   -static int supported_squashfs_filesystem(short major, short minor, short comp)
  49 +static const struct squashfs_decompressor *supported_squashfs_filesystem(short
  50 + major, short minor, short id)
49 51 {
  52 + const struct squashfs_decompressor *decompressor;
  53 +
50 54 if (major < SQUASHFS_MAJOR) {
51 55 ERROR("Major/Minor mismatch, older Squashfs %d.%d "
52 56 "filesystems are unsupported\n", major, minor);
53   - return -EINVAL;
  57 + return NULL;
54 58 } else if (major > SQUASHFS_MAJOR || minor > SQUASHFS_MINOR) {
55 59 ERROR("Major/Minor mismatch, trying to mount newer "
56 60 "%d.%d filesystem\n", major, minor);
57 61 ERROR("Please update your kernel\n");
58   - return -EINVAL;
  62 + return NULL;
59 63 }
60 64  
61   - if (comp != ZLIB_COMPRESSION)
62   - return -EINVAL;
  65 + decompressor = squashfs_lookup_decompressor(id);
  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 @@
86 94 }
87 95 msblk = sb->s_fs_info;
88 96  
89   - msblk->stream = squashfs_zlib_init();
90   - if (msblk->stream == NULL)
91   - goto failure;
92   -
93 97 sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
94 98 if (sblk == NULL) {
95 99 ERROR("Failed to allocate squashfs_super_block\n");
96 100  
97 101  
98 102  
99 103  
... ... @@ -116,25 +120,25 @@
116 120 goto failed_mount;
117 121 }
118 122  
  123 + err = -EINVAL;
  124 +
119 125 /* Check it is a SQUASHFS superblock */
120 126 sb->s_magic = le32_to_cpu(sblk->s_magic);
121 127 if (sb->s_magic != SQUASHFS_MAGIC) {
122 128 if (!silent)
123 129 ERROR("Can't find a SQUASHFS superblock on %s\n",
124 130 bdevname(sb->s_bdev, b));
125   - err = -EINVAL;
126 131 goto failed_mount;
127 132 }
128 133  
129   - /* Check the MAJOR & MINOR versions and compression type */
130   - err = supported_squashfs_filesystem(le16_to_cpu(sblk->s_major),
  134 + /* Check the MAJOR & MINOR versions and lookup compression type */
  135 + msblk->decompressor = supported_squashfs_filesystem(
  136 + le16_to_cpu(sblk->s_major),
131 137 le16_to_cpu(sblk->s_minor),
132 138 le16_to_cpu(sblk->compression));
133   - if (err < 0)
  139 + if (msblk->decompressor == NULL)
134 140 goto failed_mount;
135 141  
136   - err = -EINVAL;
137   -
138 142 /*
139 143 * Check if there's xattrs in the filesystem. These are not
140 144 * supported in this version, so warn that they will be ignored.
... ... @@ -201,6 +205,10 @@
201 205  
202 206 err = -ENOMEM;
203 207  
  208 + msblk->stream = squashfs_decompressor_init(msblk);
  209 + if (msblk->stream == NULL)
  210 + goto failed_mount;
  211 +
204 212 msblk->block_cache = squashfs_cache_init("metadata",
205 213 SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE);
206 214 if (msblk->block_cache == NULL)
... ... @@ -288,7 +296,7 @@
288 296 squashfs_cache_delete(msblk->block_cache);
289 297 squashfs_cache_delete(msblk->fragment_cache);
290 298 squashfs_cache_delete(msblk->read_page);
291   - squashfs_zlib_free(msblk->stream);
  299 + squashfs_decompressor_free(msblk, msblk->stream);
292 300 kfree(msblk->inode_lookup_table);
293 301 kfree(msblk->fragment_index);
294 302 kfree(msblk->id_table);
... ... @@ -298,7 +306,6 @@
298 306 return err;
299 307  
300 308 failure:
301   - squashfs_zlib_free(msblk->stream);
302 309 kfree(sb->s_fs_info);
303 310 sb->s_fs_info = NULL;
304 311 return -ENOMEM;
... ... @@ -342,7 +349,7 @@
342 349 squashfs_cache_delete(sbi->block_cache);
343 350 squashfs_cache_delete(sbi->fragment_cache);
344 351 squashfs_cache_delete(sbi->read_page);
345   - squashfs_zlib_free(sbi->stream);
  352 + squashfs_decompressor_free(sbi, sbi->stream);
346 353 kfree(sbi->id_table);
347 354 kfree(sbi->fragment_index);
348 355 kfree(sbi->meta_index);
fs/squashfs/zlib_wrapper.c
... ... @@ -30,8 +30,9 @@
30 30 #include "squashfs_fs_sb.h"
31 31 #include "squashfs_fs_i.h"
32 32 #include "squashfs.h"
  33 +#include "decompressor.h"
33 34  
34   -void *squashfs_zlib_init()
  35 +static void *zlib_init(struct squashfs_sb_info *dummy)
35 36 {
36 37 z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL);
37 38 if (stream == NULL)
... ... @@ -50,7 +51,7 @@
50 51 }
51 52  
52 53  
53   -void squashfs_zlib_free(void *strm)
  54 +static void zlib_free(void *strm)
54 55 {
55 56 z_stream *stream = strm;
56 57  
... ... @@ -60,7 +61,7 @@
60 61 }
61 62  
62 63  
63   -int squashfs_zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
  64 +static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
64 65 struct buffer_head **bh, int b, int offset, int length, int srclength,
65 66 int pages)
66 67 {
... ... @@ -137,4 +138,13 @@
137 138  
138 139 return -EIO;
139 140 }
  141 +
  142 +const 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 +};