a94da204fded9 (Thomas Gleixner 2019-05-24 12:04:02 +0200 1) // SPDX-License-Identifier: GPL-2.0-or-later
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2) /* -*- linux-c -*- ------------------------------------------------------- *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 3) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 4) * Copyright 2001 H. Peter Anvin - All Rights Reserved
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 5) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 6) * ----------------------------------------------------------------------- */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 7)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 8) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 9) * linux/fs/isofs/compress.c
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 10) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 11) * Transparent decompression of files on an iso9660 filesystem
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 12) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 13)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 14) #include <linux/module.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 15) #include <linux/init.h>
2f8b544477e62 (Christoph Hellwig 2016-11-01 07:40:13 -0600 16) #include <linux/bio.h>
94f2f715771d0 (Al Viro 2005-04-25 18:32:12 -0700 17)
5ac7c2fd6e710 (Kyle Spiers 2018-04-10 17:02:29 -0700 18) #include <linux/slab.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 19) #include <linux/vmalloc.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 20) #include <linux/zlib.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 21)
94f2f715771d0 (Al Viro 2005-04-25 18:32:12 -0700 22) #include "isofs.h"
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 23) #include "zisofs.h"
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 24)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 25) /* This should probably be global. */
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 26) static char zisofs_sink_page[PAGE_SIZE];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 27)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 28) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 29) * This contains the zlib memory allocation and the mutex for the
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 30) * allocation; this avoids failures at block-decompression time.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 31) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 32) static void *zisofs_zlib_workspace;
a36a151e79be1 (Dave Young 2007-10-16 23:26:10 -0700 33) static DEFINE_MUTEX(zisofs_zlib_lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 34)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 35) /*
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 36) * Read data of @inode from @block_start to @block_end and uncompress
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 37) * to one zisofs block. Store the data in the @pages array with @pcount
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 38) * entries. Start storing at offset @poffset of the first page.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 39) */
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 40) static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 41) loff_t block_end, int pcount,
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 42) struct page **pages, unsigned poffset,
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 43) int *errp)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 44) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 45) unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 46) unsigned int bufsize = ISOFS_BUFFER_SIZE(inode);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 47) unsigned int bufshift = ISOFS_BUFFER_BITS(inode);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 48) unsigned int bufmask = bufsize - 1;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 49) int i, block_size = block_end - block_start;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 50) z_stream stream = { .total_out = 0,
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 51) .avail_in = 0,
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 52) .avail_out = 0, };
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 53) int zerr;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 54) int needblocks = (block_size + (block_start & bufmask) + bufmask)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 55) >> bufshift;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 56) int haveblocks;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 57) blkcnt_t blocknum;
5ac7c2fd6e710 (Kyle Spiers 2018-04-10 17:02:29 -0700 58) struct buffer_head **bhs;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 59) int curbh, curpage;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 60)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 61) if (block_size > deflateBound(1UL << zisofs_block_shift)) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 62) *errp = -EIO;
08ca0db8aa2db (Dave Young 2008-03-19 17:01:01 -0700 63) return 0;
08ca0db8aa2db (Dave Young 2008-03-19 17:01:01 -0700 64) }
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 65) /* Empty block? */
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 66) if (block_size == 0) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 67) for ( i = 0 ; i < pcount ; i++ ) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 68) if (!pages[i])
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 69) continue;
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 70) memset(page_address(pages[i]), 0, PAGE_SIZE);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 71) flush_dcache_page(pages[i]);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 72) SetPageUptodate(pages[i]);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 73) }
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 74) return ((loff_t)pcount) << PAGE_SHIFT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 75) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 76)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 77) /* Because zlib is not thread-safe, do all the I/O at the top. */
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 78) blocknum = block_start >> bufshift;
5ac7c2fd6e710 (Kyle Spiers 2018-04-10 17:02:29 -0700 79) bhs = kcalloc(needblocks + 1, sizeof(*bhs), GFP_KERNEL);
5ac7c2fd6e710 (Kyle Spiers 2018-04-10 17:02:29 -0700 80) if (!bhs) {
5ac7c2fd6e710 (Kyle Spiers 2018-04-10 17:02:29 -0700 81) *errp = -ENOMEM;
5ac7c2fd6e710 (Kyle Spiers 2018-04-10 17:02:29 -0700 82) return 0;
5ac7c2fd6e710 (Kyle Spiers 2018-04-10 17:02:29 -0700 83) }
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 84) haveblocks = isofs_get_blocks(inode, blocknum, bhs, needblocks);
dfec8a14fc904 (Mike Christie 2016-06-05 14:31:44 -0500 85) ll_rw_block(REQ_OP_READ, 0, haveblocks, bhs);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 86)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 87) curbh = 0;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 88) curpage = 0;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 89) /*
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 90) * First block is special since it may be fractional. We also wait for
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 91) * it before grabbing the zlib mutex; odds are that the subsequent
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 92) * blocks are going to come in in short order so we don't hold the zlib
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 93) * mutex longer than necessary.
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 94) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 95)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 96) if (!bhs[0])
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 97) goto b_eio;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 98)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 99) wait_on_buffer(bhs[0]);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 100) if (!buffer_uptodate(bhs[0])) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 101) *errp = -EIO;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 102) goto b_eio;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 103) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 104)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 105) stream.workspace = zisofs_zlib_workspace;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 106) mutex_lock(&zisofs_zlib_lock);
fab5a60a29f98 (Linus Torvalds 2005-08-06 09:42:06 -0700 107)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 108) zerr = zlib_inflateInit(&stream);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 109) if (zerr != Z_OK) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 110) if (zerr == Z_MEM_ERROR)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 111) *errp = -ENOMEM;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 112) else
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 113) *errp = -EIO;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 114) printk(KERN_DEBUG "zisofs: zisofs_inflateInit returned %d\n",
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 115) zerr);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 116) goto z_eio;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 117) }
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 118)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 119) while (curpage < pcount && curbh < haveblocks &&
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 120) zerr != Z_STREAM_END) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 121) if (!stream.avail_out) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 122) if (pages[curpage]) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 123) stream.next_out = page_address(pages[curpage])
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 124) + poffset;
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 125) stream.avail_out = PAGE_SIZE - poffset;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 126) poffset = 0;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 127) } else {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 128) stream.next_out = (void *)&zisofs_sink_page;
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 129) stream.avail_out = PAGE_SIZE;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 130) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 131) }
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 132) if (!stream.avail_in) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 133) wait_on_buffer(bhs[curbh]);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 134) if (!buffer_uptodate(bhs[curbh])) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 135) *errp = -EIO;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 136) break;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 137) }
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 138) stream.next_in = bhs[curbh]->b_data +
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 139) (block_start & bufmask);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 140) stream.avail_in = min_t(unsigned, bufsize -
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 141) (block_start & bufmask),
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 142) block_size);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 143) block_size -= stream.avail_in;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 144) block_start = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 145) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 146)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 147) while (stream.avail_out && stream.avail_in) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 148) zerr = zlib_inflate(&stream, Z_SYNC_FLUSH);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 149) if (zerr == Z_BUF_ERROR && stream.avail_in == 0)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 150) break;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 151) if (zerr == Z_STREAM_END)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 152) break;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 153) if (zerr != Z_OK) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 154) /* EOF, error, or trying to read beyond end of input */
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 155) if (zerr == Z_MEM_ERROR)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 156) *errp = -ENOMEM;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 157) else {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 158) printk(KERN_DEBUG
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 159) "zisofs: zisofs_inflate returned"
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 160) " %d, inode = %lu,"
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 161) " page idx = %d, bh idx = %d,"
d97b07c54f34e (Yinghai Lu 2014-08-08 14:23:14 -0700 162) " avail_in = %ld,"
d97b07c54f34e (Yinghai Lu 2014-08-08 14:23:14 -0700 163) " avail_out = %ld\n",
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 164) zerr, inode->i_ino, curpage,
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 165) curbh, stream.avail_in,
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 166) stream.avail_out);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 167) *errp = -EIO;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 168) }
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 169) goto inflate_out;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 170) }
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 171) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 172)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 173) if (!stream.avail_out) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 174) /* This page completed */
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 175) if (pages[curpage]) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 176) flush_dcache_page(pages[curpage]);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 177) SetPageUptodate(pages[curpage]);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 178) }
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 179) curpage++;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 180) }
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 181) if (!stream.avail_in)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 182) curbh++;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 183) }
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 184) inflate_out:
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 185) zlib_inflateEnd(&stream);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 186)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 187) z_eio:
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 188) mutex_unlock(&zisofs_zlib_lock);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 189)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 190) b_eio:
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 191) for (i = 0; i < haveblocks; i++)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 192) brelse(bhs[i]);
5ac7c2fd6e710 (Kyle Spiers 2018-04-10 17:02:29 -0700 193) kfree(bhs);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 194) return stream.total_out;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 195) }
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 196)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 197) /*
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 198) * Uncompress data so that pages[full_page] is fully uptodate and possibly
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 199) * fills in other pages if we have data for them.
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 200) */
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 201) static int zisofs_fill_pages(struct inode *inode, int full_page, int pcount,
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 202) struct page **pages)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 203) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 204) loff_t start_off, end_off;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 205) loff_t block_start, block_end;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 206) unsigned int header_size = ISOFS_I(inode)->i_format_parm[0];
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 207) unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 208) unsigned int blockptr;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 209) loff_t poffset = 0;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 210) blkcnt_t cstart_block, cend_block;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 211) struct buffer_head *bh;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 212) unsigned int blkbits = ISOFS_BUFFER_BITS(inode);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 213) unsigned int blksize = 1 << blkbits;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 214) int err;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 215) loff_t ret;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 216)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 217) BUG_ON(!pages[full_page]);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 218)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 219) /*
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 220) * We want to read at least 'full_page' page. Because we have to
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 221) * uncompress the whole compression block anyway, fill the surrounding
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 222) * pages with the data we have anyway...
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 223) */
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 224) start_off = page_offset(pages[full_page]);
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 225) end_off = min_t(loff_t, start_off + PAGE_SIZE, inode->i_size);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 226)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 227) cstart_block = start_off >> zisofs_block_shift;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 228) cend_block = (end_off + (1 << zisofs_block_shift) - 1)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 229) >> zisofs_block_shift;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 230)
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 231) WARN_ON(start_off - (full_page << PAGE_SHIFT) !=
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 232) ((cstart_block << zisofs_block_shift) & PAGE_MASK));
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 233)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 234) /* Find the pointer to this specific chunk */
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 235) /* Note: we're not using isonum_731() here because the data is known aligned */
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 236) /* Note: header_size is in 32-bit words (4 bytes) */
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 237) blockptr = (header_size + cstart_block) << 2;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 238) bh = isofs_bread(inode, blockptr >> blkbits);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 239) if (!bh)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 240) return -EIO;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 241) block_start = le32_to_cpu(*(__le32 *)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 242) (bh->b_data + (blockptr & (blksize - 1))));
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 243)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 244) while (cstart_block < cend_block && pcount > 0) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 245) /* Load end of the compressed block in the file */
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 246) blockptr += 4;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 247) /* Traversed to next block? */
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 248) if (!(blockptr & (blksize - 1))) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 249) brelse(bh);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 250)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 251) bh = isofs_bread(inode, blockptr >> blkbits);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 252) if (!bh)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 253) return -EIO;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 254) }
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 255) block_end = le32_to_cpu(*(__le32 *)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 256) (bh->b_data + (blockptr & (blksize - 1))));
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 257) if (block_start > block_end) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 258) brelse(bh);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 259) return -EIO;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 260) }
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 261) err = 0;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 262) ret = zisofs_uncompress_block(inode, block_start, block_end,
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 263) pcount, pages, poffset, &err);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 264) poffset += ret;
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 265) pages += poffset >> PAGE_SHIFT;
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 266) pcount -= poffset >> PAGE_SHIFT;
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 267) full_page -= poffset >> PAGE_SHIFT;
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 268) poffset &= ~PAGE_MASK;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 269)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 270) if (err) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 271) brelse(bh);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 272) /*
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 273) * Did we finish reading the page we really wanted
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 274) * to read?
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 275) */
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 276) if (full_page < 0)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 277) return 0;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 278) return err;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 279) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 280)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 281) block_start = block_end;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 282) cstart_block++;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 283) }
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 284)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 285) if (poffset && *pages) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 286) memset(page_address(*pages) + poffset, 0,
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 287) PAGE_SIZE - poffset);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 288) flush_dcache_page(*pages);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 289) SetPageUptodate(*pages);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 290) }
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 291) return 0;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 292) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 293)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 294) /*
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 295) * When decompressing, we typically obtain more than one page
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 296) * per reference. We inject the additional pages into the page
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 297) * cache as a form of readahead.
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 298) */
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 299) static int zisofs_readpage(struct file *file, struct page *page)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 300) {
496ad9aa8ef44 (Al Viro 2013-01-23 17:07:38 -0500 301) struct inode *inode = file_inode(file);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 302) struct address_space *mapping = inode->i_mapping;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 303) int err;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 304) int i, pcount, full_page;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 305) unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 306) unsigned int zisofs_pages_per_cblock =
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 307) PAGE_SHIFT <= zisofs_block_shift ?
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 308) (1 << (zisofs_block_shift - PAGE_SHIFT)) : 0;
5ac7c2fd6e710 (Kyle Spiers 2018-04-10 17:02:29 -0700 309) struct page **pages;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 310) pgoff_t index = page->index, end_index;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 311)
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 312) end_index = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 313) /*
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 314) * If this page is wholly outside i_size we just return zero;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 315) * do_generic_file_read() will handle this for us
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 316) */
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 317) if (index >= end_index) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 318) SetPageUptodate(page);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 319) unlock_page(page);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 320) return 0;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 321) }
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 322)
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 323) if (PAGE_SHIFT <= zisofs_block_shift) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 324) /* We have already been given one page, this is the one
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 325) we must do. */
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 326) full_page = index & (zisofs_pages_per_cblock - 1);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 327) pcount = min_t(int, zisofs_pages_per_cblock,
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 328) end_index - (index & ~(zisofs_pages_per_cblock - 1)));
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 329) index -= full_page;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 330) } else {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 331) full_page = 0;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 332) pcount = 1;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 333) }
5ac7c2fd6e710 (Kyle Spiers 2018-04-10 17:02:29 -0700 334) pages = kcalloc(max_t(unsigned int, zisofs_pages_per_cblock, 1),
5ac7c2fd6e710 (Kyle Spiers 2018-04-10 17:02:29 -0700 335) sizeof(*pages), GFP_KERNEL);
5ac7c2fd6e710 (Kyle Spiers 2018-04-10 17:02:29 -0700 336) if (!pages) {
5ac7c2fd6e710 (Kyle Spiers 2018-04-10 17:02:29 -0700 337) unlock_page(page);
5ac7c2fd6e710 (Kyle Spiers 2018-04-10 17:02:29 -0700 338) return -ENOMEM;
5ac7c2fd6e710 (Kyle Spiers 2018-04-10 17:02:29 -0700 339) }
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 340) pages[full_page] = page;
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 341)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 342) for (i = 0; i < pcount; i++, index++) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 343) if (i != full_page)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 344) pages[i] = grab_cache_page_nowait(mapping, index);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 345) if (pages[i]) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 346) ClearPageError(pages[i]);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 347) kmap(pages[i]);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 348) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 349) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 350)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 351) err = zisofs_fill_pages(inode, full_page, pcount, pages);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 352)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 353) /* Release any residual pages, do not SetPageUptodate */
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 354) for (i = 0; i < pcount; i++) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 355) if (pages[i]) {
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 356) flush_dcache_page(pages[i]);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 357) if (i == full_page && err)
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 358) SetPageError(pages[i]);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 359) kunmap(pages[i]);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 360) unlock_page(pages[i]);
59bc055211b8d (Jan Kara 2009-09-23 14:44:56 +0200 361) if (i != full_page)
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 362) put_page(pages[i]);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 363) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 364) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 365)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 366) /* At this point, err contains 0 or -EIO depending on the "critical" page */
5ac7c2fd6e710 (Kyle Spiers 2018-04-10 17:02:29 -0700 367) kfree(pages);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 368) return err;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 369) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 370)
f5e54d6e53a20 (Christoph Hellwig 2006-06-28 04:26:44 -0700 371) const struct address_space_operations zisofs_aops = {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 372) .readpage = zisofs_readpage,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 373) /* No bmap operation supported */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 374) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 375)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 376) int __init zisofs_init(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 377) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 378) zisofs_zlib_workspace = vmalloc(zlib_inflate_workspacesize());
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 379) if ( !zisofs_zlib_workspace )
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 380) return -ENOMEM;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 381)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 382) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 383) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 384)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 385) void zisofs_cleanup(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 386) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 387) vfree(zisofs_zlib_workspace);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 388) }