Squashfs: add a decompressor framework
authorPhillip Lougher <phillip@lougher.demon.co.uk>
Tue, 6 Oct 2009 03:04:15 +0000 (04:04 +0100)
committerPhillip Lougher <phillip@lougher.demon.co.uk>
Wed, 20 Jan 2010 21:47:47 +0000 (21:47 +0000)
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>
fs/squashfs/Makefile
fs/squashfs/block.c
fs/squashfs/decompressor.c [new file with mode: 0644]
fs/squashfs/decompressor.h [new file with mode: 0644]
fs/squashfs/squashfs.h
fs/squashfs/squashfs_fs_sb.h
fs/squashfs/super.c
fs/squashfs/zlib_wrapper.c

index a397e6f..df8a19e 100644 (file)
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_SQUASHFS) += squashfs.o
 squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o
-squashfs-y += namei.o super.o symlink.o zlib_wrapper.o
+squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o
index 3f836e1..1cb0d81 100644 (file)
@@ -36,6 +36,7 @@
 #include "squashfs_fs_sb.h"
 #include "squashfs_fs_i.h"
 #include "squashfs.h"
+#include "decompressor.h"
 
 /*
  * 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,
        }
 
        if (compressed) {
-               length = squashfs_zlib_uncompress(msblk, buffer, bh, b, offset,
+               length = squashfs_decompress(msblk, buffer, bh, b, offset,
                         length, srclength, pages);
                if (length < 0)
                        goto read_failure;
diff --git a/fs/squashfs/decompressor.c b/fs/squashfs/decompressor.c
new file mode 100644 (file)
index 0000000..0072ccd
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ * Phillip Lougher <phillip@lougher.demon.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * decompressor.c
+ */
+
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/buffer_head.h>
+
+#include "squashfs_fs.h"
+#include "squashfs_fs_sb.h"
+#include "squashfs_fs_i.h"
+#include "decompressor.h"
+#include "squashfs.h"
+
+/*
+ * This file (and decompressor.h) implements a decompressor framework for
+ * Squashfs, allowing multiple decompressors to be easily supported
+ */
+
+static const struct squashfs_decompressor squashfs_unknown_comp_ops = {
+       NULL, NULL, NULL, 0, "unknown", 0
+};
+
+static const struct squashfs_decompressor *decompressor[] = {
+       &squashfs_zlib_comp_ops,
+       &squashfs_unknown_comp_ops
+};
+
+
+const struct squashfs_decompressor *squashfs_lookup_decompressor(int id)
+{
+       int i;
+
+       for (i = 0; decompressor[i]->id; i++)
+               if (id == decompressor[i]->id)
+                       break;
+
+       return decompressor[i];
+}
diff --git a/fs/squashfs/decompressor.h b/fs/squashfs/decompressor.h
new file mode 100644 (file)
index 0000000..7425f80
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef DECOMPRESSOR_H
+#define DECOMPRESSOR_H
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ * Phillip Lougher <phillip@lougher.demon.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * decompressor.h
+ */
+
+struct squashfs_decompressor {
+       void    *(*init)(struct squashfs_sb_info *);
+       void    (*free)(void *);
+       int     (*decompress)(struct squashfs_sb_info *, void **,
+               struct buffer_head **, int, int, int, int, int);
+       int     id;
+       char    *name;
+       int     supported;
+};
+
+static inline void *squashfs_decompressor_init(struct squashfs_sb_info *msblk)
+{
+       return msblk->decompressor->init(msblk);
+}
+
+static inline void squashfs_decompressor_free(struct squashfs_sb_info *msblk,
+       void *s)
+{
+       if (msblk->decompressor)
+               msblk->decompressor->free(s);
+}
+
+static inline int squashfs_decompress(struct squashfs_sb_info *msblk,
+       void **buffer, struct buffer_head **bh, int b, int offset, int length,
+       int srclength, int pages)
+{
+       return msblk->decompressor->decompress(msblk, buffer, bh, b, offset,
+               length, srclength, pages);
+}
+#endif
index 9c2f76a..fe2587a 100644 (file)
@@ -51,6 +51,9 @@ extern struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *,
                                u64, int);
 extern int squashfs_read_table(struct super_block *, void *, u64, int);
 
