X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fsquashfs%2Finode.c;h=ccbaeb6bf94ed11007705e5e1dcd5714c4544fa7;hb=c469b50b11a8eaa1dc314687c2b6030c8fdea5b7;hp=9e8ae2607029f5ba4adc4ffbb2c2ad1d58bbe59d;hpb=67da514125f23d27bd45d41e330ef14b6206fe69;p=linux-2.6.git diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c index 9e8ae2607..ccbaeb6bf 100644 --- a/fs/squashfs/inode.c +++ b/fs/squashfs/inode.c @@ -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 int 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_table[] = { 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 }; @@ -195,8 +209,8 @@ SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer, 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 (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; @@ -208,8 +222,8 @@ SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer, } ll_rw_block(READ, b, bh); } else { - if (index < 0 || (index + 2) > sblk->bytes_used) - goto read_failure; + if (index < 0 || (index + 2) > sblk->bytes_used) + goto read_failure; if (!(bh[0] = get_block_length(s, &cur_index, &offset, &c_byte))) @@ -223,8 +237,8 @@ SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer, 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; + 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))) @@ -259,14 +273,17 @@ SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer, msblk->stream.next_in = c_buffer; msblk->stream.avail_in = c_byte; msblk->stream.next_out = buffer; + //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; @@ -346,20 +363,18 @@ SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer, msblk->block_cache[i].block = SQUASHFS_USED_BLK; up(&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); - - 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; - } + 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; + } down(&msblk->block_cache_mutex); wake_up(&msblk->waitq); @@ -373,11 +388,12 @@ SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer, continue; } - bytes = msblk->block_cache[i].length - offset; + bytes = msblk->block_cache[i].length - offset; - if (bytes < 1) - goto out; - else if (bytes >= length) { + 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); @@ -462,7 +478,7 @@ SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_blo { int i, n; struct squashfs_sb_info *msblk = s->s_fs_info; - struct squashfs_super_block *sblk = &msblk->sblk; + struct squashfs_super_block *sblk = &msblk->sblk; while ( 1 ) { down(&msblk->fragment_mutex); @@ -508,8 +524,7 @@ SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_blo if (!(msblk->fragment[i].length = squashfs_read_data(s, msblk->fragment[i].data, - start_block, length, NULL, - sblk->block_size))) { + start_block, length, NULL, sblk->block_size))) { ERROR("Unable to read fragment cache block " "[%llx]\n", start_block); msblk->fragment[i].locked = 0; @@ -538,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); - - 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]; + long long start = msblk->inode_lookup_table[SQUASHFS_LOOKUP_BLOCK(ino - 1)]; + int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino - 1); + squashfs_inode_t inode; + + 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) + @@ -576,7 +663,7 @@ static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode 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, @@ -591,6 +678,8 @@ static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode &next_offset)) goto failed_read; + squashfs_new_inode(msblk, i, inodeb); + switch(inodeb->inode_type) { case SQUASHFS_FILE_TYPE: { unsigned int frag_size; @@ -618,9 +707,6 @@ static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode 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; @@ -670,9 +756,6 @@ static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode 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; @@ -714,9 +797,6 @@ static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode &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; @@ -752,9 +832,6 @@ static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode &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; @@ -796,9 +873,6 @@ static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode &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; @@ -832,9 +906,6 @@ static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode &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 : @@ -866,9 +937,6 @@ static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode &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; @@ -881,14 +949,50 @@ static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode 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; } @@ -898,13 +1002,12 @@ static int read_fragment_index_table(struct super_block *s) struct squashfs_super_block *sblk = &msblk->sblk; unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments); - if (length == 0) + 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; } @@ -919,8 +1022,7 @@ static int read_fragment_index_table(struct super_block *s) 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; @@ -935,7 +1037,7 @@ static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int sil { 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; @@ -1005,8 +1107,7 @@ static int squashfs_fill_super(struct super_block *s, void *data, int silent) 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, - sizeof(struct squashfs_super_block))) { + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, sizeof(struct squashfs_super_block))) { SERROR("unable to read superblock\n"); goto failed_mount; } @@ -1034,14 +1135,14 @@ static int squashfs_fill_super(struct super_block *s, void *data, int silent) 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 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; + /* 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", @@ -1068,7 +1169,7 @@ static int squashfs_fill_super(struct super_block *s, void *data, int silent) 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) * @@ -1112,9 +1213,7 @@ static int squashfs_fill_super(struct super_block *s, void *data, int silent) if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start, ((sblk->no_uids + sblk->no_guids) * sizeof(unsigned int)) | - SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, - (sblk->no_uids + sblk->no_guids) * - sizeof(unsigned int))) { + 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; } @@ -1125,9 +1224,7 @@ static int squashfs_fill_super(struct super_block *s, void *data, int silent) 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, - (sblk->no_uids + sblk->no_guids) * - sizeof(unsigned int))) { + 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; } @@ -1150,13 +1247,25 @@ static int squashfs_fill_super(struct super_block *s, void *data, int silent) 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"); @@ -1168,6 +1277,7 @@ allocate_root: return 0; failed_mount: + kfree(msblk->inode_lookup_table); kfree(msblk->fragment_index); kfree(msblk->fragment); kfree(msblk->uid); @@ -1185,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"); @@ -1413,6 +1523,8 @@ static int get_meta_index(struct inode *inode, int index, 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]; @@ -1553,8 +1665,7 @@ static int squashfs_readpage(struct file *file, struct page *page) down(&msblk->read_page_mutex); if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page, - block, bsize, NULL, - msblk->read_size))) { + block, bsize, NULL, sblk->block_size))) { ERROR("Unable to read page, block %llx, size %x\n", block, bsize); up(&msblk->read_page_mutex); @@ -1583,36 +1694,31 @@ static int squashfs_readpage(struct file *file, struct page *page) 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 if ((push_page = - grab_cache_page_nowait(page->mapping, i))) { - pageaddr = kmap_atomic(push_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(push_page); - SetPageUptodate(push_page); - unlock_page(push_page); + push_page = (i == page->index) ? page : + grab_cache_page_nowait(page->mapping, i); + + 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 @@ -1668,10 +1774,12 @@ static int squashfs_readpage4K(struct file *file, struct page *page) 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, msblk->read_size); + bsize, NULL, sblk->block_size); if (bytes) { pageaddr = kmap_atomic(page, KM_USER0); memcpy(pageaddr, msblk->read_page, bytes); @@ -1956,6 +2064,7 @@ finish: failed_read: ERROR("Unable to read directory block [%llx:%x]\n", next_block, next_offset); + kfree(dire); return 0; } @@ -1980,11 +2089,11 @@ static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry, 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, @@ -2042,35 +2151,35 @@ static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry, 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; } @@ -2103,10 +2212,12 @@ static void squashfs_put_super(struct super_block *s) } -static int 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); } @@ -2116,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))) @@ -2177,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 "); MODULE_LICENSE("GPL");