Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204// SPDX-License-Identifier: GPL-2.0-only/* * Copyright (c) 2013 * Minchan Kim <minchan@kernel.org> */#include <linux/types.h>#include <linux/mutex.h>#include <linux/slab.h>#include <linux/bio.h>#include <linux/sched.h>#include <linux/wait.h>#include <linux/cpumask.h>
#include "squashfs_fs.h"#include "squashfs_fs_sb.h"#include "decompressor.h"#include "squashfs.h"
/* * This file implements multi-threaded decompression in the * decompressor framework */
/* * The reason that multiply two is that a CPU can request new I/O * while it is waiting previous request. */#define MAX_DECOMPRESSOR (num_online_cpus() * 2)
static int squashfs_max_decompressors(void){ return MAX_DECOMPRESSOR;}
struct squashfs_stream { void *comp_opts; struct list_head strm_list; struct mutex mutex; int avail_decomp; wait_queue_head_t wait;};
struct decomp_stream { void *stream; struct list_head list;};
static void put_decomp_stream(struct decomp_stream *decomp_strm, struct squashfs_stream *stream){ mutex_lock(&stream->mutex); list_add(&decomp_strm->list, &stream->strm_list); mutex_unlock(&stream->mutex); wake_up(&stream->wait);}
static void *squashfs_decompressor_create(struct squashfs_sb_info *msblk, void *comp_opts){ struct squashfs_stream *stream; struct decomp_stream *decomp_strm = NULL; int err = -ENOMEM;
stream = kzalloc_obj(*stream); if (!stream) goto out;
stream->comp_opts = comp_opts; mutex_init(&stream->mutex); INIT_LIST_HEAD(&stream->strm_list); init_waitqueue_head(&stream->wait);
/* * We should have a decompressor at least as default * so if we fail to allocate new decompressor dynamically, * we could always fall back to default decompressor and * file system works. */ decomp_strm = kmalloc_obj(*decomp_strm); if (!decomp_strm) goto out;
decomp_strm->stream = msblk->decompressor->init(msblk, stream->comp_opts); if (IS_ERR(decomp_strm->stream)) { err = PTR_ERR(decomp_strm->stream); goto out; }
list_add(&decomp_strm->list, &stream->strm_list); stream->avail_decomp = 1; return stream;
out: kfree(decomp_strm); kfree(stream); return ERR_PTR(err);}
static void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk){ struct squashfs_stream *stream = msblk->stream; if (stream) { struct decomp_stream *decomp_strm;
while (!list_empty(&stream->strm_list)) { decomp_strm = list_entry(stream->strm_list.prev, struct decomp_stream, list); list_del(&decomp_strm->list); msblk->decompressor->free(decomp_strm->stream); kfree(decomp_strm); stream->avail_decomp--; } WARN_ON(stream->avail_decomp); kfree(stream->comp_opts); kfree(stream); }}
static struct decomp_stream *get_decomp_stream(struct squashfs_sb_info *msblk, struct squashfs_stream *stream){ struct decomp_stream *decomp_strm;
while (1) { mutex_lock(&stream->mutex);
/* There is available decomp_stream */ if (!list_empty(&stream->strm_list)) { decomp_strm = list_entry(stream->strm_list.prev, struct decomp_stream, list); list_del(&decomp_strm->list); mutex_unlock(&stream->mutex); break; }
/* * If there is no available decomp and already full, * let's wait for releasing decomp from other users. */ if (stream->avail_decomp >= msblk->max_thread_num) goto wait;
/* Let's allocate new decomp */ decomp_strm = kmalloc_obj(*decomp_strm); if (!decomp_strm) goto wait;
decomp_strm->stream = msblk->decompressor->init(msblk, stream->comp_opts); if (IS_ERR(decomp_strm->stream)) { kfree(decomp_strm); goto wait; }
stream->avail_decomp++; WARN_ON(stream->avail_decomp > msblk->max_thread_num);
mutex_unlock(&stream->mutex); break;wait: /* * If system memory is tough, let's for other's * releasing instead of hurting VM because it could * make page cache thrashing. */ mutex_unlock(&stream->mutex); wait_event(stream->wait, !list_empty(&stream->strm_list)); }
return decomp_strm;}
static int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio, int offset, int length, struct squashfs_page_actor *output){ int res; struct squashfs_stream *stream = msblk->stream; struct decomp_stream *decomp_stream = get_decomp_stream(msblk, stream); res = msblk->decompressor->decompress(msblk, decomp_stream->stream, bio, offset, length, output); put_decomp_stream(decomp_stream, stream); if (res < 0) ERROR("%s decompression failed, data probably corrupt\n", msblk->decompressor->name); return res;}
const struct squashfs_decompressor_thread_ops squashfs_decompressor_multi = { .create = squashfs_decompressor_create, .destroy = squashfs_decompressor_destroy, .decompress = squashfs_decompress, .max_decompressors = squashfs_max_decompressors,};