--- linux-2.6.28/include/linux/LzmaDecode.h
+++ linux-2.6.28/include/linux/LzmaDecode.h
@@ -22,7 +22,7 @@
 #ifndef __LZMADECODE_H
 #define __LZMADECODE_H
 
-/* #define _LZMA_IN_CB */
+#define _LZMA_IN_CB
 /* Use callback for input data */
 
 /* #define _LZMA_OUT_READ */
--- linux-2.6.28/fs/squashfs/inode.c
+++ linux-2.6.28/fs/squashfs/inode.c
@@ -172,338 +172,172 @@
 	return NULL;
 }
 
-/*------------------------------------------------------------------------------------------*\
-\*------------------------------------------------------------------------------------------*/
-#define LZMA_BUFFER_SMALL_VERSION
-#define LZMA_MAX_BUFFERS 1
-
-#if !defined(LZMA_BUFFER_SMALL_VERSION)
-struct _lzma_buffer_queue {
-    volatile unsigned int read, write;
-    const unsigned int size;
-    volatile unsigned char *buffer[LZMA_MAX_BUFFERS + 1];
-} lzma_buffer_queue = {
-    .read = 0,
-    .write = 0,
-    .size = LZMA_MAX_BUFFERS
+struct read_data_state {
+	struct _ILzmaInCallback		Callback;
+	struct squashfs_sb_info *	msblk;
+	struct buffer_head **		bh;
+	size_t				bh_used;
+	size_t				bh_cur;
+	size_t				bh_freed;
+	size_t				offset;
+	size_t				bytes;
+	size_t				c_byte;
 };
-#endif
-
-char lzma_buffers[LZMA_MAX_BUFFERS][64 << 10];
 
-#if !defined(LZMA_BUFFER_SMALL_VERSION)
-struct semaphore lzma_buffer_sema = __SEMAPHORE_INITIALIZER(lzma_buffer_sema, 0);
-#else
-struct semaphore lzma_buffer_sema = __SEMAPHORE_INITIALIZER(lzma_buffer_sema, 1);
-#endif
-/*------------------------------------------------------------------------------------------*\
-\*------------------------------------------------------------------------------------------*/
-#if !defined(LZMA_BUFFER_SMALL_VERSION)
-void free_lzma_buffer(void *ptr) {
-
-    if (ptr != lzma_buffers[0]) {
-        vfree(ptr);
-        return;
-    }
-    lzma_buffer_queue.buffer[lzma_buffer_queue.write++] = ptr;
-    if(lzma_buffer_queue.write > lzma_buffer_queue.size)
-        lzma_buffer_queue.write = 0;
-    up(&lzma_buffer_sema);
-}
-
-/*------------------------------------------------------------------------------------------*\
-\*------------------------------------------------------------------------------------------*/
-void *alloc_lzma_buffer(void) {
-    void *ptr;
-    if(lzma_buffer_queue.buffer[0] == NULL) {
-        int i;
-        for(i = 0 ; i < LZMA_MAX_BUFFERS ; i++)
-            free_lzma_buffer(lzma_buffers[i]);
-    }
-
-    if(down_interruptible(&lzma_buffer_sema)) {
-        return NULL;
-    }
-
-    ptr = (void *)lzma_buffer_queue.buffer[lzma_buffer_queue.read++];
-    if(lzma_buffer_queue.read > lzma_buffer_queue.size)
-        lzma_buffer_queue.read = 0;
-    /*--- if (lzma_buffer_queue.read == LZMA_MAX_BUFFERS) { ---*/
-        /*--- printk("SQUSHFS: %d LZMA Buffer used\n", lzma_buffer_queue.read); ---*/
-    /*--- } ---*/
-    return ptr;
-}
-#else
-void free_lzma_buffer(void *ptr __attribute__((unused))) {
-    up(&lzma_buffer_sema);
-}
-
-void *alloc_lzma_buffer(void) {
-
-    down(&lzma_buffer_sema);
-    return lzma_buffers[0];
+static int
+read_block (void *object, const unsigned char **buffer, size_t *bufferSize)
+{
+	struct read_data_state *rds = (struct read_data_state *)object;
+	struct squashfs_sb_info *msblk = rds->msblk;
+	size_t avail_bytes = min(rds->c_byte - rds->bytes, msblk->devblksize - rds->offset);
+	struct buffer_head *b = rds->bh[rds->bh_cur];
+
+	TRACE("%s: 1: free %d, cur %d, ofs %x, bytes %x, c_byte %x, avail %x\n",
+	      __FUNCTION__, rds->bh_freed, rds->bh_cur,
+	      rds->offset, rds->bytes, rds->c_byte, avail_bytes);
+	if (rds->bh_freed < rds->bh_cur) {
+		brelse(rds->bh[rds->bh_freed]);
+		rds->bh_freed++;
+	}
+
+	wait_on_buffer(b);
+	if(!buffer_uptodate(b))
+		return -1;
+
+	*buffer = b->b_data + rds->offset;
+	*bufferSize = avail_bytes;
+	rds->bytes += avail_bytes;
+	rds->offset = 0;
+	rds->bh_cur++;
+	TRACE("%s: 2: free %d, cur %d, ofs %x, bytes %x, c_byte %x, avail %x\n",
+	      __FUNCTION__, rds->bh_freed, rds->bh_cur,
+	      rds->offset, rds->bytes, rds->c_byte, avail_bytes);
+	return 0;
 }
-#endif
 
-/*------------------------------------------------------------------------------------------*\
-\*------------------------------------------------------------------------------------------*/
 SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer,
 		long long index, unsigned int length,
 		long long *next_index, int srclength)
 {
 	struct squashfs_sb_info *msblk = s->s_fs_info;
 	struct squashfs_super_block *sblk = &msblk->sblk;
-	struct buffer_head **bh;
-	unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);
 	unsigned int cur_index = index >> msblk->devblksize_log2;
-	int bytes, avail_bytes, b = 0, k = 0;
+	int avail_bytes, blocks_read = 0, cur_offset, end_offset;
 	unsigned int compressed;
-	unsigned int c_byte = length;
-
-	unsigned char *lzma_buffer = NULL;
-	unsigned int lzma_buffer_len = 0;
-
-	/*--- debug_msblk = msblk; ---*/
-
-	if(msblk->use_lzma) {
-		lzma_buffer = alloc_lzma_buffer();
-        if (!lzma_buffer) {
-            panic("no lzma_buffer\n");
-        }
-	}
-
-	bh = kmalloc(((sblk->block_size >> msblk->devblksize_log2) + 1) *
+	unsigned int out_size;
+	struct read_data_state rds;
+	rds.offset = index & ((1 << msblk->devblksize_log2) - 1);
+
+	rds.Callback.Read = read_block;
+	rds.msblk = msblk;
+	rds.bh = kmalloc(((sblk->block_size >> msblk->devblksize_log2) + 1) *
 			sizeof(struct buffer_head *), GFP_KERNEL);
-	if (bh == NULL)
+	rds.bh_used = 0;
+	rds.bh_cur = 0;
+	rds.bh_freed = 0;
+	rds.bytes = 0;
+	if (rds.bh == NULL)
 		goto read_failure;
-
-	if (c_byte) {
-		bytes = -offset;
-		compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);
-		c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
-
-		TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index,
-				compressed ? "" : "un", (unsigned int) c_byte, srclength);
-
-		if (c_byte > srclength || index < 0 || (index + c_byte) > sblk->bytes_used)
+	if (index < 0)
 			goto read_failure;
 
-		for (b = 0; bytes < (int) c_byte; b++, cur_index++) {
-			bh[b] = sb_getblk(s, cur_index);
-			if (bh[b] == NULL)
-				goto block_release;
-			bytes += msblk->devblksize;
-		}
-		ll_rw_block(READ, b, bh);
-	} else {
-		if (index < 0 || (index + 2) > sblk->bytes_used)
+	if (!length) {
+		if (index + 2 > sblk->bytes_used)
 			goto read_failure;
 
-		bh[0] = get_block_length(s, &cur_index, &offset, &c_byte);
-		if (bh[0] == NULL)
+		rds.bh[0] = get_block_length(s, &cur_index, &rds.offset, &rds.c_byte);
+		if (rds.bh[0] == NULL)
 			goto read_failure;
-		b = 1;
-
-		bytes = msblk->devblksize - offset;
-		compressed = SQUASHFS_COMPRESSED(c_byte);
-		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
+		compressed = SQUASHFS_COMPRESSED(rds.c_byte);
+		rds.c_byte = SQUASHFS_COMPRESSED_SIZE(rds.c_byte);
 
 		TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
-				? "" : "un", (unsigned int) c_byte);
+					? "" : "un", (unsigned int) rds.c_byte);
 
