From: Steve Grubb <sgrubb@redhat.com> Subject: [RHEL5 PATCH] squashfs fixup Date: Wed, 13 Dec 2006 15:27:04 -0500 Bugzilla: 219534 Message-Id: <200612131527.04499.sgrubb@redhat.com> Changelog: squashfs fixup Hi, The patch below is to fix BZ 219534. It is from the upstream maintainer of squashfs. The problem is that when fsfuzz is run against squashfs, random applications segfault due to corrupted kernel memory. There are several Oopses, too. This patch has survived fsfuzzer and appears to be safer than what we current ship. -Steve diff -urp linux-2.6.18.x86_64.orig/fs/squashfs/inode.c linux-2.6.18.x86_64/fs/squashfs/inode.c --- linux-2.6.18.x86_64.orig/fs/squashfs/inode.c 2006-12-13 13:42:35.000000000 -0500 +++ linux-2.6.18.x86_64/fs/squashfs/inode.c 2006-12-13 13:43:42.000000000 -0500 @@ -56,12 +56,14 @@ static int init_inodecache(void); static void destroy_inodecache(void); static struct dentry *squashfs_lookup(struct inode *, struct dentry *, struct nameidata *); -static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode); +static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode); static long long read_blocklist(struct inode *inode, int index, int readahead_blks, char *block_list, unsigned short **block_p, unsigned int *bsize); -static struct super_block *squashfs_get_sb(struct file_system_type *, int, - const char *, void *, struct vfsmount *); +static int squashfs_get_sb(struct file_system_type *,int, const char *, void *, + struct vfsmount *); +static void vfs_read_inode(struct inode *i); +static struct dentry *squashfs_get_parent(struct dentry *child); static struct file_system_type squashfs_fs_type = { .owner = THIS_MODULE, @@ -75,13 +77,25 @@ static unsigned char squashfs_filetype_t DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK }; -static struct super_operations squashfs_ops = { +static struct super_operations squashfs_super_ops = { .alloc_inode = squashfs_alloc_inode, .destroy_inode = squashfs_destroy_inode, .statfs = squashfs_statfs, .put_super = squashfs_put_super, }; +static struct super_operations squashfs_export_super_ops = { + .alloc_inode = squashfs_alloc_inode, + .destroy_inode = squashfs_destroy_inode, + .statfs = squashfs_statfs, + .put_super = squashfs_put_super, + .read_inode = vfs_read_inode +}; + +struct export_operations squashfs_export_ops = { + .get_parent = squashfs_get_parent +}; + SQSH_EXTERN struct address_space_operations squashfs_symlink_aops = { .readpage = squashfs_symlink_readpage }; @@ -173,14 +187,15 @@ out: SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer, long long index, unsigned int length, - long long *next_index) + 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[((SQUASHFS_FILE_MAX_SIZE - 1) >> msblk->devblksize_log2) + 2]; unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1); unsigned int cur_index = index >> msblk->devblksize_log2; - int bytes, avail_bytes, b = 0, k; + int bytes, avail_bytes, b = 0, k = 0; char *c_buffer; unsigned int compressed; unsigned int c_byte = length; @@ -191,8 +206,11 @@ SQSH_EXTERN unsigned int squashfs_read_d c_buffer = compressed ? msblk->read_data : buffer; c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte); - TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed - ? "" : "un", (unsigned int) 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) + goto read_failure; if (!(bh[0] = sb_getblk(s, cur_index))) goto block_release; @@ -204,6 +222,9 @@ SQSH_EXTERN unsigned int squashfs_read_d } ll_rw_block(READ, b, bh); } else { + if (index < 0 || (index + 2) > sblk->bytes_used) + goto read_failure; + if (!(bh[0] = get_block_length(s, &cur_index, &offset, &c_byte))) goto read_failure; @@ -216,6 +237,9 @@ SQSH_EXTERN unsigned int squashfs_read_d TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed ? "" : "un", (unsigned int) c_byte); + if (c_byte > srclength || (index + c_byte) > sblk->bytes_used) + goto read_failure; + for (b = 1; bytes < c_byte; b++) { if (!(bh[b] = sb_getblk(s, ++cur_index))) goto block_release; @@ -227,7 +251,7 @@ SQSH_EXTERN unsigned int squashfs_read_d if (compressed) down(&msblk->read_data_mutex); - for (bytes = 0, k = 0; k < b; k++) { + for (bytes = 0; k < b; k++) { avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ? msblk->devblksize - offset : c_byte - bytes; @@ -249,14 +273,17 @@ SQSH_EXTERN unsigned int squashfs_read_d msblk->stream.next_in = c_buffer; msblk->stream.avail_in = c_byte; msblk->stream.next_out = buffer; - msblk->stream.avail_out = msblk->read_size; + //msblk->stream.avail_out = msblk->read_size;//srclength; + msblk->stream.avail_out = srclength; if (((zlib_err = zlib_inflateInit(&msblk->stream)) != Z_OK) || ((zlib_err = zlib_inflate(&msblk->stream, Z_FINISH)) != Z_STREAM_END) || ((zlib_err = zlib_inflateEnd(&msblk->stream)) != Z_OK)) { - ERROR("zlib_fs returned unexpected result 0x%x\n", - zlib_err); + //ERROR("zlib_fs returned unexpected result 0x%x\n", + // zlib_err); + ERROR("zlib_fs returned unexpected result 0x%x, srclength %d\n", + zlib_err, srclength); bytes = 0; } else bytes = msblk->stream.total_out; @@ -271,8 +298,8 @@ SQSH_EXTERN unsigned int squashfs_read_d return bytes; block_release: - while (--b >= 0) - brelse(bh[b]); + for (; k < b; k++) + brelse(bh[k]); read_failure: ERROR("sb_bread failed reading block 0x%x\n", cur_index); @@ -336,12 +363,16 @@ SQSH_EXTERN int squashfs_get_cached_bloc msblk->block_cache[i].block = SQUASHFS_USED_BLK; up(&msblk->block_cache_mutex); - if (!(msblk->block_cache[i].length = - squashfs_read_data(s, - msblk->block_cache[i].data, - block, 0, &next_index))) { + msblk->block_cache[i].length = squashfs_read_data(s, + 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); + down(&msblk->block_cache_mutex); + msblk->block_cache[i].block = SQUASHFS_INVALID_BLK; + kfree(msblk->block_cache[i].data); + wake_up(&msblk->waitq); + up(&msblk->block_cache_mutex); goto out; } @@ -357,7 +388,12 @@ SQSH_EXTERN int squashfs_get_cached_bloc continue; } - if ((bytes = msblk->block_cache[i].length - offset) >= length) { + bytes = msblk->block_cache[i].length - offset; + + if (bytes < 1) { + up(&msblk->block_cache_mutex); + goto out; + } else if (bytes >= length) { if (buffer) memcpy(buffer, msblk->block_cache[i].data + offset, length); @@ -442,6 +478,7 @@ SQSH_EXTERN struct squashfs_fragment_cac { int i, n; struct squashfs_sb_info *msblk = s->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; while ( 1 ) { down(&msblk->fragment_mutex); @@ -487,7 +524,7 @@ SQSH_EXTERN struct squashfs_fragment_cac if (!(msblk->fragment[i].length = squashfs_read_data(s, msblk->fragment[i].data, - start_block, length, NULL))) { + start_block, length, NULL, sblk->block_size))) { ERROR("Unable to read fragment cache block " "[%llx]\n", start_block); msblk->fragment[i].locked = 0; @@ -516,33 +553,105 @@ out: } -static struct inode *squashfs_new_inode(struct super_block *s, +static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i, struct squashfs_base_inode_header *inodeb) { + i->i_ino = inodeb->inode_number; + i->i_mtime.tv_sec = inodeb->mtime; + i->i_atime.tv_sec = inodeb->mtime; + i->i_ctime.tv_sec = inodeb->mtime; + 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 + i->i_gid = msblk->guid[inodeb->guid]; +} + + +static squashfs_inode_t squashfs_inode_lookup(struct super_block *s, int ino) +{ struct squashfs_sb_info *msblk = s->s_fs_info; - struct inode *i = new_inode(s); + long long start = msblk->inode_lookup_table[SQUASHFS_LOOKUP_BLOCK(ino - 1)]; + int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino - 1); + squashfs_inode_t inode; - if (i) { - i->i_ino = inodeb->inode_number; - i->i_mtime.tv_sec = inodeb->mtime; - i->i_atime.tv_sec = inodeb->mtime; - i->i_ctime.tv_sec = inodeb->mtime; - 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 - i->i_gid = msblk->guid[inodeb->guid]; + TRACE("Entered squashfs_inode_lookup, inode_number = %d\n", ino); + + if (msblk->swap) { + squashfs_inode_t sinode; + + if (!squashfs_get_cached_block(s, (char *) &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, + sizeof(inode), &start, &offset)) + goto out; + + TRACE("squashfs_inode_lookup, inode = 0x%llx\n", inode); + + return inode; + +out: + return SQUASHFS_INVALID_BLK; +} + + +static void vfs_read_inode(struct inode *i) +{ + struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; + squashfs_inode_t inode = squashfs_inode_lookup(i->i_sb, i->i_ino); + + TRACE("Entered vfs_read_inode\n"); + + if(inode != SQUASHFS_INVALID_BLK) + (msblk->read_inode)(i, inode); +} + + +static struct dentry *squashfs_get_parent(struct dentry *child) +{ + struct inode *i = child->d_inode; + struct inode *parent = iget(i->i_sb, SQUASHFS_I(i)->u.s2.parent_inode); + struct dentry *rv; + + TRACE("Entered squashfs_get_parent\n"); + + if(parent == NULL) { + rv = ERR_PTR(-EACCES); + goto out; + } + + rv = d_alloc_anon(parent); + if(rv == NULL) + rv = ERR_PTR(-ENOMEM); + +out: + return rv; +} + + +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); + + TRACE("Entered squashfs_iget\n"); + + if(i && (i->i_state & I_NEW)) { + (msblk->read_inode)(i, inode); + unlock_new_inode(i); } return i; } -static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode) +static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode) { - struct inode *i; + 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) + @@ -554,7 +663,7 @@ static struct inode *squashfs_iget(struc struct squashfs_base_inode_header *inodeb = &id.base, *sinodeb = &sid.base; - TRACE("Entered squashfs_iget\n"); + TRACE("Entered squashfs_read_inode\n"); if (msblk->swap) { if (!squashfs_get_cached_block(s, (char *) sinodeb, block, @@ -569,6 +678,8 @@ static struct inode *squashfs_iget(struc &next_offset)) goto failed_read; + squashfs_new_inode(msblk, i, inodeb); + switch(inodeb->inode_type) { case SQUASHFS_FILE_TYPE: { unsigned int frag_size; @@ -596,9 +707,6 @@ static struct inode *squashfs_iget(struc inodep->fragment, &frag_blk, &frag_size)) goto failed_read; - if((i = squashfs_new_inode(s, inodeb)) == NULL) - goto failed_read1; - i->i_nlink = 1; i->i_size = inodep->file_size; i->i_fop = &generic_ro_fops; @@ -648,9 +756,6 @@ static struct inode *squashfs_iget(struc inodep->fragment, &frag_blk, &frag_size)) goto failed_read; - if((i = squashfs_new_inode(s, inodeb)) == NULL) - goto failed_read1; - i->i_nlink = inodep->nlink; i->i_size = inodep->file_size; i->i_fop = &generic_ro_fops; @@ -692,9 +797,6 @@ static struct inode *squashfs_iget(struc &next_offset)) goto failed_read; - if((i = squashfs_new_inode(s, inodeb)) == NULL) - goto failed_read1; - i->i_nlink = inodep->nlink; i->i_size = inodep->file_size; i->i_op = &squashfs_dir_inode_ops; @@ -730,9 +832,6 @@ static struct inode *squashfs_iget(struc &next_offset)) goto failed_read; - if((i = squashfs_new_inode(s, inodeb)) == NULL) - goto failed_read1; - i->i_nlink = inodep->nlink; i->i_size = inodep->file_size; i->i_op = &squashfs_dir_inode_ops; @@ -774,9 +873,6 @@ static struct inode *squashfs_iget(struc &next_offset)) goto failed_read; - if((i = squashfs_new_inode(s, inodeb)) == NULL) - goto failed_read1; - i->i_nlink = inodep->nlink; i->i_size = inodep->symlink_size; i->i_op = &page_symlink_inode_operations; @@ -810,9 +906,6 @@ static struct inode *squashfs_iget(struc &next_offset)) goto failed_read; - if ((i = squashfs_new_inode(s, inodeb)) == NULL) - goto failed_read1; - i->i_nlink = inodep->nlink; i->i_mode |= (inodeb->inode_type == SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : @@ -844,9 +937,6 @@ static struct inode *squashfs_iget(struc &next_offset)) goto failed_read; - if ((i = squashfs_new_inode(s, inodeb)) == NULL) - goto failed_read1; - i->i_nlink = inodep->nlink; i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE) ? S_IFIFO : S_IFSOCK; @@ -859,14 +949,50 @@ static struct inode *squashfs_iget(struc goto failed_read1; } - insert_inode_hash(i); - return i; + return 1; failed_read: ERROR("Unable to read inode [%llx:%x]\n", block, offset); failed_read1: - return NULL; + make_bad_inode(i); + return 0; +} + + +static int read_inode_lookup_table(struct super_block *s) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(sblk->inodes); + + TRACE("In read_inode_lookup_table, length %d\n", length); + + /* Allocate inode lookup table */ + if (!(msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL))) { + ERROR("Failed to allocate inode lookup table\n"); + return 0; + } + + if (!squashfs_read_data(s, (char *) msblk->inode_lookup_table, + sblk->lookup_table_start, length | + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) { + ERROR("unable to read inode lookup table\n"); + return 0; + } + + if (msblk->swap) { + int i; + long long block; + + for (i = 0; i < SQUASHFS_LOOKUP_BLOCKS(sblk->inodes); i++) { + SQUASHFS_SWAP_LOOKUP_BLOCKS((&block), + &msblk->inode_lookup_table[i], 1); + msblk->inode_lookup_table[i] = block; + } + } + + return 1; } @@ -874,21 +1000,20 @@ static int read_fragment_index_table(str { struct squashfs_sb_info *msblk = s->s_fs_info; struct squashfs_super_block *sblk = &msblk->sblk; + unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments); + + if(length == 0) + return 1; /* Allocate fragment index table */ - if (!(msblk->fragment_index = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES - (sblk->fragments), GFP_KERNEL))) { - ERROR("Failed to allocate uid/gid table\n"); + if (!(msblk->fragment_index = kmalloc(length, GFP_KERNEL))) { + ERROR("Failed to allocate fragment index table\n"); return 0; } - if (SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments) && - !squashfs_read_data(s, (char *) - msblk->fragment_index, - sblk->fragment_table_start, - SQUASHFS_FRAGMENT_INDEX_BYTES - (sblk->fragments) | - SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { + if (!squashfs_read_data(s, (char *) msblk->fragment_index, + sblk->fragment_table_start, length | + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) { ERROR("unable to read fragment index table\n"); return 0; } @@ -897,8 +1022,7 @@ static int read_fragment_index_table(str int i; long long fragment; - for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); - i++) { + for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); i++) { SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment), &msblk->fragment_index[i], 1); msblk->fragment_index[i] = fragment; @@ -913,7 +1037,7 @@ static int supported_squashfs_filesystem { struct squashfs_super_block *sblk = &msblk->sblk; - msblk->iget = squashfs_iget; + msblk->read_inode = squashfs_read_inode; msblk->read_blocklist = read_blocklist; msblk->read_fragment_index_table = read_fragment_index_table; @@ -980,9 +1104,10 @@ static int squashfs_fill_super(struct su init_waitqueue_head(&msblk->waitq); init_waitqueue_head(&msblk->fragment_wait_queue); + sblk->bytes_used = sizeof(struct squashfs_super_block); if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START, sizeof(struct squashfs_super_block) | - SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, sizeof(struct squashfs_super_block))) { SERROR("unable to read superblock\n"); goto failed_mount; } @@ -1010,6 +1135,15 @@ static int squashfs_fill_super(struct su if(!supported_squashfs_filesystem(msblk, silent)) goto failed_mount; + /* Check the filesystem does not extend beyond the end of the + block device */ + if(sblk->bytes_used < 0 || sblk->bytes_used > i_size_read(s->s_bdev->bd_inode)) + goto failed_mount; + + /* Check the root inode for sanity */ + if (SQUASHFS_INODE_OFFSET(sblk->root_inode) > SQUASHFS_METADATA_SIZE) + goto failed_mount; + TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b)); TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES @@ -1035,7 +1169,7 @@ static int squashfs_fill_super(struct su TRACE("sblk->uid_start %llx\n", sblk->uid_start); s->s_flags |= MS_RDONLY; - s->s_op = &squashfs_ops; + s->s_op = &squashfs_super_ops; /* Init inode_table block pointer array */ if (!(msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) * @@ -1079,7 +1213,7 @@ static int squashfs_fill_super(struct su if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start, ((sblk->no_uids + sblk->no_guids) * sizeof(unsigned int)) | - SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) { ERROR("unable to read uid/gid table\n"); goto failed_mount; } @@ -1090,7 +1224,7 @@ static int squashfs_fill_super(struct su if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start, ((sblk->no_uids + sblk->no_guids) * sizeof(unsigned int)) | - SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) { ERROR("unable to read uid/gid table\n"); goto failed_mount; } @@ -1113,13 +1247,25 @@ static int squashfs_fill_super(struct su msblk->next_fragment = 0; - /* Allocate fragment index table */ + /* Allocate and read fragment index table */ if (msblk->read_fragment_index_table(s) == 0) goto failed_mount; + if(sblk->lookup_table_start == SQUASHFS_INVALID_BLK) + goto allocate_root; + + /* Allocate and read inode lookup table */ + if (read_inode_lookup_table(s) == 0) + goto failed_mount; + + s->s_op = &squashfs_export_super_ops; + s->s_export_op = &squashfs_export_ops; + allocate_root: - if ((root = (msblk->iget)(s, sblk->root_inode)) == NULL) + root = new_inode(s); + if ((msblk->read_inode)(root, sblk->root_inode) == 0) goto failed_mount; + insert_inode_hash(root); if ((s->s_root = d_alloc_root(root)) == NULL) { ERROR("Root inode create failed\n"); @@ -1131,6 +1277,7 @@ allocate_root: return 0; failed_mount: + kfree(msblk->inode_lookup_table); kfree(msblk->fragment_index); kfree(msblk->fragment); kfree(msblk->uid); @@ -1148,9 +1295,9 @@ failure: } -static int squashfs_statfs(struct dentry *s, struct kstatfs *buf) +static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf) { - struct squashfs_sb_info *msblk = s->d_sb->s_fs_info; + struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info; struct squashfs_super_block *sblk = &msblk->sblk; TRACE("Entered squashfs_statfs\n"); @@ -1376,6 +1523,8 @@ static int get_meta_index(struct inode * skip)) == NULL) goto all_done; } else { + if(meta->entries == 0) + goto failed; offset = index < meta->offset + meta->entries ? index : meta->offset + meta->entries - 1; meta_entry = &meta->meta_entry[offset - meta->offset]; @@ -1516,7 +1665,7 @@ static int squashfs_readpage(struct file down(&msblk->read_page_mutex); if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page, - block, bsize, NULL))) { + block, bsize, NULL, sblk->block_size))) { ERROR("Unable to read page, block %llx, size %x\n", block, bsize); up(&msblk->read_page_mutex); @@ -1545,43 +1694,31 @@ static int squashfs_readpage(struct file for (i = start_index; i <= end_index && byte_offset < bytes; i++, byte_offset += PAGE_CACHE_SIZE) { struct page *push_page; - int available_bytes = (bytes - byte_offset) > PAGE_CACHE_SIZE ? + int avail = (bytes - byte_offset) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : bytes - byte_offset; TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n", - bytes, i, byte_offset, available_bytes); + bytes, i, byte_offset, avail); - if (i == page->index) { - pageaddr = kmap_atomic(page, KM_USER0); - memcpy(pageaddr, data_ptr + byte_offset, - available_bytes); - memset(pageaddr + available_bytes, 0, - PAGE_CACHE_SIZE - available_bytes); - kunmap_atomic(pageaddr, KM_USER0); - flush_dcache_page(page); - SetPageUptodate(page); - unlock_page(page); - } else { - push_page = grab_cache_page_nowait(page->mapping, i); - if (!push_page) - continue; - if (PageUptodate(push_page)) { - unlock_page(push_page); - page_cache_release(push_page); - continue; - } - pageaddr = kmap_atomic(push_page, KM_USER0); + push_page = (i == page->index) ? page : + grab_cache_page_nowait(page->mapping, i); - memcpy(pageaddr, data_ptr + byte_offset, - available_bytes); - memset(pageaddr + available_bytes, 0, - PAGE_CACHE_SIZE - available_bytes); - kunmap_atomic(pageaddr, KM_USER0); - flush_dcache_page(push_page); - SetPageUptodate(push_page); - unlock_page(push_page); + if (!push_page) + continue; + + if (PageUptodate(push_page)) + goto skip_page; + + pageaddr = kmap_atomic(push_page, KM_USER0); + memcpy(pageaddr, data_ptr + byte_offset, avail); + memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail); + kunmap_atomic(pageaddr, KM_USER0); + flush_dcache_page(push_page); + SetPageUptodate(push_page); +skip_page: + unlock_page(push_page); + if(i != page->index) page_cache_release(push_page); - } } if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK @@ -1623,15 +1760,12 @@ static int squashfs_readpage4K(struct fi if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT)) { - pageaddr = kmap_atomic(page, KM_USER0); block_list = NULL; goto skip_read; } if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) { ERROR("Failed to allocate block_list\n"); - pageaddr = kmap_atomic(page, KM_USER0); - block_list = NULL; goto skip_read; } @@ -1640,14 +1774,17 @@ static int squashfs_readpage4K(struct fi sblk->block_log)) { block = (msblk->read_blocklist)(inode, page->index, 1, block_list, NULL, &bsize); + if(block == 0) + goto skip_read; down(&msblk->read_page_mutex); bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block, - bsize, NULL); - pageaddr = kmap_atomic(page, KM_USER0); - if (bytes) + bsize, NULL, sblk->block_size); + if (bytes) { + pageaddr = kmap_atomic(page, KM_USER0); memcpy(pageaddr, msblk->read_page, bytes); - else + kunmap_atomic(pageaddr, KM_USER0); + } else ERROR("Unable to read page, block %llx, size %x\n", block, bsize); up(&msblk->read_page_mutex); @@ -1657,11 +1794,12 @@ static int squashfs_readpage4K(struct fi SQUASHFS_I(inode)-> u.s1.fragment_start_block, SQUASHFS_I(inode)-> u.s1.fragment_size); - pageaddr = kmap_atomic(page, KM_USER0); 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", @@ -1671,6 +1809,7 @@ static int squashfs_readpage4K(struct fi } 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); @@ -1925,6 +2064,7 @@ finish: failed_read: ERROR("Unable to read directory block [%llx:%x]\n", next_block, next_offset); + kfree(dire); return 0; } @@ -1949,11 +2089,11 @@ static struct dentry *squashfs_lookup(st if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { ERROR("Failed to allocate squashfs_dir_entry\n"); - goto exit_loop; + goto exit_lookup; } if (len > SQUASHFS_NAME_LEN) - goto exit_loop; + goto exit_lookup; length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset, SQUASHFS_I(i)->u.s2.directory_index_start, @@ -2011,35 +2151,35 @@ static struct dentry *squashfs_lookup(st length += dire->size + 1; if (name[0] < dire->name[0]) - goto exit_loop; + goto exit_lookup; - if ((len == dire->size + 1) && !strncmp(name, - dire->name, len)) { - squashfs_inode_t ino = - SQUASHFS_MKINODE(dirh.start_block, - dire->offset); + if ((len == dire->size + 1) && !strncmp(name, dire->name, len)) { + 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, dirh.inode_number + dire->inode_number); - inode = (msblk->iget)(i->i_sb, ino); + inode = squashfs_iget(i->i_sb, ino, dirh.inode_number + dire->inode_number); - goto exit_loop; + goto exit_lookup; } } } -exit_loop: +exit_lookup: kfree(dire); + if (inode) + return d_splice_alias(inode, dentry); d_add(dentry, inode); return ERR_PTR(0); failed_read: ERROR("Unable to read directory block [%llx:%x]\n", next_block, next_offset); - goto exit_loop; + goto exit_lookup; } @@ -2072,10 +2212,12 @@ static void squashfs_put_super(struct su } -static struct super_block *squashfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static int squashfs_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, + struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super, mnt); + return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super, + mnt); } @@ -2085,7 +2227,7 @@ static int __init init_squashfs_fs(void) if (err) goto out; - printk(KERN_INFO "squashfs: version 3.1 (2006/08/09) " + printk(KERN_INFO "squashfs: version 3.2-alpha (2006/12/12) " "Phillip Lougher\n"); if ((err = register_filesystem(&squashfs_fs_type))) @@ -2146,14 +2288,12 @@ static int __init init_inodecache(void) static void destroy_inodecache(void) { - if (kmem_cache_destroy(squashfs_inode_cachep)) - printk(KERN_INFO "squashfs_inode_cache: not all structures " - "were freed\n"); + kmem_cache_destroy(squashfs_inode_cachep); } module_init(init_squashfs_fs); module_exit(exit_squashfs_fs); -MODULE_DESCRIPTION("squashfs, a compressed read-only filesystem"); +MODULE_DESCRIPTION("squashfs 3.2, a compressed read-only filesystem"); MODULE_AUTHOR("Phillip Lougher <phillip@lougher.org.uk>"); MODULE_LICENSE("GPL"); diff -urp linux-2.6.18.x86_64.orig/fs/squashfs/squashfs2_0.c linux-2.6.18.x86_64/fs/squashfs/squashfs2_0.c --- linux-2.6.18.x86_64.orig/fs/squashfs/squashfs2_0.c 2006-12-13 13:42:35.000000000 -0500 +++ linux-2.6.18.x86_64/fs/squashfs/squashfs2_0.c 2006-12-13 13:43:42.000000000 -0500 @@ -78,7 +78,7 @@ static int read_fragment_index_table_2(s sblk->fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES_2 (sblk->fragments) | - SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments))) { ERROR("unable to read fragment index table\n"); return 0; } @@ -135,42 +135,35 @@ out: } -static struct inode *squashfs_new_inode(struct super_block *s, +static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i, struct squashfs_base_inode_header_2 *inodeb, unsigned int ino) { - struct squashfs_sb_info *msblk = s->s_fs_info; struct squashfs_super_block *sblk = &msblk->sblk; - struct inode *i = new_inode(s); - - if (i) { - i->i_ino = ino; - i->i_mtime.tv_sec = sblk->mkfs_time; - i->i_atime.tv_sec = sblk->mkfs_time; - i->i_ctime.tv_sec = sblk->mkfs_time; - i->i_uid = msblk->uid[inodeb->uid]; - i->i_mode = inodeb->mode; - i->i_nlink = 1; - i->i_size = 0; - if (inodeb->guid == SQUASHFS_GUIDS) - i->i_gid = i->i_uid; - else - i->i_gid = msblk->guid[inodeb->guid]; - } - return i; + i->i_ino = ino; + i->i_mtime.tv_sec = sblk->mkfs_time; + i->i_atime.tv_sec = sblk->mkfs_time; + i->i_ctime.tv_sec = sblk->mkfs_time; + i->i_uid = msblk->uid[inodeb->uid]; + i->i_mode = inodeb->mode; + i->i_nlink = 1; + i->i_size = 0; + if (inodeb->guid == SQUASHFS_GUIDS) + i->i_gid = i->i_uid; + else + i->i_gid = msblk->guid[inodeb->guid]; } -static struct inode *squashfs_iget_2(struct super_block *s, squashfs_inode_t inode) +static int squashfs_read_inode_2(struct inode *i, squashfs_inode_t inode) { - struct inode *i; + struct super_block *s = i->i_sb; struct squashfs_sb_info *msblk = s->s_fs_info; struct squashfs_super_block *sblk = &msblk->sblk; unsigned int block = SQUASHFS_INODE_BLK(inode) + sblk->inode_table_start; unsigned int offset = SQUASHFS_INODE_OFFSET(inode); - unsigned int ino = SQUASHFS_MK_VFS_INODE(block - - sblk->inode_table_start, offset); + unsigned int ino = i->i_ino; long long next_block; unsigned int next_offset; union squashfs_inode_header_2 id, sid; @@ -192,6 +185,8 @@ static struct inode *squashfs_iget_2(str &next_offset)) goto failed_read; + squashfs_new_inode(msblk, i, inodeb, ino); + switch(inodeb->inode_type) { case SQUASHFS_FILE_TYPE: { struct squashfs_reg_inode_header_2 *inodep = &id.reg; @@ -219,9 +214,6 @@ static struct inode *squashfs_iget_2(str inodep->fragment, &frag_blk, &frag_size)) goto failed_read; - if((i = squashfs_new_inode(s, inodeb, ino)) == NULL) - goto failed_read1; - i->i_size = inodep->file_size; i->i_fop = &generic_ro_fops; i->i_mode |= S_IFREG; @@ -265,9 +257,6 @@ static struct inode *squashfs_iget_2(str &next_offset)) goto failed_read; - if((i = squashfs_new_inode(s, inodeb, ino)) == NULL) - goto failed_read1; - i->i_size = inodep->file_size; i->i_op = &squashfs_dir_inode_ops_2; i->i_fop = &squashfs_dir_ops_2; @@ -305,9 +294,6 @@ static struct inode *squashfs_iget_2(str &next_offset)) goto failed_read; - if((i = squashfs_new_inode(s, inodeb, ino)) == NULL) - goto failed_read1; - i->i_size = inodep->file_size; i->i_op = &squashfs_dir_inode_ops_2; i->i_fop = &squashfs_dir_ops_2; @@ -351,9 +337,6 @@ static struct inode *squashfs_iget_2(str &next_offset)) goto failed_read; - if((i = squashfs_new_inode(s, inodeb, ino)) == NULL) - goto failed_read1; - i->i_size = inodep->symlink_size; i->i_op = &page_symlink_inode_operations; i->i_data.a_ops = &squashfs_symlink_aops; @@ -386,9 +369,6 @@ static struct inode *squashfs_iget_2(str &next_offset)) goto failed_read; - if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL) - goto failed_read1; - i->i_mode |= (inodeb->inode_type == SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : S_IFBLK; @@ -402,8 +382,6 @@ static struct inode *squashfs_iget_2(str } case SQUASHFS_FIFO_TYPE: case SQUASHFS_SOCKET_TYPE: { - if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL) - goto failed_read1; i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE) ? S_IFIFO : S_IFSOCK; @@ -416,14 +394,13 @@ static struct inode *squashfs_iget_2(str goto failed_read1; } - insert_inode_hash(i); - return i; + return 1; failed_read: ERROR("Unable to read inode [%x:%x]\n", block, offset); failed_read1: - return NULL; + return 0; } @@ -485,12 +462,18 @@ static int get_dir_index_using_name(stru struct squashfs_sb_info *msblk = s->s_fs_info; struct squashfs_super_block *sblk = &msblk->sblk; int i, length = 0; - char buffer[sizeof(struct squashfs_dir_index_2) + SQUASHFS_NAME_LEN + 1]; - struct squashfs_dir_index_2 *index = (struct squashfs_dir_index_2 *) buffer; - char str[SQUASHFS_NAME_LEN + 1]; + struct squashfs_dir_index_2 *index; + char *str; 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))) { + ERROR("Failed to allocate squashfs_dir_index\n"); + goto failure; + } + + index = (struct squashfs_dir_index_2 *) (str + SQUASHFS_NAME_LEN + 1); strncpy(str, name, size); str[size] = '\0'; @@ -522,6 +505,8 @@ static int get_dir_index_using_name(stru } *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; + kfree(str); +failure: return length; } @@ -533,14 +518,19 @@ static int squashfs_readdir_2(struct fil 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, dirs_read = 0, + int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count; struct squashfs_dir_header_2 dirh; - char buffer[sizeof(struct squashfs_dir_entry_2) + SQUASHFS_NAME_LEN + 1]; - struct squashfs_dir_entry_2 *dire = (struct squashfs_dir_entry_2 *) buffer; + struct squashfs_dir_entry_2 *dire; TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset); + if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + + SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { + ERROR("Failed to allocate squashfs_dir_entry\n"); + goto finish; + } + 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, @@ -618,16 +608,17 @@ static int squashfs_readdir_2(struct fil goto finish; } file->f_pos = length; - dirs_read++; } } finish: - return dirs_read; + kfree(dire); + return 0; failed_read: ERROR("Unable to read directory block [%llx:%x]\n", next_block, next_offset); + kfree(dire); return 0; } @@ -645,11 +636,16 @@ static struct dentry *squashfs_lookup_2( int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count; struct squashfs_dir_header_2 dirh; - char buffer[sizeof(struct squashfs_dir_entry_2) + SQUASHFS_NAME_LEN]; - struct squashfs_dir_entry_2 *dire = (struct squashfs_dir_entry_2 *) buffer; + struct squashfs_dir_entry_2 *dire; int sorted = sblk->s_major == 2 && sblk->s_minor >= 1; - TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset); + TRACE("Entered squashfs_lookup_2 [%llx:%x]\n", next_block, next_offset); + + if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + + SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { + ERROR("Failed to allocate squashfs_dir_entry\n"); + goto exit_loop; + } if (len > SQUASHFS_NAME_LEN) goto exit_loop; @@ -717,12 +713,14 @@ static struct dentry *squashfs_lookup_2( squashfs_inode_t ino = SQUASHFS_MKINODE(dirh.start_block, dire->offset); + unsigned int inode_number = SQUASHFS_MK_VFS_INODE(dirh.start_block, + dire->offset); TRACE("calling squashfs_iget for directory " "entry %s, inode %x:%x, %lld\n", name, dirh.start_block, dire->offset, ino); - inode = (msblk->iget)(i->i_sb, ino); + inode = squashfs_iget(i->i_sb, ino, inode_number); goto exit_loop; } @@ -730,6 +728,7 @@ static struct dentry *squashfs_lookup_2( } exit_loop: + kfree(dire); d_add(dentry, inode); return ERR_PTR(0); @@ -744,7 +743,7 @@ int squashfs_2_0_supported(struct squash { struct squashfs_super_block *sblk = &msblk->sblk; - msblk->iget = squashfs_iget_2; + msblk->read_inode = squashfs_read_inode_2; msblk->read_fragment_index_table = read_fragment_index_table_2; sblk->bytes_used = sblk->bytes_used_2; diff -urp linux-2.6.18.x86_64.orig/fs/squashfs/squashfs.h linux-2.6.18.x86_64/fs/squashfs/squashfs.h --- linux-2.6.18.x86_64.orig/fs/squashfs/squashfs.h 2006-12-13 13:42:35.000000000 -0500 +++ linux-2.6.18.x86_64/fs/squashfs/squashfs.h 2006-12-13 13:43:43.000000000 -0500 @@ -31,7 +31,7 @@ #define TRACE(s, args...) {} #endif -#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args) +#define ERROR(s, args...) printk(KERN_NOTICE "SQUASHFS error: "s, ## args) #define SERROR(s, args...) do { \ if (!silent) \ @@ -49,7 +49,7 @@ static inline struct squashfs_inode_info #define SQSH_EXTERN extern unsigned int squashfs_read_data(struct super_block *s, char *buffer, long long index, unsigned int length, - long long *next_index); + long long *next_index, int srclength); extern int squashfs_get_cached_block(struct super_block *s, char *buffer, long long block, unsigned int offset, int length, long long *next_block, @@ -59,6 +59,7 @@ extern void release_cached_fragment(stru extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block *s, long long start_block, int length); +extern struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number); extern struct address_space_operations squashfs_symlink_aops; extern struct address_space_operations squashfs_aops; extern struct address_space_operations squashfs_aops_4K; diff -urp linux-2.6.18.x86_64.orig/include/linux/squashfs_fs.h linux-2.6.18.x86_64/include/linux/squashfs_fs.h --- linux-2.6.18.x86_64.orig/include/linux/squashfs_fs.h 2006-12-13 13:42:37.000000000 -0500 +++ linux-2.6.18.x86_64/include/linux/squashfs_fs.h 2006-12-13 13:43:19.000000000 -0500 @@ -35,7 +35,7 @@ #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_CACHED_FRAGMENTS 3 #define SQUASHFS_MAJOR 3 #define SQUASHFS_MINOR 0 #define SQUASHFS_MAGIC 0x73717368 @@ -72,6 +72,7 @@ #define SQUASHFS_NO_FRAG 4 #define SQUASHFS_ALWAYS_FRAG 5 #define SQUASHFS_DUPLICATE 6 +#define SQUASHFS_EXPORT 7 #define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1) @@ -93,13 +94,16 @@ #define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \ SQUASHFS_DUPLICATE) +#define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_EXPORT) + #define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \ SQUASHFS_CHECK) #define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \ - duplicate_checking) (noi | (nod << 1) | (check_data << 2) \ + duplicate_checking, exortable) (noi | (nod << 1) | (check_data << 2) \ | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \ - (duplicate_checking << 6)) + (duplicate_checking << 6) | (exportable << 7)) /* Max number of types and file types */ #define SQUASHFS_DIR_TYPE 1 @@ -153,7 +157,7 @@ #define SQUASHFS_MODE(a) ((a) & 0xfff) /* fragment and fragment table defines */ -#define SQUASHFS_FRAGMENT_BYTES(A) (A * sizeof(struct squashfs_fragment_entry)) +#define SQUASHFS_FRAGMENT_BYTES(A) ((A) * sizeof(struct squashfs_fragment_entry)) #define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \ SQUASHFS_METADATA_SIZE) @@ -168,6 +172,22 @@ #define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\ sizeof(long long)) +/* inode lookup table defines */ +#define SQUASHFS_LOOKUP_BYTES(A) ((A) * sizeof(squashfs_inode_t)) + +#define SQUASHFS_LOOKUP_BLOCK(A) (SQUASHFS_LOOKUP_BYTES(A) / \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_LOOKUP_BLOCK_OFFSET(A) (SQUASHFS_LOOKUP_BYTES(A) % \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_LOOKUP_BLOCKS(A) ((SQUASHFS_LOOKUP_BYTES(A) + \ + SQUASHFS_METADATA_SIZE - 1) / \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_LOOKUP_BLOCK_BYTES(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\ + sizeof(long long)) + /* cached data constants for filesystem */ #define SQUASHFS_CACHED_BLKS 8 @@ -235,7 +255,7 @@ struct squashfs_super_block { long long inode_table_start; long long directory_table_start; long long fragment_table_start; - long long unused; + long long lookup_table_start; } __attribute__ ((packed)); struct squashfs_dir_index { @@ -342,7 +362,7 @@ struct squashfs_dir_header { struct squashfs_fragment_entry { long long start_block; unsigned int size; - unsigned int unused; + unsigned int pending; } __attribute__ ((packed)); extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen); @@ -391,7 +411,7 @@ extern int squashfs_uncompress_exit(void SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\ SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\ SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\ - SQUASHFS_SWAP((s)->unused, d, 888, 64);\ + SQUASHFS_SWAP((s)->lookup_table_start, d, 888, 64);\ } #define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\ @@ -507,6 +527,8 @@ extern int squashfs_uncompress_exit(void SQUASHFS_SWAP((s)->size, d, 64, 32);\ } +#define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1) + #define SQUASHFS_SWAP_SHORTS(s, d, n) {\ int entry;\ int bit_position;\ @@ -548,6 +570,7 @@ extern int squashfs_uncompress_exit(void } #define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) +#define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) #ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY diff -urp linux-2.6.18.x86_64.orig/include/linux/squashfs_fs_sb.h linux-2.6.18.x86_64/include/linux/squashfs_fs_sb.h --- linux-2.6.18.x86_64.orig/include/linux/squashfs_fs_sb.h 2006-12-13 13:42:36.000000000 -0500 +++ linux-2.6.18.x86_64/include/linux/squashfs_fs_sb.h 2006-12-13 13:43:20.000000000 -0500 @@ -65,7 +65,8 @@ struct squashfs_sb_info { wait_queue_head_t fragment_wait_queue; struct meta_index *meta_index; z_stream stream; - struct inode *(*iget)(struct super_block *s, squashfs_inode_t \ + long long *inode_lookup_table; + int (*read_inode)(struct inode *i, squashfs_inode_t \ inode); long long (*read_blocklist)(struct inode *inode, int \ index, int readahead_blks, char *block_list, \