2019-06-04 11:11:32 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2013-11-18 06:31:36 +04:00
/*
* Copyright ( c ) 2013
* Phillip Lougher < phillip @ squashfs . org . uk >
*/
# include <linux/types.h>
# include <linux/slab.h>
# include <linux/percpu.h>
# include <linux/buffer_head.h>
2020-05-27 23:11:16 +03:00
# include <linux/local_lock.h>
2013-11-18 06:31:36 +04:00
# include "squashfs_fs.h"
# include "squashfs_fs_sb.h"
# include "decompressor.h"
# include "squashfs.h"
/*
* This file implements multi - threaded decompression using percpu
* variables , one thread per cpu core .
*/
struct squashfs_stream {
2020-05-27 23:11:16 +03:00
void * stream ;
local_lock_t lock ;
2013-11-18 06:31:36 +04:00
} ;
2022-10-19 06:09:29 +03:00
static void * squashfs_decompressor_create ( struct squashfs_sb_info * msblk ,
2013-11-18 06:31:36 +04:00
void * comp_opts )
{
struct squashfs_stream * stream ;
struct squashfs_stream __percpu * percpu ;
int err , cpu ;
percpu = alloc_percpu ( struct squashfs_stream ) ;
if ( percpu = = NULL )
return ERR_PTR ( - ENOMEM ) ;
for_each_possible_cpu ( cpu ) {
stream = per_cpu_ptr ( percpu , cpu ) ;
stream - > stream = msblk - > decompressor - > init ( msblk , comp_opts ) ;
if ( IS_ERR ( stream - > stream ) ) {
err = PTR_ERR ( stream - > stream ) ;
goto out ;
}
2020-05-27 23:11:16 +03:00
local_lock_init ( & stream - > lock ) ;
2013-11-18 06:31:36 +04:00
}
kfree ( comp_opts ) ;
return ( __force void * ) percpu ;
out :
for_each_possible_cpu ( cpu ) {
stream = per_cpu_ptr ( percpu , cpu ) ;
if ( ! IS_ERR_OR_NULL ( stream - > stream ) )
msblk - > decompressor - > free ( stream - > stream ) ;
}
free_percpu ( percpu ) ;
return ERR_PTR ( err ) ;
}
2022-10-19 06:09:29 +03:00
static void squashfs_decompressor_destroy ( struct squashfs_sb_info * msblk )
2013-11-18 06:31:36 +04:00
{
struct squashfs_stream __percpu * percpu =
( struct squashfs_stream __percpu * ) msblk - > stream ;
struct squashfs_stream * stream ;
int cpu ;
if ( msblk - > stream ) {
for_each_possible_cpu ( cpu ) {
stream = per_cpu_ptr ( percpu , cpu ) ;
msblk - > decompressor - > free ( stream - > stream ) ;
}
free_percpu ( percpu ) ;
}
}
2022-10-19 06:09:29 +03:00
static int squashfs_decompress ( struct squashfs_sb_info * msblk , struct bio * bio ,
2020-06-02 07:45:23 +03:00
int offset , int length , struct squashfs_page_actor * output )
2013-11-18 06:31:36 +04:00
{
2020-05-27 23:11:16 +03:00
struct squashfs_stream * stream ;
2022-10-19 06:09:29 +03:00
struct squashfs_stream __percpu * percpu =
( struct squashfs_stream __percpu * ) msblk - > stream ;
2020-05-27 23:11:16 +03:00
int res ;
2022-10-19 06:09:29 +03:00
local_lock ( & percpu - > lock ) ;
stream = this_cpu_ptr ( percpu ) ;
2020-05-27 23:11:16 +03:00
2020-06-02 07:45:23 +03:00
res = msblk - > decompressor - > decompress ( msblk , stream - > stream , bio ,
offset , length , output ) ;
2020-05-27 23:11:16 +03:00
2022-10-19 06:09:29 +03:00
local_unlock ( & percpu - > lock ) ;
2013-11-18 06:31:36 +04:00
if ( res < 0 )
ERROR ( " %s decompression failed, data probably corrupt \n " ,
msblk - > decompressor - > name ) ;
return res ;
}
2022-10-19 06:09:29 +03:00
static int squashfs_max_decompressors ( void )
2013-11-18 06:31:36 +04:00
{
return num_possible_cpus ( ) ;
}
2022-10-19 06:09:29 +03:00
const struct squashfs_decompressor_thread_ops squashfs_decompressor_percpu = {
. create = squashfs_decompressor_create ,
. destroy = squashfs_decompressor_destroy ,
. decompress = squashfs_decompress ,
. max_decompressors = squashfs_max_decompressors ,
} ;