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

hmcdrv_cache.c (6713B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *    SE/HMC Drive (Read) Cache Functions
      4 *
      5 *    Copyright IBM Corp. 2013
      6 *    Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
      7 *
      8 */
      9
     10#define KMSG_COMPONENT "hmcdrv"
     11#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
     12
     13#include <linux/kernel.h>
     14#include <linux/mm.h>
     15#include <linux/jiffies.h>
     16
     17#include "hmcdrv_ftp.h"
     18#include "hmcdrv_cache.h"
     19
     20#define HMCDRV_CACHE_TIMEOUT		30 /* aging timeout in seconds */
     21
     22/**
     23 * struct hmcdrv_cache_entry - file cache (only used on read/dir)
     24 * @id: FTP command ID
     25 * @content: kernel-space buffer, 4k aligned
     26 * @len: size of @content cache (0 if caching disabled)
     27 * @ofs: start of content within file (-1 if no cached content)
     28 * @fname: file name
     29 * @fsize: file size
     30 * @timeout: cache timeout in jiffies
     31 *
     32 * Notice that the first three members (id, fname, fsize) are cached on all
     33 * read/dir requests. But content is cached only under some preconditions.
     34 * Uncached content is signalled by a negative value of @ofs.
     35 */
     36struct hmcdrv_cache_entry {
     37	enum hmcdrv_ftp_cmdid id;
     38	char fname[HMCDRV_FTP_FIDENT_MAX];
     39	size_t fsize;
     40	loff_t ofs;
     41	unsigned long timeout;
     42	void *content;
     43	size_t len;
     44};
     45
     46static int hmcdrv_cache_order; /* cache allocated page order */
     47
     48static struct hmcdrv_cache_entry hmcdrv_cache_file = {
     49	.fsize = SIZE_MAX,
     50	.ofs = -1,
     51	.len = 0,
     52	.fname = {'\0'}
     53};
     54
     55/**
     56 * hmcdrv_cache_get() - looks for file data/content in read cache
     57 * @ftp: pointer to FTP command specification
     58 *
     59 * Return: number of bytes read from cache or a negative number if nothing
     60 * in content cache (for the file/cmd specified in @ftp)
     61 */
     62static ssize_t hmcdrv_cache_get(const struct hmcdrv_ftp_cmdspec *ftp)
     63{
     64	loff_t pos; /* position in cache (signed) */
     65	ssize_t len;
     66
     67	if ((ftp->id != hmcdrv_cache_file.id) ||
     68	    strcmp(hmcdrv_cache_file.fname, ftp->fname))
     69		return -1;
     70
     71	if (ftp->ofs >= hmcdrv_cache_file.fsize) /* EOF ? */
     72		return 0;
     73
     74	if ((hmcdrv_cache_file.ofs < 0) || /* has content? */
     75	    time_after(jiffies, hmcdrv_cache_file.timeout))
     76		return -1;
     77
     78	/* there seems to be cached content - calculate the maximum number
     79	 * of bytes that can be returned (regarding file size and offset)
     80	 */
     81	len = hmcdrv_cache_file.fsize - ftp->ofs;
     82
     83	if (len > ftp->len)
     84		len = ftp->len;
     85
     86	/* check if the requested chunk falls into our cache (which starts
     87	 * at offset 'hmcdrv_cache_file.ofs' in the file of interest)
     88	 */
     89	pos = ftp->ofs - hmcdrv_cache_file.ofs;
     90
     91	if ((pos >= 0) &&
     92	    ((pos + len) <= hmcdrv_cache_file.len)) {
     93
     94		memcpy(ftp->buf,
     95		       hmcdrv_cache_file.content + pos,
     96		       len);
     97		pr_debug("using cached content of '%s', returning %zd/%zd bytes\n",
     98			 hmcdrv_cache_file.fname, len,
     99			 hmcdrv_cache_file.fsize);
    100
    101		return len;
    102	}
    103
    104	return -1;
    105}
    106
    107/**
    108 * hmcdrv_cache_do() - do a HMC drive CD/DVD transfer with cache update
    109 * @ftp: pointer to FTP command specification
    110 * @func: FTP transfer function to be used
    111 *
    112 * Return: number of bytes read/written or a (negative) error code
    113 */
    114static ssize_t hmcdrv_cache_do(const struct hmcdrv_ftp_cmdspec *ftp,
    115			       hmcdrv_cache_ftpfunc func)
    116{
    117	ssize_t len;
    118
    119	/* only cache content if the read/dir cache really exists
    120	 * (hmcdrv_cache_file.len > 0), is large enough to handle the
    121	 * request (hmcdrv_cache_file.len >= ftp->len) and there is a need
    122	 * to do so (ftp->len > 0)
    123	 */
    124	if ((ftp->len > 0) && (hmcdrv_cache_file.len >= ftp->len)) {
    125
    126		/* because the cache is not located at ftp->buf, we have to
    127		 * assemble a new HMC drive FTP cmd specification (pointing
    128		 * to our cache, and using the increased size)
    129		 */
    130		struct hmcdrv_ftp_cmdspec cftp = *ftp; /* make a copy */
    131		cftp.buf = hmcdrv_cache_file.content;  /* and update */
    132		cftp.len = hmcdrv_cache_file.len;      /* buffer data */
    133
    134		len = func(&cftp, &hmcdrv_cache_file.fsize); /* now do */
    135
    136		if (len > 0) {
    137			pr_debug("caching %zd bytes content for '%s'\n",
    138				 len, ftp->fname);
    139
    140			if (len > ftp->len)
    141				len = ftp->len;
    142
    143			hmcdrv_cache_file.ofs = ftp->ofs;
    144			hmcdrv_cache_file.timeout = jiffies +
    145				HMCDRV_CACHE_TIMEOUT * HZ;
    146			memcpy(ftp->buf, hmcdrv_cache_file.content, len);
    147		}
    148	} else {
    149		len = func(ftp, &hmcdrv_cache_file.fsize);
    150		hmcdrv_cache_file.ofs = -1; /* invalidate content */
    151	}
    152
    153	if (len > 0) {
    154		/* cache some file info (FTP command, file name and file
    155		 * size) unconditionally
    156		 */
    157		strlcpy(hmcdrv_cache_file.fname, ftp->fname,
    158			HMCDRV_FTP_FIDENT_MAX);
    159		hmcdrv_cache_file.id = ftp->id;
    160		pr_debug("caching cmd %d, file size %zu for '%s'\n",
    161			 ftp->id, hmcdrv_cache_file.fsize, ftp->fname);
    162	}
    163
    164	return len;
    165}
    166
    167/**
    168 * hmcdrv_cache_cmd() - perform a cached HMC drive CD/DVD transfer
    169 * @ftp: pointer to FTP command specification
    170 * @func: FTP transfer function to be used
    171 *
    172 * Attention: Notice that this function is not reentrant - so the caller
    173 * must ensure exclusive execution.
    174 *
    175 * Return: number of bytes read/written or a (negative) error code
    176 */
    177ssize_t hmcdrv_cache_cmd(const struct hmcdrv_ftp_cmdspec *ftp,
    178			 hmcdrv_cache_ftpfunc func)
    179{
    180	ssize_t len;
    181
    182	if ((ftp->id == HMCDRV_FTP_DIR) || /* read cache */
    183	    (ftp->id == HMCDRV_FTP_NLIST) ||
    184	    (ftp->id == HMCDRV_FTP_GET)) {
    185
    186		len = hmcdrv_cache_get(ftp);
    187
    188		if (len >= 0) /* got it from cache ? */
    189			return len; /* yes */
    190
    191		len = hmcdrv_cache_do(ftp, func);
    192
    193		if (len >= 0)
    194			return len;
    195
    196	} else {
    197		len = func(ftp, NULL); /* simply do original command */
    198	}
    199
    200	/* invalidate the (read) cache in case there was a write operation
    201	 * or an error on read/dir
    202	 */
    203	hmcdrv_cache_file.id = HMCDRV_FTP_NOOP;
    204	hmcdrv_cache_file.fsize = LLONG_MAX;
    205	hmcdrv_cache_file.ofs = -1;
    206
    207	return len;
    208}
    209
    210/**
    211 * hmcdrv_cache_startup() - startup of HMC drive cache
    212 * @cachesize: cache size
    213 *
    214 * Return: 0 on success, else a (negative) error code
    215 */
    216int hmcdrv_cache_startup(size_t cachesize)
    217{
    218	if (cachesize > 0) { /* perform caching ? */
    219		hmcdrv_cache_order = get_order(cachesize);
    220		hmcdrv_cache_file.content =
    221			(void *) __get_free_pages(GFP_KERNEL | GFP_DMA,
    222						  hmcdrv_cache_order);
    223
    224		if (!hmcdrv_cache_file.content) {
    225			pr_err("Allocating the requested cache size of %zu bytes failed\n",
    226			       cachesize);
    227			return -ENOMEM;
    228		}
    229
    230		pr_debug("content cache enabled, size is %zu bytes\n",
    231			 cachesize);
    232	}
    233
    234	hmcdrv_cache_file.len = cachesize;
    235	return 0;
    236}
    237
    238/**
    239 * hmcdrv_cache_shutdown() - shutdown of HMC drive cache
    240 */
    241void hmcdrv_cache_shutdown(void)
    242{
    243	if (hmcdrv_cache_file.content) {
    244		free_pages((unsigned long) hmcdrv_cache_file.content,
    245			   hmcdrv_cache_order);
    246		hmcdrv_cache_file.content = NULL;
    247	}
    248
    249	hmcdrv_cache_file.id = HMCDRV_FTP_NOOP;
    250	hmcdrv_cache_file.fsize = LLONG_MAX;
    251	hmcdrv_cache_file.ofs = -1;
    252	hmcdrv_cache_file.len = 0; /* no cache */
    253}