1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2013, 2014
4 * Phillip Lougher <phillip@squashfs.org.uk>
7 #include <linux/buffer_head.h>
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 buffer_head
**bh
, int b
, int offset
, int length
,
93 struct squashfs_page_actor
*output
)
95 struct squashfs_lz4
*stream
= strm
;
96 void *buff
= stream
->input
, *data
;
97 int avail
, i
, bytes
= length
, res
;
99 for (i
= 0; i
< b
; i
++) {
100 avail
= min(bytes
, msblk
->devblksize
- offset
);
101 memcpy(buff
, bh
[i
]->b_data
+ offset
, avail
);
108 res
= LZ4_decompress_safe(stream
->input
, stream
->output
,
109 length
, output
->length
);
115 data
= squashfs_first_page(output
);
116 buff
= stream
->output
;
118 if (bytes
<= PAGE_SIZE
) {
119 memcpy(data
, buff
, bytes
);
122 memcpy(data
, buff
, PAGE_SIZE
);
125 data
= squashfs_next_page(output
);
127 squashfs_finish_page(output
);
132 const struct squashfs_decompressor squashfs_lz4_comp_ops
= {
134 .comp_opts
= lz4_comp_opts
,
136 .decompress
= lz4_uncompress
,
137 .id
= LZ4_COMPRESSION
,