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

decompressor_multi.c (4577B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *  Copyright (c) 2013
      4 *  Minchan Kim <minchan@kernel.org>
      5 */
      6#include <linux/types.h>
      7#include <linux/mutex.h>
      8#include <linux/slab.h>
      9#include <linux/bio.h>
     10#include <linux/sched.h>
     11#include <linux/wait.h>
     12#include <linux/cpumask.h>
     13
     14#include "squashfs_fs.h"
     15#include "squashfs_fs_sb.h"
     16#include "decompressor.h"
     17#include "squashfs.h"
     18
     19/*
     20 * This file implements multi-threaded decompression in the
     21 * decompressor framework
     22 */
     23
     24
     25/*
     26 * The reason that multiply two is that a CPU can request new I/O
     27 * while it is waiting previous request.
     28 */
     29#define MAX_DECOMPRESSOR	(num_online_cpus() * 2)
     30
     31
     32int squashfs_max_decompressors(void)
     33{
     34	return MAX_DECOMPRESSOR;
     35}
     36
     37
     38struct squashfs_stream {
     39	void			*comp_opts;
     40	struct list_head	strm_list;
     41	struct mutex		mutex;
     42	int			avail_decomp;
     43	wait_queue_head_t	wait;
     44};
     45
     46
     47struct decomp_stream {
     48	void *stream;
     49	struct list_head list;
     50};
     51
     52
     53static void put_decomp_stream(struct decomp_stream *decomp_strm,
     54				struct squashfs_stream *stream)
     55{
     56	mutex_lock(&stream->mutex);
     57	list_add(&decomp_strm->list, &stream->strm_list);
     58	mutex_unlock(&stream->mutex);
     59	wake_up(&stream->wait);
     60}
     61
     62void *squashfs_decompressor_create(struct squashfs_sb_info *msblk,
     63				void *comp_opts)
     64{
     65	struct squashfs_stream *stream;
     66	struct decomp_stream *decomp_strm = NULL;
     67	int err = -ENOMEM;
     68
     69	stream = kzalloc(sizeof(*stream), GFP_KERNEL);
     70	if (!stream)
     71		goto out;
     72
     73	stream->comp_opts = comp_opts;
     74	mutex_init(&stream->mutex);
     75	INIT_LIST_HEAD(&stream->strm_list);
     76	init_waitqueue_head(&stream->wait);
     77
     78	/*
     79	 * We should have a decompressor at least as default
     80	 * so if we fail to allocate new decompressor dynamically,
     81	 * we could always fall back to default decompressor and
     82	 * file system works.
     83	 */
     84	decomp_strm = kmalloc(sizeof(*decomp_strm), GFP_KERNEL);
     85	if (!decomp_strm)
     86		goto out;
     87
     88	decomp_strm->stream = msblk->decompressor->init(msblk,
     89						stream->comp_opts);
     90	if (IS_ERR(decomp_strm->stream)) {
     91		err = PTR_ERR(decomp_strm->stream);
     92		goto out;
     93	}
     94
     95	list_add(&decomp_strm->list, &stream->strm_list);
     96	stream->avail_decomp = 1;
     97	return stream;
     98
     99out:
    100	kfree(decomp_strm);
    101	kfree(stream);
    102	return ERR_PTR(err);
    103}
    104
    105
    106void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
    107{
    108	struct squashfs_stream *stream = msblk->stream;
    109	if (stream) {
    110		struct decomp_stream *decomp_strm;
    111
    112		while (!list_empty(&stream->strm_list)) {
    113			decomp_strm = list_entry(stream->strm_list.prev,
    114						struct decomp_stream, list);
    115			list_del(&decomp_strm->list);
    116			msblk->decompressor->free(decomp_strm->stream);
    117			kfree(decomp_strm);
    118			stream->avail_decomp--;
    119		}
    120		WARN_ON(stream->avail_decomp);
    121		kfree(stream->comp_opts);
    122		kfree(stream);
    123	}
    124}
    125
    126
    127static struct decomp_stream *get_decomp_stream(struct squashfs_sb_info *msblk,
    128					struct squashfs_stream *stream)
    129{
    130	struct decomp_stream *decomp_strm;
    131
    132	while (1) {
    133		mutex_lock(&stream->mutex);
    134
    135		/* There is available decomp_stream */
    136		if (!list_empty(&stream->strm_list)) {
    137			decomp_strm = list_entry(stream->strm_list.prev,
    138				struct decomp_stream, list);
    139			list_del(&decomp_strm->list);
    140			mutex_unlock(&stream->mutex);
    141			break;
    142		}
    143
    144		/*
    145		 * If there is no available decomp and already full,
    146		 * let's wait for releasing decomp from other users.
    147		 */
    148		if (stream->avail_decomp >= MAX_DECOMPRESSOR)
    149			goto wait;
    150
    151		/* Let's allocate new decomp */
    152		decomp_strm = kmalloc(sizeof(*decomp_strm), GFP_KERNEL);
    153		if (!decomp_strm)
    154			goto wait;
    155
    156		decomp_strm->stream = msblk->decompressor->init(msblk,
    157						stream->comp_opts);
    158		if (IS_ERR(decomp_strm->stream)) {
    159			kfree(decomp_strm);
    160			goto wait;
    161		}
    162
    163		stream->avail_decomp++;
    164		WARN_ON(stream->avail_decomp > MAX_DECOMPRESSOR);
    165
    166		mutex_unlock(&stream->mutex);
    167		break;
    168wait:
    169		/*
    170		 * If system memory is tough, let's for other's
    171		 * releasing instead of hurting VM because it could
    172		 * make page cache thrashing.
    173		 */
    174		mutex_unlock(&stream->mutex);
    175		wait_event(stream->wait,
    176			!list_empty(&stream->strm_list));
    177	}
    178
    179	return decomp_strm;
    180}
    181
    182
    183int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
    184			int offset, int length,
    185			struct squashfs_page_actor *output)
    186{
    187	int res;
    188	struct squashfs_stream *stream = msblk->stream;
    189	struct decomp_stream *decomp_stream = get_decomp_stream(msblk, stream);
    190	res = msblk->decompressor->decompress(msblk, decomp_stream->stream,
    191		bio, offset, length, output);
    192	put_decomp_stream(decomp_stream, stream);
    193	if (res < 0)
    194		ERROR("%s decompression failed, data probably corrupt\n",
    195			msblk->decompressor->name);
    196	return res;
    197}