Kaynağa Gözat

get rid of dynamic buffer struct allocation during pcomp lzma decompression and instead force the caller to provide the maximum buffer list size

SVN-Revision: 17475
Felix Fietkau 16 yıl önce
ebeveyn
işleme
eda566c4e9

+ 55 - 15
target/linux/generic-2.6/patches-2.6.30/052-pcomp_lzma_support.patch

@@ -1,6 +1,6 @@
 --- /dev/null
 +++ b/crypto/unlzma.c
-@@ -0,0 +1,723 @@
+@@ -0,0 +1,748 @@
 +/*
 + * LZMA uncompresion module for pcomp
 + * Copyright (C) 2009  Felix Fietkau <[email protected]>
@@ -36,12 +36,12 @@
 +#include <linux/kthread.h>
 +
 +#include <crypto/internal/compress.h>
++#include <net/netlink.h>
 +#include "unlzma.h"
 +
 +static int instance = 0;
 +
 +struct unlzma_buffer {
-+	struct unlzma_buffer *last;
 +	int offset;
 +	int size;
 +	u8 *ptr;
@@ -68,8 +68,10 @@
 +	/* writer state */
 +	u8 previous_byte;
 +	ssize_t pos;
-+	struct unlzma_buffer *head;
 +	int buf_full;
++	int n_buffers;
++	int buffers_max;
++	struct unlzma_buffer *buffers;
 +
 +	/* cstate */
 +	int state;
@@ -92,12 +94,11 @@
 +{
 +	struct unlzma_buffer *bh;
 +
-+	bh = kzalloc(sizeof(struct unlzma_buffer), GFP_KERNEL);
++	BUG_ON(ctx->n_buffers >= ctx->buffers_max);
++	bh = &ctx->buffers[ctx->n_buffers++];
 +	bh->ptr = ctx->next_out;
 +	bh->offset = ctx->pos;
-+	bh->last = ctx->head;
 +	bh->size = ctx->avail_out;
-+	ctx->head = bh;
 +	ctx->buf_full = 0;
 +}
 +
@@ -208,17 +209,20 @@
 +static u8
 +peek_old_byte(struct unlzma_ctx *ctx, u32 offs)
 +{
-+	struct unlzma_buffer *bh = ctx->head;
++	struct unlzma_buffer *bh = &ctx->buffers[ctx->n_buffers - 1];
++	int i = ctx->n_buffers;
 +	u32 pos;
 +
++	BUG_ON(!ctx->n_buffers);
 +	pos = ctx->pos - offs;
 +	if (pos >= ctx->dict_size) {
 +		pos = (~pos % ctx->dict_size);
 +	}
 +
 +	while (bh->offset > pos) {
-+		bh = bh->last;
-+		BUG_ON(!bh);
++		bh--;
++		i--;
++		BUG_ON(!i);
 +	}
 +
 +	pos -= bh->offset;
@@ -460,6 +464,7 @@
 +		hdr_buf[i] = rc_read(ctx);
 +	}
 +
++	ctx->n_buffers = 0;
 +	ctx->pos = 0;
 +	get_buffer(ctx);
 +	ctx->active = true;
@@ -554,11 +559,6 @@
 +		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;
@@ -598,6 +598,10 @@
 +		unlzma_cancel(ctx);
 +		kthread_stop(ctx->thread);
 +		ctx->thread = NULL;
++		if (ctx->buffers)
++			kfree(ctx->buffers);
++		ctx->buffers_max = 0;
++		ctx->buffers = NULL;
 +	}
 +}
 +
