• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * compress.c
3  *
4  * Copyright (c) 2020 Google Inc.
5  *   Robin Hsu <robinhsu@google.com>
6  *  : add sload compression support
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12 
13 /* for config.h for general environment (non-Android) */
14 #include "f2fs.h"
15 
16 #include "compress.h"
17 #ifdef HAVE_LIBLZO2
18 #include <lzo/lzo1x.h>	/* for lzo1x_1_15_compress() */
19 #endif
20 #ifdef HAVE_LIBLZ4
21 #include <lz4.h>	/* for LZ4_compress_fast_extState() */
22 #endif
23 
24 /*
25  * macro/constants borrowed from kernel header (GPL-2.0):
26  * include/linux/lzo.h, and include/linux/lz4.h
27  */
28 #ifdef HAVE_LIBLZO2
29 #define lzo1x_worst_compress(x)		((x) + (x) / 16 + 64 + 3 + 2)
30 #define LZO_WORK_SIZE			ALIGN_UP(LZO1X_1_15_MEM_COMPRESS, 8)
31 #endif
32 #ifdef HAVE_LIBLZ4
33 #define LZ4_MEMORY_USAGE		14
34 #define LZ4_MAX_INPUT_SIZE		0x7E000000 /* 2 113 929 216 bytes */
35 #ifndef LZ4_STREAMSIZE
36 #define LZ4_STREAMSIZE			(LZ4_STREAMSIZE_U64 * sizeof(long long))
37 #endif
38 #define LZ4_MEM_COMPRESS		LZ4_STREAMSIZE
39 #define LZ4_ACCELERATION_DEFAULT	1
40 #define LZ4_WORK_SIZE			ALIGN_UP(LZ4_MEM_COMPRESS, 8)
41 #endif
42 
43 #if defined(HAVE_LIBLZO2) || defined(HAVE_LIBLZ4)
reset_cc(struct compress_ctx * cc)44 static void reset_cc(struct compress_ctx *cc)
45 {
46 	memset(cc->rbuf, 0, cc->cluster_size * F2FS_BLKSIZE);
47 	memset(cc->cbuf->cdata, 0, cc->cluster_size * F2FS_BLKSIZE
48 			- F2FS_BLKSIZE);
49 }
50 #endif
51 
52 #ifdef HAVE_LIBLZO2
lzo_compress_init(struct compress_ctx * cc)53 static void lzo_compress_init(struct compress_ctx *cc)
54 {
55 	size_t size = cc->cluster_size * F2FS_BLKSIZE;
56 	size_t alloc = size + lzo1x_worst_compress(size)
57 			+ COMPRESS_HEADER_SIZE + LZO_WORK_SIZE;
58 	cc->private = malloc(alloc);
59 	ASSERT(cc->private);
60 	cc->rbuf = (char *) cc->private + LZO_WORK_SIZE;
61 	cc->cbuf = (struct compress_data *)((char *) cc->rbuf + size);
62 }
63 
lzo_compress(struct compress_ctx * cc)64 static int lzo_compress(struct compress_ctx *cc)
65 {
66 	int ret = lzo1x_1_15_compress(cc->rbuf, cc->rlen, cc->cbuf->cdata,
67 			(lzo_uintp)(&cc->clen), cc->private);
68 	cc->cbuf->clen = cpu_to_le32(cc->clen);
69 	return ret;
70 }
71 #endif
72 
73 #ifdef HAVE_LIBLZ4
lz4_compress_init(struct compress_ctx * cc)74 static void lz4_compress_init(struct compress_ctx *cc)
75 {
76 	size_t size = cc->cluster_size * F2FS_BLKSIZE;
77 	size_t alloc = size + LZ4_COMPRESSBOUND(size)
78 			+ COMPRESS_HEADER_SIZE + LZ4_WORK_SIZE;
79 	cc->private = malloc(alloc);
80 	ASSERT(cc->private);
81 	cc->rbuf = (char *) cc->private + LZ4_WORK_SIZE;
82 	cc->cbuf = (struct compress_data *)((char *) cc->rbuf + size);
83 }
84 
lz4_compress(struct compress_ctx * cc)85 static int lz4_compress(struct compress_ctx *cc)
86 {
87 	cc->clen = LZ4_compress_fast_extState(cc->private, cc->rbuf,
88 			(char *)cc->cbuf->cdata, cc->rlen,
89 			cc->rlen - F2FS_BLKSIZE * c.compress.min_blocks -
90 			COMPRESS_HEADER_SIZE,
91 			LZ4_ACCELERATION_DEFAULT);
92 
93 	if (!cc->clen)
94 		return 1;
95 
96 	cc->cbuf->clen = cpu_to_le32(cc->clen);
97 	return 0;
98 }
99 #endif
100 
101 const char *supported_comp_names[] = {
102 	"lzo",
103 	"lz4",
104 	"",
105 };
106 
107 compress_ops supported_comp_ops[] = {
108 #ifdef HAVE_LIBLZO2
109 	{lzo_compress_init, lzo_compress, reset_cc},
110 #else
111 	{NULL, NULL, NULL},
112 #endif
113 #ifdef HAVE_LIBLZ4
114 	{lz4_compress_init, lz4_compress, reset_cc},
115 #else
116 	{NULL, NULL, NULL},
117 #endif
118 };
119 
120 /* linked list */
121 typedef struct _ext_t {
122 	const char *ext;
123 	struct _ext_t *next;
124 } ext_t;
125 
126 static ext_t *extension_list;
127 
ext_found(const char * ext)128 static bool ext_found(const char *ext)
129 {
130 	ext_t *p = extension_list;
131 
132 	while (p != NULL && strcmp(ext, p->ext))
133 		p = p->next;
134 	return (p != NULL);
135 }
136 
get_ext(const char * path)137 static const char *get_ext(const char *path)
138 {
139 	char *p = strrchr(path, '.');
140 
141 	return p == NULL ? path + strlen(path) : p + 1;
142 }
143 
ext_do_filter(const char * path)144 static bool ext_do_filter(const char *path)
145 {
146 	return (ext_found(get_ext(path)) == true) ^
147 		(c.compress.filter == COMPR_FILTER_ALLOW);
148 }
149 
ext_filter_add(const char * ext)150 static void ext_filter_add(const char *ext)
151 {
152 	ext_t *node;
153 
154 	ASSERT(ext != NULL);
155 	if (ext_found(ext))
156 		return; /* ext was already registered */
157 	node = malloc(sizeof(ext_t));
158 	ASSERT(node != NULL);
159 	node->ext = ext;
160 	node->next = extension_list;
161 	extension_list = node;
162 }
163 
ext_filter_destroy(void)164 static void ext_filter_destroy(void)
165 {
166 	ext_t *p;
167 
168 	while (extension_list != NULL) {
169 		p = extension_list;
170 		extension_list = p->next;
171 		free(p);
172 	}
173 }
174 
175 filter_ops ext_filter = {
176 	.add = ext_filter_add,
177 	.destroy = ext_filter_destroy,
178 	.filter = ext_do_filter,
179 };
180