2.6.30: add lzma support to squashfs through pcomp
authorFelix Fietkau <nbd@openwrt.org>
Wed, 20 May 2009 15:12:57 +0000 (15:12 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Wed, 20 May 2009 15:12:57 +0000 (15:12 +0000)
SVN-Revision: 15934

target/linux/generic-2.6/config-2.6.30
target/linux/generic-2.6/patches-2.6.30/050-pcomp_update.patch [new file with mode: 0644]
target/linux/generic-2.6/patches-2.6.30/051-squashfs_pcomp.patch [new file with mode: 0644]
target/linux/generic-2.6/patches-2.6.30/052-pcomp_lzma_support.patch [new file with mode: 0644]
target/linux/generic-2.6/patches-2.6.30/053-squashfs_lzma.patch [new file with mode: 0644]
target/linux/ixp4xx/patches-2.6.30/205-npe_driver_separate_phy_functions.patch

index 6e751e4..4c63216 100644 (file)
@@ -322,7 +322,7 @@ CONFIG_CRYPTO_AEAD2=m
 # CONFIG_CRYPTO_AEAD is not set
 # CONFIG_CRYPTO_AES_586 is not set
 CONFIG_CRYPTO_AES=m
-CONFIG_CRYPTO_ALGAPI2=m
+CONFIG_CRYPTO_ALGAPI2=y
 CONFIG_CRYPTO_ALGAPI=m
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 # CONFIG_CRYPTO_ANUBIS is not set
@@ -363,7 +363,7 @@ CONFIG_CRYPTO_MANAGER=m
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
 # CONFIG_CRYPTO_NULL is not set
 # CONFIG_CRYPTO_PCBC is not set
-CONFIG_CRYPTO_PCOMP=m
+CONFIG_CRYPTO_PCOMP=y
 # CONFIG_CRYPTO_PRNG is not set
 # CONFIG_CRYPTO_RMD128 is not set
 # CONFIG_CRYPTO_RMD160 is not set
@@ -385,12 +385,13 @@ CONFIG_CRYPTO_RNG2=m
 # CONFIG_CRYPTO_TWOFISH_586 is not set
 # CONFIG_CRYPTO_TWOFISH_COMMON is not set
 # CONFIG_CRYPTO_TWOFISH is not set
+CONFIG_CRYPTO_UNLZMA=y
 CONFIG_CRYPTO_WORKQUEUE=m
 # CONFIG_CRYPTO_WP512 is not set
 # CONFIG_CRYPTO_XCBC is not set
 # CONFIG_CRYPTO_XTS is not set
 CONFIG_CRYPTO=y
-# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_ZLIB=y
 # CONFIG_DAB is not set
 # CONFIG_DAVICOM_PHY is not set
 # CONFIG_DCB is not set
@@ -1307,6 +1308,7 @@ CONFIG_NFS_V4=y
 # CONFIG_NFTL is not set
 # CONFIG_NILFS2_FS is not set
 CONFIG_NL80211=y
+CONFIG_NLATTR=y
 # CONFIG_NLS_ASCII is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
@@ -1947,6 +1949,8 @@ CONFIG_SND_VERBOSE_PROCFS=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_SQUASHFS_EMBEDDED is not set
 CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+CONFIG_SQUASHFS_SUPPORT_LZMA=y
+CONFIG_SQUASHFS_SUPPORT_ZLIB=y
 # CONFIG_SQUASHFS_VMALLOC is not set
 CONFIG_SQUASHFS=y
 # CONFIG_SSB_BLOCKIO is not set
diff --git a/target/linux/generic-2.6/patches-2.6.30/050-pcomp_update.patch b/target/linux/generic-2.6/patches-2.6.30/050-pcomp_update.patch
new file mode 100644 (file)
index 0000000..abad724
--- /dev/null
@@ -0,0 +1,280 @@
+--- a/crypto/testmgr.c
++++ b/crypto/testmgr.c
+@@ -914,24 +914,25 @@ static int test_pcomp(struct crypto_pcom
+       const char *algo = crypto_tfm_alg_driver_name(crypto_pcomp_tfm(tfm));
+       unsigned int i;
+       char result[COMP_BUF_SIZE];
+-      int error;
++      int res;
+       for (i = 0; i < ctcount; i++) {
+               struct comp_request req;
++              unsigned int produced = 0;
+-              error = crypto_compress_setup(tfm, ctemplate[i].params,
+-                                            ctemplate[i].paramsize);
+-              if (error) {
++              res = crypto_compress_setup(tfm, ctemplate[i].params,
++                                          ctemplate[i].paramsize);
++              if (res) {
+                       pr_err("alg: pcomp: compression setup failed on test "
+-                             "%d for %s: error=%d\n", i + 1, algo, error);
+-                      return error;
++                             "%d for %s: error=%d\n", i + 1, algo, res);
++                      return res;
+               }
+-              error = crypto_compress_init(tfm);
+-              if (error) {
++              res = crypto_compress_init(tfm);
++              if (res) {
+                       pr_err("alg: pcomp: compression init failed on test "
+-                             "%d for %s: error=%d\n", i + 1, algo, error);
+-                      return error;
++                             "%d for %s: error=%d\n", i + 1, algo, res);
++                      return res;
+               }
+               memset(result, 0, sizeof(result));
+@@ -941,32 +942,37 @@ static int test_pcomp(struct crypto_pcom
+               req.next_out = result;
+               req.avail_out = ctemplate[i].outlen / 2;
+-              error = crypto_compress_update(tfm, &req);
+-              if (error && (error != -EAGAIN || req.avail_in)) {
++              res = crypto_compress_update(tfm, &req);
++              if (res < 0 && (res != -EAGAIN || req.avail_in)) {
+                       pr_err("alg: pcomp: compression update failed on test "
+-                             "%d for %s: error=%d\n", i + 1, algo, error);
+-                      return error;
++                             "%d for %s: error=%d\n", i + 1, algo, res);
++                      return res;
+               }
++              if (res > 0)
++                      produced += res;
+               /* Add remaining input data */
+               req.avail_in += (ctemplate[i].inlen + 1) / 2;
+-              error = crypto_compress_update(tfm, &req);
+-              if (error && (error != -EAGAIN || req.avail_in)) {
++              res = crypto_compress_update(tfm, &req);
++              if (res < 0 && (res != -EAGAIN || req.avail_in)) {
+                       pr_err("alg: pcomp: compression update failed on test "
+-                             "%d for %s: error=%d\n", i + 1, algo, error);
+-                      return error;
++                             "%d for %s: error=%d\n", i + 1, algo, res);
++                      return res;
+               }
++              if (res > 0)
++                      produced += res;
+               /* Provide remaining output space */
+               req.avail_out += COMP_BUF_SIZE - ctemplate[i].outlen / 2;
+-              error = crypto_compress_final(tfm, &req);
+-              if (error) {
++              res = crypto_compress_final(tfm, &req);
++              if (res < 0) {
+                       pr_err("alg: pcomp: compression final failed on test "
+-                             "%d for %s: error=%d\n", i + 1, algo, error);
+-                      return error;
++                             "%d for %s: error=%d\n", i + 1, algo, res);
++                      return res;
+               }
++              produced += res;
+               if (COMP_BUF_SIZE - req.avail_out != ctemplate[i].outlen) {
+                       pr_err("alg: comp: Compression test %d failed for %s: "
+@@ -976,6 +982,13 @@ static int test_pcomp(struct crypto_pcom
+                       return -EINVAL;
+               }
++              if (produced != ctemplate[i].outlen) {
++                      pr_err("alg: comp: Compression test %d failed for %s: "
++                             "returned len = %u (expected %d)\n", i + 1,
++                             algo, produced, ctemplate[i].outlen);
++                      return -EINVAL;
++              }
++
+               if (memcmp(result, ctemplate[i].output, ctemplate[i].outlen)) {
+                       pr_err("alg: pcomp: Compression test %d failed for "
+                              "%s\n", i + 1, algo);
+@@ -986,21 +999,21 @@ static int test_pcomp(struct crypto_pcom
+       for (i = 0; i < dtcount; i++) {
+               struct comp_request req;
++              unsigned int produced = 0;
+-              error = crypto_decompress_setup(tfm, dtemplate[i].params,
+-                                              dtemplate[i].paramsize);
+-              if (error) {
++              res = crypto_decompress_setup(tfm, dtemplate[i].params,
++                                            dtemplate[i].paramsize);
++              if (res) {
+                       pr_err("alg: pcomp: decompression setup failed on "
+-                             "test %d for %s: error=%d\n", i + 1, algo,
+-                             error);
+-                      return error;
++                             "test %d for %s: error=%d\n", i + 1, algo, res);
++                      return res;
+               }
+-              error = crypto_decompress_init(tfm);
+-              if (error) {
++              res = crypto_decompress_init(tfm);
++              if (res) {
+                       pr_err("alg: pcomp: decompression init failed on test "
+-                             "%d for %s: error=%d\n", i + 1, algo, error);
+-                      return error;
++                             "%d for %s: error=%d\n", i + 1, algo, res);
++                      return res;
+               }
+               memset(result, 0, sizeof(result));
+@@ -1010,35 +1023,38 @@ static int test_pcomp(struct crypto_pcom
+               req.next_out = result;
+               req.avail_out = dtemplate[i].outlen / 2;
+-              error = crypto_decompress_update(tfm, &req);
+-              if (error  && (error != -EAGAIN || req.avail_in)) {
++              res = crypto_decompress_update(tfm, &req);
++              if (res < 0 && (res != -EAGAIN || req.avail_in)) {
+                       pr_err("alg: pcomp: decompression update failed on "
+-                             "test %d for %s: error=%d\n", i + 1, algo,
+-                             error);
+-                      return error;
++                             "test %d for %s: error=%d\n", i + 1, algo, res);
++                      return res;
+               }
++              if (res > 0)
++                      produced += res;
+               /* Add remaining input data */
+               req.avail_in += (dtemplate[i].inlen + 1) / 2;
+-              error = crypto_decompress_update(tfm, &req);
+-              if (error  && (error != -EAGAIN || req.avail_in)) {
++              res = crypto_decompress_update(tfm, &req);
++              if (res < 0 && (res != -EAGAIN || req.avail_in)) {
+                       pr_err("alg: pcomp: decompression update failed on "
+-                             "test %d for %s: error=%d\n", i + 1, algo,
+-                             error);
+-                      return error;
++                             "test %d for %s: error=%d\n", i + 1, algo, res);
++                      return res;
+               }
++              if (res > 0)
++                      produced += res;
+               /* Provide remaining output space */
+               req.avail_out += COMP_BUF_SIZE - dtemplate[i].outlen / 2;
+-              error = crypto_decompress_final(tfm, &req);
+-              if (error  && (error != -EAGAIN || req.avail_in)) {
++              res = crypto_decompress_final(tfm, &req);
++              if (res < 0 && (res != -EAGAIN || req.avail_in)) {
+                       pr_err("alg: pcomp: decompression final failed on "
+-                             "test %d for %s: error=%d\n", i + 1, algo,
+-                             error);
+-                      return error;
++                             "test %d for %s: error=%d\n", i + 1, algo, res);
++                      return res;
+               }
++              if (res > 0)
++                      produced += res;
+               if (COMP_BUF_SIZE - req.avail_out != dtemplate[i].outlen) {
+                       pr_err("alg: comp: Decompression test %d failed for "
+@@ -1048,6 +1064,13 @@ static int test_pcomp(struct crypto_pcom
+                       return -EINVAL;
+               }
++              if (produced != dtemplate[i].outlen) {
++                      pr_err("alg: comp: Decompression test %d failed for "
++                             "%s: returned len = %u (expected %d)\n", i + 1,
++                             algo, produced, dtemplate[i].outlen);
++                      return -EINVAL;
++              }
++
+               if (memcmp(result, dtemplate[i].output, dtemplate[i].outlen)) {
+                       pr_err("alg: pcomp: Decompression test %d failed for "
+                              "%s\n", i + 1, algo);
+--- a/crypto/zlib.c
++++ b/crypto/zlib.c
+@@ -165,15 +165,15 @@ static int zlib_compress_update(struct c
+               return -EINVAL;
+       }
++      ret = req->avail_out - stream->avail_out;
+       pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
+                stream->avail_in, stream->avail_out,
+-               req->avail_in - stream->avail_in,
+-               req->avail_out - stream->avail_out);
++               req->avail_in - stream->avail_in, ret);
+       req->next_in = stream->next_in;
+       req->avail_in = stream->avail_in;
+       req->next_out = stream->next_out;
+       req->avail_out = stream->avail_out;
+-      return 0;
++      return ret;
+ }
+ static int zlib_compress_final(struct crypto_pcomp *tfm,
+@@ -195,15 +195,15 @@ static int zlib_compress_final(struct cr
+               return -EINVAL;
+       }
++      ret = req->avail_out - stream->avail_out;
+       pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
+                stream->avail_in, stream->avail_out,
+-               req->avail_in - stream->avail_in,
+-               req->avail_out - stream->avail_out);
++               req->avail_in - stream->avail_in, ret);
+       req->next_in = stream->next_in;
+       req->avail_in = stream->avail_in;
+       req->next_out = stream->next_out;
+       req->avail_out = stream->avail_out;
+-      return 0;
++      return ret;
+ }
+@@ -280,15 +280,15 @@ static int zlib_decompress_update(struct
+               return -EINVAL;
+       }
++      ret = req->avail_out - stream->avail_out;
+       pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
+                stream->avail_in, stream->avail_out,
+-               req->avail_in - stream->avail_in,
+-               req->avail_out - stream->avail_out);
++               req->avail_in - stream->avail_in, ret);
+       req->next_in = stream->next_in;
+       req->avail_in = stream->avail_in;
+       req->next_out = stream->next_out;
+       req->avail_out = stream->avail_out;
+-      return 0;
++      return ret;
+ }
+ static int zlib_decompress_final(struct crypto_pcomp *tfm,
+@@ -328,15 +328,15 @@ static int zlib_decompress_final(struct 
+               return -EINVAL;
+       }
++      ret = req->avail_out - stream->avail_out;
+       pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
+                stream->avail_in, stream->avail_out,
+-               req->avail_in - stream->avail_in,
+-               req->avail_out - stream->avail_out);
++               req->avail_in - stream->avail_in, ret);
+       req->next_in = stream->next_in;
+       req->avail_in = stream->avail_in;
+       req->next_out = stream->next_out;
+       req->avail_out = stream->avail_out;
+-      return 0;
++      return ret;
+ }
diff --git a/target/linux/generic-2.6/patches-2.6.30/051-squashfs_pcomp.patch b/target/linux/generic-2.6/patches-2.6.30/051-squashfs_pcomp.patch
new file mode 100644 (file)
index 0000000..271c4e5
--- /dev/null
@@ -0,0 +1,234 @@
+--- a/fs/squashfs/Kconfig
++++ b/fs/squashfs/Kconfig
+@@ -1,7 +1,8 @@
+ config SQUASHFS
+       tristate "SquashFS 4.0 - Squashed file system support"
+       depends on BLOCK
+-      select ZLIB_INFLATE
++      select CRYPTO
++      select CRYPTO_ZLIB
+       help
+         Saying Y here includes support for SquashFS 4.0 (a Compressed
+         Read-Only File System).  Squashfs is a highly compressed read-only
+--- a/fs/squashfs/block.c
++++ b/fs/squashfs/block.c
+@@ -32,7 +32,8 @@
+ #include <linux/mutex.h>
+ #include <linux/string.h>
+ #include <linux/buffer_head.h>
+-#include <linux/zlib.h>
++
++#include <crypto/compress.h>
+ #include "squashfs_fs.h"
+ #include "squashfs_fs_sb.h"
+@@ -153,7 +154,8 @@ int squashfs_read_data(struct super_bloc
+       }
+       if (compressed) {
+-              int zlib_err = 0, zlib_init = 0;
++              int res = 0, decomp_init = 0;
++              struct comp_request req;
+               /*
+                * Uncompress block.
+@@ -161,12 +163,13 @@ int squashfs_read_data(struct super_bloc
+               mutex_lock(&msblk->read_data_mutex);
+-              msblk->stream.avail_out = 0;
+-              msblk->stream.avail_in = 0;
++              req.avail_out = 0;
++              req.avail_in = 0;
+               bytes = length;
++              length = 0;
+               do {
+-                      if (msblk->stream.avail_in == 0 && k < b) {
++                      if (req.avail_in == 0 && k < b) {
+                               avail = min(bytes, msblk->devblksize - offset);
+                               bytes -= avail;
+                               wait_on_buffer(bh[k]);
+@@ -179,45 +182,47 @@ int squashfs_read_data(struct super_bloc
+                                       continue;
+                               }
+-                              msblk->stream.next_in = bh[k]->b_data + offset;
+-                              msblk->stream.avail_in = avail;
++                              req.next_in = bh[k]->b_data + offset;
++                              req.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 (req.avail_out == 0 && page < pages) {
++                              req.next_out = buffer[page++];
++                              req.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);
++                      if (!decomp_init) {
++                              res = crypto_decompress_init(msblk->tfm);
++                              if (res) {
++                                      ERROR("crypto_decompress_init "
++                                              "returned %d, srclength %d\n",
++                                              res, srclength);
+                                       goto release_mutex;
+                               }
+-                              zlib_init = 1;
++                              decomp_init = 1;
+                       }
+-                      zlib_err = zlib_inflate(&msblk->stream, Z_SYNC_FLUSH);
++                      res = crypto_decompress_update(msblk->tfm, &req);
++                      if (res < 0) {
++                              ERROR("crypto_decompress_update returned %d, "
++                                      "data probably corrupt\n", res);
++                              goto release_mutex;
++                      }
++                      length += res;
+-                      if (msblk->stream.avail_in == 0 && k < b)
++                      if (req.avail_in == 0 && k < b)
+                               put_bh(bh[k++]);
+-              } while (zlib_err == Z_OK);
++              } while (bytes || res);
+-              if (zlib_err != Z_STREAM_END) {
+-                      ERROR("zlib_inflate error, data probably corrupt\n");
++              res = crypto_decompress_final(msblk->tfm, &req);
++              if (res < 0) {
++                      ERROR("crypto_decompress_final returned %d, data "
++                              "probably corrupt\n", res);
+                       goto release_mutex;
+               }
++              length += res;
+-              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);
+       } else {
+               /*
+--- a/fs/squashfs/squashfs_fs_sb.h
++++ b/fs/squashfs/squashfs_fs_sb.h
+@@ -64,7 +64,7 @@ struct squashfs_sb_info {
+       struct mutex            read_data_mutex;
+       struct mutex            meta_index_mutex;
+       struct meta_index       *meta_index;
+-      z_stream                stream;
++      struct crypto_pcomp     *tfm;
+       __le64                  *inode_lookup_table;
+       u64                     inode_table;
+       u64                     directory_table;
+--- a/fs/squashfs/super.c
++++ b/fs/squashfs/super.c
+@@ -37,11 +37,19 @@
+ #include <linux/zlib.h>
+ #include <linux/magic.h>
++#include <crypto/compress.h>
++
++#include <net/netlink.h>
++
+ #include "squashfs_fs.h"
+ #include "squashfs_fs_sb.h"
+ #include "squashfs_fs_i.h"
+ #include "squashfs.h"
++
++#define SQUASHFS_CRYPTO_ALG   "zlib"
++
++
+ static struct file_system_type squashfs_fs_type;
+ static struct super_operations squashfs_super_ops;
+@@ -75,6 +83,16 @@ static int squashfs_fill_super(struct su
+       unsigned short flags;
+       unsigned int fragments;
+       u64 lookup_table_start;
++      struct {
++              struct nlattr nla;
++              int val;
++      } params = {
++              .nla = {
++                      .nla_len        = nla_attr_size(sizeof(int)),
++                      .nla_type       = ZLIB_DECOMP_WINDOWBITS,
++              },
++              .val                    = DEF_WBITS,
++      };
+       int err;
+       TRACE("Entered squashfs_fill_superblock\n");
+@@ -86,16 +104,25 @@ static int squashfs_fill_super(struct su
+       }
+       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");
++      msblk->tfm = crypto_alloc_pcomp(SQUASHFS_CRYPTO_ALG, 0,
++                                      CRYPTO_ALG_ASYNC);
++      if (IS_ERR(msblk->tfm)) {
++              ERROR("Failed to load %s crypto module\n",
++                    SQUASHFS_CRYPTO_ALG);
++              err = PTR_ERR(msblk->tfm);
++              goto failed_pcomp;
++      }
++
++      err = crypto_decompress_setup(msblk->tfm, &params, sizeof(params));
++      if (err) {
++              ERROR("Failed to set up decompression parameters\n");
+               goto failure;
+       }
+       sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
+       if (sblk == NULL) {
+               ERROR("Failed to allocate squashfs_super_block\n");
++              err = -ENOMEM;
+               goto failure;
+       }
+@@ -284,17 +311,18 @@ failed_mount:
+       kfree(msblk->inode_lookup_table);
+       kfree(msblk->fragment_index);
+       kfree(msblk->id_table);
+-      kfree(msblk->stream.workspace);
++      crypto_free_pcomp(msblk->tfm);
+       kfree(sb->s_fs_info);
+       sb->s_fs_info = NULL;
+       kfree(sblk);
+       return err;
+ failure:
+-      kfree(msblk->stream.workspace);
++      crypto_free_pcomp(msblk->tfm);
++failed_pcomp:
+       kfree(sb->s_fs_info);
+       sb->s_fs_info = NULL;
+-      return -ENOMEM;
++      return err;
+ }
+@@ -333,7 +361,7 @@ static void squashfs_put_super(struct su
+               kfree(sbi->id_table);
+               kfree(sbi->fragment_index);
+               kfree(sbi->meta_index);
+-              kfree(sbi->stream.workspace);
++              crypto_free_pcomp(sbi->tfm);
+               kfree(sb->s_fs_info);
+               sb->s_fs_info = NULL;
+       }
diff --git a/target/linux/generic-2.6/patches-2.6.30/052-pcomp_lzma_support.patch b/target/linux/generic-2.6/patches-2.6.30/052-pcomp_lzma_support.patch
new file mode 100644 (file)
index 0000000..c5265e9
--- /dev/null
@@ -0,0 +1,821 @@
+--- /dev/null
++++ b/crypto/unlzma.c
+@@ -0,0 +1,710 @@
++/*
++ * LZMA uncompresion module for pcomp
++ * Copyright (C) 2009  Felix Fietkau <nbd@openwrt.org>
++ *
++ * Based on:
++ *  Initial Linux kernel adaptation
++ *  Copyright (C) 2006  Alain < alain@knaff.lu >
++ *
++ *  Based on small lzma deflate implementation/Small range coder
++ *  implementation for lzma.
++ *  Copyright (C) 2006  Aurelien Jacobs < aurel@gnuage.org >
++ *
++ *  Based on LzmaDecode.c from the LZMA SDK 4.22 (http://www.7-zip.org/)
++ *  Copyright (C) 1999-2005  Igor Pavlov
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ * FIXME: the current implementation assumes that the caller will
++ * not free any output buffers until the whole decompression has been
++ * completed. This is necessary, because LZMA looks back at old output
++ * instead of doing a separate dictionary allocation, which saves RAM.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/vmalloc.h>
++#include <linux/interrupt.h>
++#include <linux/mm.h>
++#include <linux/net.h>
++#include <linux/slab.h>
++#include <linux/kthread.h>
++
++#include <crypto/internal/compress.h>
++#include "unlzma.h"
++
++static int instance = 0;
++
++struct unlzma_buffer {
++      struct unlzma_buffer *last;
++      int offset;
++      int size;
++      u8 *ptr;
++};
++
++struct unlzma_ctx {
++      struct task_struct *thread;
++      wait_queue_head_t next_req;
++      struct mutex mutex;
++      bool active;
++      bool cancel;
++
++      const u8 *next_in;
++      int avail_in;
++
++      u8 *next_out;
++      int avail_out;
++
++      /* reader state */
++      u32 code;
++      u32 range;
++      u32 bound;
++
++      /* writer state */
++      u8 previous_byte;
++      ssize_t pos;
++      struct unlzma_buffer *head;
++
++      /* cstate */
++      int state;
++      u32 rep0, rep1, rep2, rep3;
++
++      u32 dict_size;
++
++      void *workspace;
++      int workspace_size;
++};
++
++static inline bool
++unlzma_should_stop(struct unlzma_ctx *ctx)
++{
++      return unlikely(kthread_should_stop() || ctx->cancel);
++}
++
++static void
++unlzma_request_buffer(struct unlzma_ctx *ctx, int *avail)
++{
++      mutex_unlock(&ctx->mutex);
++      wait_event(ctx->next_req, unlzma_should_stop(ctx) || (*avail > 0));
++      mutex_lock(&ctx->mutex);
++}
++
++static u8
++rc_read(struct unlzma_ctx *ctx)
++{
++      if (unlikely(ctx->avail_in <= 0))
++              unlzma_request_buffer(ctx, &ctx->avail_in);
++
++      if (unlzma_should_stop(ctx))
++              return 0;
++
++      ctx->avail_in--;
++      return *(ctx->next_in++);
++}
++
++
++static inline void
++rc_get_code(struct unlzma_ctx *ctx)
++{
++      ctx->code = (ctx->code << 8) | rc_read(ctx);
++}
++
++static void
++rc_normalize(struct unlzma_ctx *ctx)
++{
++      if (ctx->range < (1 << RC_TOP_BITS)) {
++              ctx->range <<= 8;
++              rc_get_code(ctx);
++      }
++}
++
++static int
++rc_is_bit_0(struct unlzma_ctx *ctx, u16 *p)
++{
++      rc_normalize(ctx);
++      ctx->bound = *p * (ctx->range >> RC_MODEL_TOTAL_BITS);
++      return ctx->code < ctx->bound;
++}
++
++static void
++rc_update_bit_0(struct unlzma_ctx *ctx, u16 *p)
++{
++      ctx->range = ctx->bound;
++      *p += ((1 << RC_MODEL_TOTAL_BITS) - *p) >> RC_MOVE_BITS;
++}
++
++static void
++rc_update_bit_1(struct unlzma_ctx *ctx, u16 *p)
++{
++      ctx->range -= ctx->bound;
++      ctx->code -= ctx->bound;
++      *p -= *p >> RC_MOVE_BITS;
++}
++
++static bool
++rc_get_bit(struct unlzma_ctx *ctx, u16 *p, int *symbol)
++{
++      if (rc_is_bit_0(ctx, p)) {
++              rc_update_bit_0(ctx, p);
++              *symbol *= 2;
++              return 0;
++      } else {
++              rc_update_bit_1(ctx, p);
++              *symbol = *symbol * 2 + 1;
++              return 1;
++      }
++}
++
++static int
++rc_direct_bit(struct unlzma_ctx *ctx)
++{
++      rc_normalize(ctx);
++      ctx->range >>= 1;
++      if (ctx->code >= ctx->range) {
++              ctx->code -= ctx->range;
++              return 1;
++      }
++      return 0;
++}
++
++static void
++rc_bit_tree_decode(struct unlzma_ctx *ctx, u16 *p, int num_levels, int *symbol)
++{
++      int i = num_levels;
++
++      *symbol = 1;
++      while (i--)
++              rc_get_bit(ctx, p + *symbol, symbol);
++      *symbol -= 1 << num_levels;
++}
++
++static u8
++peek_old_byte(struct unlzma_ctx *ctx, u32 offs)
++{
++      struct unlzma_buffer *bh = ctx->head;
++      u32 pos;
++
++      pos = ctx->pos - offs;
++      if (pos >= ctx->dict_size) {
++              pos = (~pos % ctx->dict_size);
++      }
++
++      while (bh->offset > pos) {
++              bh = bh->last;
++              if (!bh)
++                      return 0;
++      }
++
++      pos -= bh->offset;
++      if (pos > bh->size)
++              return 0;
++
++      return bh->ptr[pos];
++}
++
++static void
++get_buffer(struct unlzma_ctx *ctx)
++{
++      struct unlzma_buffer *bh;
++
++      bh = kzalloc(sizeof(struct unlzma_buffer), GFP_KERNEL);
++      bh->ptr = ctx->next_out;
++      bh->offset = ctx->pos;
++      bh->last = ctx->head;
++      bh->size = ctx->avail_out;
++      ctx->head = bh;
++}
++
++static void
++write_byte(struct unlzma_ctx *ctx, u8 byte)
++{
++      if (unlikely(ctx->avail_out <= 0)) {
++              unlzma_request_buffer(ctx, &ctx->avail_out);
++              get_buffer(ctx);
++      }
++
++      if (!ctx->avail_out)
++              return;
++
++      ctx->previous_byte = byte;
++      *(ctx->next_out++) = byte;
++      ctx->avail_out--;
++      ctx->pos++;
++}
++
++
++static inline void
++copy_byte(struct unlzma_ctx *ctx, u32 offs)
++{
++      write_byte(ctx, peek_old_byte(ctx, offs));
++}
++
++static void
++copy_bytes(struct unlzma_ctx *ctx, u32 rep0, int len)
++{
++      do {
++              copy_byte(ctx, rep0);
++              len--;
++              if (unlzma_should_stop(ctx))
++                      break;
++      } while (len != 0);
++}
++
++static void
++process_bit0(struct unlzma_ctx *ctx, u16 *p, int pos_state, u16 *prob,
++             int lc, u32 literal_pos_mask)
++{
++      int mi = 1;
++      rc_update_bit_0(ctx, prob);
++      prob = (p + LZMA_LITERAL +
++              (LZMA_LIT_SIZE
++               * (((ctx->pos & literal_pos_mask) << lc)
++                  + (ctx->previous_byte >> (8 - lc))))
++              );
++
++      if (ctx->state >= LZMA_NUM_LIT_STATES) {
++              int match_byte = peek_old_byte(ctx, ctx->rep0);
++              do {
++                      u16 bit;
++                      u16 *prob_lit;
++
++                      match_byte <<= 1;
++                      bit = match_byte & 0x100;
++                      prob_lit = prob + 0x100 + bit + mi;
++                      if (rc_get_bit(ctx, prob_lit, &mi) != !!bit)
++                              break;
++              } while (mi < 0x100);
++      }
++      while (mi < 0x100) {
++              u16 *prob_lit = prob + mi;
++              rc_get_bit(ctx, prob_lit, &mi);
++      }
++      write_byte(ctx, mi);
++      if (ctx->state < 4)
++              ctx->state = 0;
++      else if (ctx->state < 10)
++              ctx->state -= 3;
++      else
++              ctx->state -= 6;
++}
++
++static void
++process_bit1(struct unlzma_ctx *ctx, u16 *p, int pos_state, u16 *prob)
++{
++      int offset;
++      u16 *prob_len;
++      int num_bits;
++      int len;
++
++      rc_update_bit_1(ctx, prob);
++      prob = p + LZMA_IS_REP + ctx->state;
++      if (rc_is_bit_0(ctx, prob)) {
++              rc_update_bit_0(ctx, prob);
++              ctx->rep3 = ctx->rep2;
++              ctx->rep2 = ctx->rep1;
++              ctx->rep1 = ctx->rep0;
++              ctx->state = ctx->state < LZMA_NUM_LIT_STATES ? 0 : 3;
++              prob = p + LZMA_LEN_CODER;
++      } else {
++              rc_update_bit_1(ctx, prob);
++              prob = p + LZMA_IS_REP_G0 + ctx->state;
++              if (rc_is_bit_0(ctx, prob)) {
++                      rc_update_bit_0(ctx, prob);
++                      prob = (p + LZMA_IS_REP_0_LONG
++                              + (ctx->state <<
++                                 LZMA_NUM_POS_BITS_MAX) +
++                              pos_state);
++                      if (rc_is_bit_0(ctx, prob)) {
++                              rc_update_bit_0(ctx, prob);
++
++                              ctx->state = ctx->state < LZMA_NUM_LIT_STATES ?
++                                      9 : 11;
++                              copy_byte(ctx, ctx->rep0);
++                              return;
++                      } else {
++                              rc_update_bit_1(ctx, prob);
++                      }
++              } else {
++                      u32 distance;
++
++                      rc_update_bit_1(ctx, prob);
++                      prob = p + LZMA_IS_REP_G1 + ctx->state;
++                      if (rc_is_bit_0(ctx, prob)) {
++                              rc_update_bit_0(ctx, prob);
++                              distance = ctx->rep1;
++                      } else {
++                              rc_update_bit_1(ctx, prob);
++                              prob = p + LZMA_IS_REP_G2 + ctx->state;
++                              if (rc_is_bit_0(ctx, prob)) {
++                                      rc_update_bit_0(ctx, prob);
++                                      distance = ctx->rep2;
++                              } else {
++                                      rc_update_bit_1(ctx, prob);
++                                      distance = ctx->rep3;
++                                      ctx->rep3 = ctx->rep2;
++                              }
++                              ctx->rep2 = ctx->rep1;
++                      }
++                      ctx->rep1 = ctx->rep0;
++                      ctx->rep0 = distance;
++              }
++              ctx->state = ctx->state < LZMA_NUM_LIT_STATES ? 8 : 11;
++              prob = p + LZMA_REP_LEN_CODER;
++      }
++
++      prob_len = prob + LZMA_LEN_CHOICE;
++      if (rc_is_bit_0(ctx, prob_len)) {
++              rc_update_bit_0(ctx, prob_len);
++              prob_len = (prob + LZMA_LEN_LOW
++                          + (pos_state <<
++                             LZMA_LEN_NUM_LOW_BITS));
++              offset = 0;
++              num_bits = LZMA_LEN_NUM_LOW_BITS;
++      } else {
++              rc_update_bit_1(ctx, prob_len);
++              prob_len = prob + LZMA_LEN_CHOICE_2;
++              if (rc_is_bit_0(ctx, prob_len)) {
++                      rc_update_bit_0(ctx, prob_len);
++                      prob_len = (prob + LZMA_LEN_MID
++                                  + (pos_state <<
++                                     LZMA_LEN_NUM_MID_BITS));
++                      offset = 1 << LZMA_LEN_NUM_LOW_BITS;
++                      num_bits = LZMA_LEN_NUM_MID_BITS;
++              } else {
++                      rc_update_bit_1(ctx, prob_len);
++                      prob_len = prob + LZMA_LEN_HIGH;
++                      offset = ((1 << LZMA_LEN_NUM_LOW_BITS)
++                                + (1 << LZMA_LEN_NUM_MID_BITS));
++                      num_bits = LZMA_LEN_NUM_HIGH_BITS;
++              }
++      }
++
++      rc_bit_tree_decode(ctx, prob_len, num_bits, &len);
++      len += offset;
++
++      if (ctx->state < 4) {
++              int pos_slot;
++
++              ctx->state += LZMA_NUM_LIT_STATES;
++              prob =
++                      p + LZMA_POS_SLOT +
++                      ((len <
++                        LZMA_NUM_LEN_TO_POS_STATES ? len :
++                        LZMA_NUM_LEN_TO_POS_STATES - 1)
++                       << LZMA_NUM_POS_SLOT_BITS);
++              rc_bit_tree_decode(ctx, prob,
++                                 LZMA_NUM_POS_SLOT_BITS,
++                                 &pos_slot);
++              if (pos_slot >= LZMA_START_POS_MODEL_INDEX) {
++                      int i, mi;
++                      num_bits = (pos_slot >> 1) - 1;
++                      ctx->rep0 = 2 | (pos_slot & 1);
++                      if (pos_slot < LZMA_END_POS_MODEL_INDEX) {
++                              ctx->rep0 <<= num_bits;
++                              prob = p + LZMA_SPEC_POS +
++                                      ctx->rep0 - pos_slot - 1;
++                      } else {
++                              num_bits -= LZMA_NUM_ALIGN_BITS;
++                              while (num_bits--)
++                                      ctx->rep0 = (ctx->rep0 << 1) |
++                                              rc_direct_bit(ctx);
++                              prob = p + LZMA_ALIGN;
++                              ctx->rep0 <<= LZMA_NUM_ALIGN_BITS;
++                              num_bits = LZMA_NUM_ALIGN_BITS;
++                      }
++                      i = 1;
++                      mi = 1;
++                      while (num_bits--) {
++                              if (rc_get_bit(ctx, prob + mi, &mi))
++                                      ctx->rep0 |= i;
++                              i <<= 1;
++                      }
++              } else
++                      ctx->rep0 = pos_slot;
++              if (++(ctx->rep0) == 0)
++                      return;
++      }
++
++      len += LZMA_MATCH_MIN_LEN;
++
++      copy_bytes(ctx, ctx->rep0, len);
++}
++
++
++static int
++do_unlzma(struct unlzma_ctx *ctx)
++{
++      u8 hdr_buf[sizeof(struct lzma_header)];
++      struct lzma_header *header = (struct lzma_header *)hdr_buf;
++      u32 pos_state_mask;
++      u32 literal_pos_mask;
++      int lc, pb, lp;
++      int num_probs;
++      int i, mi;
++      u16 *p;
++
++      for (i = 0; i < sizeof(struct lzma_header); i++) {
++              hdr_buf[i] = rc_read(ctx);
++      }
++
++      ctx->pos = 0;
++      get_buffer(ctx);
++      ctx->active = true;
++      ctx->state = 0;
++      ctx->rep0 = ctx->rep1 = ctx->rep2 = ctx->rep3 = 1;
++
++      ctx->previous_byte = 0;
++      ctx->code = 0;
++      ctx->range = 0xFFFFFFFF;
++
++      ctx->dict_size = le32_to_cpu(header->dict_size);
++
++      if (header->pos >= (9 * 5 * 5))
++              return -1;
++
++      mi = 0;
++      lc = header->pos;
++      while (lc >= 9) {
++              mi++;
++              lc -= 9;
++      }
++      pb = 0;
++      lp = mi;
++      while (lp >= 5) {
++              pb++;
++              lp -= 5;
++      }
++      pos_state_mask = (1 << pb) - 1;
++      literal_pos_mask = (1 << lp) - 1;
++
++      if (ctx->dict_size == 0)
++              ctx->dict_size = 1;
++
++      num_probs = LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp));
++      if (ctx->workspace_size < num_probs * sizeof(*p)) {
++              if (ctx->workspace)
++                      vfree(ctx->workspace);
++              ctx->workspace = vmalloc(num_probs * sizeof(*p));
++      }
++      p = (u16 *) ctx->workspace;
++      if (!p)
++              return -1;
++
++      num_probs = LZMA_LITERAL + (LZMA_LIT_SIZE << (lc + lp));
++      for (i = 0; i < num_probs; i++)
++              p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1;
++
++      for (i = 0; i < 5; i++)
++              rc_get_code(ctx);
++
++      while (1) {
++              int pos_state = ctx->pos & pos_state_mask;
++              u16 *prob = p + LZMA_IS_MATCH +
++                      (ctx->state << LZMA_NUM_POS_BITS_MAX) + pos_state;
++              if (rc_is_bit_0(ctx, prob))
++                      process_bit0(ctx, p, pos_state, prob,
++                                   lc, literal_pos_mask);
++              else {
++                      process_bit1(ctx, p, pos_state, prob);
++                      if (ctx->rep0 == 0)
++                              break;
++              }
++              if (unlzma_should_stop(ctx))
++                      break;
++      }
++
++      return ctx->pos;
++}
++
++
++static void
++unlzma_reset_buf(struct unlzma_ctx *ctx)
++{
++      ctx->avail_in = 0;
++      ctx->next_in = NULL;
++      ctx->avail_out = 0;
++      ctx->next_out = NULL;
++}
++
++static int
++unlzma_thread(void *data)
++{
++      struct unlzma_ctx *ctx = data;
++
++      mutex_lock(&ctx->mutex);
++      do {
++              if (do_unlzma(ctx) < 0)
++                      ctx->pos = 0;
++              unlzma_reset_buf(ctx);
++              ctx->cancel = false;
++              ctx->active = false;
++              while (ctx->head) {
++                      struct unlzma_buffer *bh = ctx->head;
++                      ctx->head = bh->last;
++                      kfree(bh);
++              }
++      } while (!kthread_should_stop());
++      mutex_unlock(&ctx->mutex);
++      return 0;
++}
++
++
++static int
++unlzma_init(struct crypto_tfm *tfm)
++{
++      return 0;
++}
++
++static void
++unlzma_cancel(struct unlzma_ctx *ctx)
++{
++      unlzma_reset_buf(ctx);
++
++      if (!ctx->active)
++              return;
++
++      ctx->cancel = true;
++      do {
++              mutex_unlock(&ctx->mutex);
++              wake_up(&ctx->next_req);
++              schedule();
++              mutex_lock(&ctx->mutex);
++      } while (ctx->cancel);
++}
++
++
++static void
++unlzma_exit(struct crypto_tfm *tfm)
++{
++      struct unlzma_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      if (ctx->thread) {
++              unlzma_cancel(ctx);
++              kthread_stop(ctx->thread);
++              ctx->thread = NULL;
++      }
++}
++
++static int
++unlzma_decompress_setup(struct crypto_pcomp *tfm, void *p, unsigned int len)
++{
++      struct unlzma_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
++      int ret = 0;
++
++      if (ctx->thread)
++              return 0;
++
++      mutex_init(&ctx->mutex);
++      init_waitqueue_head(&ctx->next_req);
++      ctx->thread = kthread_run(unlzma_thread, ctx, "unlzma/%d", instance++);
++      if (IS_ERR(ctx->thread)) {
++              ret = PTR_ERR(ctx->thread);
++              ctx->thread = NULL;
++      }
++
++      return ret;
++}
++
++static int
++unlzma_decompress_init(struct crypto_pcomp *tfm)
++{
++      struct unlzma_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
++
++      ctx->pos = 0;
++      return 0;
++}
++
++static void
++unlzma_wait_complete(struct unlzma_ctx *ctx, bool finish)
++{
++      do {
++              mutex_unlock(&ctx->mutex);
++              wake_up(&ctx->next_req);
++              schedule();
++              mutex_lock(&ctx->mutex);
++      } while (ctx->active && (ctx->avail_in > 0) && (ctx->avail_out > 0));
++}
++
++static int
++unlzma_decompress_update(struct crypto_pcomp *tfm, struct comp_request *req)
++{
++      struct unlzma_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
++      size_t pos = 0;
++
++      mutex_lock(&ctx->mutex);
++      if (!ctx->active && !req->avail_in)
++              goto out;
++
++      pos = ctx->pos;
++      ctx->next_in = req->next_in;
++      ctx->avail_in = req->avail_in;
++      ctx->next_out = req->next_out;
++      ctx->avail_out = req->avail_out;
++
++      unlzma_wait_complete(ctx, false);
++
++      req->next_in = ctx->next_in;
++      req->avail_in = ctx->avail_in;
++      req->next_out = ctx->next_out;
++      req->avail_out = ctx->avail_out;
++      pos = ctx->pos - pos;
++
++out:
++      mutex_unlock(&ctx->mutex);
++      return pos;
++}
++
++static int
++unlzma_decompress_final(struct crypto_pcomp *tfm, struct comp_request *req)
++{
++      struct unlzma_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
++      int ret = 0;
++
++      /* cancel pending operation */
++      mutex_lock(&ctx->mutex);
++      if (ctx->active) {
++              // ret = -EINVAL;
++              unlzma_cancel(ctx);
++      }
++      ctx->pos = 0;
++      mutex_unlock(&ctx->mutex);
++      return ret;
++}
++
++
++static struct pcomp_alg unlzma_alg = {
++      .decompress_setup       = unlzma_decompress_setup,
++      .decompress_init        = unlzma_decompress_init,
++      .decompress_update      = unlzma_decompress_update,
++      .decompress_final       = unlzma_decompress_final,
++
++      .base                   = {
++              .cra_name       = "lzma",
++              .cra_flags      = CRYPTO_ALG_TYPE_PCOMPRESS,
++              .cra_ctxsize    = sizeof(struct unlzma_ctx),
++              .cra_module     = THIS_MODULE,
++              .cra_init       = unlzma_init,
++              .cra_exit       = unlzma_exit,
++      }
++};
++
++static int __init
++unlzma_mod_init(void)
++{
++      return crypto_register_pcomp(&unlzma_alg);
++}
++
++static void __exit
++unlzma_mod_exit(void)
++{
++      crypto_unregister_pcomp(&unlzma_alg);
++}
++
++module_init(unlzma_mod_init);
++module_exit(unlzma_mod_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("LZMA Decompression Algorithm");
++MODULE_AUTHOR("Felix Fietkau <nbd@openwrt.org>");
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -728,6 +728,12 @@ config CRYPTO_ZLIB
+       help
+         This is the zlib algorithm.
++config CRYPTO_UNLZMA
++      tristate "LZMA decompression"
++      select CRYPTO_PCOMP
++      help
++        This is the lzma decompression module.
++
+ config CRYPTO_LZO
+       tristate "LZO compression algorithm"
+       select CRYPTO_ALGAPI
+--- a/crypto/Makefile
++++ b/crypto/Makefile
+@@ -73,6 +73,7 @@ obj-$(CONFIG_CRYPTO_SEED) += seed.o
+ obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o
+ obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
+ obj-$(CONFIG_CRYPTO_ZLIB) += zlib.o
++obj-$(CONFIG_CRYPTO_UNLZMA) += unlzma.o
+ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
+ obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
+ obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o
+--- /dev/null
++++ b/crypto/unlzma.h
+@@ -0,0 +1,80 @@
++/* LZMA uncompresion module for pcomp
++ * Copyright (C) 2009  Felix Fietkau <nbd@openwrt.org>
++ *
++ * Based on:
++ *  Initial Linux kernel adaptation
++ *  Copyright (C) 2006  Alain < alain@knaff.lu >
++ *
++ *  Based on small lzma deflate implementation/Small range coder
++ *  implementation for lzma.
++ *  Copyright (C) 2006  Aurelien Jacobs < aurel@gnuage.org >
++ *
++ *  Based on LzmaDecode.c from the LZMA SDK 4.22 (http://www.7-zip.org/)
++ *  Copyright (C) 1999-2005  Igor Pavlov
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++#ifndef __UNLZMA_H
++#define __UNLZMA_H
++
++struct lzma_header {
++      __u8 pos;
++      __le32 dict_size;
++} __attribute__ ((packed)) ;
++
++
++#define RC_TOP_BITS 24
++#define RC_MOVE_BITS 5
++#define RC_MODEL_TOTAL_BITS 11
++
++#define LZMA_BASE_SIZE 1846
++#define LZMA_LIT_SIZE 768
++
++#define LZMA_NUM_POS_BITS_MAX 4
++
++#define LZMA_LEN_NUM_LOW_BITS 3
++#define LZMA_LEN_NUM_MID_BITS 3
++#define LZMA_LEN_NUM_HIGH_BITS 8
++
++#define LZMA_LEN_CHOICE 0
++#define LZMA_LEN_CHOICE_2 (LZMA_LEN_CHOICE + 1)
++#define LZMA_LEN_LOW (LZMA_LEN_CHOICE_2 + 1)
++#define LZMA_LEN_MID (LZMA_LEN_LOW \
++                    + (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_LOW_BITS)))
++#define LZMA_LEN_HIGH (LZMA_LEN_MID \
++                     +(1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_MID_BITS)))
++#define LZMA_NUM_LEN_PROBS (LZMA_LEN_HIGH + (1 << LZMA_LEN_NUM_HIGH_BITS))
++
++#define LZMA_NUM_STATES 12
++#define LZMA_NUM_LIT_STATES 7
++
++#define LZMA_START_POS_MODEL_INDEX 4
++#define LZMA_END_POS_MODEL_INDEX 14
++#define LZMA_NUM_FULL_DISTANCES (1 << (LZMA_END_POS_MODEL_INDEX >> 1))
++
++#define LZMA_NUM_POS_SLOT_BITS 6
++#define LZMA_NUM_LEN_TO_POS_STATES 4
++
++#define LZMA_NUM_ALIGN_BITS 4
++
++#define LZMA_MATCH_MIN_LEN 2
++
++#define LZMA_IS_MATCH 0
++#define LZMA_IS_REP (LZMA_IS_MATCH + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX))
++#define LZMA_IS_REP_G0 (LZMA_IS_REP + LZMA_NUM_STATES)
++#define LZMA_IS_REP_G1 (LZMA_IS_REP_G0 + LZMA_NUM_STATES)
++#define LZMA_IS_REP_G2 (LZMA_IS_REP_G1 + LZMA_NUM_STATES)
++#define LZMA_IS_REP_0_LONG (LZMA_IS_REP_G2 + LZMA_NUM_STATES)
++#define LZMA_POS_SLOT (LZMA_IS_REP_0_LONG \
++                     + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX))
++#define LZMA_SPEC_POS (LZMA_POS_SLOT \
++                     +(LZMA_NUM_LEN_TO_POS_STATES << LZMA_NUM_POS_SLOT_BITS))
++#define LZMA_ALIGN (LZMA_SPEC_POS \
++                  + LZMA_NUM_FULL_DISTANCES - LZMA_END_POS_MODEL_INDEX)
++#define LZMA_LEN_CODER (LZMA_ALIGN + (1 << LZMA_NUM_ALIGN_BITS))
++#define LZMA_REP_LEN_CODER (LZMA_LEN_CODER + LZMA_NUM_LEN_PROBS)
++#define LZMA_LITERAL (LZMA_REP_LEN_CODER + LZMA_NUM_LEN_PROBS)
++
++#endif
diff --git a/target/linux/generic-2.6/patches-2.6.30/053-squashfs_lzma.patch b/target/linux/generic-2.6/patches-2.6.30/053-squashfs_lzma.patch
new file mode 100644 (file)
index 0000000..b632e05
--- /dev/null
@@ -0,0 +1,214 @@
+--- a/fs/squashfs/Kconfig
++++ b/fs/squashfs/Kconfig
+@@ -2,7 +2,6 @@ config SQUASHFS
+       tristate "SquashFS 4.0 - Squashed file system support"
+       depends on BLOCK
+       select CRYPTO
+-      select CRYPTO_ZLIB
+       help
+         Saying Y here includes support for SquashFS 4.0 (a Compressed
+         Read-Only File System).  Squashfs is a highly compressed read-only
+@@ -37,6 +36,26 @@ config SQUASHFS_EMBEDDED
+         If unsure, say N.
++config SQUASHFS_SUPPORT_ZLIB
++      bool
++      prompt "Support ZLIB compression" if SQUASHFS_SUPPORT_LZMA
++      depends on SQUASHFS
++      select CRYPTO_ZLIB
++      default y
++      help
++        ZLIB is the default compression used in squashfs. If you are
++        using LZMA compression instead, you can remove support for ZLIB
++        entirely.
++
++config SQUASHFS_SUPPORT_LZMA
++      bool "Support LZMA compression"
++      depends on SQUASHFS
++      select CRYPTO_LZMA
++      help
++        By default SquashFS uses ZLIB compression, however (if your tools
++        support it, you can use LZMA instead, which saves space.
++
++
+ config SQUASHFS_FRAGMENT_CACHE_SIZE
+       int "Number of fragments cached" if SQUASHFS_EMBEDDED
+       depends on SQUASHFS
+--- a/fs/squashfs/squashfs_fs.h
++++ b/fs/squashfs/squashfs_fs.h
+@@ -212,6 +212,7 @@ struct meta_index {
+  * definitions for structures on disk
+  */
+ #define ZLIB_COMPRESSION       1
++#define LZMA_COMPRESSION       2
+ struct squashfs_super_block {
+       __le32                  s_magic;
+--- a/fs/squashfs/super.c
++++ b/fs/squashfs/super.c
+@@ -47,13 +47,65 @@
+ #include "squashfs.h"
+-#define SQUASHFS_CRYPTO_ALG   "zlib"
++static int squashfs_setup_zlib(struct squashfs_sb_info *msblk)
++{
++      int err = -EOPNOTSUPP;
++
++#ifdef CONFIG_SQUASHFS_SUPPORT_ZLIB
++      struct {
++              struct nlattr nla;
++              int val;
++      } params = {
++              .nla = {
++                      .nla_len        = nla_attr_size(sizeof(int)),
++                      .nla_type       = ZLIB_DECOMP_WINDOWBITS,
++              },
++              .val                    = DEF_WBITS,
++      };
++
++      msblk->tfm = crypto_alloc_pcomp("zlib", 0,
++                                      CRYPTO_ALG_ASYNC);
++      if (IS_ERR(msblk->tfm)) {
++              ERROR("Failed to load zlib crypto module\n");
++              return PTR_ERR(msblk->tfm);
++      }
++
++      err = crypto_decompress_setup(msblk->tfm, &params, sizeof(params));
++      if (err) {
++              ERROR("Failed to set up decompression parameters\n");
++              crypto_free_pcomp(msblk->tfm);
++      }
++#endif
++      return err;
++}
++
++static int squashfs_setup_lzma(struct squashfs_sb_info *msblk)
++{
++      int err = -EOPNOTSUPP;
++
++#ifdef CONFIG_SQUASHFS_SUPPORT_LZMA
++      msblk->tfm = crypto_alloc_pcomp("lzma", 0,
++                                      CRYPTO_ALG_ASYNC);
++      if (IS_ERR(msblk->tfm)) {
++              ERROR("Failed to load lzma crypto module\n");
++              return PTR_ERR(msblk->tfm);
++      }
++
++      err = crypto_decompress_setup(msblk->tfm, NULL, 0);
++      if (err) {
++              ERROR("Failed to set up decompression parameters\n");
++              crypto_free_pcomp(msblk->tfm);
++      }
++#endif
++
++      return err;
++}
+ static struct file_system_type squashfs_fs_type;
+ static struct super_operations squashfs_super_ops;
+-static int supported_squashfs_filesystem(short major, short minor, short comp)
++static int supported_squashfs_filesystem(short major, short minor)
+ {
+       if (major < SQUASHFS_MAJOR) {
+               ERROR("Major/Minor mismatch, older Squashfs %d.%d "
+@@ -66,9 +118,6 @@ static int supported_squashfs_filesystem
+               return -EINVAL;
+       }
+-      if (comp != ZLIB_COMPRESSION)
+-              return -EINVAL;
+-
+       return 0;
+ }
+@@ -83,16 +132,6 @@ static int squashfs_fill_super(struct su
+       unsigned short flags;
+       unsigned int fragments;
+       u64 lookup_table_start;
+-      struct {
+-              struct nlattr nla;
+-              int val;
+-      } params = {
+-              .nla = {
+-                      .nla_len        = nla_attr_size(sizeof(int)),
+-                      .nla_type       = ZLIB_DECOMP_WINDOWBITS,
+-              },
+-              .val                    = DEF_WBITS,
+-      };
+       int err;
+       TRACE("Entered squashfs_fill_superblock\n");
+@@ -104,21 +143,6 @@ static int squashfs_fill_super(struct su
+       }
+       msblk = sb->s_fs_info;
+-      msblk->tfm = crypto_alloc_pcomp(SQUASHFS_CRYPTO_ALG, 0,
+-                                      CRYPTO_ALG_ASYNC);
+-      if (IS_ERR(msblk->tfm)) {
+-              ERROR("Failed to load %s crypto module\n",
+-                    SQUASHFS_CRYPTO_ALG);
+-              err = PTR_ERR(msblk->tfm);
+-              goto failed_pcomp;
+-      }
+-
+-      err = crypto_decompress_setup(msblk->tfm, &params, sizeof(params));
+-      if (err) {
+-              ERROR("Failed to set up decompression parameters\n");
+-              goto failure;
+-      }
+-
+       sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
+       if (sblk == NULL) {
+               ERROR("Failed to allocate squashfs_super_block\n");
+@@ -158,8 +182,21 @@ static int squashfs_fill_super(struct su
+       /* Check the MAJOR & MINOR versions and compression type */
+       err = supported_squashfs_filesystem(le16_to_cpu(sblk->s_major),
+-                      le16_to_cpu(sblk->s_minor),
+-                      le16_to_cpu(sblk->compression));
++                      le16_to_cpu(sblk->s_minor));
++      if (err < 0)
++              goto failed_mount;
++
++      switch(le16_to_cpu(sblk->compression)) {
++      case ZLIB_COMPRESSION:
++              err = squashfs_setup_zlib(msblk);
++              break;
++      case LZMA_COMPRESSION:
++              err = squashfs_setup_lzma(msblk);
++              break;
++      default:
++              err = -EINVAL;
++              break;
++      }
+       if (err < 0)
+               goto failed_mount;
+@@ -305,21 +342,16 @@ allocate_root:
+       return 0;
+ failed_mount:
++      if (msblk->tfm)
++              crypto_free_pcomp(msblk->tfm);
+       squashfs_cache_delete(msblk->block_cache);
+       squashfs_cache_delete(msblk->fragment_cache);
+       squashfs_cache_delete(msblk->read_page);
+       kfree(msblk->inode_lookup_table);
+       kfree(msblk->fragment_index);
+       kfree(msblk->id_table);
+-      crypto_free_pcomp(msblk->tfm);
+-      kfree(sb->s_fs_info);
+-      sb->s_fs_info = NULL;
+       kfree(sblk);
+-      return err;
+-
+ failure:
+-      crypto_free_pcomp(msblk->tfm);
+-failed_pcomp:
+       kfree(sb->s_fs_info);
+       sb->s_fs_info = NULL;
+       return err;
index a7ce893..885ecec 100644 (file)
        int err;
  
        if (!(dev = alloc_etherdev(sizeof(struct port))))
-@@ -1212,22 +1257,9 @@ static int __devinit eth_init_one(struct
+@@ -1207,18 +1252,10 @@ static int __devinit eth_init_one(struct
        __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
        udelay(50);
  
 -      snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, "0", plat->phy);
 -      port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link, 0,
 -                                 PHY_INTERFACE_MODE_MII);
--      if (IS_ERR(port->phydev)) {
--              printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
--              return PTR_ERR(port->phydev);
--      }
--
+-      if ((err = IS_ERR(port->phydev)))
++      err = ixp4xx_phy_connect(dev);
++      if (err)
+               goto err_free_mem;
 -      /* mask with MAC supported features */
 -      port->phydev->supported &= PHY_BASIC_FEATURES;
 -      port->phydev->advertising = port->phydev->supported;
 -
 -      port->phydev->irq = PHY_POLL;
 -
--      printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy,
--             npe_name(port->npe));
-+      err = ixp4xx_phy_connect(dev);
-+      if (err)
-+              goto err_unreg;
-       return 0;
+       if ((err = register_netdev(dev)))
+               goto err_phy_dis;
  
-@@ -1245,7 +1277,7 @@ static int __devexit eth_remove_one(stru
+@@ -1245,7 +1282,7 @@ static int __devexit eth_remove_one(stru
        struct net_device *dev = platform_get_drvdata(pdev);
        struct port *port = netdev_priv(dev);
  
 -      phy_disconnect(port->phydev);
 +      ixp4xx_phy_disconnect(dev);
        unregister_netdev(dev);
+       phy_disconnect(port->phydev);
        npe_port_tab[NPE_ID(port->id)] = NULL;
-       platform_set_drvdata(pdev, NULL);