-		if (c_byte > srclength || (index + c_byte) > sblk->bytes_used)
-			goto block_release;
+		rds.bh_used++;
+		cur_index++;
+		cur_offset = msblk->devblksize;
+		}
+	else {
+		compressed = SQUASHFS_COMPRESSED_BLOCK(length);
+		rds.c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(length);
 
-		for (; bytes < c_byte; b++) {
-			bh[b] = sb_getblk(s, ++cur_index);
-			if (bh[b] == NULL)
-				goto block_release;
-			bytes += msblk->devblksize;
+		TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index,
+					compressed ? "" : "un", (unsigned int) rds.c_byte, srclength);
+
+		cur_offset = 0;
 		}
-		ll_rw_block(READ, b - 1, bh + 1);
+	if (rds.c_byte > srclength || index + rds.c_byte > sblk->bytes_used)
+		goto read_failure;
+
+	blocks_read = rds.bh_used;
+	end_offset = rds.offset + rds.c_byte;
+	while (cur_offset < end_offset) {
+		rds.bh[rds.bh_used] = sb_getblk(s, cur_index);
+		if (rds.bh[rds.bh_used] == NULL)
+			goto block_release;
+		rds.bh_used++;
+		cur_index++;
+		cur_offset += msblk->devblksize;
 	}
