1 /*
2 * JFFS2 -- Journalling Flash File System, Version 2.
3 *
4 * Copyright © 2001-2007 Red Hat, Inc.
5 * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
6 *
7 * Created by David Woodhouse <dwmw2@infradead.org>
8 *
9 * For licensing information, see the file 'LICENCE' in this directory.
10 *
11 */
12
13 #include <linux/kernel.h>
14 #include <zlib.h>
15 #include <linux/zutil.h>
16 #include <linux/semaphore.h>
17 #include "nodelist.h"
18 #include "compr.h"
19
20 /* Plan: call deflate() with avail_in == *sourcelen,
21 avail_out = *dstlen - 12 and flush == Z_FINISH.
22 If it doesn't manage to finish, call it again with
23 avail_in == 0 and avail_out set to the remaining 12
24 bytes for it to clean up.
25 Q: Is 12 bytes sufficient?
26 */
27 #define STREAM_END_SPACE 12
28
29 static DEFINE_MUTEX(deflate_mutex);
30 static DEFINE_MUTEX(inflate_mutex);
31 static z_stream inf_strm, def_strm;
32
33 #define alloc_workspaces() (0)
34 #define free_workspaces() do { } while(0)
35
jffs2_zlib_compress(unsigned char * data_in,unsigned char * cpage_out,uint32_t * sourcelen,uint32_t * dstlen)36 static int jffs2_zlib_compress(unsigned char *data_in,
37 unsigned char *cpage_out,
38 uint32_t *sourcelen, uint32_t *dstlen)
39 {
40 int ret;
41
42 if (*dstlen <= STREAM_END_SPACE)
43 return -1;
44
45 mutex_lock(&deflate_mutex);
46
47 if (Z_OK != deflateInit(&def_strm, 3)) {
48 pr_warn("deflateInit failed\n");
49 mutex_unlock(&deflate_mutex);
50 return -1;
51 }
52
53 def_strm.next_in = data_in;
54 def_strm.total_in = 0;
55
56 def_strm.next_out = cpage_out;
57 def_strm.total_out = 0;
58
59 while (def_strm.total_out < *dstlen - STREAM_END_SPACE && def_strm.total_in < *sourcelen) {
60 def_strm.avail_out = *dstlen - (def_strm.total_out + STREAM_END_SPACE);
61 def_strm.avail_in = min_t(unsigned long,
62 (*sourcelen-def_strm.total_in), def_strm.avail_out);
63 jffs2_dbg(1, "calling deflate with avail_in %ld, avail_out %ld\n",
64 def_strm.avail_in, def_strm.avail_out);
65 ret = deflate(&def_strm, Z_PARTIAL_FLUSH);
66 jffs2_dbg(1, "deflate returned with avail_in %ld, avail_out %ld, total_in %ld, total_out %ld\n",
67 def_strm.avail_in, def_strm.avail_out,
68 def_strm.total_in, def_strm.total_out);
69 if (ret != Z_OK) {
70 jffs2_dbg(1, "deflate in loop returned %d\n", ret);
71 deflateEnd(&def_strm);
72 mutex_unlock(&deflate_mutex);
73 return -1;
74 }
75 }
76 def_strm.avail_out += STREAM_END_SPACE;
77 def_strm.avail_in = 0;
78 ret = deflate(&def_strm, Z_FINISH);
79 deflateEnd(&def_strm);
80
81 if (ret != Z_STREAM_END) {
82 jffs2_dbg(1, "final deflate returned %d\n", ret);
83 ret = -1;
84 goto out;
85 }
86
87 if (def_strm.total_out >= def_strm.total_in) {
88 jffs2_dbg(1, "zlib compressed %ld bytes into %ld; failing\n",
89 def_strm.total_in, def_strm.total_out);
90 ret = -1;
91 goto out;
92 }
93
94 jffs2_dbg(1, "zlib compressed %ld bytes into %ld\n",
95 def_strm.total_in, def_strm.total_out);
96
97 *dstlen = def_strm.total_out;
98 *sourcelen = def_strm.total_in;
99 ret = 0;
100 out:
101 mutex_unlock(&deflate_mutex);
102 return ret;
103 }
104
jffs2_zlib_decompress(unsigned char * data_in,unsigned char * cpage_out,uint32_t srclen,uint32_t destlen)105 static int jffs2_zlib_decompress(unsigned char *data_in,
106 unsigned char *cpage_out,
107 uint32_t srclen, uint32_t destlen)
108 {
109 int ret;
110 int wbits = MAX_WBITS;
111
112 mutex_lock(&inflate_mutex);
113
114 inf_strm.next_in = data_in;
115 inf_strm.avail_in = srclen;
116 inf_strm.total_in = 0;
117
118 inf_strm.next_out = cpage_out;
119 inf_strm.avail_out = destlen;
120 inf_strm.total_out = 0;
121
122 /* If it's deflate, and it's got no preset dictionary, then
123 we can tell zlib to skip the adler32 check. */
124 if (srclen > 2 && !(data_in[1] & PRESET_DICT) &&
125 ((data_in[0] & 0x0f) == Z_DEFLATED) &&
126 !(((data_in[0]<<8) + data_in[1]) % 31)) {
127
128 jffs2_dbg(2, "inflate skipping adler32\n");
129 wbits = -((data_in[0] >> 4) + 8);
130 inf_strm.next_in += 2;
131 inf_strm.avail_in -= 2;
132 } else {
133 /* Let this remain D1 for now -- it should never happen */
134 jffs2_dbg(1, "inflate not skipping adler32\n");
135 }
136
137
138 if (Z_OK != inflateInit2(&inf_strm, wbits)) {
139 pr_warn("inflateInit failed\n");
140 mutex_unlock(&inflate_mutex);
141 return 1;
142 }
143
144 while((ret = inflate(&inf_strm, Z_FINISH)) == Z_OK)
145 ;
146 if (ret != Z_STREAM_END) {
147 pr_notice("inflate returned %d\n", ret);
148 }
149 inflateEnd(&inf_strm);
150 mutex_unlock(&inflate_mutex);
151 return 0;
152 }
153
154 static struct jffs2_compressor jffs2_zlib_comp = {
155 .priority = JFFS2_ZLIB_PRIORITY,
156 .name = "zlib",
157 .compr = JFFS2_COMPR_ZLIB,
158 .compress = &jffs2_zlib_compress,
159 .decompress = &jffs2_zlib_decompress,
160 #ifdef JFFS2_ZLIB_DISABLED
161 .disabled = 1,
162 #else
163 .disabled = 0,
164 #endif
165 };
166
jffs2_zlib_init(void)167 int __init jffs2_zlib_init(void)
168 {
169 int ret;
170
171 ret = alloc_workspaces();
172 if (ret)
173 return ret;
174
175 pthread_mutex_init(&deflate_mutex, NULL);
176 pthread_mutex_init(&inflate_mutex, NULL);
177 ret = jffs2_register_compressor(&jffs2_zlib_comp);
178 if (ret)
179 free_workspaces();
180
181 return ret;
182 }
183
jffs2_zlib_exit(void)184 void jffs2_zlib_exit(void)
185 {
186 pthread_mutex_destroy(&deflate_mutex);
187 pthread_mutex_destroy(&inflate_mutex);
188 jffs2_unregister_compressor(&jffs2_zlib_comp);
189 free_workspaces();
190 }
191