cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

compress.c (10189B)


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