xref: /openbmc/linux/fs/squashfs/decompressor.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
168252eb5SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
24c0f0bb2SPhillip Lougher /*
34c0f0bb2SPhillip Lougher  * Squashfs - a compressed read only filesystem for Linux
44c0f0bb2SPhillip Lougher  *
54c0f0bb2SPhillip Lougher  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
6d7f2ff67SPhillip Lougher  * Phillip Lougher <phillip@squashfs.org.uk>
74c0f0bb2SPhillip Lougher  *
84c0f0bb2SPhillip Lougher  * decompressor.c
94c0f0bb2SPhillip Lougher  */
104c0f0bb2SPhillip Lougher 
114c0f0bb2SPhillip Lougher #include <linux/types.h>
124c0f0bb2SPhillip Lougher #include <linux/mutex.h>
13b7fc0ff0SPhillip Lougher #include <linux/slab.h>
144c0f0bb2SPhillip Lougher 
154c0f0bb2SPhillip Lougher #include "squashfs_fs.h"
164c0f0bb2SPhillip Lougher #include "squashfs_fs_sb.h"
174c0f0bb2SPhillip Lougher #include "decompressor.h"
184c0f0bb2SPhillip Lougher #include "squashfs.h"
19846b730eSPhillip Lougher #include "page_actor.h"
204c0f0bb2SPhillip Lougher 
214c0f0bb2SPhillip Lougher /*
224c0f0bb2SPhillip Lougher  * This file (and decompressor.h) implements a decompressor framework for
234c0f0bb2SPhillip Lougher  * Squashfs, allowing multiple decompressors to be easily supported
244c0f0bb2SPhillip Lougher  */
254c0f0bb2SPhillip Lougher 
26dc325678SPhillip Lougher static const struct squashfs_decompressor squashfs_lzma_unsupported_comp_ops = {
279508c6b9SPhillip Lougher 	NULL, NULL, NULL, NULL, LZMA_COMPRESSION, "lzma", 0
28dc325678SPhillip Lougher };
29dc325678SPhillip Lougher 
3062421645SPhillip Lougher #ifndef CONFIG_SQUASHFS_LZ4
3162421645SPhillip Lougher static const struct squashfs_decompressor squashfs_lz4_comp_ops = {
3262421645SPhillip Lougher 	NULL, NULL, NULL, NULL, LZ4_COMPRESSION, "lz4", 0
3362421645SPhillip Lougher };
3462421645SPhillip Lougher #endif
3562421645SPhillip Lougher 
3679cb8cedSChan Jeong #ifndef CONFIG_SQUASHFS_LZO
3701a678c5SPhillip Lougher static const struct squashfs_decompressor squashfs_lzo_comp_ops = {
389508c6b9SPhillip Lougher 	NULL, NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0
39dc325678SPhillip Lougher };
4079cb8cedSChan Jeong #endif
41dc325678SPhillip Lougher 
427a43ae52SPhillip Lougher #ifndef CONFIG_SQUASHFS_XZ
437a43ae52SPhillip Lougher static const struct squashfs_decompressor squashfs_xz_comp_ops = {
449508c6b9SPhillip Lougher 	NULL, NULL, NULL, NULL, XZ_COMPRESSION, "xz", 0
457a43ae52SPhillip Lougher };
467a43ae52SPhillip Lougher #endif
477a43ae52SPhillip Lougher 
48cc6d3497SPhillip Lougher #ifndef CONFIG_SQUASHFS_ZLIB
49cc6d3497SPhillip Lougher static const struct squashfs_decompressor squashfs_zlib_comp_ops = {
509508c6b9SPhillip Lougher 	NULL, NULL, NULL, NULL, ZLIB_COMPRESSION, "zlib", 0
51cc6d3497SPhillip Lougher };
52cc6d3497SPhillip Lougher #endif
53cc6d3497SPhillip Lougher 
5487bf54bbSSean Purcell #ifndef CONFIG_SQUASHFS_ZSTD
5587bf54bbSSean Purcell static const struct squashfs_decompressor squashfs_zstd_comp_ops = {
5687bf54bbSSean Purcell 	NULL, NULL, NULL, NULL, ZSTD_COMPRESSION, "zstd", 0
5787bf54bbSSean Purcell };
5887bf54bbSSean Purcell #endif
5987bf54bbSSean Purcell 
604c0f0bb2SPhillip Lougher static const struct squashfs_decompressor squashfs_unknown_comp_ops = {
619508c6b9SPhillip Lougher 	NULL, NULL, NULL, NULL, 0, "unknown", 0
624c0f0bb2SPhillip Lougher };
634c0f0bb2SPhillip Lougher 
644c0f0bb2SPhillip Lougher static const struct squashfs_decompressor *decompressor[] = {
654c0f0bb2SPhillip Lougher 	&squashfs_zlib_comp_ops,
6662421645SPhillip Lougher 	&squashfs_lz4_comp_ops,
6779cb8cedSChan Jeong 	&squashfs_lzo_comp_ops,
687a43ae52SPhillip Lougher 	&squashfs_xz_comp_ops,
6901a678c5SPhillip Lougher 	&squashfs_lzma_unsupported_comp_ops,
7087bf54bbSSean Purcell 	&squashfs_zstd_comp_ops,
714c0f0bb2SPhillip Lougher 	&squashfs_unknown_comp_ops
724c0f0bb2SPhillip Lougher };
734c0f0bb2SPhillip Lougher 
744c0f0bb2SPhillip Lougher 
squashfs_lookup_decompressor(int id)754c0f0bb2SPhillip Lougher const struct squashfs_decompressor *squashfs_lookup_decompressor(int id)
764c0f0bb2SPhillip Lougher {
774c0f0bb2SPhillip Lougher 	int i;
784c0f0bb2SPhillip Lougher 
794c0f0bb2SPhillip Lougher 	for (i = 0; decompressor[i]->id; i++)
804c0f0bb2SPhillip Lougher 		if (id == decompressor[i]->id)
814c0f0bb2SPhillip Lougher 			break;
824c0f0bb2SPhillip Lougher 
834c0f0bb2SPhillip Lougher 	return decompressor[i];
844c0f0bb2SPhillip Lougher }
85b7fc0ff0SPhillip Lougher 
86b7fc0ff0SPhillip Lougher 
get_comp_opts(struct super_block * sb,unsigned short flags)879508c6b9SPhillip Lougher static void *get_comp_opts(struct super_block *sb, unsigned short flags)
88b7fc0ff0SPhillip Lougher {
89b7fc0ff0SPhillip Lougher 	struct squashfs_sb_info *msblk = sb->s_fs_info;
909508c6b9SPhillip Lougher 	void *buffer = NULL, *comp_opts;
91846b730eSPhillip Lougher 	struct squashfs_page_actor *actor = NULL;
92b7fc0ff0SPhillip Lougher 	int length = 0;
93b7fc0ff0SPhillip Lougher 
94b7fc0ff0SPhillip Lougher 	/*
95b7fc0ff0SPhillip Lougher 	 * Read decompressor specific options from file system if present
96b7fc0ff0SPhillip Lougher 	 */
97b7fc0ff0SPhillip Lougher 	if (SQUASHFS_COMP_OPTS(flags)) {
9809cbfeafSKirill A. Shutemov 		buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
999508c6b9SPhillip Lougher 		if (buffer == NULL) {
1009508c6b9SPhillip Lougher 			comp_opts = ERR_PTR(-ENOMEM);
1019508c6b9SPhillip Lougher 			goto out;
1029508c6b9SPhillip Lougher 		}
103b7fc0ff0SPhillip Lougher 
104846b730eSPhillip Lougher 		actor = squashfs_page_actor_init(&buffer, 1, 0);
105846b730eSPhillip Lougher 		if (actor == NULL) {
106846b730eSPhillip Lougher 			comp_opts = ERR_PTR(-ENOMEM);
107846b730eSPhillip Lougher 			goto out;
108846b730eSPhillip Lougher 		}
109846b730eSPhillip Lougher 
110846b730eSPhillip Lougher 		length = squashfs_read_data(sb,
111846b730eSPhillip Lougher 			sizeof(struct squashfs_super_block), 0, NULL, actor);
112b7fc0ff0SPhillip Lougher 
113b7fc0ff0SPhillip Lougher 		if (length < 0) {
1149508c6b9SPhillip Lougher 			comp_opts = ERR_PTR(length);
1159508c6b9SPhillip Lougher 			goto out;
116b7fc0ff0SPhillip Lougher 		}
117b7fc0ff0SPhillip Lougher 	}
118b7fc0ff0SPhillip Lougher 
1199508c6b9SPhillip Lougher 	comp_opts = squashfs_comp_opts(msblk, buffer, length);
120b7fc0ff0SPhillip Lougher 
1219508c6b9SPhillip Lougher out:
122846b730eSPhillip Lougher 	kfree(actor);
123b7fc0ff0SPhillip Lougher 	kfree(buffer);
1249508c6b9SPhillip Lougher 	return comp_opts;
1259508c6b9SPhillip Lougher }
126b7fc0ff0SPhillip Lougher 
1279508c6b9SPhillip Lougher 
squashfs_decompressor_setup(struct super_block * sb,unsigned short flags)1289508c6b9SPhillip Lougher void *squashfs_decompressor_setup(struct super_block *sb, unsigned short flags)
1299508c6b9SPhillip Lougher {
1309508c6b9SPhillip Lougher 	struct squashfs_sb_info *msblk = sb->s_fs_info;
1319508c6b9SPhillip Lougher 	void *stream, *comp_opts = get_comp_opts(sb, flags);
1329508c6b9SPhillip Lougher 
1339508c6b9SPhillip Lougher 	if (IS_ERR(comp_opts))
1349508c6b9SPhillip Lougher 		return comp_opts;
1359508c6b9SPhillip Lougher 
136*80f78409SXiaoming Ni 	stream = msblk->thread_ops->create(msblk, comp_opts);
1379508c6b9SPhillip Lougher 	if (IS_ERR(stream))
1389508c6b9SPhillip Lougher 		kfree(comp_opts);
1399508c6b9SPhillip Lougher 
1409508c6b9SPhillip Lougher 	return stream;
141b7fc0ff0SPhillip Lougher }
142