162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* -*- linux-c -*- ------------------------------------------------------- *
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *   Copyright 2001 H. Peter Anvin - All Rights Reserved
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * ----------------------------------------------------------------------- */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci * linux/fs/isofs/compress.c
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Transparent decompression of files on an iso9660 filesystem
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/init.h>
1662306a36Sopenharmony_ci#include <linux/bio.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <linux/slab.h>
1962306a36Sopenharmony_ci#include <linux/vmalloc.h>
2062306a36Sopenharmony_ci#include <linux/zlib.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include "isofs.h"
2362306a36Sopenharmony_ci#include "zisofs.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* This should probably be global. */
2662306a36Sopenharmony_cistatic char zisofs_sink_page[PAGE_SIZE];
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/*
2962306a36Sopenharmony_ci * This contains the zlib memory allocation and the mutex for the
3062306a36Sopenharmony_ci * allocation; this avoids failures at block-decompression time.
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_cistatic void *zisofs_zlib_workspace;
3362306a36Sopenharmony_cistatic DEFINE_MUTEX(zisofs_zlib_lock);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/*
3662306a36Sopenharmony_ci * Read data of @inode from @block_start to @block_end and uncompress
3762306a36Sopenharmony_ci * to one zisofs block. Store the data in the @pages array with @pcount
3862306a36Sopenharmony_ci * entries. Start storing at offset @poffset of the first page.
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_cistatic loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
4162306a36Sopenharmony_ci				      loff_t block_end, int pcount,
4262306a36Sopenharmony_ci				      struct page **pages, unsigned poffset,
4362306a36Sopenharmony_ci				      int *errp)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
4662306a36Sopenharmony_ci	unsigned int bufsize = ISOFS_BUFFER_SIZE(inode);
4762306a36Sopenharmony_ci	unsigned int bufshift = ISOFS_BUFFER_BITS(inode);
4862306a36Sopenharmony_ci	unsigned int bufmask = bufsize - 1;
4962306a36Sopenharmony_ci	int i, block_size = block_end - block_start;
5062306a36Sopenharmony_ci	z_stream stream = { .total_out = 0,
5162306a36Sopenharmony_ci			    .avail_in = 0,
5262306a36Sopenharmony_ci			    .avail_out = 0, };
5362306a36Sopenharmony_ci	int zerr;
5462306a36Sopenharmony_ci	int needblocks = (block_size + (block_start & bufmask) + bufmask)
5562306a36Sopenharmony_ci				>> bufshift;
5662306a36Sopenharmony_ci	int haveblocks;
5762306a36Sopenharmony_ci	blkcnt_t blocknum;
5862306a36Sopenharmony_ci	struct buffer_head **bhs;
5962306a36Sopenharmony_ci	int curbh, curpage;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	if (block_size > deflateBound(1UL << zisofs_block_shift)) {
6262306a36Sopenharmony_ci		*errp = -EIO;
6362306a36Sopenharmony_ci		return 0;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci	/* Empty block? */
6662306a36Sopenharmony_ci	if (block_size == 0) {
6762306a36Sopenharmony_ci		for ( i = 0 ; i < pcount ; i++ ) {
6862306a36Sopenharmony_ci			if (!pages[i])
6962306a36Sopenharmony_ci				continue;
7062306a36Sopenharmony_ci			memzero_page(pages[i], 0, PAGE_SIZE);
7162306a36Sopenharmony_ci			SetPageUptodate(pages[i]);
7262306a36Sopenharmony_ci		}
7362306a36Sopenharmony_ci		return ((loff_t)pcount) << PAGE_SHIFT;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	/* Because zlib is not thread-safe, do all the I/O at the top. */
7762306a36Sopenharmony_ci	blocknum = block_start >> bufshift;
7862306a36Sopenharmony_ci	bhs = kcalloc(needblocks + 1, sizeof(*bhs), GFP_KERNEL);
7962306a36Sopenharmony_ci	if (!bhs) {
8062306a36Sopenharmony_ci		*errp = -ENOMEM;
8162306a36Sopenharmony_ci		return 0;
8262306a36Sopenharmony_ci	}
8362306a36Sopenharmony_ci	haveblocks = isofs_get_blocks(inode, blocknum, bhs, needblocks);
8462306a36Sopenharmony_ci	bh_read_batch(haveblocks, bhs);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	curbh = 0;
8762306a36Sopenharmony_ci	curpage = 0;
8862306a36Sopenharmony_ci	/*
8962306a36Sopenharmony_ci	 * First block is special since it may be fractional.  We also wait for
9062306a36Sopenharmony_ci	 * it before grabbing the zlib mutex; odds are that the subsequent
9162306a36Sopenharmony_ci	 * blocks are going to come in in short order so we don't hold the zlib
9262306a36Sopenharmony_ci	 * mutex longer than necessary.
9362306a36Sopenharmony_ci	 */
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	if (!bhs[0])
9662306a36Sopenharmony_ci		goto b_eio;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	wait_on_buffer(bhs[0]);
9962306a36Sopenharmony_ci	if (!buffer_uptodate(bhs[0])) {
10062306a36Sopenharmony_ci		*errp = -EIO;
10162306a36Sopenharmony_ci		goto b_eio;
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	stream.workspace = zisofs_zlib_workspace;
10562306a36Sopenharmony_ci	mutex_lock(&zisofs_zlib_lock);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	zerr = zlib_inflateInit(&stream);
10862306a36Sopenharmony_ci	if (zerr != Z_OK) {
10962306a36Sopenharmony_ci		if (zerr == Z_MEM_ERROR)
11062306a36Sopenharmony_ci			*errp = -ENOMEM;
11162306a36Sopenharmony_ci		else
11262306a36Sopenharmony_ci			*errp = -EIO;
11362306a36Sopenharmony_ci		printk(KERN_DEBUG "zisofs: zisofs_inflateInit returned %d\n",
11462306a36Sopenharmony_ci			       zerr);
11562306a36Sopenharmony_ci		goto z_eio;
11662306a36Sopenharmony_ci	}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	while (curpage < pcount && curbh < haveblocks &&
11962306a36Sopenharmony_ci	       zerr != Z_STREAM_END) {
12062306a36Sopenharmony_ci		if (!stream.avail_out) {
12162306a36Sopenharmony_ci			if (pages[curpage]) {
12262306a36Sopenharmony_ci				stream.next_out = kmap_local_page(pages[curpage])
12362306a36Sopenharmony_ci						+ poffset;
12462306a36Sopenharmony_ci				stream.avail_out = PAGE_SIZE - poffset;
12562306a36Sopenharmony_ci				poffset = 0;
12662306a36Sopenharmony_ci			} else {
12762306a36Sopenharmony_ci				stream.next_out = (void *)&zisofs_sink_page;
12862306a36Sopenharmony_ci				stream.avail_out = PAGE_SIZE;
12962306a36Sopenharmony_ci			}
13062306a36Sopenharmony_ci		}
13162306a36Sopenharmony_ci		if (!stream.avail_in) {
13262306a36Sopenharmony_ci			wait_on_buffer(bhs[curbh]);
13362306a36Sopenharmony_ci			if (!buffer_uptodate(bhs[curbh])) {
13462306a36Sopenharmony_ci				*errp = -EIO;
13562306a36Sopenharmony_ci				break;
13662306a36Sopenharmony_ci			}
13762306a36Sopenharmony_ci			stream.next_in  = bhs[curbh]->b_data +
13862306a36Sopenharmony_ci						(block_start & bufmask);
13962306a36Sopenharmony_ci			stream.avail_in = min_t(unsigned, bufsize -
14062306a36Sopenharmony_ci						(block_start & bufmask),
14162306a36Sopenharmony_ci						block_size);
14262306a36Sopenharmony_ci			block_size -= stream.avail_in;
14362306a36Sopenharmony_ci			block_start = 0;
14462306a36Sopenharmony_ci		}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci		while (stream.avail_out && stream.avail_in) {
14762306a36Sopenharmony_ci			zerr = zlib_inflate(&stream, Z_SYNC_FLUSH);
14862306a36Sopenharmony_ci			if (zerr == Z_BUF_ERROR && stream.avail_in == 0)
14962306a36Sopenharmony_ci				break;
15062306a36Sopenharmony_ci			if (zerr == Z_STREAM_END)
15162306a36Sopenharmony_ci				break;
15262306a36Sopenharmony_ci			if (zerr != Z_OK) {
15362306a36Sopenharmony_ci				/* EOF, error, or trying to read beyond end of input */
15462306a36Sopenharmony_ci				if (zerr == Z_MEM_ERROR)
15562306a36Sopenharmony_ci					*errp = -ENOMEM;
15662306a36Sopenharmony_ci				else {
15762306a36Sopenharmony_ci					printk(KERN_DEBUG
15862306a36Sopenharmony_ci					       "zisofs: zisofs_inflate returned"
15962306a36Sopenharmony_ci					       " %d, inode = %lu,"
16062306a36Sopenharmony_ci					       " page idx = %d, bh idx = %d,"
16162306a36Sopenharmony_ci					       " avail_in = %ld,"
16262306a36Sopenharmony_ci					       " avail_out = %ld\n",
16362306a36Sopenharmony_ci					       zerr, inode->i_ino, curpage,
16462306a36Sopenharmony_ci					       curbh, stream.avail_in,
16562306a36Sopenharmony_ci					       stream.avail_out);
16662306a36Sopenharmony_ci					*errp = -EIO;
16762306a36Sopenharmony_ci				}
16862306a36Sopenharmony_ci				goto inflate_out;
16962306a36Sopenharmony_ci			}
17062306a36Sopenharmony_ci		}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci		if (!stream.avail_out) {
17362306a36Sopenharmony_ci			/* This page completed */
17462306a36Sopenharmony_ci			if (pages[curpage]) {
17562306a36Sopenharmony_ci				flush_dcache_page(pages[curpage]);
17662306a36Sopenharmony_ci				SetPageUptodate(pages[curpage]);
17762306a36Sopenharmony_ci			}
17862306a36Sopenharmony_ci			if (stream.next_out != (unsigned char *)zisofs_sink_page) {
17962306a36Sopenharmony_ci				kunmap_local(stream.next_out);
18062306a36Sopenharmony_ci				stream.next_out = NULL;
18162306a36Sopenharmony_ci			}
18262306a36Sopenharmony_ci			curpage++;
18362306a36Sopenharmony_ci		}
18462306a36Sopenharmony_ci		if (!stream.avail_in)
18562306a36Sopenharmony_ci			curbh++;
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ciinflate_out:
18862306a36Sopenharmony_ci	zlib_inflateEnd(&stream);
18962306a36Sopenharmony_ci	if (stream.next_out && stream.next_out != (unsigned char *)zisofs_sink_page)
19062306a36Sopenharmony_ci		kunmap_local(stream.next_out);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ciz_eio:
19362306a36Sopenharmony_ci	mutex_unlock(&zisofs_zlib_lock);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cib_eio:
19662306a36Sopenharmony_ci	for (i = 0; i < haveblocks; i++)
19762306a36Sopenharmony_ci		brelse(bhs[i]);
19862306a36Sopenharmony_ci	kfree(bhs);
19962306a36Sopenharmony_ci	return stream.total_out;
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci/*
20362306a36Sopenharmony_ci * Uncompress data so that pages[full_page] is fully uptodate and possibly
20462306a36Sopenharmony_ci * fills in other pages if we have data for them.
20562306a36Sopenharmony_ci */
20662306a36Sopenharmony_cistatic int zisofs_fill_pages(struct inode *inode, int full_page, int pcount,
20762306a36Sopenharmony_ci			     struct page **pages)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	loff_t start_off, end_off;
21062306a36Sopenharmony_ci	loff_t block_start, block_end;
21162306a36Sopenharmony_ci	unsigned int header_size = ISOFS_I(inode)->i_format_parm[0];
21262306a36Sopenharmony_ci	unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
21362306a36Sopenharmony_ci	unsigned int blockptr;
21462306a36Sopenharmony_ci	loff_t poffset = 0;
21562306a36Sopenharmony_ci	blkcnt_t cstart_block, cend_block;
21662306a36Sopenharmony_ci	struct buffer_head *bh;
21762306a36Sopenharmony_ci	unsigned int blkbits = ISOFS_BUFFER_BITS(inode);
21862306a36Sopenharmony_ci	unsigned int blksize = 1 << blkbits;
21962306a36Sopenharmony_ci	int err;
22062306a36Sopenharmony_ci	loff_t ret;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	BUG_ON(!pages[full_page]);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	/*
22562306a36Sopenharmony_ci	 * We want to read at least 'full_page' page. Because we have to
22662306a36Sopenharmony_ci	 * uncompress the whole compression block anyway, fill the surrounding
22762306a36Sopenharmony_ci	 * pages with the data we have anyway...
22862306a36Sopenharmony_ci	 */
22962306a36Sopenharmony_ci	start_off = page_offset(pages[full_page]);
23062306a36Sopenharmony_ci	end_off = min_t(loff_t, start_off + PAGE_SIZE, inode->i_size);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	cstart_block = start_off >> zisofs_block_shift;
23362306a36Sopenharmony_ci	cend_block = (end_off + (1 << zisofs_block_shift) - 1)
23462306a36Sopenharmony_ci			>> zisofs_block_shift;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	WARN_ON(start_off - (full_page << PAGE_SHIFT) !=
23762306a36Sopenharmony_ci		((cstart_block << zisofs_block_shift) & PAGE_MASK));
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	/* Find the pointer to this specific chunk */
24062306a36Sopenharmony_ci	/* Note: we're not using isonum_731() here because the data is known aligned */
24162306a36Sopenharmony_ci	/* Note: header_size is in 32-bit words (4 bytes) */
24262306a36Sopenharmony_ci	blockptr = (header_size + cstart_block) << 2;
24362306a36Sopenharmony_ci	bh = isofs_bread(inode, blockptr >> blkbits);
24462306a36Sopenharmony_ci	if (!bh)
24562306a36Sopenharmony_ci		return -EIO;
24662306a36Sopenharmony_ci	block_start = le32_to_cpu(*(__le32 *)
24762306a36Sopenharmony_ci				(bh->b_data + (blockptr & (blksize - 1))));
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	while (cstart_block < cend_block && pcount > 0) {
25062306a36Sopenharmony_ci		/* Load end of the compressed block in the file */
25162306a36Sopenharmony_ci		blockptr += 4;
25262306a36Sopenharmony_ci		/* Traversed to next block? */
25362306a36Sopenharmony_ci		if (!(blockptr & (blksize - 1))) {
25462306a36Sopenharmony_ci			brelse(bh);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci			bh = isofs_bread(inode, blockptr >> blkbits);
25762306a36Sopenharmony_ci			if (!bh)
25862306a36Sopenharmony_ci				return -EIO;
25962306a36Sopenharmony_ci		}
26062306a36Sopenharmony_ci		block_end = le32_to_cpu(*(__le32 *)
26162306a36Sopenharmony_ci				(bh->b_data + (blockptr & (blksize - 1))));
26262306a36Sopenharmony_ci		if (block_start > block_end) {
26362306a36Sopenharmony_ci			brelse(bh);
26462306a36Sopenharmony_ci			return -EIO;
26562306a36Sopenharmony_ci		}
26662306a36Sopenharmony_ci		err = 0;
26762306a36Sopenharmony_ci		ret = zisofs_uncompress_block(inode, block_start, block_end,
26862306a36Sopenharmony_ci					      pcount, pages, poffset, &err);
26962306a36Sopenharmony_ci		poffset += ret;
27062306a36Sopenharmony_ci		pages += poffset >> PAGE_SHIFT;
27162306a36Sopenharmony_ci		pcount -= poffset >> PAGE_SHIFT;
27262306a36Sopenharmony_ci		full_page -= poffset >> PAGE_SHIFT;
27362306a36Sopenharmony_ci		poffset &= ~PAGE_MASK;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci		if (err) {
27662306a36Sopenharmony_ci			brelse(bh);
27762306a36Sopenharmony_ci			/*
27862306a36Sopenharmony_ci			 * Did we finish reading the page we really wanted
27962306a36Sopenharmony_ci			 * to read?
28062306a36Sopenharmony_ci			 */
28162306a36Sopenharmony_ci			if (full_page < 0)
28262306a36Sopenharmony_ci				return 0;
28362306a36Sopenharmony_ci			return err;
28462306a36Sopenharmony_ci		}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci		block_start = block_end;
28762306a36Sopenharmony_ci		cstart_block++;
28862306a36Sopenharmony_ci	}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	if (poffset && *pages) {
29162306a36Sopenharmony_ci		memzero_page(*pages, poffset, PAGE_SIZE - poffset);
29262306a36Sopenharmony_ci		SetPageUptodate(*pages);
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci	return 0;
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci/*
29862306a36Sopenharmony_ci * When decompressing, we typically obtain more than one page
29962306a36Sopenharmony_ci * per reference.  We inject the additional pages into the page
30062306a36Sopenharmony_ci * cache as a form of readahead.
30162306a36Sopenharmony_ci */
30262306a36Sopenharmony_cistatic int zisofs_read_folio(struct file *file, struct folio *folio)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	struct page *page = &folio->page;
30562306a36Sopenharmony_ci	struct inode *inode = file_inode(file);
30662306a36Sopenharmony_ci	struct address_space *mapping = inode->i_mapping;
30762306a36Sopenharmony_ci	int err;
30862306a36Sopenharmony_ci	int i, pcount, full_page;
30962306a36Sopenharmony_ci	unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
31062306a36Sopenharmony_ci	unsigned int zisofs_pages_per_cblock =
31162306a36Sopenharmony_ci		PAGE_SHIFT <= zisofs_block_shift ?
31262306a36Sopenharmony_ci		(1 << (zisofs_block_shift - PAGE_SHIFT)) : 0;
31362306a36Sopenharmony_ci	struct page **pages;
31462306a36Sopenharmony_ci	pgoff_t index = page->index, end_index;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	end_index = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
31762306a36Sopenharmony_ci	/*
31862306a36Sopenharmony_ci	 * If this page is wholly outside i_size we just return zero;
31962306a36Sopenharmony_ci	 * do_generic_file_read() will handle this for us
32062306a36Sopenharmony_ci	 */
32162306a36Sopenharmony_ci	if (index >= end_index) {
32262306a36Sopenharmony_ci		SetPageUptodate(page);
32362306a36Sopenharmony_ci		unlock_page(page);
32462306a36Sopenharmony_ci		return 0;
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	if (PAGE_SHIFT <= zisofs_block_shift) {
32862306a36Sopenharmony_ci		/* We have already been given one page, this is the one
32962306a36Sopenharmony_ci		   we must do. */
33062306a36Sopenharmony_ci		full_page = index & (zisofs_pages_per_cblock - 1);
33162306a36Sopenharmony_ci		pcount = min_t(int, zisofs_pages_per_cblock,
33262306a36Sopenharmony_ci			end_index - (index & ~(zisofs_pages_per_cblock - 1)));
33362306a36Sopenharmony_ci		index -= full_page;
33462306a36Sopenharmony_ci	} else {
33562306a36Sopenharmony_ci		full_page = 0;
33662306a36Sopenharmony_ci		pcount = 1;
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci	pages = kcalloc(max_t(unsigned int, zisofs_pages_per_cblock, 1),
33962306a36Sopenharmony_ci					sizeof(*pages), GFP_KERNEL);
34062306a36Sopenharmony_ci	if (!pages) {
34162306a36Sopenharmony_ci		unlock_page(page);
34262306a36Sopenharmony_ci		return -ENOMEM;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci	pages[full_page] = page;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	for (i = 0; i < pcount; i++, index++) {
34762306a36Sopenharmony_ci		if (i != full_page)
34862306a36Sopenharmony_ci			pages[i] = grab_cache_page_nowait(mapping, index);
34962306a36Sopenharmony_ci		if (pages[i])
35062306a36Sopenharmony_ci			ClearPageError(pages[i]);
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	err = zisofs_fill_pages(inode, full_page, pcount, pages);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	/* Release any residual pages, do not SetPageUptodate */
35662306a36Sopenharmony_ci	for (i = 0; i < pcount; i++) {
35762306a36Sopenharmony_ci		if (pages[i]) {
35862306a36Sopenharmony_ci			flush_dcache_page(pages[i]);
35962306a36Sopenharmony_ci			if (i == full_page && err)
36062306a36Sopenharmony_ci				SetPageError(pages[i]);
36162306a36Sopenharmony_ci			unlock_page(pages[i]);
36262306a36Sopenharmony_ci			if (i != full_page)
36362306a36Sopenharmony_ci				put_page(pages[i]);
36462306a36Sopenharmony_ci		}
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	/* At this point, err contains 0 or -EIO depending on the "critical" page */
36862306a36Sopenharmony_ci	kfree(pages);
36962306a36Sopenharmony_ci	return err;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ciconst struct address_space_operations zisofs_aops = {
37362306a36Sopenharmony_ci	.read_folio = zisofs_read_folio,
37462306a36Sopenharmony_ci	/* No bmap operation supported */
37562306a36Sopenharmony_ci};
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ciint __init zisofs_init(void)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	zisofs_zlib_workspace = vmalloc(zlib_inflate_workspacesize());
38062306a36Sopenharmony_ci	if ( !zisofs_zlib_workspace )
38162306a36Sopenharmony_ci		return -ENOMEM;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	return 0;
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_civoid zisofs_cleanup(void)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	vfree(zisofs_zlib_workspace);
38962306a36Sopenharmony_ci}
390