VisionFive2 Linux kernel

StarFive Tech Linux Kernel for VisionFive (JH7110) boards (mirror)

More than 9999 Commits   32 Branches   54 Tags
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) }