1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2013, 2014
4 * Phillip Lougher <phillip@squashfs.org.uk>
8 #include <linux/mutex.h>
9 #include <linux/slab.h>
10 #include <linux/vmalloc.h>
11 #include <linux/lz4.h>
13 #include "squashfs_fs.h"
14 #include "squashfs_fs_sb.h"
16 #include "decompressor.h"
17 #include "page_actor.h"
21 struct lz4_comp_opts
{
32 static void *lz4_comp_opts(struct squashfs_sb_info
*msblk
,
35 struct lz4_comp_opts
*comp_opts
= buff
;
37 /* LZ4 compressed filesystems always have compression options */
38 if (comp_opts
== NULL
|| len
< sizeof(*comp_opts
))
41 if (le32_to_cpu(comp_opts
->version
) != LZ4_LEGACY
) {
42 /* LZ4 format currently used by the kernel is the 'legacy'
44 ERROR("Unknown LZ4 version\n");
45 return ERR_PTR(-EINVAL
);
52 static void *lz4_init(struct squashfs_sb_info
*msblk
, void *buff
)
54 int block_size
= max_t(int, msblk
->block_size
, SQUASHFS_METADATA_SIZE
);
55 struct squashfs_lz4
*stream
;
57 stream
= kzalloc(sizeof(*stream
), GFP_KERNEL
);
60 stream
->input
= vmalloc(block_size
);
61 if (stream
->input
== NULL
)
63 stream
->output
= vmalloc(block_size
);
64 if (stream
->output
== NULL
)
74 ERROR("Failed to initialise LZ4 decompressor\n");
75 return ERR_PTR(-ENOMEM
);
79 static void lz4_free(void *strm
)
81 struct squashfs_lz4
*stream
= strm
;
85 vfree(stream
->output
);
91 static int lz4_uncompress(struct squashfs_sb_info
*msblk
, void *strm
,
92 struct bio
*bio
, int offset
, int length
,
93 struct squashfs_page_actor
*output
)
95 struct bvec_iter_all iter_all
= {};
96 struct bio_vec
*bvec
= bvec_init_iter_all(&iter_all
);
97 struct squashfs_lz4
*stream
= strm
;
98 void *buff
= stream
->input
, *data
;
99 int bytes
= length
, res
;
101 while (bio_next_segment(bio
, &iter_all
)) {
102 int avail
= min(bytes
, ((int)bvec
->bv_len
) - offset
);
104 data
= page_address(bvec
->bv_page
) + bvec
->bv_offset
;
105 memcpy(buff
, data
+ offset
, avail
);
111 res
= LZ4_decompress_safe(stream
->input
, stream
->output
,
112 length
, output
->length
);
118 data
= squashfs_first_page(output
);
119 buff
= stream
->output
;
121 if (bytes
<= PAGE_SIZE
) {
122 memcpy(data
, buff
, bytes
);
125 memcpy(data
, buff
, PAGE_SIZE
);
128 data
= squashfs_next_page(output
);
130 squashfs_finish_page(output
);
135 const struct squashfs_decompressor squashfs_lz4_comp_ops
= {
137 .comp_opts
= lz4_comp_opts
,
139 .decompress
= lz4_uncompress
,
140 .id
= LZ4_COMPRESSION
,