+	ll_rw_block(READ, rds.bh_used - blocks_read, rds.bh + blocks_read);
 
 	if (compressed) {
 		int zlib_err = 0;
-
 		/*
 		 * uncompress block
 		 */
 
 		mutex_lock(&msblk->read_data_mutex);
-
-		msblk->stream.next_out = buffer;
-		msblk->stream.avail_out = srclength;
-
-		/*----------------------------------------------------------------------------------*\
-		  \*----------------------------------------------------------------------------------*/
-		for (bytes = 0; k < b; k++) {
-			avail_bytes = min(c_byte - bytes, msblk->devblksize - offset);
-
-			wait_on_buffer(bh[k]);
-			if (!buffer_uptodate(bh[k]))
-				goto release_mutex;
-
-			msblk->stream.next_in = bh[k]->b_data + offset;
-			msblk->stream.avail_in = avail_bytes;
-
-			if(msblk->use_lzma) {
-				unsigned int processed_in = 0, processed_out = 0;
-				if (k == 0) {
-					lzma_buffer_len = 0;
-					msblk->stream.total_out = 0;
-
-					if (avail_bytes == 0) {
-						offset = 0;
-						brelse(bh[k]);
-						continue;
-					}
-				}
-				if(avail_bytes < c_byte) {
-					TRACE("[LzmaDecode] not enough bytes avail %u c_byte %u\n", avail_bytes, c_byte);
-					memcpy(lzma_buffer + lzma_buffer_len, msblk->stream.next_in, msblk->stream.avail_in);
-					msblk->stream.next_in  = lzma_buffer;
-					lzma_buffer_len += msblk->stream.avail_in;
-					msblk->stream.avail_in = lzma_buffer_len;
-				} else {
-					lzma_buffer_len = avail_bytes;
-				}
-
-				TRACE("[LzmaDecode] next_in 0x%x avail_in %u next_out 0x%x avail_out %u\n",
-						(unsigned int)msblk->stream.next_in, msblk->stream.avail_in, (unsigned int)msblk->stream.next_out, msblk->stream.avail_out);
-
-				TRACE("[LzmaDecode] lzma_buffer_len %u\n", lzma_buffer_len);
-				if(lzma_buffer_len >= c_byte) {
-					/*--- static unsigned int lzma_used = 0; ---*/
-					/*--- lzma_used++; ---*/
 					zlib_err = LzmaDecode(&msblk->lzma_decoder_state, 
+#ifdef _LZMA_IN_CB
+				      &rds.Callback,
+#else
 							msblk->stream.next_in,
 							msblk->stream.avail_in,
 							&processed_in, 
-							msblk->stream.next_out, 
-							msblk->stream.avail_out,
-							&processed_out);
-
-					TRACE(" processed_in %u  processed_out %u\n", processed_in, processed_out);
-
-					/*--- dump_block("LzmaDecode", msblk->stream.next_in, msblk->stream.avail_in); ---*/
+#endif
+				      buffer,
+				      srclength,
+				      &out_size);
 
-					if ((zlib_err != LZMA_RESULT_OK) || !processed_in) { 
-						/*--- int ii; ---*/
+		if ((zlib_err != LZMA_RESULT_OK)) {
 						ERROR("<LzmaDecode returned Error 0x%x>\n", zlib_err);
-						/*--- printk("LZMA: avail_out 0x%x avail_in 0x%x lzma_buffer_len 0x%x c_byte 0x%x\n", msblk->stream.avail_out, msblk->stream.avail_in, lzma_buffer_len, c_byte); ---*/
-						/*--- printk("LZAM: processed: in 0x%x out 0x%x lzma_used %d\n", processed_in, processed_out, lzma_used); ---*/
-						/*--- for(ii = 0 ; ii < 10 ; ii++) { ---*/
-						/*--- if(current_last_block == 0) ---*/
-						/*--- current_last_block = 9; ---*/
-						/*--- else ---*/
-						/*--- current_last_block--; ---*/
-						/*--- printk("block %u %s crypted\n", ---*/ 
-						/*--- last_block_nr[current_last_block], ---*/
-						/*--- last_block_crypt[current_last_block] ? "was" : " was not"); ---*/
-						/*--- squashfs_dump_block("cryped", last_crypted_block[current_last_block], 1024); ---*/
-						/*--- } ---*/
-						/*--- lzma_used--; ---*/
-						/*--- panic("LZMA ERROR !!!!"); ---*/
-						/*--- for(k = 0 ; k < b ; k++) { ---*/
-						/*--- if (atomic_read(&(bh[k]->b_count))) { ---*/
-						/*--- brelse(bh[k]); ---*/
-						/*--- } ---*/
-						/*--- } ---*/
-						goto release_mutex;
-					}
-					/*--- lzma_used--; ---*/
-					zlib_err = Z_OK;
-
-					msblk->stream.next_out  += processed_out;
-					msblk->stream.avail_out -= processed_out;
-					msblk->stream.total_out += processed_out;
-				}
-			} else {
-
-				if (k == 0) {
-					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;
 					}
-
-					if (avail_bytes == 0) {
-						offset = 0;
-						brelse(bh[k]);
-						continue;
-					}
-				}
-
-				zlib_err = zlib_inflate(&msblk->stream, Z_NO_FLUSH);
-				if (zlib_err != Z_OK && zlib_err != Z_STREAM_END) {
-					ERROR("zlib_inflate returned unexpected result 0x%x,"
-							" srclength %d, avail_in %d, avail_out %d\n", zlib_err,
-							srclength, msblk->stream.avail_in, msblk->stream.avail_out);
-					goto release_mutex;
-				}
-
-			}
-			bytes += avail_bytes;
-			offset = 0;
-			brelse(bh[k]);
-		}
-
-		if(msblk->use_lzma == 0) {
-			if (zlib_err != Z_STREAM_END)
-				goto release_mutex;
-
-			zlib_err = zlib_inflateEnd(&msblk->stream);
-			if (zlib_err != Z_OK) {
-				ERROR("zlib_inflateEnd returned unexpected result 0x%x,"
-						" srclength %d\n", zlib_err, srclength);
-				goto release_mutex;
-			}
-		}
-		bytes = msblk->stream.total_out;
 		mutex_unlock(&msblk->read_data_mutex);
 	} else {
-		int i;
-
-		for(i = 0; i < b; i++) {
-			wait_on_buffer(bh[i]);
-			if (!buffer_uptodate(bh[i]))
+		TRACE("uncompressed: %d\n", rds.c_byte);
+		while (rds.bytes < rds.c_byte) {
+			const unsigned char *src;
+			size_t bytes = rds.bytes;
+			if (rds.Callback.Read (&rds.Callback, &src, &avail_bytes))
 				goto block_release;
+			TRACE("Read -> %p %d, @%x\n", src, avail_bytes, bytes);
+			memcpy(buffer + bytes, src, avail_bytes);
 		}
-
-		for (bytes = 0; k < b; k++) {
-			avail_bytes = min(c_byte - bytes, msblk->devblksize - offset);
-
-			memcpy(buffer + bytes, bh[k]->b_data + offset, avail_bytes);
-			bytes += avail_bytes;
-			offset = 0;
-			brelse(bh[k]);
-		}
+		out_size = rds.bytes;
 	}
 
-	if (next_index){
-		*next_index = index + c_byte + (length ? 0 :
+	if (next_index)
+		*next_index = index + rds.c_byte + (length ? 0 :
 				(SQUASHFS_CHECK_DATA(msblk->sblk.flags) ? 3 : 2));
-	}
 
-	if(lzma_buffer)
-        free_lzma_buffer(lzma_buffer);
-	kfree(bh);
-	return bytes;
+	for (; rds.bh_freed < rds.bh_used; rds.bh_freed++)
+		brelse(rds.bh[rds.bh_freed]);
+	kfree(rds.bh);
+	return out_size;
 
 release_mutex:
 	mutex_unlock(&msblk->read_data_mutex);
 
 block_release:
-	for (; k < b; k++)
-		brelse(bh[k]);
+	for (; rds.bh_freed < rds.bh_used; rds.bh_freed++)
+		brelse(rds.bh[rds.bh_freed]);
 
 read_failure:
 	ERROR("sb_bread failed reading block 0x%x\n", cur_index);
-	if(lzma_buffer)
-        free_lzma_buffer(lzma_buffer);
-	kfree(bh);
+	kfree(rds.bh);
 	return 0;
 }
 
