brintos

brintos / linux-shallow public Read only

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