2 * Copyright (c) 2013, 2014
3 * Phillip Lougher <phillip@squashfs.org.uk>
5 * This work is licensed under the terms of the GNU GPL, version 2. See
6 * the COPYING file in the top-level directory.
9 #include <linux/buffer_head.h>
10 #include <linux/mutex.h>
11 #include <linux/slab.h>
12 #include <linux/vmalloc.h>
13 #include <linux/lz4.h>
15 #include "squashfs_fs.h"
16 #include "squashfs_fs_sb.h"
18 #include "decompressor.h"
19 #include "page_actor.h"
23 struct lz4_comp_opts
{
34 static void *lz4_comp_opts(struct squashfs_sb_info
*msblk
,
37 struct lz4_comp_opts
*comp_opts
= buff
;
39 /* LZ4 compressed filesystems always have compression options */
40 if (comp_opts
== NULL
|| len
< sizeof(*comp_opts
))
43 if (le32_to_cpu(comp_opts
->version
) != LZ4_LEGACY
) {
44 /* LZ4 format currently used by the kernel is the 'legacy'
46 ERROR("Unknown LZ4 version\n");
47 return ERR_PTR(-EINVAL
);
54 static void *lz4_init(struct squashfs_sb_info
*msblk
, void *buff
)
56 int block_size
= max_t(int, msblk
->block_size
, SQUASHFS_METADATA_SIZE
);
57 struct squashfs_lz4
*stream
;
59 stream
= kzalloc(sizeof(*stream
), GFP_KERNEL
);
62 stream
->input
= vmalloc(block_size
);
63 if (stream
->input
== NULL
)
65 stream
->output
= vmalloc(block_size
);
66 if (stream
->output
== NULL
)
76 ERROR("Failed to initialise LZ4 decompressor\n");
77 return ERR_PTR(-ENOMEM
);
81 static void lz4_free(void *strm
)
83 struct squashfs_lz4
*stream
= strm
;
87 vfree(stream
->output
);
93 static int lz4_uncompress(struct squashfs_sb_info
*msblk
, void *strm
,
94 struct buffer_head
**bh
, int b
, int offset
, int length
,
95 struct squashfs_page_actor
*output
)
97 struct squashfs_lz4
*stream
= strm
;
98 void *buff
= stream
->input
, *data
;
99 int avail
, i
, bytes
= length
, res
;
100 size_t dest_len
= output
->length
;
102 for (i
= 0; i
< b
; i
++) {
103 avail
= min(bytes
, msblk
->devblksize
- offset
);
104 memcpy(buff
, bh
[i
]->b_data
+ offset
, avail
);
111 res
= lz4_decompress_unknownoutputsize(stream
->input
, length
,
112 stream
->output
, &dest_len
);
117 data
= squashfs_first_page(output
);
118 buff
= stream
->output
;
120 if (bytes
<= PAGE_CACHE_SIZE
) {
121 memcpy(data
, buff
, bytes
);
124 memcpy(data
, buff
, PAGE_CACHE_SIZE
);
125 buff
+= PAGE_CACHE_SIZE
;
126 bytes
-= PAGE_CACHE_SIZE
;
127 data
= squashfs_next_page(output
);
129 squashfs_finish_page(output
);
134 const struct squashfs_decompressor squashfs_lz4_comp_ops
= {
136 .comp_opts
= lz4_comp_opts
,
138 .decompress
= lz4_uncompress
,
139 .id
= LZ4_COMPRESSION
,