@@ -43,6 +43,7 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
int *errp)
{
unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
+ unsigned long zisofs_block_size = 1UL << zisofs_block_shift;
unsigned int bufsize = ISOFS_BUFFER_SIZE(inode);
unsigned int bufshift = ISOFS_BUFFER_BITS(inode);
unsigned int bufmask = bufsize - 1;
@@ -57,21 +58,39 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
blkcnt_t blocknum;
struct buffer_head **bhs;
int curbh, curpage;
+ loff_t zeros_count = 0;
+ unsigned int zeros_chunk;
- if (block_size > deflateBound(1UL << zisofs_block_shift)) {
+ if (block_size > deflateBound(zisofs_block_size)) {
*errp = -EIO;
return 0;
}
/* Empty block? */
if (block_size == 0) {
+ /*
+ * If poffset is > 0 take care to fill only a part of pages[0].
+ * This is supposed to happen only if
+ * zisofs_block_size < PAGE_SIZE
+ * pcount is then supposed to be 1, but better enforce the
+ * loop end after the first pass.
+ */
for ( i = 0 ; i < pcount ; i++ ) {
- if (!pages[i])
- continue;
- memset(page_address(pages[i]), 0, PAGE_SIZE);
- flush_dcache_page(pages[i]);
- SetPageUptodate(pages[i]);
+ zeros_chunk = min_t(unsigned long, PAGE_SIZE - poffset,
+ zisofs_block_size);
+ zeros_count += zeros_chunk;
+ if (pages[i]) {
+ memset(page_address(pages[i]) + poffset, 0,
+ zeros_chunk);
+ if (poffset + zeros_chunk >= PAGE_SIZE) {
+ flush_dcache_page(pages[i]);
+ SetPageUptodate(pages[i]);
+ }
+ }
+ poffset = 0;
+ if (zisofs_block_size < PAGE_SIZE)
+ break;
}
- return ((loff_t)pcount) << PAGE_SHIFT;
+ return zeros_count;
}
/* Because zlib is not thread-safe, do all the I/O at the top. */