+/* decompressor.c */
+extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int);
+
 /* export.c */
 extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64,
                                unsigned int);
@@ -70,14 +73,8 @@ extern struct inode *squashfs_iget(struct super_block *, long long,
                                unsigned int);
 extern int squashfs_read_inode(struct inode *, long long);
 
-/* zlib_wrapper.c */
-extern void *squashfs_zlib_init(void);
-extern void squashfs_zlib_free(void *);
-extern int squashfs_zlib_uncompress(struct squashfs_sb_info *, void **,
-                               struct buffer_head **, int, int, int, int, int);
-
 /*
- * Inodes and files operations
+ * Inodes, files and decompressor operations
  */
 
 /* dir.c */
@@ -94,3 +91,6 @@ extern const struct inode_operations squashfs_dir_inode_ops;
 
 /* symlink.c */
 extern const struct address_space_operations squashfs_symlink_aops;
+
+/* zlib_wrapper.c */
+extern const struct squashfs_decompressor squashfs_zlib_comp_ops;
index 23a67fa..7533350 100644 (file)
@@ -52,25 +52,26 @@ struct squashfs_cache_entry {
 };
 
 struct squashfs_sb_info {
-       int                     devblksize;
-       int                     devblksize_log2;
-       struct squashfs_cache   *block_cache;
-       struct squashfs_cache   *fragment_cache;
-       struct squashfs_cache   *read_page;
-       int                     next_meta_index;
-       __le64                  *id_table;
-       __le64                  *fragment_index;
-       unsigned int            *fragment_index_2;
-       struct mutex            read_data_mutex;
-       struct mutex            meta_index_mutex;
-       struct meta_index       *meta_index;
-       void                    *stream;
-       __le64                  *inode_lookup_table;
-       u64                     inode_table;
-       u64                     directory_table;
-       unsigned int            block_size;
-       unsigned short          block_log;
-       long long               bytes_used;
-       unsigned int            inodes;
+       const struct squashfs_decompressor      *decompressor;
+       int                                     devblksize;
+       int                                     devblksize_log2;
+       struct squashfs_cache                   *block_cache;
+       struct squashfs_cache                   *fragment_cache;
+       struct squashfs_cache                   *read_page;
+       int                                     next_meta_index;
+       __le64                                  *id_table;
+       __le64                                  *fragment_index;
+       unsigned int                            *fragment_index_2;
+       struct mutex                            read_data_mutex;
+       struct mutex                            meta_index_mutex;
+       struct meta_index                       *meta_index;
+       void                                    *stream;
+       __le64                                  *inode_lookup_table;
+       u64                                     inode_table;
+       u64                                     directory_table;
+       unsigned int                            block_size;
+       unsigned short                          block_log;
+       long long                               bytes_used;
+       unsigned int                            inodes;
 };
 #endif
index b9f8c6a..3550aec 100644 (file)
 #include "squashfs_fs_sb.h"
 #include "squashfs_fs_i.h"
 #include "squashfs.h"
+#include "decompressor.h"
 
 static struct file_system_type squashfs_fs_type;
 static const struct super_operations squashfs_super_ops;
 
-static int supported_squashfs_filesystem(short major, short minor, short comp)
+static const struct squashfs_decompressor *supported_squashfs_filesystem(short
+       major, short minor, short id)
 {
+       const struct squashfs_decompressor *decompressor;
+
        if (major < SQUASHFS_MAJOR) {
                ERROR("Major/Minor mismatch, older Squashfs %d.%d "
                        "filesystems are unsupported\n", major, minor);
-               return -EINVAL;
+               return NULL;
        } else if (major > SQUASHFS_MAJOR || minor > SQUASHFS_MINOR) {
                ERROR("Major/Minor mismatch, trying to mount newer "
                        "%d.%d filesystem\n", major, minor);
                ERROR("Please update your kernel\n");
-               return -EINVAL;
+               return NULL;
        }
 
-       if (comp != ZLIB_COMPRESSION)
-               return -EINVAL;
+       decompressor = squashfs_lookup_decompressor(id);
+       if (!decompressor->supported) {
+               ERROR("Filesystem uses \"%s\" compression. This is not "
+                       "supported\n", decompressor->name);
+               return NULL;
+       }
 
-       return 0;
+       return decompressor;
 }
 
 
@@ -86,10 +94,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
        }
        msblk = sb->s_fs_info;
 
-       msblk->stream = squashfs_zlib_init();
-       if (msblk->stream == NULL)
-               goto failure;
-
        sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
        if (sblk == NULL) {
                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)
                goto failed_mount;
        }
 
+       err = -EINVAL;
+
        /* Check it is a SQUASHFS superblock */
        sb->s_magic = le32_to_cpu(sblk->s_magic);
        if (sb->s_magic != SQUASHFS_MAGIC) {
                if (!silent)
                        ERROR("Can't find a SQUASHFS superblock on %s\n",
                                                bdevname(sb->s_bdev, b));
-               err = -EINVAL;
                goto failed_mount;
        }
 
-       /* Check the MAJOR & MINOR versions and compression type */
-       err = supported_squashfs_filesystem(le16_to_cpu(sblk->s_major),
+       /* Check the MAJOR & MINOR versions and lookup compression type */
+       msblk->decompressor = supported_squashfs_filesystem(
+                       le16_to_cpu(sblk->s_major),
                        le16_to_cpu(sblk->s_minor),
                        le16_to_cpu(sblk->compression));
-       if (err < 0)
+       if (msblk->decompressor == NULL)
                goto failed_mount;
 
-       err = -EINVAL;
-
        /*
         * Check if there's xattrs in the filesystem.  These are not
         * 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)
 
        err = -ENOMEM;
 
+       msblk->stream = squashfs_decompressor_init(msblk);
+       if (msblk->stream == NULL)
+               goto failed_mount;
+
        msblk->block_cache = squashfs_cache_init("metadata",
                        SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE);
        if (msblk->block_cache == NULL)
@@ -288,7 +296,7 @@ failed_mount:
        squashfs_cache_delete(msblk->block_cache);
        squashfs_cache_delete(msblk->fragment_cache);
        squashfs_cache_delete(msblk->read_page);
-       squashfs_zlib_free(msblk->stream);
+       squashfs_decompressor_free(msblk, msblk->stream);
        kfree(msblk->inode_lookup_table);
        kfree(msblk->fragment_index);
        kfree(msblk->id_table);
@@ -298,7 +306,6 @@ failed_mount:
        return err;
 
 failure:
-       squashfs_zlib_free(msblk->stream);
        kfree(sb->s_fs_info);
        sb->s_fs_info = NULL;
        return -ENOMEM;
@@ -342,7 +349,7 @@ static void squashfs_put_super(struct super_block *sb)
                squashfs_cache_delete(sbi->block_cache);
                squashfs_cache_delete(sbi->fragment_cache);
                squashfs_cache_delete(sbi->read_page);
-               squashfs_zlib_free(sbi->stream);
+               squashfs_decompressor_free(sbi, sbi->stream);
                kfree(sbi->id_table);
                kfree(sbi->fragment_index);
                kfree(sbi->meta_index);
index c814594..4dd70e0 100644 (file)
@@ -30,8 +30,9 @@
 #include "squashfs_fs_sb.h"
 #include "squashfs_fs_i.h"
 #include "squashfs.h"
+#include "decompressor.h"
 
-void *squashfs_zlib_init()
+static void *zlib_init(struct squashfs_sb_info *dummy)
 {
        z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL);
        if (stream == NULL)
@@ -50,7 +51,7 @@ failed:
 }
 
 
-void squashfs_zlib_free(void *strm)
+static void zlib_free(void *strm)
 {
        z_stream *stream = strm;
 
@@ -60,7 +61,7 @@ void squashfs_zlib_free(void *strm)
 }
 
 
-int squashfs_zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
+static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
        struct buffer_head **bh, int b, int offset, int length, int srclength,
        int pages)
 {
@@ -137,3 +138,13 @@ release_mutex:
 
        return -EIO;
 }
+
+const struct squashfs_decompressor squashfs_zlib_comp_ops = {
+       .init = zlib_init,
+       .free = zlib_free,
+       .decompress = zlib_uncompress,
+       .id = ZLIB_COMPRESSION,
+       .name = "zlib",
+       .supported = 1
+};
+