cramfs: propagate uncompression errors
David VomLehn [Thu, 2 Apr 2009 23:59:15 +0000 (16:59 -0700)]
Decompression errors can arise due to corruption of compressed blocks on
flash or in memory.  This patch propagates errors detected during
decompression back to the block layer.

Signed-off-by: David VomLehn <dvomlehn@cisco.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

fs/cramfs/inode.c
fs/cramfs/uncompress.c

index a07338d..46e5298 100644 (file)
@@ -459,11 +459,14 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s
 static int cramfs_readpage(struct file *file, struct page * page)
 {
        struct inode *inode = page->mapping->host;
-       u32 maxblock, bytes_filled;
+       u32 maxblock;
+       int bytes_filled;
        void *pgdata;
 
        maxblock = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
        bytes_filled = 0;
+       pgdata = kmap(page);
+
        if (page->index < maxblock) {
                struct super_block *sb = inode->i_sb;
                u32 blkptr_offset = OFFSET(inode) + page->index*4;
@@ -472,30 +475,43 @@ static int cramfs_readpage(struct file *file, struct page * page)
                start_offset = OFFSET(inode) + maxblock*4;
                mutex_lock(&read_mutex);
                if (page->index)
-                       start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4, 4);
-               compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4) - start_offset);
+                       start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4,
+                               4);
+               compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4) -
+                       start_offset);
                mutex_unlock(&read_mutex);
-               pgdata = kmap(page);
+
                if (compr_len == 0)
                        ; /* hole */
-               else if (compr_len > (PAGE_CACHE_SIZE << 1))
-                       printk(KERN_ERR "cramfs: bad compressed blocksize %u\n", compr_len);
-               else {
+               else if (unlikely(compr_len > (PAGE_CACHE_SIZE << 1))) {
+                       pr_err("cramfs: bad compressed blocksize %u\n",
+                               compr_len);
+                       goto err;
+               } else {
                        mutex_lock(&read_mutex);
                        bytes_filled = cramfs_uncompress_block(pgdata,
                                 PAGE_CACHE_SIZE,
                                 cramfs_read(sb, start_offset, compr_len),
                                 compr_len);
                        mutex_unlock(&read_mutex);
+                       if (unlikely(bytes_filled < 0))
+                               goto err;
                }
-       } else
-               pgdata = kmap(page);
+       }
+
        memset(pgdata + bytes_filled, 0, PAGE_CACHE_SIZE - bytes_filled);
-       kunmap(page);
        flush_dcache_page(page);
+       kunmap(page);
        SetPageUptodate(page);
        unlock_page(page);
        return 0;
+
+err:
+       kunmap(page);
+       ClearPageUptodate(page);
+       SetPageError(page);
+       unlock_page(page);
+       return 0;
 }
 
 static const struct address_space_operations cramfs_aops = {
index fc3ccb7..0233298 100644 (file)
@@ -50,7 +50,7 @@ int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen)
 err:
        printk("Error %d while decompressing!\n", err);
        printk("%p(%d)->%p(%d)\n", src, srclen, dst, dstlen);
-       return 0;
+       return -EIO;
 }
 
 int cramfs_uncompress_init(void)