@@ -605,10 +609,31 @@
 +unlzma_decompress_setup(struct crypto_pcomp *tfm, void *p, unsigned int len)
 +{
 +	struct unlzma_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
++	struct nlattr *tb[UNLZMA_DECOMP_MAX + 1];
 +	int ret = 0;
 +
 +	if (ctx->thread)
-+		return 0;
++		return -EINVAL;
++
++	if (!p)
++		return -EINVAL;
++
++	ret = nla_parse(tb, UNLZMA_DECOMP_MAX, p, len, NULL);
++	if (!tb[UNLZMA_DECOMP_OUT_BUFFERS])
++		return -EINVAL;
++
++	if (ctx->buffers_max && (ctx->buffers_max <
++	    nla_get_u32(tb[UNLZMA_DECOMP_OUT_BUFFERS]))) {
++		kfree(ctx->buffers);
++		ctx->buffers_max = 0;
++		ctx->buffers = NULL;
++	}
++	if (!ctx->buffers) {
++		ctx->buffers_max = nla_get_u32(tb[UNLZMA_DECOMP_OUT_BUFFERS]);
++		ctx->buffers = kzalloc(sizeof(struct unlzma_buffer) * ctx->buffers_max, GFP_KERNEL);
++	}
++	if (!ctx->buffers)
++		return -ENOMEM;
 +
 +	mutex_init(&ctx->mutex);
 +	init_waitqueue_head(&ctx->next_req);
@@ -832,3 +857,18 @@
 +#define LZMA_LITERAL (LZMA_REP_LEN_CODER + LZMA_NUM_LEN_PROBS)
 +
 +#endif
+--- a/include/crypto/compress.h
++++ b/include/crypto/compress.h
+@@ -49,6 +49,12 @@ enum zlib_decomp_params {
+ 
+ #define ZLIB_DECOMP_MAX	(__ZLIB_DECOMP_MAX - 1)
+ 
++enum unlzma_decomp_params {
++	UNLZMA_DECOMP_OUT_BUFFERS = 1, /* naximum number of output buffers */
++	__UNLZMA_DECOMP_MAX,
++};
++#define UNLZMA_DECOMP_MAX	(__UNLZMA_DECOMP_MAX - 1)
++
+ 
+ struct crypto_pcomp {
+ 	struct crypto_tfm base;

+ 38 - 8
target/linux/generic-2.6/patches-2.6.30/053-squashfs_lzma.patch

@@ -47,7 +47,7 @@
  	__le32			s_magic;
 --- a/fs/squashfs/super.c
 +++ b/fs/squashfs/super.c
-@@ -47,13 +47,65 @@
+@@ -47,13 +47,76 @@
  #include "squashfs.h"
  
  
@@ -81,7 +81,7 @@
 +		crypto_free_pcomp(msblk->tfm);
 +	}
 +#endif
- 
++
 +	return err;
 +}
 +
@@ -90,6 +90,17 @@
 +	int err = -EOPNOTSUPP;
 +
 +#ifdef CONFIG_SQUASHFS_SUPPORT_LZMA
++	struct {
++		struct nlattr nla;
++		int val;
++	} params = {
++		.nla = {
++			.nla_len	= nla_attr_size(sizeof(int)),
++			.nla_type	= UNLZMA_DECOMP_OUT_BUFFERS,
++		},
++		.val = (msblk->block_size / PAGE_CACHE_SIZE) + 1
++	};
+ 
 +	msblk->tfm = crypto_alloc_pcomp("lzma", 0,
 +					CRYPTO_ALG_ASYNC);
 +	if (IS_ERR(msblk->tfm)) {
@@ -97,7 +108,7 @@
 +		return PTR_ERR(msblk->tfm);
 +	}
 +
-+	err = crypto_decompress_setup(msblk->tfm, NULL, 0);
++	err = crypto_decompress_setup(msblk->tfm, &params, sizeof(params));
 +	if (err) {
 +		ERROR("Failed to set up decompression parameters\n");
 +		crypto_free_pcomp(msblk->tfm);
@@ -115,7 +126,7 @@
  {
  	if (major < SQUASHFS_MAJOR) {
  		ERROR("Major/Minor mismatch, older Squashfs %d.%d "
-@@ -66,9 +118,6 @@ static int supported_squashfs_filesystem
+@@ -66,9 +129,6 @@ static int supported_squashfs_filesystem
  		return -EINVAL;
  	}
  
@@ -125,7 +136,7 @@
  	return 0;
  }
  
-@@ -83,16 +132,6 @@ static int squashfs_fill_super(struct su
+@@ -83,16 +143,6 @@ static int squashfs_fill_super(struct su
  	unsigned short flags;
  	unsigned int fragments;
  	u64 lookup_table_start;
@@ -142,7 +153,7 @@
  	int err;
  
  	TRACE("Entered squashfs_fill_superblock\n");
-@@ -104,21 +143,6 @@ static int squashfs_fill_super(struct su
+@@ -104,21 +154,6 @@ static int squashfs_fill_super(struct su
  	}
  	msblk = sb->s_fs_info;
  
@@ -164,8 +175,15 @@
  	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
+@@ -156,10 +191,28 @@ static int squashfs_fill_super(struct su
+ 		goto failed_mount;
+ 	}
  
++	/* Check block size for sanity */
++	msblk->block_size = le32_to_cpu(sblk->block_size);
++	if (msblk->block_size > SQUASHFS_FILE_MAX_SIZE)
++		goto failed_mount;
++
  	/* Check the MAJOR & MINOR versions and compression type */
  	err = supported_squashfs_filesystem(le16_to_cpu(sblk->s_major),
 -			le16_to_cpu(sblk->s_minor),
@@ -188,7 +206,19 @@
  	if (err < 0)
  		goto failed_mount;
  
-@@ -315,21 +352,16 @@ allocate_root:
+@@ -179,11 +232,6 @@ static int squashfs_fill_super(struct su
+ 			i_size_read(sb->s_bdev->bd_inode))
+ 		goto failed_mount;
+ 
+-	/* Check block size for sanity */
+-	msblk->block_size = le32_to_cpu(sblk->block_size);
+-	if (msblk->block_size > SQUASHFS_FILE_MAX_SIZE)
+-		goto failed_mount;
+-
+ 	/*
+ 	 * Check the system page size is not larger than the filesystem
+ 	 * block size (by default 128K).  This is currently not supported.
+@@ -315,21 +363,16 @@ allocate_root:
  	return 0;
  
  failed_mount: