diff --git a/fs/squashfs/decompressor.c b/fs/squashfs/decompressor.c index a5940e54c4dd..e921bd213738 100644 --- a/fs/squashfs/decompressor.c +++ b/fs/squashfs/decompressor.c @@ -23,6 +23,7 @@ #include #include +#include #include #include "squashfs_fs.h" @@ -74,3 +75,36 @@ const struct squashfs_decompressor *squashfs_lookup_decompressor(int id) return decompressor[i]; } + + +void *squashfs_decompressor_init(struct super_block *sb, unsigned short flags) +{ + struct squashfs_sb_info *msblk = sb->s_fs_info; + void *strm, *buffer = NULL; + int length = 0; + + /* + * Read decompressor specific options from file system if present + */ + if (SQUASHFS_COMP_OPTS(flags)) { + buffer = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL); + if (buffer == NULL) + return ERR_PTR(-ENOMEM); + + length = squashfs_read_data(sb, &buffer, + sizeof(struct squashfs_super_block), 0, NULL, + PAGE_CACHE_SIZE, 1); + + if (length < 0) { + strm = ERR_PTR(length); + goto finished; + } + } + + strm = msblk->decompressor->init(msblk, buffer, length); + +finished: + kfree(buffer); + + return strm; +} diff --git a/fs/squashfs/decompressor.h b/fs/squashfs/decompressor.h index 3b305a70f7aa..099745ad5691 100644 --- a/fs/squashfs/decompressor.h +++ b/fs/squashfs/decompressor.h @@ -24,7 +24,7 @@ */ struct squashfs_decompressor { - void *(*init)(struct squashfs_sb_info *); + void *(*init)(struct squashfs_sb_info *, void *, int); void (*free)(void *); int (*decompress)(struct squashfs_sb_info *, void **, struct buffer_head **, int, int, int, int, int); @@ -33,11 +33,6 @@ struct squashfs_decompressor { 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) { diff --git a/fs/squashfs/lzo_wrapper.c b/fs/squashfs/lzo_wrapper.c index 7da759e34c52..00f4dfc5f088 100644 --- a/fs/squashfs/lzo_wrapper.c +++ b/fs/squashfs/lzo_wrapper.c @@ -37,7 +37,7 @@ struct squashfs_lzo { void *output; }; -static void *lzo_init(struct squashfs_sb_info *msblk) +static void *lzo_init(struct squashfs_sb_info *msblk, void *buff, int len) { int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); @@ -58,7 +58,7 @@ failed2: failed: ERROR("Failed to allocate lzo workspace\n"); kfree(stream); - return NULL; + return ERR_PTR(-ENOMEM); } diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index ba729d808876..1f2e608b8785 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h @@ -48,6 +48,7 @@ extern int squashfs_read_table(struct super_block *, void *, u64, int); /* decompressor.c */ extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int); +extern void *squashfs_decompressor_init(struct super_block *, unsigned short); /* export.c */ extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h index 39533feffd6d..4582c568ef4d 100644 --- a/fs/squashfs/squashfs_fs.h +++ b/fs/squashfs/squashfs_fs.h @@ -57,6 +57,7 @@ #define SQUASHFS_ALWAYS_FRAG 5 #define SQUASHFS_DUPLICATE 6 #define SQUASHFS_EXPORT 7 +#define SQUASHFS_COMP_OPT 10 #define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1) @@ -81,6 +82,9 @@ #define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \ SQUASHFS_EXPORT) +#define SQUASHFS_COMP_OPTS(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_COMP_OPT) + /* Max number of types and file types */ #define SQUASHFS_DIR_TYPE 1 #define SQUASHFS_REG_TYPE 2 diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 20700b9f2b4c..95467db71a8e 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -199,10 +199,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) 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) @@ -215,6 +211,13 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) goto failed_mount; } + msblk->stream = squashfs_decompressor_init(sb, flags); + if (IS_ERR(msblk->stream)) { + err = PTR_ERR(msblk->stream); + msblk->stream = NULL; + goto failed_mount; + } + /* Allocate and read id index table */ msblk->id_table = squashfs_read_id_index_table(sb, le64_to_cpu(sblk->id_table_start), le16_to_cpu(sblk->no_ids)); diff --git a/fs/squashfs/xz_wrapper.c b/fs/squashfs/xz_wrapper.c index c4eb40018256..397adea72eb9 100644 --- a/fs/squashfs/xz_wrapper.c +++ b/fs/squashfs/xz_wrapper.c @@ -38,7 +38,8 @@ struct squashfs_xz { struct xz_buf buf; }; -static void *squashfs_xz_init(struct squashfs_sb_info *msblk) +static void *squashfs_xz_init(struct squashfs_sb_info *msblk, void *buff, + int len) { int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); @@ -55,7 +56,7 @@ static void *squashfs_xz_init(struct squashfs_sb_info *msblk) failed: ERROR("Failed to allocate xz workspace\n"); kfree(stream); - return NULL; + return ERR_PTR(-ENOMEM); } diff --git a/fs/squashfs/zlib_wrapper.c b/fs/squashfs/zlib_wrapper.c index 4661ae2b1cec..195b0d035e9b 100644 --- a/fs/squashfs/zlib_wrapper.c +++ b/fs/squashfs/zlib_wrapper.c @@ -32,7 +32,7 @@ #include "squashfs.h" #include "decompressor.h" -static void *zlib_init(struct squashfs_sb_info *dummy) +static void *zlib_init(struct squashfs_sb_info *dummy, void *buff, int len) { z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL); if (stream == NULL) @@ -47,7 +47,7 @@ static void *zlib_init(struct squashfs_sb_info *dummy) failed: ERROR("Failed to allocate zlib workspace\n"); kfree(stream); - return NULL; + return ERR_PTR(-ENOMEM); }