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

file_direct.c (4237B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2013
      4 * Phillip Lougher <phillip@squashfs.org.uk>
      5 */
      6
      7#include <linux/fs.h>
      8#include <linux/vfs.h>
      9#include <linux/kernel.h>
     10#include <linux/slab.h>
     11#include <linux/string.h>
     12#include <linux/pagemap.h>
     13#include <linux/mutex.h>
     14
     15#include "squashfs_fs.h"
     16#include "squashfs_fs_sb.h"
     17#include "squashfs_fs_i.h"
     18#include "squashfs.h"
     19#include "page_actor.h"
     20
     21static int squashfs_read_cache(struct page *target_page, u64 block, int bsize,
     22	int pages, struct page **page, int bytes);
     23
     24/* Read separately compressed datablock directly into page cache */
     25int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,
     26	int expected)
     27
     28{
     29	struct inode *inode = target_page->mapping->host;
     30	struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
     31
     32	int file_end = (i_size_read(inode) - 1) >> PAGE_SHIFT;
     33	int mask = (1 << (msblk->block_log - PAGE_SHIFT)) - 1;
     34	int start_index = target_page->index & ~mask;
     35	int end_index = start_index | mask;
     36	int i, n, pages, missing_pages, bytes, res = -ENOMEM;
     37	struct page **page;
     38	struct squashfs_page_actor *actor;
     39	void *pageaddr;
     40
     41	if (end_index > file_end)
     42		end_index = file_end;
     43
     44	pages = end_index - start_index + 1;
     45
     46	page = kmalloc_array(pages, sizeof(void *), GFP_KERNEL);
     47	if (page == NULL)
     48		return res;
     49
     50	/*
     51	 * Create a "page actor" which will kmap and kunmap the
     52	 * page cache pages appropriately within the decompressor
     53	 */
     54	actor = squashfs_page_actor_init_special(page, pages, 0);
     55	if (actor == NULL)
     56		goto out;
     57
     58	/* Try to grab all the pages covered by the Squashfs block */
     59	for (missing_pages = 0, i = 0, n = start_index; i < pages; i++, n++) {
     60		page[i] = (n == target_page->index) ? target_page :
     61			grab_cache_page_nowait(target_page->mapping, n);
     62
     63		if (page[i] == NULL) {
     64			missing_pages++;
     65			continue;
     66		}
     67
     68		if (PageUptodate(page[i])) {
     69			unlock_page(page[i]);
     70			put_page(page[i]);
     71			page[i] = NULL;
     72			missing_pages++;
     73		}
     74	}
     75
     76	if (missing_pages) {
     77		/*
     78		 * Couldn't get one or more pages, this page has either
     79		 * been VM reclaimed, but others are still in the page cache
     80		 * and uptodate, or we're racing with another thread in
     81		 * squashfs_readpage also trying to grab them.  Fall back to
     82		 * using an intermediate buffer.
     83		 */
     84		res = squashfs_read_cache(target_page, block, bsize, pages,
     85							page, expected);
     86		if (res < 0)
     87			goto mark_errored;
     88
     89		goto out;
     90	}
     91
     92	/* Decompress directly into the page cache buffers */
     93	res = squashfs_read_data(inode->i_sb, block, bsize, NULL, actor);
     94	if (res < 0)
     95		goto mark_errored;
     96
     97	if (res != expected) {
     98		res = -EIO;
     99		goto mark_errored;
    100	}
    101
    102	/* Last page may have trailing bytes not filled */
    103	bytes = res % PAGE_SIZE;
    104	if (bytes) {
    105		pageaddr = kmap_atomic(page[pages - 1]);
    106		memset(pageaddr + bytes, 0, PAGE_SIZE - bytes);
    107		kunmap_atomic(pageaddr);
    108	}
    109
    110	/* Mark pages as uptodate, unlock and release */
    111	for (i = 0; i < pages; i++) {
    112		flush_dcache_page(page[i]);
    113		SetPageUptodate(page[i]);
    114		unlock_page(page[i]);
    115		if (page[i] != target_page)
    116			put_page(page[i]);
    117	}
    118
    119	kfree(actor);
    120	kfree(page);
    121
    122	return 0;
    123
    124mark_errored:
    125	/* Decompression failed, mark pages as errored.  Target_page is
    126	 * dealt with by the caller
    127	 */
    128	for (i = 0; i < pages; i++) {
    129		if (page[i] == NULL || page[i] == target_page)
    130			continue;
    131		flush_dcache_page(page[i]);
    132		SetPageError(page[i]);
    133		unlock_page(page[i]);
    134		put_page(page[i]);
    135	}
    136
    137out:
    138	kfree(actor);
    139	kfree(page);
    140	return res;
    141}
    142
    143
    144static int squashfs_read_cache(struct page *target_page, u64 block, int bsize,
    145	int pages, struct page **page, int bytes)
    146{
    147	struct inode *i = target_page->mapping->host;
    148	struct squashfs_cache_entry *buffer = squashfs_get_datablock(i->i_sb,
    149						 block, bsize);
    150	int res = buffer->error, n, offset = 0;
    151
    152	if (res) {
    153		ERROR("Unable to read page, block %llx, size %x\n", block,
    154			bsize);
    155		goto out;
    156	}
    157
    158	for (n = 0; n < pages && bytes > 0; n++,
    159			bytes -= PAGE_SIZE, offset += PAGE_SIZE) {
    160		int avail = min_t(int, bytes, PAGE_SIZE);
    161
    162		if (page[n] == NULL)
    163			continue;
    164
    165		squashfs_fill_page(page[n], buffer, offset, avail);
    166		unlock_page(page[n]);
    167		if (page[n] != target_page)
    168			put_page(page[n]);
    169	}
    170
    171out:
    172	squashfs_cache_put(buffer);
    173	return res;
    174}