diff --git a/Makefile b/Makefile index 5f290ef..762cbd2 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,9 @@ CRUXVERSION = 2.4 COLLECTIONS = core opt xorg KERNEL_MIRROR = ftp://ftp.kernel.org KERNEL_VERSION = 2.6.23.9 -KERNEL_PATCHES = squashfs3.2-patch +KERNEL_PATCHES = squashfs3.3-patch STATIC_BB = http://jaeger.morpheus.net/linux/crux/files/busybox.bz2 -SYSLINUX_VERSION = 3.51 +SYSLINUX_VERSION = 3.54 FAKE_ROOT_DIR = $(PWD)/tmp/fake_root SQUASHFS_DIR = $(PWD)/tmp/squashfs DATE_STR = `date +'%Y%m%d'` diff --git a/kernel/squashfs3.2-patch b/kernel/squashfs3.3-patch similarity index 80% rename from kernel/squashfs3.2-patch rename to kernel/squashfs3.3-patch index d2ea6df..4bb62e4 100644 --- a/kernel/squashfs3.2-patch +++ b/kernel/squashfs3.3-patch @@ -1,26 +1,27 @@ -diff -Nru linux-2.6.23.1.orig/fs/Kconfig linux-2.6.23.1/fs/Kconfig ---- linux-2.6.23.1.orig/fs/Kconfig 2007-10-22 14:00:10.000000000 +0200 -+++ linux-2.6.23.1/fs/Kconfig 2007-10-22 14:00:50.000000000 +0200 -@@ -1364,6 +1364,71 @@ +diff -urN linux-2.6.23.9.orig/fs/Kconfig linux-2.6.23.9/fs/Kconfig +--- linux-2.6.23.9.orig/fs/Kconfig 2007-11-26 11:51:43.000000000 -0600 ++++ linux-2.6.23.9/fs/Kconfig 2007-12-12 14:49:36.000000000 -0600 +@@ -1364,6 +1364,56 @@ If unsure, say N. +config SQUASHFS -+ tristate "SquashFS 3.2 - Squashed file system support" ++ tristate "SquashFS 3.3 - Squashed file system support" + select ZLIB_INFLATE + help -+ Saying Y here includes support for SquashFS 3.2 (a Compressed Read-Only File -+ System). Squashfs is a highly compressed read-only filesystem for Linux. -+ It uses zlib compression to compress both files, inodes and directories. -+ Inodes in the system are very small and all blocks are packed to minimise -+ data overhead. Block sizes greater than 4K are supported up to a maximum of 64K. -+ SquashFS 3.1 supports 64 bit filesystems and files (larger than 4GB), full -+ uid/gid information, hard links and timestamps. ++ Saying Y here includes support for SquashFS 3.3 (a Compressed ++ Read-Only File System). Squashfs is a highly compressed read-only ++ filesystem for Linux. It uses zlib compression to compress both ++ files, inodes and directories. Inodes in the system are very small ++ and all blocks are packed to minimise data overhead. Block sizes ++ greater than 4K are supported up to a maximum of 1 Mbytes (default ++ block size 128K). SquashFS 3.3 supports 64 bit filesystems and files ++ (larger than 4GB), full uid/gid information, hard links and timestamps. + -+ Squashfs is intended for general read-only filesystem use, for archival -+ use (i.e. in cases where a .tar.gz file may be used), and in embedded -+ systems where low overhead is needed. Further information and filesystem tools -+ are available from http://squashfs.sourceforge.net. ++ Squashfs is intended for general read-only filesystem use, for ++ archival use (i.e. in cases where a .tar.gz file may be used), and in ++ embedded systems where low overhead is needed. Further information ++ and filesystem tools are available from http://squashfs.sourceforge.net. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), @@ -32,13 +33,11 @@ diff -Nru linux-2.6.23.1.orig/fs/Kconfig linux-2.6.23.1/fs/Kconfig + +config SQUASHFS_EMBEDDED + -+ bool "Additional options for memory-constrained systems" ++ bool "Additional option for memory-constrained systems" + depends on SQUASHFS + default n + help -+ Saying Y here allows you to specify cache sizes and how Squashfs -+ allocates memory. This is only intended for memory constrained -+ systems. ++ Saying Y here allows you to specify cache size. + + If unsure, say N. + @@ -55,27 +54,13 @@ diff -Nru linux-2.6.23.1.orig/fs/Kconfig linux-2.6.23.1/fs/Kconfig + + Note there must be at least one cached fragment. Anything + much more than three will probably not make much difference. -+ -+config SQUASHFS_VMALLOC -+ bool "Use Vmalloc rather than Kmalloc" if SQUASHFS_EMBEDDED -+ depends on SQUASHFS -+ default n -+ help -+ By default SquashFS uses kmalloc to obtain fragment cache memory. -+ Kmalloc memory is the standard kernel allocator, but it can fail -+ on memory constrained systems. Because of the way Vmalloc works, -+ Vmalloc can succeed when kmalloc fails. Specifying this option -+ will make SquashFS always use Vmalloc to allocate the -+ fragment cache memory. -+ -+ If unsure, say N. + config VXFS_FS tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)" depends on BLOCK -diff -Nru linux-2.6.23.1.orig/fs/Makefile linux-2.6.23.1/fs/Makefile ---- linux-2.6.23.1.orig/fs/Makefile 2007-10-22 14:00:10.000000000 +0200 -+++ linux-2.6.23.1/fs/Makefile 2007-10-22 14:00:50.000000000 +0200 +diff -urN linux-2.6.23.9.orig/fs/Makefile linux-2.6.23.9/fs/Makefile +--- linux-2.6.23.9.orig/fs/Makefile 2007-11-26 11:51:43.000000000 -0600 ++++ linux-2.6.23.9/fs/Makefile 2007-12-12 14:49:36.000000000 -0600 @@ -72,6 +72,7 @@ obj-$(CONFIG_JBD2) += jbd2/ obj-$(CONFIG_EXT2_FS) += ext2/ @@ -84,9 +69,9 @@ diff -Nru linux-2.6.23.1.orig/fs/Makefile linux-2.6.23.1/fs/Makefile obj-$(CONFIG_RAMFS) += ramfs/ obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ obj-$(CONFIG_CODA_FS) += coda/ -diff -Nru linux-2.6.23.1.orig/fs/squashfs/Makefile linux-2.6.23.1/fs/squashfs/Makefile ---- linux-2.6.23.1.orig/fs/squashfs/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.23.1/fs/squashfs/Makefile 2007-10-22 14:00:52.000000000 +0200 +diff -urN linux-2.6.23.9.orig/fs/squashfs/Makefile linux-2.6.23.9/fs/squashfs/Makefile +--- linux-2.6.23.9.orig/fs/squashfs/Makefile 1969-12-31 18:00:00.000000000 -0600 ++++ linux-2.6.23.9/fs/squashfs/Makefile 2007-12-12 14:49:36.000000000 -0600 @@ -0,0 +1,7 @@ +# +# Makefile for the linux squashfs routines. @@ -95,15 +80,15 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/Makefile linux-2.6.23.1/fs/squashfs/Ma +obj-$(CONFIG_SQUASHFS) += squashfs.o +squashfs-y += inode.o +squashfs-y += squashfs2_0.o -diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/inode.c ---- linux-2.6.23.1.orig/fs/squashfs/inode.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.23.1/fs/squashfs/inode.c 2007-10-22 14:01:59.000000000 +0200 -@@ -0,0 +1,2342 @@ +diff -urN linux-2.6.23.9.orig/fs/squashfs/inode.c linux-2.6.23.9/fs/squashfs/inode.c +--- linux-2.6.23.9.orig/fs/squashfs/inode.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-2.6.23.9/fs/squashfs/inode.c 2007-12-12 14:49:52.000000000 -0600 +@@ -0,0 +1,2193 @@ +/* + * Squashfs - a compressed read only filesystem for Linux + * + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 -+ * Phillip Lougher ++ * Phillip Lougher + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License @@ -124,7 +109,6 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + +#include +#include -+#include +#include +#include +#include @@ -132,14 +116,14 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino +#include +#include +#include ++#include +#include -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)) +#include -+#endif + +#include "squashfs.h" + ++int squashfs_cached_blks; ++ +static void vfs_read_inode(struct inode *i); +static struct dentry *squashfs_get_parent(struct dentry *child); +static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode); @@ -149,7 +133,6 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + int readahead_blks, char *block_list, + unsigned short **block_p, unsigned int *bsize); +static int squashfs_readpage(struct file *file, struct page *page); -+static int squashfs_readpage4K(struct file *file, struct page *page); +static int squashfs_readdir(struct file *, void *, filldir_t); +static struct dentry *squashfs_lookup(struct inode *, struct dentry *, + struct nameidata *); @@ -202,10 +185,6 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + .readpage = squashfs_readpage +}; + -+SQSH_EXTERN const struct address_space_operations squashfs_aops_4K = { -+ .readpage = squashfs_readpage4K -+}; -+ +static const struct file_operations squashfs_dir_ops = { + .read = generic_read_dir, + .readdir = squashfs_readdir @@ -289,30 +268,36 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; -+ struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >> -+ msblk->devblksize_log2) + 2]; ++ 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; + unsigned int compressed; + unsigned int c_byte = length; + ++ bh = kmalloc(((sblk->block_size >> msblk->devblksize_log2) + 1) * ++ sizeof(struct buffer_head *), GFP_KERNEL); ++ if (bh == NULL) ++ goto read_failure; ++ + if (c_byte) { + bytes = msblk->devblksize - 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); ++ 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) + goto read_failure; + -+ if (!(bh[0] = sb_getblk(s, cur_index))) ++ bh[0] = sb_getblk(s, cur_index); ++ if (bh[0] == NULL) + goto block_release; + + for (b = 1; bytes < c_byte; b++) { -+ if (!(bh[b] = sb_getblk(s, ++cur_index))) ++ bh[b] = sb_getblk(s, ++cur_index); ++ if (bh[b] == NULL) + goto block_release; + bytes += msblk->devblksize; + } @@ -321,8 +306,8 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + if (index < 0 || (index + 2) > sblk->bytes_used) + goto read_failure; + -+ if (!(bh[0] = get_block_length(s, &cur_index, &offset, -+ &c_byte))) ++ bh[0] = get_block_length(s, &cur_index, &offset, &c_byte); ++ if (bh[0] == NULL) + goto read_failure; + + bytes = msblk->devblksize - offset; @@ -336,7 +321,8 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + goto read_failure; + + for (b = 1; bytes < c_byte; b++) { -+ if (!(bh[b] = sb_getblk(s, ++cur_index))) ++ bh[b] = sb_getblk(s, ++cur_index); ++ if (bh[b] == NULL) + goto block_release; + bytes += msblk->devblksize; + } @@ -356,9 +342,8 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + msblk->stream.avail_out = srclength; + + for (bytes = 0; k < b; k++) { -+ avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ? -+ msblk->devblksize - offset : -+ c_byte - bytes; ++ avail_bytes = min(c_byte - bytes, msblk->devblksize - offset); ++ + wait_on_buffer(bh[k]); + if (!buffer_uptodate(bh[k])) + goto release_mutex; @@ -369,8 +354,8 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + 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); ++ ERROR("zlib_inflateInit returned unexpected result 0x%x," ++ " srclength %d\n", zlib_err, srclength); + goto release_mutex; + } + @@ -383,8 +368,9 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + + 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); ++ 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; + } + @@ -398,8 +384,8 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + + 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); ++ ERROR("zlib_inflateEnd returned unexpected result 0x%x," ++ " srclength %d\n", zlib_err, srclength); + goto release_mutex; + } + bytes = msblk->stream.total_out; @@ -409,14 +395,13 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + + for(i = 0; i < b; i++) { + wait_on_buffer(bh[i]); -+ if(!buffer_uptodate(bh[i])) ++ if (!buffer_uptodate(bh[i])) + goto block_release; + } + + for (bytes = 0; k < b; k++) { -+ avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ? -+ msblk->devblksize - offset : -+ c_byte - bytes; ++ avail_bytes = min(c_byte - bytes, msblk->devblksize - offset); ++ + memcpy(buffer + bytes, bh[k]->b_data + offset, avail_bytes); + bytes += avail_bytes; + offset = 0; @@ -426,8 +411,9 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + + if (next_index) + *next_index = index + c_byte + (length ? 0 : -+ (SQUASHFS_CHECK_DATA(msblk->sblk.flags) -+ ? 3 : 2)); ++ (SQUASHFS_CHECK_DATA(msblk->sblk.flags) ? 3 : 2)); ++ ++ kfree(bh); + return bytes; + +release_mutex: @@ -439,11 +425,12 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + +read_failure: + ERROR("sb_bread failed reading block 0x%x\n", cur_index); ++ kfree(bh); + return 0; +} + + -+SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer, ++SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, void *buffer, + long long block, unsigned int offset, + int length, long long *next_block, + unsigned int *next_offset) @@ -454,68 +441,65 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + + TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset); + -+ while ( 1 ) { -+ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++) ++ while (1) { ++ for (i = 0; i < squashfs_cached_blks; i++) + if (msblk->block_cache[i].block == block) + break; + + mutex_lock(&msblk->block_cache_mutex); + -+ if (i == SQUASHFS_CACHED_BLKS) { ++ if (i == squashfs_cached_blks) { + /* read inode header block */ -+ for (i = msblk->next_cache, n = SQUASHFS_CACHED_BLKS; -+ n ; n --, i = (i + 1) % -+ SQUASHFS_CACHED_BLKS) -+ if (msblk->block_cache[i].block != -+ SQUASHFS_USED_BLK) -+ break; -+ -+ if (n == 0) { -+ wait_queue_t wait; -+ -+ init_waitqueue_entry(&wait, current); -+ add_wait_queue(&msblk->waitq, &wait); -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ mutex_unlock(&msblk->block_cache_mutex); -+ schedule(); -+ set_current_state(TASK_RUNNING); -+ remove_wait_queue(&msblk->waitq, &wait); ++ if (msblk->unused_cache_blks == 0) { ++ mutex_unlock(&msblk->block_cache_mutex); ++ wait_event(msblk->waitq, msblk->unused_cache_blks); + continue; + } -+ msblk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS; + -+ if (msblk->block_cache[i].block == -+ SQUASHFS_INVALID_BLK) { -+ if (!(msblk->block_cache[i].data = -+ kmalloc(SQUASHFS_METADATA_SIZE, -+ GFP_KERNEL))) { -+ ERROR("Failed to allocate cache" -+ "block\n"); ++ i = msblk->next_cache; ++ for (n = 0; n < squashfs_cached_blks; n++) { ++ if (msblk->block_cache[i].block != SQUASHFS_USED_BLK) ++ break; ++ i = (i + 1) % squashfs_cached_blks; ++ } ++ ++ msblk->next_cache = (i + 1) % squashfs_cached_blks; ++ ++ if (msblk->block_cache[i].block == SQUASHFS_INVALID_BLK) { ++ msblk->block_cache[i].data = vmalloc(SQUASHFS_METADATA_SIZE); ++ if (msblk->block_cache[i].data == NULL) { ++ ERROR("Failed to allocate cache block\n"); + mutex_unlock(&msblk->block_cache_mutex); + goto out; + } + } + + msblk->block_cache[i].block = SQUASHFS_USED_BLK; ++ msblk->unused_cache_blks --; + mutex_unlock(&msblk->block_cache_mutex); + + msblk->block_cache[i].length = squashfs_read_data(s, -+ msblk->block_cache[i].data, block, 0, &next_index, SQUASHFS_METADATA_SIZE); ++ msblk->block_cache[i].data, block, 0, &next_index, ++ SQUASHFS_METADATA_SIZE); ++ + if (msblk->block_cache[i].length == 0) { -+ ERROR("Unable to read cache block [%llx:%x]\n", -+ block, offset); ++ ERROR("Unable to read cache block [%llx:%x]\n", block, offset); + mutex_lock(&msblk->block_cache_mutex); + msblk->block_cache[i].block = SQUASHFS_INVALID_BLK; -+ kfree(msblk->block_cache[i].data); ++ msblk->unused_cache_blks ++; ++ smp_mb(); ++ vfree(msblk->block_cache[i].data); + wake_up(&msblk->waitq); + mutex_unlock(&msblk->block_cache_mutex); + goto out; + } + + mutex_lock(&msblk->block_cache_mutex); -+ wake_up(&msblk->waitq); + msblk->block_cache[i].block = block; + msblk->block_cache[i].next_index = next_index; ++ msblk->unused_cache_blks ++; ++ smp_mb(); ++ wake_up(&msblk->waitq); + TRACE("Read cache block [%llx:%x]\n", block, offset); + } + @@ -531,8 +515,7 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + goto out; + } else if (bytes >= length) { + if (buffer) -+ memcpy(buffer, msblk->block_cache[i].data + -+ offset, length); ++ memcpy(buffer, msblk->block_cache[i].data + offset, length); + if (msblk->block_cache[i].length - offset == length) { + *next_block = msblk->block_cache[i].next_index; + *next_offset = 0; @@ -544,9 +527,8 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + goto finish; + } else { + if (buffer) { -+ memcpy(buffer, msblk->block_cache[i].data + -+ offset, bytes); -+ buffer += bytes; ++ memcpy(buffer, msblk->block_cache[i].data + offset, bytes); ++ buffer = (char *) buffer + bytes; + } + block = msblk->block_cache[i].next_index; + mutex_unlock(&msblk->block_cache_mutex); @@ -575,17 +557,13 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + if (msblk->swap) { + struct squashfs_fragment_entry sfragment_entry; + -+ if (!squashfs_get_cached_block(s, (char *) &sfragment_entry, -+ start_block, offset, -+ sizeof(sfragment_entry), &start_block, -+ &offset)) ++ if (!squashfs_get_cached_block(s, &sfragment_entry, start_block, offset, ++ sizeof(sfragment_entry), &start_block, &offset)) + goto out; + SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry); + } else -+ if (!squashfs_get_cached_block(s, (char *) &fragment_entry, -+ start_block, offset, -+ sizeof(fragment_entry), &start_block, -+ &offset)) ++ if (!squashfs_get_cached_block(s, &fragment_entry, start_block, offset, ++ sizeof(fragment_entry), &start_block, &offset)) + goto out; + + *fragment_start_block = fragment_entry.start_block; @@ -598,90 +576,92 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino +} + + -+SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, struct -+ squashfs_fragment_cache *fragment) ++SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, ++ struct squashfs_fragment_cache *fragment) +{ + mutex_lock(&msblk->fragment_mutex); + fragment->locked --; -+ wake_up(&msblk->fragment_wait_queue); ++ if (fragment->locked == 0) { ++ msblk->unused_frag_blks ++; ++ smp_mb(); ++ wake_up(&msblk->fragment_wait_queue); ++ } + mutex_unlock(&msblk->fragment_mutex); +} + + -+SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_block -+ *s, long long start_block, -+ int length) ++SQSH_EXTERN ++struct squashfs_fragment_cache *get_cached_fragment(struct super_block *s, ++ long long start_block, int length) +{ + int i, n; + struct squashfs_sb_info *msblk = s->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + -+ while ( 1 ) { ++ while (1) { + mutex_lock(&msblk->fragment_mutex); + + for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS && + msblk->fragment[i].block != start_block; i++); + + if (i == SQUASHFS_CACHED_FRAGMENTS) { -+ for (i = msblk->next_fragment, n = -+ SQUASHFS_CACHED_FRAGMENTS; n && -+ msblk->fragment[i].locked; n--, i = (i + 1) % -+ SQUASHFS_CACHED_FRAGMENTS); -+ -+ if (n == 0) { -+ wait_queue_t wait; -+ -+ init_waitqueue_entry(&wait, current); -+ add_wait_queue(&msblk->fragment_wait_queue, -+ &wait); -+ set_current_state(TASK_UNINTERRUPTIBLE); ++ if (msblk->unused_frag_blks == 0) { + mutex_unlock(&msblk->fragment_mutex); -+ schedule(); -+ set_current_state(TASK_RUNNING); -+ remove_wait_queue(&msblk->fragment_wait_queue, -+ &wait); ++ wait_event(msblk->fragment_wait_queue, msblk->unused_frag_blks); + continue; + } ++ ++ i = msblk->next_fragment; ++ for (n = 0; n < SQUASHFS_CACHED_FRAGMENTS; n++) { ++ if (msblk->fragment[i].locked == 0) ++ break; ++ i = (i + 1) % SQUASHFS_CACHED_FRAGMENTS; ++ } ++ + msblk->next_fragment = (msblk->next_fragment + 1) % + SQUASHFS_CACHED_FRAGMENTS; + -+ if (msblk->fragment[i].data == NULL) -+ if (!(msblk->fragment[i].data = SQUASHFS_ALLOC -+ (SQUASHFS_FILE_MAX_SIZE))) { -+ ERROR("Failed to allocate fragment " -+ "cache block\n"); ++ if (msblk->fragment[i].data == NULL) { ++ msblk->fragment[i].data = vmalloc(sblk->block_size); ++ if (msblk->fragment[i].data == NULL) { ++ ERROR("Failed to allocate fragment cache block\n"); + mutex_unlock(&msblk->fragment_mutex); + goto out; + } ++ } + ++ msblk->unused_frag_blks --; + msblk->fragment[i].block = SQUASHFS_INVALID_BLK; + msblk->fragment[i].locked = 1; + mutex_unlock(&msblk->fragment_mutex); + -+ if (!(msblk->fragment[i].length = squashfs_read_data(s, -+ msblk->fragment[i].data, -+ start_block, length, NULL, sblk->block_size))) { -+ ERROR("Unable to read fragment cache block " -+ "[%llx]\n", start_block); ++ msblk->fragment[i].length = squashfs_read_data(s, ++ msblk->fragment[i].data, start_block, length, NULL, ++ sblk->block_size); ++ ++ if (msblk->fragment[i].length == 0) { ++ ERROR("Unable to read fragment cache block [%llx]\n", start_block); + msblk->fragment[i].locked = 0; ++ msblk->unused_frag_blks ++; + smp_mb(); ++ wake_up(&msblk->fragment_wait_queue); + goto out; + } + + mutex_lock(&msblk->fragment_mutex); + msblk->fragment[i].block = start_block; + TRACE("New fragment %d, start block %lld, locked %d\n", -+ i, msblk->fragment[i].block, -+ msblk->fragment[i].locked); ++ i, msblk->fragment[i].block, msblk->fragment[i].locked); + mutex_unlock(&msblk->fragment_mutex); + break; + } + ++ if (msblk->fragment[i].locked == 0) ++ msblk->unused_frag_blks --; + msblk->fragment[i].locked++; + mutex_unlock(&msblk->fragment_mutex); + TRACE("Got fragment %d, start block %lld, locked %d\n", i, -+ msblk->fragment[i].block, -+ msblk->fragment[i].locked); ++ msblk->fragment[i].block, msblk->fragment[i].locked); + break; + } + @@ -693,7 +673,7 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + + +static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i, -+ struct squashfs_base_inode_header *inodeb) ++ struct squashfs_base_inode_header *inodeb) +{ + i->i_ino = inodeb->inode_number; + i->i_mtime.tv_sec = inodeb->mtime; @@ -702,6 +682,7 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + i->i_uid = msblk->uid[inodeb->uid]; + i->i_mode = inodeb->mode; + i->i_size = 0; ++ + if (inodeb->guid == SQUASHFS_GUIDS) + i->i_gid = i->i_uid; + else @@ -721,11 +702,11 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + if (msblk->swap) { + squashfs_inode_t sinode; + -+ if (!squashfs_get_cached_block(s, (char *) &sinode, start, offset, ++ if (!squashfs_get_cached_block(s, &sinode, start, offset, + sizeof(sinode), &start, &offset)) + goto out; + SQUASHFS_SWAP_INODE_T((&inode), &sinode); -+ } else if (!squashfs_get_cached_block(s, (char *) &inode, start, offset, ++ } else if (!squashfs_get_cached_block(s, &inode, start, offset, + sizeof(inode), &start, &offset)) + goto out; + @@ -772,7 +753,8 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino +} + + -+SQSH_EXTERN struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number) ++SQSH_EXTERN struct inode *squashfs_iget(struct super_block *s, ++ squashfs_inode_t inode, unsigned int inode_number) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + struct inode *i = iget_locked(s, inode_number); @@ -793,28 +775,23 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + struct super_block *s = i->i_sb; + struct squashfs_sb_info *msblk = s->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; -+ long long block = SQUASHFS_INODE_BLK(inode) + -+ sblk->inode_table_start; ++ long long block = SQUASHFS_INODE_BLK(inode) + sblk->inode_table_start; + unsigned int offset = SQUASHFS_INODE_OFFSET(inode); + long long next_block; + unsigned int next_offset; + union squashfs_inode_header id, sid; -+ struct squashfs_base_inode_header *inodeb = &id.base, -+ *sinodeb = &sid.base; ++ struct squashfs_base_inode_header *inodeb = &id.base, *sinodeb = &sid.base; + + TRACE("Entered squashfs_read_inode\n"); + + if (msblk->swap) { -+ if (!squashfs_get_cached_block(s, (char *) sinodeb, block, -+ offset, sizeof(*sinodeb), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(s, sinodeb, block, offset, ++ sizeof(*sinodeb), &next_block, &next_offset)) + goto failed_read; -+ SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb, -+ sizeof(*sinodeb)); ++ SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb, sizeof(*sinodeb)); + } else -+ if (!squashfs_get_cached_block(s, (char *) inodeb, block, -+ offset, sizeof(*inodeb), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(s, inodeb, block, offset, ++ sizeof(*inodeb), &next_block, &next_offset)) + goto failed_read; + + squashfs_new_inode(msblk, i, inodeb); @@ -827,24 +804,21 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + struct squashfs_reg_inode_header *sinodep = &sid.reg; + + if (msblk->swap) { -+ if (!squashfs_get_cached_block(s, (char *) -+ sinodep, block, offset, -+ sizeof(*sinodep), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep); + } else -+ if (!squashfs_get_cached_block(s, (char *) -+ inodep, block, offset, -+ sizeof(*inodep), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) + goto failed_read; + + frag_blk = SQUASHFS_INVALID_BLK; -+ if (inodep->fragment != SQUASHFS_INVALID_FRAG && -+ !get_fragment_location(s, -+ inodep->fragment, &frag_blk, &frag_size)) -+ goto failed_read; ++ ++ if (inodep->fragment != SQUASHFS_INVALID_FRAG) ++ if(!get_fragment_location(s, inodep->fragment, &frag_blk, ++ &frag_size)) ++ goto failed_read; + + i->i_nlink = 1; + i->i_size = inodep->file_size; @@ -857,10 +831,7 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + SQUASHFS_I(i)->start_block = inodep->start_block; + SQUASHFS_I(i)->u.s1.block_list_start = next_block; + SQUASHFS_I(i)->offset = next_offset; -+ if (sblk->block_size > 4096) -+ i->i_data.a_ops = &squashfs_aops; -+ else -+ i->i_data.a_ops = &squashfs_aops_4K; ++ i->i_data.a_ops = &squashfs_aops; + + TRACE("File inode %x:%x, start_block %llx, " + "block_list_start %llx, offset %x\n", @@ -876,24 +847,21 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + struct squashfs_lreg_inode_header *sinodep = &sid.lreg; + + if (msblk->swap) { -+ if (!squashfs_get_cached_block(s, (char *) -+ sinodep, block, offset, -+ sizeof(*sinodep), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep); + } else -+ if (!squashfs_get_cached_block(s, (char *) -+ inodep, block, offset, -+ sizeof(*inodep), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) + goto failed_read; + + frag_blk = SQUASHFS_INVALID_BLK; -+ if (inodep->fragment != SQUASHFS_INVALID_FRAG && -+ !get_fragment_location(s, -+ inodep->fragment, &frag_blk, &frag_size)) -+ goto failed_read; ++ ++ if (inodep->fragment != SQUASHFS_INVALID_FRAG) ++ if (!get_fragment_location(s, inodep->fragment, &frag_blk, ++ &frag_size)) ++ goto failed_read; + + i->i_nlink = inodep->nlink; + i->i_size = inodep->file_size; @@ -906,10 +874,7 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + SQUASHFS_I(i)->start_block = inodep->start_block; + SQUASHFS_I(i)->u.s1.block_list_start = next_block; + SQUASHFS_I(i)->offset = next_offset; -+ if (sblk->block_size > 4096) -+ i->i_data.a_ops = &squashfs_aops; -+ else -+ i->i_data.a_ops = &squashfs_aops_4K; ++ i->i_data.a_ops = &squashfs_aops; + + TRACE("File inode %x:%x, start_block %llx, " + "block_list_start %llx, offset %x\n", @@ -923,17 +888,13 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + struct squashfs_dir_inode_header *sinodep = &sid.dir; + + if (msblk->swap) { -+ if (!squashfs_get_cached_block(s, (char *) -+ sinodep, block, offset, -+ sizeof(*sinodep), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep); + } else -+ if (!squashfs_get_cached_block(s, (char *) -+ inodep, block, offset, -+ sizeof(*inodep), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) + goto failed_read; + + i->i_nlink = inodep->nlink; @@ -957,18 +918,13 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + struct squashfs_ldir_inode_header *sinodep = &sid.ldir; + + if (msblk->swap) { -+ if (!squashfs_get_cached_block(s, (char *) -+ sinodep, block, offset, -+ sizeof(*sinodep), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) + goto failed_read; -+ SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep, -+ sinodep); ++ SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep, sinodep); + } else -+ if (!squashfs_get_cached_block(s, (char *) -+ inodep, block, offset, -+ sizeof(*inodep), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) + goto failed_read; + + i->i_nlink = inodep->nlink; @@ -979,37 +935,27 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + SQUASHFS_I(i)->start_block = inodep->start_block; + SQUASHFS_I(i)->offset = inodep->offset; + SQUASHFS_I(i)->u.s2.directory_index_start = next_block; -+ SQUASHFS_I(i)->u.s2.directory_index_offset = -+ next_offset; -+ SQUASHFS_I(i)->u.s2.directory_index_count = -+ inodep->i_count; ++ SQUASHFS_I(i)->u.s2.directory_index_offset = next_offset; ++ SQUASHFS_I(i)->u.s2.directory_index_count = inodep->i_count; + SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode; + -+ TRACE("Long directory inode %x:%x, start_block %x, " -+ "offset %x\n", ++ TRACE("Long directory inode %x:%x, start_block %x, offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, + inodep->start_block, inodep->offset); + break; + } + case SQUASHFS_SYMLINK_TYPE: { -+ struct squashfs_symlink_inode_header *inodep = -+ &id.symlink; -+ struct squashfs_symlink_inode_header *sinodep = -+ &sid.symlink; ++ struct squashfs_symlink_inode_header *inodep = &id.symlink; ++ struct squashfs_symlink_inode_header *sinodep = &sid.symlink; + + if (msblk->swap) { -+ if (!squashfs_get_cached_block(s, (char *) -+ sinodep, block, offset, -+ sizeof(*sinodep), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) + goto failed_read; -+ SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, -+ sinodep); ++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, sinodep); + } else -+ if (!squashfs_get_cached_block(s, (char *) -+ inodep, block, offset, -+ sizeof(*inodep), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) + goto failed_read; + + i->i_nlink = inodep->nlink; @@ -1020,8 +966,7 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + SQUASHFS_I(i)->start_block = next_block; + SQUASHFS_I(i)->offset = next_offset; + -+ TRACE("Symbolic link inode %x:%x, start_block %llx, " -+ "offset %x\n", ++ TRACE("Symbolic link inode %x:%x, start_block %llx, offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, + next_block, next_offset); + break; @@ -1032,29 +977,22 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + struct squashfs_dev_inode_header *sinodep = &sid.dev; + + if (msblk->swap) { -+ if (!squashfs_get_cached_block(s, (char *) -+ sinodep, block, offset, -+ sizeof(*sinodep), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep); + } else -+ if (!squashfs_get_cached_block(s, (char *) -+ inodep, block, offset, -+ sizeof(*inodep), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) + goto failed_read; + + i->i_nlink = inodep->nlink; -+ i->i_mode |= (inodeb->inode_type == -+ SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : -+ S_IFBLK; -+ init_special_inode(i, i->i_mode, -+ old_decode_dev(inodep->rdev)); ++ i->i_mode |= (inodeb->inode_type == SQUASHFS_CHRDEV_TYPE) ? ++ S_IFCHR : S_IFBLK; ++ init_special_inode(i, i->i_mode, old_decode_dev(inodep->rdev)); + + TRACE("Device inode %x:%x, rdev %x\n", -+ SQUASHFS_INODE_BLK(inode), offset, -+ inodep->rdev); ++ SQUASHFS_INODE_BLK(inode), offset, inodep->rdev); + break; + } + case SQUASHFS_FIFO_TYPE: @@ -1063,17 +1001,13 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + struct squashfs_ipc_inode_header *sinodep = &sid.ipc; + + if (msblk->swap) { -+ if (!squashfs_get_cached_block(s, (char *) -+ sinodep, block, offset, -+ sizeof(*sinodep), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep); + } else -+ if (!squashfs_get_cached_block(s, (char *) -+ inodep, block, offset, -+ sizeof(*inodep), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) + goto failed_read; + + i->i_nlink = inodep->nlink; @@ -1108,7 +1042,8 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + TRACE("In read_inode_lookup_table, length %d\n", length); + + /* Allocate inode lookup table */ -+ if (!(msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL))) { ++ msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL); ++ if (msblk->inode_lookup_table == NULL) { + ERROR("Failed to allocate inode lookup table\n"); + return 0; + } @@ -1125,6 +1060,7 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + long long block; + + for (i = 0; i < SQUASHFS_LOOKUP_BLOCKS(sblk->inodes); i++) { ++ /* XXX */ + SQUASHFS_SWAP_LOOKUP_BLOCKS((&block), + &msblk->inode_lookup_table[i], 1); + msblk->inode_lookup_table[i] = block; @@ -1145,7 +1081,8 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + return 1; + + /* Allocate fragment index table */ -+ if (!(msblk->fragment_index = kmalloc(length, GFP_KERNEL))) { ++ msblk->fragment_index = kmalloc(length, GFP_KERNEL); ++ if (msblk->fragment_index == NULL) { + ERROR("Failed to allocate fragment index table\n"); + return 0; + } @@ -1162,6 +1099,7 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + long long fragment; + + for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); i++) { ++ /* XXX */ + SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment), + &msblk->fragment_index[i], 1); + msblk->fragment_index[i] = fragment; @@ -1172,6 +1110,34 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino +} + + ++static int readahead_metadata(struct super_block *s) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ int i; ++ ++ squashfs_cached_blks = SQUASHFS_CACHED_BLKS; ++ ++ /* Init inode_table block pointer array */ ++ msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) * ++ squashfs_cached_blks, GFP_KERNEL); ++ if (msblk->block_cache == NULL) { ++ ERROR("Failed to allocate block cache\n"); ++ goto failed; ++ } ++ ++ for (i = 0; i < squashfs_cached_blks; i++) ++ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK; ++ ++ msblk->next_cache = 0; ++ msblk->unused_cache_blks = squashfs_cached_blks; ++ ++ return 1; ++ ++failed: ++ return 0; ++} ++ ++ +static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent) +{ + struct squashfs_super_block *sblk = &msblk->sblk; @@ -1184,16 +1150,14 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + if (!squashfs_1_0_supported(msblk)) { + SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems " + "are unsupported\n"); -+ SERROR("Please recompile with " -+ "Squashfs 1.0 support enabled\n"); ++ SERROR("Please recompile with Squashfs 1.0 support enabled\n"); + return 0; + } + } else if (sblk->s_major == 2) { + if (!squashfs_2_0_supported(msblk)) { + SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems " + "are unsupported\n"); -+ SERROR("Please recompile with " -+ "Squashfs 2.0 support enabled\n"); ++ SERROR("Please recompile with Squashfs 2.0 support enabled\n"); + return 0; + } + } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor > @@ -1216,16 +1180,17 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + char b[BDEVNAME_SIZE]; + struct inode *root; + -+ TRACE("Entered squashfs_read_superblock\n"); ++ TRACE("Entered squashfs_fill_superblock\n"); + -+ if (!(s->s_fs_info = kmalloc(sizeof(struct squashfs_sb_info), -+ GFP_KERNEL))) { ++ s->s_fs_info = kzalloc(sizeof(struct squashfs_sb_info), GFP_KERNEL); ++ if (s->s_fs_info == NULL) { + ERROR("Failed to allocate superblock\n"); + goto failure; + } -+ memset(s->s_fs_info, 0, sizeof(struct squashfs_sb_info)); + msblk = s->s_fs_info; -+ if (!(msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize()))) { ++ ++ msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize()); ++ if (msblk->stream.workspace == NULL) { + ERROR("Failed to allocate zlib workspace\n"); + goto failure; + } @@ -1243,6 +1208,9 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + init_waitqueue_head(&msblk->waitq); + init_waitqueue_head(&msblk->fragment_wait_queue); + ++ /* sblk->bytes_used is checked in squashfs_read_data to ensure reads are not ++ * beyond filesystem end. As we're using squashfs_read_data to read sblk here, ++ * first set sblk->bytes_used to a useful value */ + sblk->bytes_used = sizeof(struct squashfs_super_block); + if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START, + sizeof(struct squashfs_super_block) | @@ -1252,13 +1220,12 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + } + + /* Check it is a SQUASHFS superblock */ -+ msblk->swap = 0; + if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) { + if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) { + struct squashfs_super_block ssblk; + -+ WARNING("Mounting a different endian SQUASHFS " -+ "filesystem on %s\n", bdevname(s->s_bdev, b)); ++ WARNING("Mounting a different endian SQUASHFS filesystem on %s\n", ++ bdevname(s->s_bdev, b)); + + SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk); + memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block)); @@ -1284,15 +1251,12 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + goto failed_mount; + + TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b)); -+ TRACE("Inodes are %scompressed\n", -+ SQUASHFS_UNCOMPRESSED_INODES -+ (sblk->flags) ? "un" : ""); -+ TRACE("Data is %scompressed\n", -+ SQUASHFS_UNCOMPRESSED_DATA(sblk->flags) ++ TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sblk->flags) + ? "un" : ""); -+ TRACE("Check data is %s present in the filesystem\n", -+ SQUASHFS_CHECK_DATA(sblk->flags) ? -+ "" : "not"); ++ TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sblk->flags) ++ ? "un" : ""); ++ TRACE("Check data is %spresent in the filesystem\n", ++ SQUASHFS_CHECK_DATA(sblk->flags) ? "" : "not "); + TRACE("Filesystem size %lld bytes\n", sblk->bytes_used); + TRACE("Block size %d\n", sblk->block_size); + TRACE("Number of inodes %d\n", sblk->inodes); @@ -1303,34 +1267,27 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start); + TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start); + if (sblk->s_major > 1) -+ TRACE("sblk->fragment_table_start %llx\n", -+ sblk->fragment_table_start); ++ TRACE("sblk->fragment_table_start %llx\n", sblk->fragment_table_start); + TRACE("sblk->uid_start %llx\n", sblk->uid_start); + ++ s->s_maxbytes = MAX_LFS_FILESIZE; + s->s_flags |= MS_RDONLY; + s->s_op = &squashfs_super_ops; + -+ /* Init inode_table block pointer array */ -+ if (!(msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) * -+ SQUASHFS_CACHED_BLKS, GFP_KERNEL))) { -+ ERROR("Failed to allocate block cache\n"); ++ if (readahead_metadata(s) == 0) + goto failed_mount; -+ } -+ -+ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++) -+ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK; -+ -+ msblk->next_cache = 0; + + /* Allocate read_page block */ -+ if (!(msblk->read_page = kmalloc(sblk->block_size, GFP_KERNEL))) { ++ msblk->read_page = vmalloc(sblk->block_size); ++ if (msblk->read_page == NULL) { + ERROR("Failed to allocate read_page block\n"); + goto failed_mount; + } + + /* Allocate uid and gid tables */ -+ if (!(msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) * -+ sizeof(unsigned int), GFP_KERNEL))) { ++ msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) * ++ sizeof(unsigned int), GFP_KERNEL); ++ if (msblk->uid == NULL) { + ERROR("Failed to allocate uid/gid table\n"); + goto failed_mount; + } @@ -1362,19 +1319,19 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + if (sblk->s_major == 1 && squashfs_1_0_supported(msblk)) + goto allocate_root; + -+ if (!(msblk->fragment = kmalloc(sizeof(struct squashfs_fragment_cache) * -+ SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) { ++ msblk->fragment = kzalloc(sizeof(struct squashfs_fragment_cache) * ++ SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL); ++ if (msblk->fragment == NULL) { + ERROR("Failed to allocate fragment block cache\n"); + goto failed_mount; + } + + for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) { -+ msblk->fragment[i].locked = 0; + msblk->fragment[i].block = SQUASHFS_INVALID_BLK; -+ msblk->fragment[i].data = NULL; + } + + msblk->next_fragment = 0; ++ msblk->unused_frag_blks = SQUASHFS_CACHED_FRAGMENTS; + + /* Allocate and read fragment index table */ + if (msblk->read_fragment_index_table(s) == 0) @@ -1396,13 +1353,14 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + goto failed_mount; + insert_inode_hash(root); + -+ if ((s->s_root = d_alloc_root(root)) == NULL) { ++ s->s_root = d_alloc_root(root); ++ if (s->s_root == NULL) { + ERROR("Root inode create failed\n"); + iput(root); + goto failed_mount; + } + -+ TRACE("Leaving squashfs_read_super\n"); ++ TRACE("Leaving squashfs_fill_super\n"); + return 0; + +failed_mount: @@ -1410,7 +1368,7 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + kfree(msblk->fragment_index); + kfree(msblk->fragment); + kfree(msblk->uid); -+ kfree(msblk->read_page); ++ vfree(msblk->read_page); + kfree(msblk->block_cache); + kfree(msblk->fragment_index_2); + vfree(msblk->stream.workspace); @@ -1445,7 +1403,7 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino +static int squashfs_symlink_readpage(struct file *file, struct page *page) +{ + struct inode *inode = page->mapping->host; -+ int index = page->index << PAGE_CACHE_SHIFT, length, bytes; ++ int index = page->index << PAGE_CACHE_SHIFT, length, bytes, avail_bytes; + long long block = SQUASHFS_I(inode)->start_block; + int offset = SQUASHFS_I(inode)->offset; + void *pageaddr = kmap(page); @@ -1456,11 +1414,10 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + SQUASHFS_I(inode)->offset); + + for (length = 0; length < index; length += bytes) { -+ if (!(bytes = squashfs_get_cached_block(inode->i_sb, NULL, -+ block, offset, PAGE_CACHE_SIZE, &block, -+ &offset))) { -+ ERROR("Unable to read symbolic link [%llx:%x]\n", block, -+ offset); ++ bytes = squashfs_get_cached_block(inode->i_sb, NULL, block, ++ offset, PAGE_CACHE_SIZE, &block, &offset); ++ if (bytes == 0) { ++ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset); + goto skip_read; + } + } @@ -1471,11 +1428,11 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + goto skip_read; + } + -+ bytes = (i_size_read(inode) - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : -+ i_size_read(inode) - length; ++ avail_bytes = min_t(int, i_size_read(inode) - length, PAGE_CACHE_SIZE); + -+ if (!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, -+ offset, bytes, &block, &offset))) ++ bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, offset, ++ avail_bytes, &block, &offset); ++ if (bytes == 0) + ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset); + +skip_read: @@ -1499,10 +1456,10 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + + TRACE("locate_meta_index: index %d, offset %d\n", index, offset); + -+ if(msblk->meta_index == NULL) ++ if (msblk->meta_index == NULL) + goto not_allocated; + -+ for (i = 0; i < SQUASHFS_META_NUMBER; i ++) ++ for (i = 0; i < SQUASHFS_META_NUMBER; i ++) { + if (msblk->meta_index[i].inode_number == inode->i_ino && + msblk->meta_index[i].offset >= offset && + msblk->meta_index[i].offset <= index && @@ -1512,6 +1469,7 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + meta = &msblk->meta_index[i]; + offset = meta->offset; + } ++ } + + if (meta) + meta->locked = 1; @@ -1533,25 +1491,26 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + + TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip); + -+ if(msblk->meta_index == NULL) { -+ if (!(msblk->meta_index = kmalloc(sizeof(struct meta_index) * -+ SQUASHFS_META_NUMBER, GFP_KERNEL))) { ++ if (msblk->meta_index == NULL) { ++ msblk->meta_index = kmalloc(sizeof(struct meta_index) * ++ SQUASHFS_META_NUMBER, GFP_KERNEL); ++ if (msblk->meta_index == NULL) { + ERROR("Failed to allocate meta_index\n"); + goto failed; + } -+ for(i = 0; i < SQUASHFS_META_NUMBER; i++) { ++ for (i = 0; i < SQUASHFS_META_NUMBER; i++) { + msblk->meta_index[i].inode_number = 0; + msblk->meta_index[i].locked = 0; + } + msblk->next_meta_index = 0; + } + -+ for(i = SQUASHFS_META_NUMBER; i && ++ for (i = SQUASHFS_META_NUMBER; i && + msblk->meta_index[msblk->next_meta_index].locked; i --) + msblk->next_meta_index = (msblk->next_meta_index + 1) % + SQUASHFS_META_NUMBER; + -+ if(i == 0) { ++ if (i == 0) { + TRACE("empty_meta_index: failed!\n"); + goto failed; + } @@ -1584,7 +1543,7 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + + +static int read_block_index(struct super_block *s, int blocks, char *block_list, -+ long long *start_block, int *offset) ++ long long *start_block, int *offset) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + unsigned int *block_listp; @@ -1595,19 +1554,18 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + + if (!squashfs_get_cached_block(s, sblock_list, *start_block, + *offset, blocks << 2, start_block, offset)) { -+ ERROR("Unable to read block list [%llx:%x]\n", -+ *start_block, *offset); ++ ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset); + goto failure; + } + SQUASHFS_SWAP_INTS(((unsigned int *)block_list), + ((unsigned int *)sblock_list), blocks); -+ } else ++ } else { + if (!squashfs_get_cached_block(s, block_list, *start_block, + *offset, blocks << 2, start_block, offset)) { -+ ERROR("Unable to read block list [%llx:%x]\n", -+ *start_block, *offset); ++ ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset); + goto failure; + } ++ } + + for (block_listp = (unsigned int *) block_list; blocks; + block_listp++, blocks --) @@ -1645,25 +1603,26 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + + index /= SQUASHFS_META_INDEXES * skip; + -+ while ( offset < index ) { ++ while (offset < index) { + meta = locate_meta_index(inode, index, offset + 1); + + if (meta == NULL) { -+ if ((meta = empty_meta_index(inode, offset + 1, -+ skip)) == NULL) ++ meta = empty_meta_index(inode, offset + 1, skip); ++ if (meta == NULL) + goto all_done; + } else { + if(meta->entries == 0) + goto failed; ++ /* XXX */ + offset = index < meta->offset + meta->entries ? index : + meta->offset + meta->entries - 1; ++ /* XXX */ + meta_entry = &meta->meta_entry[offset - meta->offset]; + cur_index_block = meta_entry->index_block + sblk->inode_table_start; + cur_offset = meta_entry->offset; + cur_data_block = meta_entry->data_block; + TRACE("get_meta_index: offset %d, meta->offset %d, " -+ "meta->entries %d\n", offset, meta->offset, -+ meta->entries); ++ "meta->entries %d\n", offset, meta->offset, meta->entries); + TRACE("get_meta_index: index_block 0x%llx, offset 0x%x" + " data_block 0x%llx\n", cur_index_block, + cur_offset, cur_data_block); @@ -1674,11 +1633,9 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + int blocks = skip * SQUASHFS_META_INDEXES; + + while (blocks) { -+ int block = blocks > (SIZE >> 2) ? (SIZE >> 2) : -+ blocks; -+ int res = read_block_index(inode->i_sb, block, -+ block_list, &cur_index_block, -+ &cur_offset); ++ int block = blocks > (SIZE >> 2) ? (SIZE >> 2) : blocks; ++ int res = read_block_index(inode->i_sb, block, block_list, ++ &cur_index_block, &cur_offset); + + if (res == -1) + goto failed; @@ -1725,15 +1682,14 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + block_list); + + TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset" -+ " 0x%x, block 0x%llx\n", res, index, block_ptr, offset, -+ block); ++ " 0x%x, block 0x%llx\n", res, index, block_ptr, offset, block); + + if(res == -1) + goto failure; + + index -= res; + -+ while ( index ) { ++ while (index) { + int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index; + int res = read_block_index(inode->i_sb, blocks, block_list, + &block_ptr, &offset); @@ -1743,8 +1699,7 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + index -= blocks; + } + -+ if (read_block_index(inode->i_sb, 1, block_list, -+ &block_ptr, &offset) == -1) ++ if (read_block_index(inode->i_sb, 1, block_list, &block_ptr, &offset) == -1) + goto failure; + *bsize = *((unsigned int *) block_list); + @@ -1760,9 +1715,10 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + struct inode *inode = page->mapping->host; + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; -+ unsigned char *block_list; ++ unsigned char *block_list = NULL; + long long block; -+ unsigned int bsize, i = 0, bytes = 0, byte_offset = 0; ++ unsigned int bsize, i; ++ int bytes; + int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT); + void *pageaddr; + struct squashfs_fragment_cache *fragment = NULL; @@ -1771,64 +1727,65 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1; + int start_index = page->index & ~mask; + int end_index = start_index | mask; ++ int file_end = i_size_read(inode) >> sblk->block_log; ++ int sparse = 0; + + TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n", -+ page->index, -+ SQUASHFS_I(inode)->start_block); -+ -+ if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) { -+ ERROR("Failed to allocate block_list\n"); -+ goto skip_read; -+ } ++ page->index, SQUASHFS_I(inode)->start_block); + + if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> + PAGE_CACHE_SHIFT)) -+ goto skip_read; ++ goto out; + + if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK -+ || index < (i_size_read(inode) >> -+ sblk->block_log)) { -+ if ((block = (msblk->read_blocklist)(inode, index, 1, -+ block_list, NULL, &bsize)) == 0) -+ goto skip_read; ++ || index < file_end) { ++ block_list = kmalloc(SIZE, GFP_KERNEL); ++ if (block_list == NULL) { ++ ERROR("Failed to allocate block_list\n"); ++ goto error_out; ++ } + -+ mutex_lock(&msblk->read_page_mutex); ++ block = (msblk->read_blocklist)(inode, index, 1, block_list, NULL, &bsize); ++ if (block == 0) ++ goto error_out; ++ ++ if (bsize == 0) { /* hole */ ++ bytes = index == file_end ? ++ (i_size_read(inode) & (sblk->block_size - 1)) : sblk->block_size; ++ sparse = 1; ++ } else { ++ mutex_lock(&msblk->read_page_mutex); + -+ if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page, -+ block, bsize, NULL, sblk->block_size))) { -+ ERROR("Unable to read page, block %llx, size %x\n", block, -+ bsize); -+ mutex_unlock(&msblk->read_page_mutex); -+ goto skip_read; ++ bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block, ++ bsize, NULL, sblk->block_size); ++ ++ if (bytes == 0) { ++ ERROR("Unable to read page, block %llx, size %x\n", block, bsize); ++ mutex_unlock(&msblk->read_page_mutex); ++ goto error_out; ++ } + } + } else { -+ if ((fragment = get_cached_fragment(inode->i_sb, -+ SQUASHFS_I(inode)-> -+ u.s1.fragment_start_block, -+ SQUASHFS_I(inode)->u.s1.fragment_size)) -+ == NULL) { ++ fragment = get_cached_fragment(inode->i_sb, ++ SQUASHFS_I(inode)-> u.s1.fragment_start_block, ++ SQUASHFS_I(inode)->u.s1.fragment_size); ++ ++ if (fragment == NULL) { + ERROR("Unable to read page, block %llx, size %x\n", -+ SQUASHFS_I(inode)-> -+ u.s1.fragment_start_block, -+ (int) SQUASHFS_I(inode)-> -+ u.s1.fragment_size); -+ goto skip_read; ++ SQUASHFS_I(inode)->u.s1.fragment_start_block, ++ (int) SQUASHFS_I(inode)->u.s1.fragment_size); ++ goto error_out; + } -+ bytes = SQUASHFS_I(inode)->u.s1.fragment_offset + -+ (i_size_read(inode) & (sblk->block_size -+ - 1)); -+ byte_offset = SQUASHFS_I(inode)->u.s1.fragment_offset; -+ data_ptr = fragment->data; ++ bytes = i_size_read(inode) & (sblk->block_size - 1); ++ data_ptr = fragment->data + SQUASHFS_I(inode)->u.s1.fragment_offset; + } + -+ for (i = start_index; i <= end_index && byte_offset < bytes; -+ i++, byte_offset += PAGE_CACHE_SIZE) { ++ for (i = start_index; i <= end_index && bytes > 0; i++, ++ bytes -= PAGE_CACHE_SIZE, data_ptr += PAGE_CACHE_SIZE) { + struct page *push_page; -+ int avail = (bytes - byte_offset) > PAGE_CACHE_SIZE ? -+ PAGE_CACHE_SIZE : bytes - byte_offset; ++ int avail = sparse ? 0 : min_t(unsigned int, bytes, PAGE_CACHE_SIZE); + -+ TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n", -+ bytes, i, byte_offset, avail); ++ TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail); + + push_page = (i == page->index) ? page : + grab_cache_page_nowait(page->mapping, i); @@ -1840,7 +1797,7 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + goto skip_page; + + pageaddr = kmap_atomic(push_page, KM_USER0); -+ memcpy(pageaddr, data_ptr + byte_offset, avail); ++ memcpy(pageaddr, data_ptr, avail); + memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail); + kunmap_atomic(pageaddr, KM_USER0); + flush_dcache_page(push_page); @@ -1852,21 +1809,24 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + } + + if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK -+ || index < (i_size_read(inode) >> -+ sblk->block_log)) -+ mutex_unlock(&msblk->read_page_mutex); -+ else ++ || index < file_end) { ++ if (!sparse) ++ mutex_unlock(&msblk->read_page_mutex); ++ kfree(block_list); ++ } else + release_cached_fragment(msblk, fragment); + -+ kfree(block_list); + return 0; + -+skip_read: ++error_out: ++ SetPageError(page); ++out: + pageaddr = kmap_atomic(page, KM_USER0); -+ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); ++ memset(pageaddr, 0, PAGE_CACHE_SIZE); + kunmap_atomic(pageaddr, KM_USER0); + flush_dcache_page(page); -+ SetPageUptodate(page); ++ if (!PageError(page)) ++ SetPageUptodate(page); + unlock_page(page); + + kfree(block_list); @@ -1874,87 +1834,9 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino +} + + -+static int squashfs_readpage4K(struct file *file, struct page *page) -+{ -+ struct inode *inode = page->mapping->host; -+ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; -+ struct squashfs_super_block *sblk = &msblk->sblk; -+ unsigned char *block_list; -+ long long block; -+ unsigned int bsize, bytes = 0; -+ void *pageaddr; -+ -+ TRACE("Entered squashfs_readpage4K, page index %lx, start block %llx\n", -+ page->index, -+ SQUASHFS_I(inode)->start_block); -+ -+ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> -+ PAGE_CACHE_SHIFT)) { -+ block_list = NULL; -+ goto skip_read; -+ } -+ -+ if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) { -+ ERROR("Failed to allocate block_list\n"); -+ goto skip_read; -+ } -+ -+ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK -+ || page->index < (i_size_read(inode) >> -+ sblk->block_log)) { -+ block = (msblk->read_blocklist)(inode, page->index, 1, -+ block_list, NULL, &bsize); -+ if(block == 0) -+ goto skip_read; -+ -+ mutex_lock(&msblk->read_page_mutex); -+ bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block, -+ bsize, NULL, sblk->block_size); -+ if (bytes) { -+ pageaddr = kmap_atomic(page, KM_USER0); -+ memcpy(pageaddr, msblk->read_page, bytes); -+ kunmap_atomic(pageaddr, KM_USER0); -+ } else -+ ERROR("Unable to read page, block %llx, size %x\n", -+ block, bsize); -+ mutex_unlock(&msblk->read_page_mutex); -+ } else { -+ struct squashfs_fragment_cache *fragment = -+ get_cached_fragment(inode->i_sb, -+ SQUASHFS_I(inode)-> -+ u.s1.fragment_start_block, -+ SQUASHFS_I(inode)-> u.s1.fragment_size); -+ if (fragment) { -+ bytes = i_size_read(inode) & (sblk->block_size - 1); -+ pageaddr = kmap_atomic(page, KM_USER0); -+ memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)-> -+ u.s1.fragment_offset, bytes); -+ kunmap_atomic(pageaddr, KM_USER0); -+ release_cached_fragment(msblk, fragment); -+ } else -+ ERROR("Unable to read page, block %llx, size %x\n", -+ SQUASHFS_I(inode)-> -+ u.s1.fragment_start_block, (int) -+ SQUASHFS_I(inode)-> u.s1.fragment_size); -+ } -+ -+skip_read: -+ pageaddr = kmap_atomic(page, KM_USER0); -+ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); -+ kunmap_atomic(pageaddr, KM_USER0); -+ flush_dcache_page(page); -+ SetPageUptodate(page); -+ unlock_page(page); -+ -+ kfree(block_list); -+ return 0; -+} -+ -+ -+static int get_dir_index_using_offset(struct super_block *s, long long -+ *next_block, unsigned int *next_offset, -+ long long index_start, -+ unsigned int index_offset, int i_count, ++static int get_dir_index_using_offset(struct super_block *s, ++ long long *next_block, unsigned int *next_offset, ++ long long index_start, unsigned int index_offset, int i_count, + long long f_pos) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; @@ -1972,23 +1854,18 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + for (i = 0; i < i_count; i++) { + if (msblk->swap) { + struct squashfs_dir_index sindex; -+ squashfs_get_cached_block(s, (char *) &sindex, -+ index_start, index_offset, -+ sizeof(sindex), &index_start, -+ &index_offset); ++ squashfs_get_cached_block(s, &sindex, index_start, index_offset, ++ sizeof(sindex), &index_start, &index_offset); + SQUASHFS_SWAP_DIR_INDEX(&index, &sindex); + } else -+ squashfs_get_cached_block(s, (char *) &index, -+ index_start, index_offset, -+ sizeof(index), &index_start, -+ &index_offset); ++ squashfs_get_cached_block(s, &index, index_start, index_offset, ++ sizeof(index), &index_start, &index_offset); + + if (index.index > f_pos) + break; + + squashfs_get_cached_block(s, NULL, index_start, index_offset, -+ index.size + 1, &index_start, -+ &index_offset); ++ index.size + 1, &index_start, &index_offset); + + length = index.index; + *next_block = index.start_block + sblk->directory_table_start; @@ -2001,10 +1878,9 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino +} + + -+static int get_dir_index_using_name(struct super_block *s, long long -+ *next_block, unsigned int *next_offset, -+ long long index_start, -+ unsigned int index_offset, int i_count, ++static int get_dir_index_using_name(struct super_block *s, ++ long long *next_block, unsigned int *next_offset, ++ long long index_start, unsigned int index_offset, int i_count, + const char *name, int size) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; @@ -2015,8 +1891,9 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + + TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); + -+ if (!(str = kmalloc(sizeof(struct squashfs_dir_index) + -+ (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) { ++ str = kmalloc(sizeof(struct squashfs_dir_index) + ++ (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL); ++ if (str == NULL) { + ERROR("Failed to allocate squashfs_dir_index\n"); + goto failure; + } @@ -2028,20 +1905,15 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + for (i = 0; i < i_count; i++) { + if (msblk->swap) { + struct squashfs_dir_index sindex; -+ squashfs_get_cached_block(s, (char *) &sindex, -+ index_start, index_offset, -+ sizeof(sindex), &index_start, -+ &index_offset); ++ squashfs_get_cached_block(s, &sindex, index_start, index_offset, ++ sizeof(sindex), &index_start, &index_offset); + SQUASHFS_SWAP_DIR_INDEX(index, &sindex); + } else -+ squashfs_get_cached_block(s, (char *) index, -+ index_start, index_offset, -+ sizeof(struct squashfs_dir_index), -+ &index_start, &index_offset); ++ squashfs_get_cached_block(s, index, index_start, index_offset, ++ sizeof(struct squashfs_dir_index), &index_start, &index_offset); + -+ squashfs_get_cached_block(s, index->name, index_start, -+ index_offset, index->size + 1, -+ &index_start, &index_offset); ++ squashfs_get_cached_block(s, index->name, index_start, index_offset, ++ index->size + 1, &index_start, &index_offset); + + index->name[index->size + 1] = '\0'; + @@ -2054,6 +1926,7 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; + kfree(str); ++ +failure: + return length + 3; +} @@ -2066,15 +1939,15 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + struct squashfs_super_block *sblk = &msblk->sblk; + long long next_block = SQUASHFS_I(i)->start_block + + sblk->directory_table_start; -+ int next_offset = SQUASHFS_I(i)->offset, length = 0, -+ dir_count; ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count; + struct squashfs_dir_header dirh; + struct squashfs_dir_entry *dire; + + TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset); + -+ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + -+ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { ++ dire = kmalloc(sizeof(struct squashfs_dir_entry) + ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL); ++ if (dire == NULL) { + ERROR("Failed to allocate squashfs_dir_entry\n"); + goto finish; + } @@ -2094,14 +1967,12 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + } + TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n", + (unsigned int) dirent, name, size, (int) -+ file->f_pos, i_ino, -+ squashfs_filetype_table[1]); ++ file->f_pos, i_ino, squashfs_filetype_table[1]); + -+ if (filldir(dirent, name, size, -+ file->f_pos, i_ino, ++ if (filldir(dirent, name, size, file->f_pos, i_ino, + squashfs_filetype_table[1]) < 0) { + TRACE("Filldir returned less than 0\n"); -+ goto finish; ++ goto finish; + } + file->f_pos += size; + } @@ -2109,25 +1980,22 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset, + SQUASHFS_I(i)->u.s2.directory_index_start, + SQUASHFS_I(i)->u.s2.directory_index_offset, -+ SQUASHFS_I(i)->u.s2.directory_index_count, -+ file->f_pos); ++ SQUASHFS_I(i)->u.s2.directory_index_count, file->f_pos); + + while (length < i_size_read(i)) { + /* read directory header */ + if (msblk->swap) { + struct squashfs_dir_header sdirh; + -+ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, -+ next_block, next_offset, sizeof(sdirh), -+ &next_block, &next_offset)) ++ if (!squashfs_get_cached_block(i->i_sb, &sdirh, next_block, ++ next_offset, sizeof(sdirh), &next_block, &next_offset)) + goto failed_read; + + length += sizeof(sdirh); + SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); + } else { -+ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, -+ next_block, next_offset, sizeof(dirh), -+ &next_block, &next_offset)) ++ if (!squashfs_get_cached_block(i->i_sb, &dirh, next_block, ++ next_offset, sizeof(dirh), &next_block, &next_offset)) + goto failed_read; + + length += sizeof(dirh); @@ -2137,28 +2005,22 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + while (dir_count--) { + if (msblk->swap) { + struct squashfs_dir_entry sdire; -+ if (!squashfs_get_cached_block(i->i_sb, (char *) -+ &sdire, next_block, next_offset, -+ sizeof(sdire), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(i->i_sb, &sdire, next_block, ++ next_offset, sizeof(sdire), &next_block, &next_offset)) + goto failed_read; + + length += sizeof(sdire); + SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); + } else { -+ if (!squashfs_get_cached_block(i->i_sb, (char *) -+ dire, next_block, next_offset, -+ sizeof(*dire), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(i->i_sb, dire, next_block, ++ next_offset, sizeof(*dire), &next_block, &next_offset)) + goto failed_read; + + length += sizeof(*dire); + } + -+ if (!squashfs_get_cached_block(i->i_sb, dire->name, -+ next_block, next_offset, -+ dire->size + 1, &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block, ++ next_offset, dire->size + 1, &next_block, &next_offset)) + goto failed_read; + + length += dire->size + 1; @@ -2169,17 +2031,14 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + dire->name[dire->size + 1] = '\0'; + + TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n", -+ (unsigned int) dirent, dire->name, -+ dire->size + 1, (int) file->f_pos, -+ dirh.start_block, dire->offset, ++ (unsigned int) dirent, dire->name, dire->size + 1, ++ (int) file->f_pos, dirh.start_block, dire->offset, + dirh.inode_number + dire->inode_number, + squashfs_filetype_table[dire->type]); + -+ if (filldir(dirent, dire->name, dire->size + 1, -+ file->f_pos, ++ if (filldir(dirent, dire->name, dire->size + 1, file->f_pos, + dirh.inode_number + dire->inode_number, -+ squashfs_filetype_table[dire->type]) -+ < 0) { ++ squashfs_filetype_table[dire->type]) < 0) { + TRACE("Filldir returned less than 0\n"); + goto finish; + } @@ -2209,15 +2068,15 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + struct squashfs_super_block *sblk = &msblk->sblk; + long long next_block = SQUASHFS_I(i)->start_block + + sblk->directory_table_start; -+ int next_offset = SQUASHFS_I(i)->offset, length = 0, -+ dir_count; ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count; + struct squashfs_dir_header dirh; + struct squashfs_dir_entry *dire; + + TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset); + -+ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + -+ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { ++ dire = kmalloc(sizeof(struct squashfs_dir_entry) + ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL); ++ if (dire == NULL) { + ERROR("Failed to allocate squashfs_dir_entry\n"); + goto exit_lookup; + } @@ -2228,24 +2087,21 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset, + SQUASHFS_I(i)->u.s2.directory_index_start, + SQUASHFS_I(i)->u.s2.directory_index_offset, -+ SQUASHFS_I(i)->u.s2.directory_index_count, name, -+ len); ++ SQUASHFS_I(i)->u.s2.directory_index_count, name, len); + + while (length < i_size_read(i)) { + /* read directory header */ + if (msblk->swap) { + struct squashfs_dir_header sdirh; -+ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, -+ next_block, next_offset, sizeof(sdirh), -+ &next_block, &next_offset)) ++ if (!squashfs_get_cached_block(i->i_sb, &sdirh, next_block, ++ next_offset, sizeof(sdirh), &next_block, &next_offset)) + goto failed_read; + + length += sizeof(sdirh); + SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); + } else { -+ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, -+ next_block, next_offset, sizeof(dirh), -+ &next_block, &next_offset)) ++ if (!squashfs_get_cached_block(i->i_sb, &dirh, next_block, ++ next_offset, sizeof(dirh), &next_block, &next_offset)) + goto failed_read; + + length += sizeof(dirh); @@ -2255,27 +2111,22 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + while (dir_count--) { + if (msblk->swap) { + struct squashfs_dir_entry sdire; -+ if (!squashfs_get_cached_block(i->i_sb, (char *) -+ &sdire, next_block,next_offset, -+ sizeof(sdire), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(i->i_sb, &sdire, next_block, ++ next_offset, sizeof(sdire), &next_block, &next_offset)) + goto failed_read; + + length += sizeof(sdire); + SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); + } else { -+ if (!squashfs_get_cached_block(i->i_sb, (char *) -+ dire, next_block,next_offset, -+ sizeof(*dire), &next_block, -+ &next_offset)) ++ if (!squashfs_get_cached_block(i->i_sb, dire, next_block, ++ next_offset, sizeof(*dire), &next_block, &next_offset)) + goto failed_read; + + length += sizeof(*dire); + } + -+ if (!squashfs_get_cached_block(i->i_sb, dire->name, -+ next_block, next_offset, dire->size + 1, -+ &next_block, &next_offset)) ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block, ++ next_offset, dire->size + 1, &next_block, &next_offset)) + goto failed_read; + + length += dire->size + 1; @@ -2287,9 +2138,8 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + squashfs_inode_t ino = SQUASHFS_MKINODE(dirh.start_block, + dire->offset); + -+ TRACE("calling squashfs_iget for directory " -+ "entry %s, inode %x:%x, %d\n", name, -+ dirh.start_block, dire->offset, ++ TRACE("calling squashfs_iget for directory entry %s, inode" ++ " %x:%x, %d\n", name, dirh.start_block, dire->offset, + dirh.inode_number + dire->inode_number); + + inode = squashfs_iget(i->i_sb, ino, dirh.inode_number + dire->inode_number); @@ -2327,16 +2177,15 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + if (s->s_fs_info) { + struct squashfs_sb_info *sbi = s->s_fs_info; + if (sbi->block_cache) -+ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++) -+ if (sbi->block_cache[i].block != -+ SQUASHFS_INVALID_BLK) -+ kfree(sbi->block_cache[i].data); ++ for (i = 0; i < squashfs_cached_blks; i++) ++ if (sbi->block_cache[i].block != SQUASHFS_INVALID_BLK) ++ vfree(sbi->block_cache[i].data); + if (sbi->fragment) + for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) -+ SQUASHFS_FREE(sbi->fragment[i].data); ++ vfree(sbi->fragment[i].data); + kfree(sbi->fragment); + kfree(sbi->block_cache); -+ kfree(sbi->read_page); ++ vfree(sbi->read_page); + kfree(sbi->uid); + kfree(sbi->fragment_index); + kfree(sbi->fragment_index_2); @@ -2349,8 +2198,7 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + + +static int squashfs_get_sb(struct file_system_type *fs_type, int flags, -+ const char *dev_name, void *data, -+ struct vfsmount *mnt) ++ const char *dev_name, void *data, struct vfsmount *mnt) +{ + return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super, + mnt); @@ -2363,10 +2211,11 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + if (err) + goto out; + -+ printk(KERN_INFO "squashfs: version 3.2-r2 (2007/01/15) " ++ printk(KERN_INFO "squashfs: version 3.3 (2007/10/31) " + "Phillip Lougher\n"); + -+ if ((err = register_filesystem(&squashfs_fs_type))) ++ err = register_filesystem(&squashfs_fs_type); ++ if (err) + destroy_inodecache(); + +out: @@ -2388,9 +2237,7 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino +{ + struct squashfs_inode_info *ei; + ei = kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL); -+ if (!ei) -+ return NULL; -+ return &ei->vfs_inode; ++ return ei ? &ei->vfs_inode : NULL; +} + + @@ -2404,12 +2251,6 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino +{ + struct squashfs_inode_info *ei = foo; + -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)) -+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == -+ SLAB_CTOR_CONSTRUCTOR) -+ return; -+#endif -+ + inode_init_once(&ei->vfs_inode); +} + @@ -2417,13 +2258,8 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino +static int __init init_inodecache(void) +{ + squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache", -+ sizeof(struct squashfs_inode_info), -+ 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)) -+ init_once, NULL); -+#else -+ init_once); -+#endif ++ sizeof(struct squashfs_inode_info), 0, ++ SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, init_once); + if (squashfs_inode_cachep == NULL) + return -ENOMEM; + return 0; @@ -2438,18 +2274,18 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/inode.c linux-2.6.23.1/fs/squashfs/ino + +module_init(init_squashfs_fs); +module_exit(exit_squashfs_fs); -+MODULE_DESCRIPTION("squashfs 3.2-r2, a compressed read-only filesystem"); -+MODULE_AUTHOR("Phillip Lougher "); ++MODULE_DESCRIPTION("squashfs 3.2-r2-CVS, a compressed read-only filesystem"); ++MODULE_AUTHOR("Phillip Lougher "); +MODULE_LICENSE("GPL"); -diff -Nru linux-2.6.23.1.orig/fs/squashfs/squashfs.h linux-2.6.23.1/fs/squashfs/squashfs.h ---- linux-2.6.23.1.orig/fs/squashfs/squashfs.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.23.1/fs/squashfs/squashfs.h 2007-10-22 14:00:52.000000000 +0200 -@@ -0,0 +1,87 @@ +diff -urN linux-2.6.23.9.orig/fs/squashfs/squashfs.h linux-2.6.23.9/fs/squashfs/squashfs.h +--- linux-2.6.23.9.orig/fs/squashfs/squashfs.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-2.6.23.9/fs/squashfs/squashfs.h 2007-12-12 14:49:36.000000000 -0600 +@@ -0,0 +1,86 @@ +/* + * Squashfs - a compressed read only filesystem for Linux + * + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 -+ * Phillip Lougher ++ * Phillip Lougher + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License @@ -2497,7 +2333,7 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/squashfs.h linux-2.6.23.1/fs/squashfs/ +extern unsigned int squashfs_read_data(struct super_block *s, char *buffer, + long long index, unsigned int length, + long long *next_index, int srclength); -+extern int squashfs_get_cached_block(struct super_block *s, char *buffer, ++extern int squashfs_get_cached_block(struct super_block *s, void *buffer, + long long block, unsigned int offset, + int length, long long *next_block, + unsigned int *next_offset); @@ -2509,7 +2345,6 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/squashfs.h linux-2.6.23.1/fs/squashfs/ +extern struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number); +extern const struct address_space_operations squashfs_symlink_aops; +extern const struct address_space_operations squashfs_aops; -+extern const struct address_space_operations squashfs_aops_4K; +extern struct inode_operations squashfs_dir_inode_ops; +#else +#define SQSH_EXTERN static @@ -2532,15 +2367,15 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/squashfs.h linux-2.6.23.1/fs/squashfs/ + return 0; +} +#endif -diff -Nru linux-2.6.23.1.orig/fs/squashfs/squashfs2_0.c linux-2.6.23.1/fs/squashfs/squashfs2_0.c ---- linux-2.6.23.1.orig/fs/squashfs/squashfs2_0.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.23.1/fs/squashfs/squashfs2_0.c 2007-10-22 14:00:52.000000000 +0200 -@@ -0,0 +1,742 @@ +diff -urN linux-2.6.23.9.orig/fs/squashfs/squashfs2_0.c linux-2.6.23.9/fs/squashfs/squashfs2_0.c +--- linux-2.6.23.9.orig/fs/squashfs/squashfs2_0.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-2.6.23.9/fs/squashfs/squashfs2_0.c 2007-12-12 14:49:36.000000000 -0600 +@@ -0,0 +1,740 @@ +/* + * Squashfs - a compressed read only filesystem for Linux + * + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 -+ * Phillip Lougher ++ * Phillip Lougher + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License @@ -2686,14 +2521,15 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/squashfs2_0.c linux-2.6.23.1/fs/squash + unsigned int block = SQUASHFS_INODE_BLK(inode) + + sblk->inode_table_start; + unsigned int offset = SQUASHFS_INODE_OFFSET(inode); -+ unsigned int ino = i->i_ino; ++ unsigned int ino = SQUASHFS_MK_VFS_INODE(block - ++ sblk->inode_table_start, offset); + long long next_block; + unsigned int next_offset; + union squashfs_inode_header_2 id, sid; + struct squashfs_base_inode_header_2 *inodeb = &id.base, + *sinodeb = &sid.base; + -+ TRACE("Entered squashfs_iget\n"); ++ TRACE("Entered squashfs_read_inode_2\n"); + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) sinodeb, block, @@ -2750,10 +2586,7 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/squashfs2_0.c linux-2.6.23.1/fs/squash + SQUASHFS_I(i)->start_block = inodep->start_block; + SQUASHFS_I(i)->u.s1.block_list_start = next_block; + SQUASHFS_I(i)->offset = next_offset; -+ if (sblk->block_size > 4096) -+ i->i_data.a_ops = &squashfs_aops; -+ else -+ i->i_data.a_ops = &squashfs_aops_4K; ++ i->i_data.a_ops = &squashfs_aops; + + TRACE("File inode %x:%x, start_block %x, " + "block_list_start %llx, offset %x\n", @@ -3278,10 +3111,10 @@ diff -Nru linux-2.6.23.1.orig/fs/squashfs/squashfs2_0.c linux-2.6.23.1/fs/squash + + return 1; +} -diff -Nru linux-2.6.23.1.orig/include/linux/squashfs_fs.h linux-2.6.23.1/include/linux/squashfs_fs.h ---- linux-2.6.23.1.orig/include/linux/squashfs_fs.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.23.1/include/linux/squashfs_fs.h 2007-10-22 14:00:52.000000000 +0200 -@@ -0,0 +1,934 @@ +diff -urN linux-2.6.23.9.orig/include/linux/squashfs_fs.h linux-2.6.23.9/include/linux/squashfs_fs.h +--- linux-2.6.23.9.orig/include/linux/squashfs_fs.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-2.6.23.9/include/linux/squashfs_fs.h 2007-12-12 14:49:36.000000000 -0600 +@@ -0,0 +1,935 @@ +#ifndef SQUASHFS_FS +#define SQUASHFS_FS + @@ -3289,7 +3122,7 @@ diff -Nru linux-2.6.23.1.orig/include/linux/squashfs_fs.h linux-2.6.23.1/include + * Squashfs + * + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 -+ * Phillip Lougher ++ * Phillip Lougher + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License @@ -3312,16 +3145,9 @@ diff -Nru linux-2.6.23.1.orig/include/linux/squashfs_fs.h linux-2.6.23.1/include +#define CONFIG_SQUASHFS_2_0_COMPATIBILITY +#endif + -+#ifdef CONFIG_SQUASHFS_VMALLOC -+#define SQUASHFS_ALLOC(a) vmalloc(a) -+#define SQUASHFS_FREE(a) vfree(a) -+#else -+#define SQUASHFS_ALLOC(a) kmalloc(a, GFP_KERNEL) -+#define SQUASHFS_FREE(a) kfree(a) -+#endif +#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE +#define SQUASHFS_MAJOR 3 -+#define SQUASHFS_MINOR 0 ++#define SQUASHFS_MINOR 1 +#define SQUASHFS_MAGIC 0x73717368 +#define SQUASHFS_MAGIC_SWAP 0x68737173 +#define SQUASHFS_START 0 @@ -3331,10 +3157,10 @@ diff -Nru linux-2.6.23.1.orig/include/linux/squashfs_fs.h linux-2.6.23.1/include +#define SQUASHFS_METADATA_LOG 13 + +/* default size of data blocks */ -+#define SQUASHFS_FILE_SIZE 65536 -+#define SQUASHFS_FILE_LOG 16 ++#define SQUASHFS_FILE_SIZE 131072 ++#define SQUASHFS_FILE_LOG 17 + -+#define SQUASHFS_FILE_MAX_SIZE 65536 ++#define SQUASHFS_FILE_MAX_SIZE 1048576 + +/* Max number of uids and gids */ +#define SQUASHFS_UIDS 256 @@ -3415,9 +3241,8 @@ diff -Nru linux-2.6.23.1.orig/include/linux/squashfs_fs.h linux-2.6.23.1/include + +#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24) + -+#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) (((B) & \ -+ ~SQUASHFS_COMPRESSED_BIT_BLOCK) ? (B) & \ -+ ~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK) ++#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) ((B) & \ ++ ~SQUASHFS_COMPRESSED_BIT_BLOCK) + +#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) + @@ -3913,6 +3738,15 @@ diff -Nru linux-2.6.23.1.orig/include/linux/squashfs_fs.h linux-2.6.23.1/include + unsigned int start_block:24; +} __attribute__ ((packed)); + ++union squashfs_inode_header_1 { ++ struct squashfs_base_inode_header_1 base; ++ struct squashfs_dev_inode_header_1 dev; ++ struct squashfs_symlink_inode_header_1 symlink; ++ struct squashfs_reg_inode_header_1 reg; ++ struct squashfs_dir_inode_header_1 dir; ++ struct squashfs_ipc_inode_header_1 ipc; ++}; ++ +#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \ + SQUASHFS_MEMSET(s, d, n);\ + SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ @@ -4216,9 +4050,9 @@ diff -Nru linux-2.6.23.1.orig/include/linux/squashfs_fs.h linux-2.6.23.1/include + +#endif +#endif -diff -Nru linux-2.6.23.1.orig/include/linux/squashfs_fs_i.h linux-2.6.23.1/include/linux/squashfs_fs_i.h ---- linux-2.6.23.1.orig/include/linux/squashfs_fs_i.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.23.1/include/linux/squashfs_fs_i.h 2007-10-22 14:00:52.000000000 +0200 +diff -urN linux-2.6.23.9.orig/include/linux/squashfs_fs_i.h linux-2.6.23.9/include/linux/squashfs_fs_i.h +--- linux-2.6.23.9.orig/include/linux/squashfs_fs_i.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-2.6.23.9/include/linux/squashfs_fs_i.h 2007-12-12 14:49:36.000000000 -0600 @@ -0,0 +1,45 @@ +#ifndef SQUASHFS_FS_I +#define SQUASHFS_FS_I @@ -4226,7 +4060,7 @@ diff -Nru linux-2.6.23.1.orig/include/linux/squashfs_fs_i.h linux-2.6.23.1/inclu + * Squashfs + * + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 -+ * Phillip Lougher ++ * Phillip Lougher + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License @@ -4265,17 +4099,17 @@ diff -Nru linux-2.6.23.1.orig/include/linux/squashfs_fs_i.h linux-2.6.23.1/inclu + struct inode vfs_inode; +}; +#endif -diff -Nru linux-2.6.23.1.orig/include/linux/squashfs_fs_sb.h linux-2.6.23.1/include/linux/squashfs_fs_sb.h ---- linux-2.6.23.1.orig/include/linux/squashfs_fs_sb.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.23.1/include/linux/squashfs_fs_sb.h 2007-10-22 14:00:52.000000000 +0200 -@@ -0,0 +1,74 @@ +diff -urN linux-2.6.23.9.orig/include/linux/squashfs_fs_sb.h linux-2.6.23.9/include/linux/squashfs_fs_sb.h +--- linux-2.6.23.9.orig/include/linux/squashfs_fs_sb.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-2.6.23.9/include/linux/squashfs_fs_sb.h 2007-12-12 14:49:36.000000000 -0600 +@@ -0,0 +1,76 @@ +#ifndef SQUASHFS_FS_SB +#define SQUASHFS_FS_SB +/* + * Squashfs + * + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 -+ * Phillip Lougher ++ * Phillip Lougher + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License @@ -4335,6 +4169,8 @@ diff -Nru linux-2.6.23.1.orig/include/linux/squashfs_fs_sb.h linux-2.6.23.1/incl + struct meta_index *meta_index; + z_stream stream; + long long *inode_lookup_table; ++ int unused_cache_blks; ++ int unused_frag_blks; + int (*read_inode)(struct inode *i, squashfs_inode_t \ + inode); + long long (*read_blocklist)(struct inode *inode, int \ @@ -4343,9 +4179,9 @@ diff -Nru linux-2.6.23.1.orig/include/linux/squashfs_fs_sb.h linux-2.6.23.1/incl + int (*read_fragment_index_table)(struct super_block *s); +}; +#endif -diff -Nru linux-2.6.23.1.orig/init/do_mounts_rd.c linux-2.6.23.1/init/do_mounts_rd.c ---- linux-2.6.23.1.orig/init/do_mounts_rd.c 2007-10-22 14:00:11.000000000 +0200 -+++ linux-2.6.23.1/init/do_mounts_rd.c 2007-10-22 14:00:52.000000000 +0200 +diff -urN linux-2.6.23.9.orig/init/do_mounts_rd.c linux-2.6.23.9/init/do_mounts_rd.c +--- linux-2.6.23.9.orig/init/do_mounts_rd.c 2007-11-26 11:51:43.000000000 -0600 ++++ linux-2.6.23.9/init/do_mounts_rd.c 2007-12-12 14:49:36.000000000 -0600 @@ -5,6 +5,7 @@ #include #include