--- /dev/null
+diff --git a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig
+index 25a00d1..7ec5d7e 100644
+--- a/fs/squashfs/Kconfig
++++ b/fs/squashfs/Kconfig
+@@ -26,6 +26,12 @@ config SQUASHFS
+
+ If unsure, say N.
+
++config SQUASHFS_LZMA
++ bool "Include support for LZMA compressed file systems"
++ depends on SQUASHFS
++ select DECOMPRESS_LZMA
++ select DECOMPRESS_LZMA_NEEDED
++
+ config SQUASHFS_EMBEDDED
+
+ bool "Additional option for memory-constrained systems"
+diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile
+index 70e3244..45aaefd 100644
+--- a/fs/squashfs/Makefile
++++ b/fs/squashfs/Makefile
+@@ -4,4 +4,5 @@
+
+ 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
++squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o
++squashfs-$(CONFIG_SQUASHFS_LZMA) += lzma_wrapper.o
+diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c
+index 2a79603..6f9914d 100644
+--- a/fs/squashfs/block.c
++++ b/fs/squashfs/block.c
+@@ -29,16 +29,14 @@
+ #include <linux/fs.h>
+ #include <linux/vfs.h>
+ #include <linux/slab.h>
+-#include <linux/mutex.h>
+ #include <linux/string.h>
+ #include <linux/buffer_head.h>
+-#include <linux/zlib.h>
+
+ #include "squashfs_fs.h"
+ #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
+ * bytes of the metadata block.
+@@ -153,72 +151,10 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
+ }
+
+ if (compressed) {
+- int zlib_err = 0, zlib_init = 0;
+-
+- /*
+- * Uncompress block.
+- */
+-
+- mutex_lock(&msblk->read_data_mutex);
+-
+- msblk->stream.avail_out = 0;
+- msblk->stream.avail_in = 0;
+-
+- bytes = length;
+- do {
+- if (msblk->stream.avail_in == 0 && k < b) {
+- avail = min(bytes, msblk->devblksize - offset);
+- bytes -= avail;
+- wait_on_buffer(bh[k]);
+- if (!buffer_uptodate(bh[k]))
+- goto release_mutex;
+-
+- if (avail == 0) {
+- offset = 0;
+- put_bh(bh[k++]);
+- continue;
+- }
+-
+- msblk->stream.next_in = bh[k]->b_data + offset;
+- msblk->stream.avail_in = avail;
+- offset = 0;
+- }
+-
+- if (msblk->stream.avail_out == 0 && page < pages) {
+- msblk->stream.next_out = buffer[page++];
+- msblk->stream.avail_out = PAGE_CACHE_SIZE;
+- }
+-
+- if (!zlib_init) {
+- zlib_err = zlib_inflateInit(&msblk->stream);
+- if (zlib_err != Z_OK) {
+- ERROR("zlib_inflateInit returned"
+- " unexpected result 0x%x,"
+- " srclength %d\n", zlib_err,
+- srclength);
+- goto release_mutex;
+- }
+- zlib_init = 1;
+- }
+-
+- zlib_err = zlib_inflate(&msblk->stream, Z_SYNC_FLUSH);
+-
+- if (msblk->stream.avail_in == 0 && k < b)
+- put_bh(bh[k++]);
+- } while (zlib_err == Z_OK);
+-
+- if (zlib_err != Z_STREAM_END) {
+- ERROR("zlib_inflate error, data probably corrupt\n");
+- goto release_mutex;
+- }
+-
+- zlib_err = zlib_inflateEnd(&msblk->stream);
+- if (zlib_err != Z_OK) {
+- ERROR("zlib_inflate error, data probably corrupt\n");
+- goto release_mutex;
+- }
+- length = msblk->stream.total_out;
+- mutex_unlock(&msblk->read_data_mutex);
++ length = squashfs_decompress(msblk, buffer, bh, b, offset,
++ length, srclength, pages);
++ if (length < 0)
++ goto read_failure;
+ } else {
+ /*
+ * Block is uncompressed.
+@@ -255,9 +191,6 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
+ kfree(bh);
+ return length;
+
+-release_mutex:
+- mutex_unlock(&msblk->read_data_mutex);
+-
+ block_release:
+ for (; k < b; k++)
+ put_bh(bh[k]);
+diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c
+index 40c98fa..57314be 100644
+--- a/fs/squashfs/cache.c
++++ b/fs/squashfs/cache.c
+@@ -51,7 +51,6 @@
+ #include <linux/sched.h>
+ #include <linux/spinlock.h>
+ #include <linux/wait.h>
+-#include <linux/zlib.h>
+ #include <linux/pagemap.h>
+
+ #include "squashfs_fs.h"
+diff --git a/fs/squashfs/decompressor.c b/fs/squashfs/decompressor.c
+new file mode 100644
+index 0000000..0b6ad9b
+--- /dev/null
++++ b/fs/squashfs/decompressor.c
+@@ -0,0 +1,72 @@
++/*
++ * 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_lzma_unsupported_comp_ops = {
++ NULL, NULL, NULL, LZMA_COMPRESSION, "lzma", 0
++};
++
++static const struct squashfs_decompressor squashfs_lzo_unsupported_comp_ops = {
++ NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0
++};
++
++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,
++#ifdef CONFIG_SQUASHFS_LZMA
++ &squashfs_lzma_comp_ops,
++#else
++ &squashfs_lzma_unsupported_comp_ops,
++#endif
++ &squashfs_lzo_unsupported_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
+index 0000000..7425f80
+--- /dev/null
++++ b/fs/squashfs/decompressor.h
+@@ -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
+diff --git a/fs/squashfs/dir.c b/fs/squashfs/dir.c
+index 566b0ea..12b933a 100644
+--- a/fs/squashfs/dir.c
++++ b/fs/squashfs/dir.c
+@@ -30,7 +30,6 @@
+ #include <linux/fs.h>
+ #include <linux/vfs.h>
+ #include <linux/slab.h>
+-#include <linux/zlib.h>
+
+ #include "squashfs_fs.h"
+ #include "squashfs_fs_sb.h"
+diff --git a/fs/squashfs/export.c b/fs/squashfs/export.c
+index 2b1b8fe..7f93d5a 100644
+--- a/fs/squashfs/export.c
++++ b/fs/squashfs/export.c
+@@ -39,7 +39,6 @@
+ #include <linux/vfs.h>
+ #include <linux/dcache.h>
+ #include <linux/exportfs.h>
+-#include <linux/zlib.h>
+ #include <linux/slab.h>
+
+ #include "squashfs_fs.h"
+diff --git a/fs/squashfs/file.c b/fs/squashfs/file.c
+index 717767d..a25c506 100644
+--- a/fs/squashfs/file.c
++++ b/fs/squashfs/file.c
+@@ -47,7 +47,6 @@
+ #include <linux/string.h>
+ #include <linux/pagemap.h>
+ #include <linux/mutex.h>
+-#include <linux/zlib.h>
+
+ #include "squashfs_fs.h"
+ #include "squashfs_fs_sb.h"
+diff --git a/fs/squashfs/fragment.c b/fs/squashfs/fragment.c
+index b5a2c15..7c90bbd 100644
+--- a/fs/squashfs/fragment.c
++++ b/fs/squashfs/fragment.c
+@@ -36,7 +36,6 @@
+ #include <linux/fs.h>
+ #include <linux/vfs.h>
+ #include <linux/slab.h>
+-#include <linux/zlib.h>
+
+ #include "squashfs_fs.h"
+ #include "squashfs_fs_sb.h"
+diff --git a/fs/squashfs/id.c b/fs/squashfs/id.c
+index 3795b83..b7f64bc 100644
+--- a/fs/squashfs/id.c
++++ b/fs/squashfs/id.c
+@@ -34,7 +34,6 @@
+ #include <linux/fs.h>
+ #include <linux/vfs.h>
+ #include <linux/slab.h>
+-#include <linux/zlib.h>
+
+ #include "squashfs_fs.h"
+ #include "squashfs_fs_sb.h"
+diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c
+index 9101dbd..49daaf6 100644
+--- a/fs/squashfs/inode.c
++++ b/fs/squashfs/inode.c
+@@ -40,7 +40,6 @@
+
+ #include <linux/fs.h>
+ #include <linux/vfs.h>
+-#include <linux/zlib.h>
+
+ #include "squashfs_fs.h"
+ #include "squashfs_fs_sb.h"
+diff --git a/fs/squashfs/lzma_wrapper.c b/fs/squashfs/lzma_wrapper.c
+new file mode 100644
+index 0000000..9fa617d
+--- /dev/null
++++ b/fs/squashfs/lzma_wrapper.c
+@@ -0,0 +1,151 @@
++/*
++ * 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.
++ *
++ * lzma_wrapper.c
++ */
++
++#include <asm/unaligned.h>
++#include <linux/buffer_head.h>
++#include <linux/mutex.h>
++#include <linux/vmalloc.h>
++#include <linux/decompress/unlzma.h>
++
++#include "squashfs_fs.h"
++#include "squashfs_fs_sb.h"
++#include "squashfs_fs_i.h"
++#include "squashfs.h"
++#include "decompressor.h"
++
++struct squashfs_lzma {
++ void *input;
++ void *output;
++};
++
++/* decompress_unlzma.c is currently non re-entrant... */
++DEFINE_MUTEX(lzma_mutex);
++
++/* decompress_unlzma.c doesn't provide any context in its callbacks... */
++static int lzma_error;
++
++static void error(char *m)
++{
++ ERROR("unlzma error: %s\n", m);
++ lzma_error = 1;
++}
++
++
++static void *lzma_init(struct squashfs_sb_info *msblk)
++{
++ struct squashfs_lzma *stream = kzalloc(sizeof(*stream), GFP_KERNEL);
++ if (stream == NULL)
++ goto failed;
++ stream->input = vmalloc(msblk->block_size);
++ if (stream->input == NULL)
++ goto failed;
++ stream->output = vmalloc(msblk->block_size);
++ if (stream->output == NULL)
++ goto failed2;
++
++ return stream;
++
++failed2:
++ vfree(stream->input);
++failed:
++ ERROR("failed to allocate lzma workspace\n");
++ kfree(stream);
++ return NULL;
++}
++
++
++static void lzma_free(void *strm)
++{
++ struct squashfs_lzma *stream = strm;
++
++ if (stream) {
++ vfree(stream->input);
++ vfree(stream->output);
++ }
++ kfree(stream);
++}
++
++
++static int lzma_uncompress(struct squashfs_sb_info *msblk, void **buffer,
++ struct buffer_head **bh, int b, int offset, int length, int srclength,
++ int pages)
++{
++ struct squashfs_lzma *stream = msblk->stream;
++ void *buff = stream->input;
++ int avail, i, bytes = length, res;
++
++ mutex_lock(&lzma_mutex);
++
++ for (i = 0; i < b; i++) {
++ wait_on_buffer(bh[i]);
++ if (!buffer_uptodate(bh[i]))
++ goto block_release;
++
++ avail = min(bytes, msblk->devblksize - offset);
++ memcpy(buff, bh[i]->b_data + offset, avail);
++ buff += avail;
++ bytes -= avail;
++ offset = 0;
++ put_bh(bh[i]);
++ }
++
++ lzma_error = 0;
++ res = unlzma(stream->input, length, NULL, NULL, stream->output, NULL,
++ error);
++ if (res || lzma_error)
++ goto failed;
++
++ /* uncompressed size is stored in the LZMA header (5 byte offset) */
++ res = bytes = get_unaligned_le32(stream->input + 5);
++ for (i = 0, buff = stream->output; bytes && i < pages; i++) {
++ avail = min_t(int, bytes, PAGE_CACHE_SIZE);
++ memcpy(buffer[i], buff, avail);
++ buff += avail;
++ bytes -= avail;
++ }
++ if (bytes)
++ goto failed;
++
++ mutex_unlock(&lzma_mutex);
++ return res;
++
++block_release:
++ for (; i < b; i++)
++ put_bh(bh[i]);
++
++failed:
++ mutex_unlock(&lzma_mutex);
++
++ ERROR("lzma decompression failed, data probably corrupt\n");
++ return -EIO;
++}
++
++const struct squashfs_decompressor squashfs_lzma_comp_ops = {
++ .init = lzma_init,
++ .free = lzma_free,
++ .decompress = lzma_uncompress,
++ .id = LZMA_COMPRESSION,
++ .name = "lzma",
++ .supported = 1
++};
++
+diff --git a/fs/squashfs/namei.c b/fs/squashfs/namei.c
+index 9e39865..5266bd8 100644
+--- a/fs/squashfs/namei.c
++++ b/fs/squashfs/namei.c
+@@ -57,7 +57,6 @@
+ #include <linux/slab.h>
+ #include <linux/string.h>
+ #include <linux/dcache.h>
+-#include <linux/zlib.h>
+
+ #include "squashfs_fs.h"
+ #include "squashfs_fs_sb.h"
+diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h
+index 0e9feb6..d094886 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 *,
+ 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);
+@@ -71,7 +74,7 @@ extern struct inode *squashfs_iget(struct super_block *, long long,
+ extern int squashfs_read_inode(struct inode *, long long);
+
+ /*
+- * Inodes and files operations
++ * Inodes, files and decompressor operations
+ */
+
+ /* dir.c */
+@@ -88,3 +91,9 @@ 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;
++
++/* lzma wrapper.c */
++extern const struct squashfs_decompressor squashfs_lzma_comp_ops;
+diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h
+index 283daaf..36e1604 100644
+--- a/fs/squashfs/squashfs_fs.h
++++ b/fs/squashfs/squashfs_fs.h
+@@ -211,7 +211,9 @@ struct meta_index {
+ /*
+ * definitions for structures on disk
+ */
+-#define ZLIB_COMPRESSION 1
++#define ZLIB_COMPRESSION 1
++#define LZMA_COMPRESSION 2
++#define LZO_COMPRESSION 3
+
+ struct squashfs_super_block {
+ __le32 s_magic;
+diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h
+index c8c6561..7533350 100644
+--- a/fs/squashfs/squashfs_fs_sb.h
++++ b/fs/squashfs/squashfs_fs_sb.h
+@@ -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;
+- z_stream 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
+diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c
+index 6c197ef..3550aec 100644
+--- a/fs/squashfs/super.c
++++ b/fs/squashfs/super.c
+@@ -35,34 +35,41 @@
+ #include <linux/pagemap.h>
+ #include <linux/init.h>
+ #include <linux/module.h>
+-#include <linux/zlib.h>
+ #include <linux/magic.h>
+
+ #include "squashfs_fs.h"
+ #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;
+ }
+
+
+@@ -87,13 +94,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
+ }
+ msblk = sb->s_fs_info;
+
+- msblk->stream.workspace = kmalloc(zlib_inflate_workspacesize(),
+- GFP_KERNEL);
+- if (msblk->stream.workspace == NULL) {
+- ERROR("Failed to allocate zlib workspace\n");
+- goto failure;
+- }
+-
+ sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
+ if (sblk == NULL) {
+ ERROR("Failed to allocate squashfs_super_block\n");
+@@ -120,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.
+@@ -205,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)
+@@ -292,17 +296,16 @@ failed_mount:
+ squashfs_cache_delete(msblk->block_cache);
+ squashfs_cache_delete(msblk->fragment_cache);
+ squashfs_cache_delete(msblk->read_page);
++ squashfs_decompressor_free(msblk, msblk->stream);
+ kfree(msblk->inode_lookup_table);
+ kfree(msblk->fragment_index);
+ kfree(msblk->id_table);
+- kfree(msblk->stream.workspace);
+ kfree(sb->s_fs_info);
+ sb->s_fs_info = NULL;
+ kfree(sblk);
+ return err;
+
+ failure:
+- kfree(msblk->stream.workspace);
+ kfree(sb->s_fs_info);
+ sb->s_fs_info = NULL;
+ return -ENOMEM;
+@@ -346,10 +349,10 @@ 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_decompressor_free(sbi, sbi->stream);
+ kfree(sbi->id_table);
+ kfree(sbi->fragment_index);
+ kfree(sbi->meta_index);
+- kfree(sbi->stream.workspace);
+ kfree(sb->s_fs_info);
+ sb->s_fs_info = NULL;
+ }
+diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c
+index 83d8788..e80be20 100644
+--- a/fs/squashfs/symlink.c
++++ b/fs/squashfs/symlink.c
+@@ -36,7 +36,6 @@
+ #include <linux/slab.h>
+ #include <linux/string.h>
+ #include <linux/pagemap.h>
+-#include <linux/zlib.h>
+
+ #include "squashfs_fs.h"
+ #include "squashfs_fs_sb.h"
+diff --git a/fs/squashfs/zlib_wrapper.c b/fs/squashfs/zlib_wrapper.c
+new file mode 100644
+index 0000000..4dd70e0
+--- /dev/null
++++ b/fs/squashfs/zlib_wrapper.c
+@@ -0,0 +1,150 @@
++/*
++ * 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.
++ *
++ * zlib_wrapper.c
++ */
++
++
++#include <linux/mutex.h>
++#include <linux/buffer_head.h>
++#include <linux/zlib.h>
++
++#include "squashfs_fs.h"
++#include "squashfs_fs_sb.h"
++#include "squashfs_fs_i.h"
++#include "squashfs.h"
++#include "decompressor.h"
++
++static void *zlib_init(struct squashfs_sb_info *dummy)
++{
++ z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL);
++ if (stream == NULL)
++ goto failed;
++ stream->workspace = kmalloc(zlib_inflate_workspacesize(),
++ GFP_KERNEL);
++ if (stream->workspace == NULL)
++ goto failed;
++
++ return stream;
++
++failed:
++ ERROR("Failed to allocate zlib workspace\n");
++ kfree(stream);
++ return NULL;
++}
++
++
++static void zlib_free(void *strm)
++{
++ z_stream *stream = strm;
++
++ if (stream)
++ kfree(stream->workspace);
++ kfree(stream);
++}
++
++
++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)
++{
++ int zlib_err = 0, zlib_init = 0;
++ int avail, bytes, k = 0, page = 0;
++ z_stream *stream = msblk->stream;
++
++ mutex_lock(&msblk->read_data_mutex);
++
++ stream->avail_out = 0;
++ stream->avail_in = 0;
++
++ bytes = length;
++ do {
++ if (stream->avail_in == 0 && k < b) {
++ avail = min(bytes, msblk->devblksize - offset);
++ bytes -= avail;
++ wait_on_buffer(bh[k]);
++ if (!buffer_uptodate(bh[k]))
++ goto release_mutex;
++
++ if (avail == 0) {
++ offset = 0;
++ put_bh(bh[k++]);
++ continue;
++ }
++
++ stream->next_in = bh[k]->b_data + offset;
++ stream->avail_in = avail;
++ offset = 0;
++ }
++
++ if (stream->avail_out == 0 && page < pages) {
++ stream->next_out = buffer[page++];
++ stream->avail_out = PAGE_CACHE_SIZE;
++ }
++
++ if (!zlib_init) {
++ zlib_err = zlib_inflateInit(stream);
++ if (zlib_err != Z_OK) {
++ ERROR("zlib_inflateInit returned unexpected "
++ "result 0x%x, srclength %d\n",
++ zlib_err, srclength);
++ goto release_mutex;
++ }
++ zlib_init = 1;
++ }
++
++ zlib_err = zlib_inflate(stream, Z_SYNC_FLUSH);
++
++ if (stream->avail_in == 0 && k < b)
++ put_bh(bh[k++]);
++ } while (zlib_err == Z_OK);
++
++ if (zlib_err != Z_STREAM_END) {
++ ERROR("zlib_inflate error, data probably corrupt\n");
++ goto release_mutex;
++ }
++
++ zlib_err = zlib_inflateEnd(stream);
++ if (zlib_err != Z_OK) {
++ ERROR("zlib_inflate error, data probably corrupt\n");
++ goto release_mutex;
++ }
++
++ mutex_unlock(&msblk->read_data_mutex);
++ return stream->total_out;
++
++release_mutex:
++ mutex_unlock(&msblk->read_data_mutex);
++
++ for (; k < b; k++)
++ put_bh(bh[k]);
++
++ 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
++};
++
+diff --git a/include/linux/decompress/bunzip2_mm.h b/include/linux/decompress/bunzip2_mm.h
+new file mode 100644
+index 0000000..863efd0
+--- /dev/null
++++ b/include/linux/decompress/bunzip2_mm.h
+@@ -0,0 +1,13 @@
++#ifndef BUNZIP2_MM_H
++#define BUNZIP2_MM_H
++
++#ifdef STATIC
++/* Code active when included from pre-boot environment: */
++#define INIT
++#else
++/* Compile for initramfs/initrd code only */
++#define INIT __init
++static void(*error)(char *m);
++#endif
++
++#endif
+diff --git a/include/linux/decompress/inflate_mm.h b/include/linux/decompress/inflate_mm.h
+new file mode 100644
+index 0000000..87a742b
+--- /dev/null
++++ b/include/linux/decompress/inflate_mm.h
+@@ -0,0 +1,13 @@
++#ifndef INFLATE_MM_H
++#define INFLATE_MM_H
++
++#ifdef STATIC
++/* Code active when included from pre-boot environment: */
++#define INIT
++#else
++/* Compile for initramfs/initrd code only */
++#define INIT __init
++static void(*error)(char *m);
++#endif
++
++#endif
+diff --git a/include/linux/decompress/mm.h b/include/linux/decompress/mm.h
+index 12ff8c3..44f6e14 100644
+--- a/include/linux/decompress/mm.h
++++ b/include/linux/decompress/mm.h
+@@ -25,7 +25,7 @@ static void *malloc(int size)
+ void *p;
+
+ if (size < 0)
+- error("Malloc error");
++ return NULL;
+ if (!malloc_ptr)
+ malloc_ptr = free_mem_ptr;
+
+@@ -35,7 +35,7 @@ static void *malloc(int size)
+ malloc_ptr += size;
+
+ if (free_mem_end_ptr && malloc_ptr >= free_mem_end_ptr)
+- error("Out of memory");
++ return NULL;
+
+ malloc_count++;
+ return p;
+@@ -53,8 +53,6 @@ static void free(void *where)
+
+ #define set_error_fn(x)
+
+-#define INIT
+-
+ #else /* STATIC */
+
+ /* Code active when compiled standalone for use when loading ramdisk: */
+@@ -74,10 +72,8 @@ static void free(void *where)
+ #define large_malloc(a) vmalloc(a)
+ #define large_free(a) vfree(a)
+
+-static void(*error)(char *m);
+ #define set_error_fn(x) error = x;
+
+-#define INIT __init
+ #define STATIC
+
+ #include <linux/init.h>
+diff --git a/include/linux/decompress/unlzma_mm.h b/include/linux/decompress/unlzma_mm.h
+new file mode 100644
+index 0000000..859287e
+--- /dev/null
++++ b/include/linux/decompress/unlzma_mm.h
+@@ -0,0 +1,20 @@
++#ifndef UNLZMA_MM_H
++#define UNLZMA_MM_H
++
++#ifdef STATIC
++
++/* Code active when included from pre-boot environment: */
++#define INIT
++
++#elif defined(CONFIG_DECOMPRESS_LZMA_NEEDED)
++
++/* Make it available to non initramfs/initrd code */
++#define INIT
++#include <linux/module.h>
++#else
++
++/* Compile for initramfs/initrd code only */
++#define INIT __init
++#endif
++
++#endif
+diff --git a/lib/Kconfig b/lib/Kconfig
+index bb1326d..25e7f28 100644
+--- a/lib/Kconfig
++++ b/lib/Kconfig
+@@ -117,6 +117,9 @@ config DECOMPRESS_BZIP2
+ config DECOMPRESS_LZMA
+ tristate
+
++config DECOMPRESS_LZMA_NEEDED
++ boolean
++
+ #
+ # Generic allocator support is selected if needed
+ #
+diff --git a/lib/decompress_bunzip2.c b/lib/decompress_bunzip2.c
+index 600f473..7db58b9 100644
+--- a/lib/decompress_bunzip2.c
++++ b/lib/decompress_bunzip2.c
+@@ -52,6 +52,7 @@
+ #include <linux/slab.h>
+ #endif /* STATIC */
+
++#include <linux/decompress/bunzip2_mm.h>
+ #include <linux/decompress/mm.h>
+
+ #ifndef INT_MAX
+@@ -637,6 +638,8 @@ static int INIT start_bunzip(struct bunzip_data **bdp, void *inbuf, int len,
+
+ /* Allocate bunzip_data. Most fields initialize to zero. */
+ bd = *bdp = malloc(i);
++ if (!bd)
++ return RETVAL_OUT_OF_MEMORY;
+ memset(bd, 0, sizeof(struct bunzip_data));
+ /* Setup input buffer */
+ bd->inbuf = inbuf;
+@@ -664,6 +667,8 @@ static int INIT start_bunzip(struct bunzip_data **bdp, void *inbuf, int len,
+ bd->dbufSize = 100000*(i-BZh0);
+
+ bd->dbuf = large_malloc(bd->dbufSize * sizeof(int));
++ if (!bd->dbuf)
++ return RETVAL_OUT_OF_MEMORY;
+ return RETVAL_OK;
+ }
+
+@@ -686,7 +691,7 @@ STATIC int INIT bunzip2(unsigned char *buf, int len,
+
+ if (!outbuf) {
+ error("Could not allocate output bufer");
+- return -1;
++ return RETVAL_OUT_OF_MEMORY;
+ }
+ if (buf)
+ inbuf = buf;
+@@ -694,6 +699,7 @@ STATIC int INIT bunzip2(unsigned char *buf, int len,
+ inbuf = malloc(BZIP2_IOBUF_SIZE);
+ if (!inbuf) {
+ error("Could not allocate input bufer");
++ i = RETVAL_OUT_OF_MEMORY;
+ goto exit_0;
+ }
+ i = start_bunzip(&bd, inbuf, len, fill);
+@@ -720,11 +726,14 @@ STATIC int INIT bunzip2(unsigned char *buf, int len,
+ } else if (i == RETVAL_UNEXPECTED_OUTPUT_EOF) {
+ error("Compressed file ends unexpectedly");
+ }
++ if (!bd)
++ goto exit_1;
+ if (bd->dbuf)
+ large_free(bd->dbuf);
+ if (pos)
+ *pos = bd->inbufPos;
+ free(bd);
++exit_1:
+ if (!buf)
+ free(inbuf);
+ exit_0:
+diff --git a/lib/decompress_inflate.c b/lib/decompress_inflate.c
+index fc686c7..cb6bcab 100644
+--- a/lib/decompress_inflate.c
++++ b/lib/decompress_inflate.c
+@@ -23,6 +23,7 @@
+
+ #endif /* STATIC */
+
++#include <linux/decompress/inflate_mm.h>
+ #include <linux/decompress/mm.h>
+
+ #define GZIP_IOBUF_SIZE (16*1024)
+diff --git a/lib/decompress_unlzma.c b/lib/decompress_unlzma.c
+index ca82fde..30d7f8e 100644
+--- a/lib/decompress_unlzma.c
++++ b/lib/decompress_unlzma.c
+@@ -36,6 +36,7 @@
+ #include <linux/slab.h>
+ #endif /* STATIC */
+
++#include <linux/decompress/unlzma_mm.h>
+ #include <linux/decompress/mm.h>
+
+ #define MIN(a, b) (((a) < (b)) ? (a) : (b))
+@@ -88,7 +89,7 @@ static int nofill(void *buffer, unsigned int len)
+ }
+
+ /* Called twice: once at startup and once in rc_normalize() */
+-static void INIT rc_read(struct rc *rc)
++static void INIT rc_read(struct rc *rc, void(*error)(char *x))
+ {
+ rc->buffer_size = rc->fill((char *)rc->buffer, LZMA_IOBUF_SIZE);
+ if (rc->buffer_size <= 0)
+@@ -115,13 +116,13 @@ static inline void INIT rc_init(struct rc *rc,
+ rc->range = 0xFFFFFFFF;
+ }
+
+-static inline void INIT rc_init_code(struct rc *rc)
++static inline void INIT rc_init_code(struct rc *rc, void(*error)(char *x))
+ {
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ if (rc->ptr >= rc->buffer_end)
+- rc_read(rc);
++ rc_read(rc, error);
+ rc->code = (rc->code << 8) | *rc->ptr++;
+ }
+ }
+@@ -134,32 +135,33 @@ static inline void INIT rc_free(struct rc *rc)
+ }
+
+ /* Called twice, but one callsite is in inline'd rc_is_bit_0_helper() */
+-static void INIT rc_do_normalize(struct rc *rc)
++static void INIT rc_do_normalize(struct rc *rc, void(*error)(char *x))
+ {
+ if (rc->ptr >= rc->buffer_end)
+- rc_read(rc);
++ rc_read(rc, error);
+ rc->range <<= 8;
+ rc->code = (rc->code << 8) | *rc->ptr++;
+ }
+-static inline void INIT rc_normalize(struct rc *rc)
++static inline void INIT rc_normalize(struct rc *rc, void(*error)(char *x))
+ {
+ if (rc->range < (1 << RC_TOP_BITS))
+- rc_do_normalize(rc);
++ rc_do_normalize(rc, error);
+ }
+
+ /* Called 9 times */
+ /* Why rc_is_bit_0_helper exists?
+ *Because we want to always expose (rc->code < rc->bound) to optimizer
+ */
+-static inline uint32_t INIT rc_is_bit_0_helper(struct rc *rc, uint16_t *p)
++static inline uint32_t INIT rc_is_bit_0_helper(struct rc *rc, uint16_t *p,
++ void (*error)(char *x))
+ {
+- rc_normalize(rc);
++ rc_normalize(rc, error);
+ rc->bound = *p * (rc->range >> RC_MODEL_TOTAL_BITS);
+ return rc->bound;
+ }
+-static inline int INIT rc_is_bit_0(struct rc *rc, uint16_t *p)
++static inline int INIT rc_is_bit_0(struct rc *rc, uint16_t *p, void(*error)(char *x))
+ {
+- uint32_t t = rc_is_bit_0_helper(rc, p);
++ uint32_t t = rc_is_bit_0_helper(rc, p, error);
+ return rc->code < t;
+ }
+
+@@ -177,9 +179,9 @@ static inline void rc_update_bit_1(struct rc *rc, uint16_t *p)
+ }
+
+ /* Called 4 times in unlzma loop */
+-static int INIT rc_get_bit(struct rc *rc, uint16_t *p, int *symbol)
++static int INIT rc_get_bit(struct rc *rc, uint16_t *p, int *symbol, void(*error)(char *x))
+ {
+- if (rc_is_bit_0(rc, p)) {
++ if (rc_is_bit_0(rc, p, error)) {
+ rc_update_bit_0(rc, p);
+ *symbol *= 2;
+ return 0;
+@@ -191,9 +193,9 @@ static int INIT rc_get_bit(struct rc *rc, uint16_t *p, int *symbol)
+ }
+
+ /* Called once */
+-static inline int INIT rc_direct_bit(struct rc *rc)
++static inline int INIT rc_direct_bit(struct rc *rc , void(*error)(char *x))
+ {
+- rc_normalize(rc);
++ rc_normalize(rc, error);
+ rc->range >>= 1;
+ if (rc->code >= rc->range) {
+ rc->code -= rc->range;
+@@ -204,13 +206,14 @@ static inline int INIT rc_direct_bit(struct rc *rc)
+
+ /* Called twice */
+ static inline void INIT
+-rc_bit_tree_decode(struct rc *rc, uint16_t *p, int num_levels, int *symbol)
++rc_bit_tree_decode(struct rc *rc, uint16_t *p, int num_levels, int *symbol,
++ void(*error)(char *x))
+ {
+ int i = num_levels;
+
+ *symbol = 1;
+ while (i--)
+- rc_get_bit(rc, p + *symbol, symbol);
++ rc_get_bit(rc, p + *symbol, symbol, error);
+ *symbol -= 1 << num_levels;
+ }
+
+@@ -347,7 +350,8 @@ static inline void INIT copy_bytes(struct writer *wr,
+ static inline void INIT process_bit0(struct writer *wr, struct rc *rc,
+ struct cstate *cst, uint16_t *p,
+ int pos_state, uint16_t *prob,
+- int lc, uint32_t literal_pos_mask) {
++ int lc, uint32_t literal_pos_mask,
++ void(*error)(char *x)) {
+ int mi = 1;
+ rc_update_bit_0(rc, prob);
+ prob = (p + LZMA_LITERAL +
+@@ -365,7 +369,7 @@ static inline void INIT process_bit0(struct writer *wr, struct rc *rc,
+ match_byte <<= 1;
+ bit = match_byte & 0x100;
+ prob_lit = prob + 0x100 + bit + mi;
+- if (rc_get_bit(rc, prob_lit, &mi)) {
++ if (rc_get_bit(rc, prob_lit, &mi, error)) {
+ if (!bit)
+ break;
+ } else {
+@@ -376,7 +380,7 @@ static inline void INIT process_bit0(struct writer *wr, struct rc *rc,
+ }
+ while (mi < 0x100) {
+ uint16_t *prob_lit = prob + mi;
+- rc_get_bit(rc, prob_lit, &mi);
++ rc_get_bit(rc, prob_lit, &mi, error);
+ }
+ write_byte(wr, mi);
+ if (cst->state < 4)
+@@ -389,7 +393,8 @@ static inline void INIT process_bit0(struct writer *wr, struct rc *rc,
+
+ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
+ struct cstate *cst, uint16_t *p,
+- int pos_state, uint16_t *prob) {
++ int pos_state, uint16_t *prob,
++ void(*error)(char *x)) {
+ int offset;
+ uint16_t *prob_len;
+ int num_bits;
+@@ -397,7 +402,7 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
+
+ rc_update_bit_1(rc, prob);
+ prob = p + LZMA_IS_REP + cst->state;
+- if (rc_is_bit_0(rc, prob)) {
++ if (rc_is_bit_0(rc, prob, error)) {
+ rc_update_bit_0(rc, prob);
+ cst->rep3 = cst->rep2;
+ cst->rep2 = cst->rep1;
+@@ -407,13 +412,13 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
+ } else {
+ rc_update_bit_1(rc, prob);
+ prob = p + LZMA_IS_REP_G0 + cst->state;
+- if (rc_is_bit_0(rc, prob)) {
++ if (rc_is_bit_0(rc, prob, error)) {
+ rc_update_bit_0(rc, prob);
+ prob = (p + LZMA_IS_REP_0_LONG
+ + (cst->state <<
+ LZMA_NUM_POS_BITS_MAX) +
+ pos_state);
+- if (rc_is_bit_0(rc, prob)) {
++ if (rc_is_bit_0(rc, prob, error)) {
+ rc_update_bit_0(rc, prob);
+
+ cst->state = cst->state < LZMA_NUM_LIT_STATES ?
+@@ -428,13 +433,13 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
+
+ rc_update_bit_1(rc, prob);
+ prob = p + LZMA_IS_REP_G1 + cst->state;
+- if (rc_is_bit_0(rc, prob)) {
++ if (rc_is_bit_0(rc, prob, error)) {
+ rc_update_bit_0(rc, prob);
+ distance = cst->rep1;
+ } else {
+ rc_update_bit_1(rc, prob);
+ prob = p + LZMA_IS_REP_G2 + cst->state;
+- if (rc_is_bit_0(rc, prob)) {
++ if (rc_is_bit_0(rc, prob, error)) {
+ rc_update_bit_0(rc, prob);
+ distance = cst->rep2;
+ } else {
+@@ -452,7 +457,7 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
+ }
+
+ prob_len = prob + LZMA_LEN_CHOICE;
+- if (rc_is_bit_0(rc, prob_len)) {
++ if (rc_is_bit_0(rc, prob_len, error)) {
+ rc_update_bit_0(rc, prob_len);
+ prob_len = (prob + LZMA_LEN_LOW
+ + (pos_state <<
+@@ -462,7 +467,7 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
+ } else {
+ rc_update_bit_1(rc, prob_len);
+ prob_len = prob + LZMA_LEN_CHOICE_2;
+- if (rc_is_bit_0(rc, prob_len)) {
++ if (rc_is_bit_0(rc, prob_len, error)) {
+ rc_update_bit_0(rc, prob_len);
+ prob_len = (prob + LZMA_LEN_MID
+ + (pos_state <<
+@@ -478,7 +483,7 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
+ }
+ }
+
+- rc_bit_tree_decode(rc, prob_len, num_bits, &len);
++ rc_bit_tree_decode(rc, prob_len, num_bits, &len, error);
+ len += offset;
+
+ if (cst->state < 4) {
+@@ -493,7 +498,7 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
+ << LZMA_NUM_POS_SLOT_BITS);
+ rc_bit_tree_decode(rc, prob,
+ LZMA_NUM_POS_SLOT_BITS,
+- &pos_slot);
++ &pos_slot, error);
+ if (pos_slot >= LZMA_START_POS_MODEL_INDEX) {
+ int i, mi;
+ num_bits = (pos_slot >> 1) - 1;
+@@ -506,7 +511,7 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
+ num_bits -= LZMA_NUM_ALIGN_BITS;
+ while (num_bits--)
+ cst->rep0 = (cst->rep0 << 1) |
+- rc_direct_bit(rc);
++ rc_direct_bit(rc, error);
+ prob = p + LZMA_ALIGN;
+ cst->rep0 <<= LZMA_NUM_ALIGN_BITS;
+ num_bits = LZMA_NUM_ALIGN_BITS;
+@@ -514,7 +519,7 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
+ i = 1;
+ mi = 1;
+ while (num_bits--) {
+- if (rc_get_bit(rc, prob + mi, &mi))
++ if (rc_get_bit(rc, prob + mi, &mi, error))
+ cst->rep0 |= i;
+ i <<= 1;
+ }
+@@ -531,12 +536,12 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
+
+
+
+-STATIC inline int INIT unlzma(unsigned char *buf, int in_len,
++STATIC int INIT unlzma(unsigned char *buf, int in_len,
+ int(*fill)(void*, unsigned int),
+ int(*flush)(void*, unsigned int),
+ unsigned char *output,
+ int *posp,
+- void(*error_fn)(char *x)
++ void(*error)(char *x)
+ )
+ {
+ struct lzma_header header;
+@@ -552,8 +557,6 @@ STATIC inline int INIT unlzma(unsigned char *buf, int in_len,
+ unsigned char *inbuf;
+ int ret = -1;
+
+- set_error_fn(error_fn);
+-
+ if (buf)
+ inbuf = buf;
+ else
+@@ -576,7 +579,7 @@ STATIC inline int INIT unlzma(unsigned char *buf, int in_len,
+
+ for (i = 0; i < sizeof(header); i++) {
+ if (rc.ptr >= rc.buffer_end)
+- rc_read(&rc);
++ rc_read(&rc, error);
+ ((unsigned char *)&header)[i] = *rc.ptr++;
+ }
+
+@@ -621,17 +624,17 @@ STATIC inline int INIT unlzma(unsigned char *buf, int in_len,
+ for (i = 0; i < num_probs; i++)
+ p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1;
+
+- rc_init_code(&rc);
++ rc_init_code(&rc, error);
+
+ while (get_pos(&wr) < header.dst_size) {
+ int pos_state = get_pos(&wr) & pos_state_mask;
+ uint16_t *prob = p + LZMA_IS_MATCH +
+ (cst.state << LZMA_NUM_POS_BITS_MAX) + pos_state;
+- if (rc_is_bit_0(&rc, prob))
++ if (rc_is_bit_0(&rc, prob, error))
+ process_bit0(&wr, &rc, &cst, p, pos_state, prob,
+- lc, literal_pos_mask);
++ lc, literal_pos_mask, error);
+ else {
+- process_bit1(&wr, &rc, &cst, p, pos_state, prob);
++ process_bit1(&wr, &rc, &cst, p, pos_state, prob, error);
+ if (cst.rep0 == 0)
+ break;
+ }
+@@ -664,4 +667,6 @@ STATIC int INIT decompress(unsigned char *buf, int in_len,
+ {
+ return unlzma(buf, in_len - 4, fill, flush, output, posp, error_fn);
+ }
++#elif defined(CONFIG_DECOMPRESS_LZMA_NEEDED)
++EXPORT_SYMBOL(unlzma);
+ #endif