120c8ccb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2d208383dSPhillip Lougher /*
3d208383dSPhillip Lougher * Copyright (c) 2013
4d208383dSPhillip Lougher * Phillip Lougher <phillip@squashfs.org.uk>
5d208383dSPhillip Lougher */
6d208383dSPhillip Lougher
7d208383dSPhillip Lougher #include <linux/types.h>
8d208383dSPhillip Lougher #include <linux/slab.h>
9d208383dSPhillip Lougher #include <linux/percpu.h>
10fd56200aSJulia Cartwright #include <linux/local_lock.h>
11d208383dSPhillip Lougher
12d208383dSPhillip Lougher #include "squashfs_fs.h"
13d208383dSPhillip Lougher #include "squashfs_fs_sb.h"
14d208383dSPhillip Lougher #include "decompressor.h"
15d208383dSPhillip Lougher #include "squashfs.h"
16d208383dSPhillip Lougher
17d208383dSPhillip Lougher /*
18d208383dSPhillip Lougher * This file implements multi-threaded decompression using percpu
19d208383dSPhillip Lougher * variables, one thread per cpu core.
20d208383dSPhillip Lougher */
21d208383dSPhillip Lougher
22d208383dSPhillip Lougher struct squashfs_stream {
23d208383dSPhillip Lougher void *stream;
24fd56200aSJulia Cartwright local_lock_t lock;
25d208383dSPhillip Lougher };
26d208383dSPhillip Lougher
squashfs_decompressor_create(struct squashfs_sb_info * msblk,void * comp_opts)27*80f78409SXiaoming Ni static void *squashfs_decompressor_create(struct squashfs_sb_info *msblk,
28d208383dSPhillip Lougher void *comp_opts)
29d208383dSPhillip Lougher {
30d208383dSPhillip Lougher struct squashfs_stream *stream;
31d208383dSPhillip Lougher struct squashfs_stream __percpu *percpu;
32d208383dSPhillip Lougher int err, cpu;
33d208383dSPhillip Lougher
34d208383dSPhillip Lougher percpu = alloc_percpu(struct squashfs_stream);
35d208383dSPhillip Lougher if (percpu == NULL)
36d208383dSPhillip Lougher return ERR_PTR(-ENOMEM);
37d208383dSPhillip Lougher
38d208383dSPhillip Lougher for_each_possible_cpu(cpu) {
39d208383dSPhillip Lougher stream = per_cpu_ptr(percpu, cpu);
40d208383dSPhillip Lougher stream->stream = msblk->decompressor->init(msblk, comp_opts);
41d208383dSPhillip Lougher if (IS_ERR(stream->stream)) {
42d208383dSPhillip Lougher err = PTR_ERR(stream->stream);
43d208383dSPhillip Lougher goto out;
44d208383dSPhillip Lougher }
45fd56200aSJulia Cartwright local_lock_init(&stream->lock);
46d208383dSPhillip Lougher }
47d208383dSPhillip Lougher
48d208383dSPhillip Lougher kfree(comp_opts);
49d208383dSPhillip Lougher return (__force void *) percpu;
50d208383dSPhillip Lougher
51d208383dSPhillip Lougher out:
52d208383dSPhillip Lougher for_each_possible_cpu(cpu) {
53d208383dSPhillip Lougher stream = per_cpu_ptr(percpu, cpu);
54d208383dSPhillip Lougher if (!IS_ERR_OR_NULL(stream->stream))
55d208383dSPhillip Lougher msblk->decompressor->free(stream->stream);
56d208383dSPhillip Lougher }
57d208383dSPhillip Lougher free_percpu(percpu);
58d208383dSPhillip Lougher return ERR_PTR(err);
59d208383dSPhillip Lougher }
60d208383dSPhillip Lougher
squashfs_decompressor_destroy(struct squashfs_sb_info * msblk)61*80f78409SXiaoming Ni static void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
62d208383dSPhillip Lougher {
63d208383dSPhillip Lougher struct squashfs_stream __percpu *percpu =
64d208383dSPhillip Lougher (struct squashfs_stream __percpu *) msblk->stream;
65d208383dSPhillip Lougher struct squashfs_stream *stream;
66d208383dSPhillip Lougher int cpu;
67d208383dSPhillip Lougher
68d208383dSPhillip Lougher if (msblk->stream) {
69d208383dSPhillip Lougher for_each_possible_cpu(cpu) {
70d208383dSPhillip Lougher stream = per_cpu_ptr(percpu, cpu);
71d208383dSPhillip Lougher msblk->decompressor->free(stream->stream);
72d208383dSPhillip Lougher }
73d208383dSPhillip Lougher free_percpu(percpu);
74d208383dSPhillip Lougher }
75d208383dSPhillip Lougher }
76d208383dSPhillip Lougher
squashfs_decompress(struct squashfs_sb_info * msblk,struct bio * bio,int offset,int length,struct squashfs_page_actor * output)77*80f78409SXiaoming Ni static int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
7893e72b3cSPhilippe Liard int offset, int length, struct squashfs_page_actor *output)
79d208383dSPhillip Lougher {
80fd56200aSJulia Cartwright struct squashfs_stream *stream;
81*80f78409SXiaoming Ni struct squashfs_stream __percpu *percpu =
82*80f78409SXiaoming Ni (struct squashfs_stream __percpu *) msblk->stream;
83fd56200aSJulia Cartwright int res;
84fd56200aSJulia Cartwright
85*80f78409SXiaoming Ni local_lock(&percpu->lock);
86*80f78409SXiaoming Ni stream = this_cpu_ptr(percpu);
87fd56200aSJulia Cartwright
8893e72b3cSPhilippe Liard res = msblk->decompressor->decompress(msblk, stream->stream, bio,
89846b730eSPhillip Lougher offset, length, output);
90fd56200aSJulia Cartwright
91*80f78409SXiaoming Ni local_unlock(&percpu->lock);
92d208383dSPhillip Lougher
93d208383dSPhillip Lougher if (res < 0)
94d208383dSPhillip Lougher ERROR("%s decompression failed, data probably corrupt\n",
95d208383dSPhillip Lougher msblk->decompressor->name);
96d208383dSPhillip Lougher
97d208383dSPhillip Lougher return res;
98d208383dSPhillip Lougher }
99d208383dSPhillip Lougher
squashfs_max_decompressors(void)100*80f78409SXiaoming Ni static int squashfs_max_decompressors(void)
101d208383dSPhillip Lougher {
102d208383dSPhillip Lougher return num_possible_cpus();
103d208383dSPhillip Lougher }
104*80f78409SXiaoming Ni
105*80f78409SXiaoming Ni const struct squashfs_decompressor_thread_ops squashfs_decompressor_percpu = {
106*80f78409SXiaoming Ni .create = squashfs_decompressor_create,
107*80f78409SXiaoming Ni .destroy = squashfs_decompressor_destroy,
108*80f78409SXiaoming Ni .decompress = squashfs_decompress,
109*80f78409SXiaoming Ni .max_decompressors = squashfs_max_decompressors,
110*80f78409SXiaoming Ni };
111