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 LZ4_ACCELERATION_DEFAULT);
91
92 if (!cc->clen)
93 return 1;
94
95 cc->cbuf->clen = cpu_to_le32(cc->clen);
96 return 0;
97 }
98 #endif
99
100 const char *supported_comp_names[] = {
101 "lzo",
102 "lz4",
103 "",
104 };
105
106 compress_ops supported_comp_ops[] = {
107 #ifdef HAVE_LIBLZO2
108 {lzo_compress_init, lzo_compress, reset_cc},
109 #else
110 {NULL, NULL, NULL},
111 #endif
112 #ifdef HAVE_LIBLZ4
113 {lz4_compress_init, lz4_compress, reset_cc},
114 #else
115 {NULL, NULL, NULL},
116 #endif
117 };
118
119 /* linked list */
120 typedef struct _ext_t {
121 const char *ext;
122 struct _ext_t *next;
123 } ext_t;
124
125 static ext_t *extension_list;
126
ext_found(const char * ext)127 static bool ext_found(const char *ext)
128 {
129 ext_t *p = extension_list;
130
131 while (p != NULL && strcmp(ext, p->ext))
132 p = p->next;
133 return (p != NULL);
134 }
135
get_ext(const char * path)136 static const char *get_ext(const char *path)
137 {
138 char *p = strrchr(path, '.');
139
140 return p == NULL ? path + strlen(path) : p + 1;
141 }
142
ext_do_filter(const char * path)143 static bool ext_do_filter(const char *path)
144 {
145 return (ext_found(get_ext(path)) == true) ^
146 (c.compress.filter == COMPR_FILTER_ALLOW);
147 }
148
ext_filter_add(const char * ext)149 static void ext_filter_add(const char *ext)
150 {
151 ext_t *node;
152
153 ASSERT(ext != NULL);
154 if (ext_found(ext))
155 return; /* ext was already registered */
156 node = malloc(sizeof(ext_t));
157 ASSERT(node != NULL);
158 node->ext = ext;
159 node->next = extension_list;
160 extension_list = node;
161 }
162
ext_filter_destroy(void)163 static void ext_filter_destroy(void)
164 {
165 ext_t *p;
166
167 while (extension_list != NULL) {
168 p = extension_list;
169 extension_list = p->next;
170 free(p);
171 }
172 }
173
174 filter_ops ext_filter = {
175 .add = ext_filter_add,
176 .destroy = ext_filter_destroy,
177 .filter = ext_do_filter,
178 };
179