From e552a596687bf0e1802c744a7bb113afbd2bf4d4 Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Thu, 29 Dec 2011 03:50:20 +0000 Subject: Squashfs: add missing block release on error condition squashfs_read_metadata forgets to release the cache block if an error has occurred. Signed-off-by: Phillip Lougher --- fs/squashfs/cache.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'fs/squashfs') diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c index f744be98cd5..ea6e798e548 100644 --- a/fs/squashfs/cache.c +++ b/fs/squashfs/cache.c @@ -332,17 +332,20 @@ int squashfs_read_metadata(struct super_block *sb, void *buffer, u64 *block, int *offset, int length) { struct squashfs_sb_info *msblk = sb->s_fs_info; - int bytes, copied = length; + int bytes, res = length; struct squashfs_cache_entry *entry; TRACE("Entered squashfs_read_metadata [%llx:%x]\n", *block, *offset); while (length) { entry = squashfs_cache_get(sb, msblk->block_cache, *block, 0); - if (entry->error) - return entry->error; - else if (*offset >= entry->length) - return -EIO; + if (entry->error) { + res = entry->error; + goto error; + } else if (*offset >= entry->length) { + res = -EIO; + goto error; + } bytes = squashfs_copy_data(buffer, entry, *offset, length); if (buffer) @@ -358,7 +361,11 @@ int squashfs_read_metadata(struct super_block *sb, void *buffer, squashfs_cache_put(entry); } - return copied; + return res; + +error: + squashfs_cache_put(entry); + return res; } -- cgit v1.2.3 From d7fbd893388d9e86d29b7cfbd5457bcf03496fbf Mon Sep 17 00:00:00 2001 From: Ajeet Yadav Date: Tue, 27 Dec 2011 15:10:04 +0530 Subject: Squashfs: optimise squashfs_cache_get entry search squashfs_cache_get() iterates over all entries to search for block its looking for. Often get() / put() are called for same block. If we cache the current entry index, then we can optimise the subsequent *_get() calls. Signed-off-by: Ajeet Yadav Signed-off-by: Phillip Lougher --- fs/squashfs/cache.c | 11 ++++++++--- fs/squashfs/squashfs_fs_sb.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'fs/squashfs') diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c index ea6e798e548..af0b7380259 100644 --- a/fs/squashfs/cache.c +++ b/fs/squashfs/cache.c @@ -70,11 +70,15 @@ struct squashfs_cache_entry *squashfs_cache_get(struct super_block *sb, spin_lock(&cache->lock); while (1) { - for (i = 0; i < cache->entries; i++) - if (cache->entry[i].block == block) + for (i = cache->curr_blk, n = 0; n < cache->entries; n++) { + if (cache->entry[i].block == block) { + cache->curr_blk = i; break; + } + i = (i + 1) % cache->entries; + } - if (i == cache->entries) { + if (n == cache->entries) { /* * Block not in cache, if all cache entries are used * go to sleep waiting for one to become available. @@ -245,6 +249,7 @@ struct squashfs_cache *squashfs_cache_init(char *name, int entries, goto cleanup; } + cache->curr_blk = 0; cache->next_blk = 0; cache->unused = entries; cache->entries = entries; diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h index 651f0b31d29..52934a22f29 100644 --- a/fs/squashfs/squashfs_fs_sb.h +++ b/fs/squashfs/squashfs_fs_sb.h @@ -28,6 +28,7 @@ struct squashfs_cache { char *name; int entries; + int curr_blk; int next_blk; int num_waiters; int unused; -- cgit v1.2.3 From cc37f75a9ffbbfcb1c3297534f293c8284e3c5a6 Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Mon, 2 Jan 2012 17:47:14 +0000 Subject: Squashfs: fix mount time sanity check for corrupted superblock A Squashfs filesystem containing nothing but an empty directory, although unusual and ultimately pointless, is still valid. The directory_table >= next_table sanity check rejects these filesystems as invalid because the directory_table is empty and equal to next_table. Signed-off-by: Phillip Lougher --- fs/squashfs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/squashfs') diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 2da1715452a..4619247d74e 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -290,7 +290,7 @@ handle_fragments: check_directory_table: /* Sanity check directory_table */ - if (msblk->directory_table >= next_table) { + if (msblk->directory_table > next_table) { err = -EINVAL; goto failed_mount; } -- cgit v1.2.3 From 3d4a1c80c4eb97187b3a61b3bfa8c804327f7a45 Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Tue, 3 Jan 2012 02:58:13 +0000 Subject: Squashfs: fix i_blocks calculation with extended regular files The le64_to_cpu() forces the calculation to be unsigned, with the effect that it can underflow leading to an incorrect large value. This bug only triggers in rare(ish) circumstances, an empty file encoded as an extended regular file or a completely sparse file. Normally empty files are encoded as a regular file rather than as an extended regular file (and the regular file i_blocks calculation doesn't have this bug). To save space regular file inodes are optimised to encode the most commonly occurring files. Less common regular files are encoded using extended regular file inodes which contain extra information. Empty files with nlinks greater than 1, and or empty files with extended attributes are encoded using extended regular file inodes and they will hit this bug. Signed-off-by: Phillip Lougher --- fs/squashfs/inode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/squashfs') diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c index fd7b3b3bda1..81afbccfa84 100644 --- a/fs/squashfs/inode.c +++ b/fs/squashfs/inode.c @@ -208,8 +208,8 @@ int squashfs_read_inode(struct inode *inode, long long ino) inode->i_op = &squashfs_inode_ops; inode->i_fop = &generic_ro_fops; inode->i_mode |= S_IFREG; - inode->i_blocks = ((inode->i_size - - le64_to_cpu(sqsh_ino->sparse) - 1) >> 9) + 1; + inode->i_blocks = (inode->i_size - + le64_to_cpu(sqsh_ino->sparse) + 511) >> 9; squashfs_i(inode)->fragment_block = frag_blk; squashfs_i(inode)->fragment_size = frag_size; -- cgit v1.2.3