Blame view

fs/jffs2/compr_zlib.c 5.79 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   * JFFS2 -- Journalling Flash File System, Version 2.
   *
c00c310ea   David Woodhouse   [JFFS2] Tidy up l...
4
   * Copyright © 2001-2007 Red Hat, Inc.
6088c0587   David Woodhouse   jffs2: Update cop...
5
   * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
9
10
   *
   * Created by David Woodhouse <dwmw2@infradead.org>
   *
   * For licensing information, see the file 'LICENCE' in this directory.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
14
15
   */
  
  #if !defined(__KERNEL__) && !defined(__ECOS)
  #error "The userspace support got too messy and was removed. Update your mkfs.jffs2"
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
  #include <linux/zlib.h>
  #include <linux/zutil.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
  #include "nodelist.h"
  #include "compr.h"
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
21
22
  	/* Plan: call deflate() with avail_in == *sourcelen,
  		avail_out = *dstlen - 12 and flush == Z_FINISH.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
  		If it doesn't manage to finish,	call it again with
  		avail_in == 0 and avail_out set to the remaining 12
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
25
  		bytes for it to clean up.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
28
  	   Q: Is 12 bytes sufficient?
  	*/
  #define STREAM_END_SPACE 12
353ab6e97   Ingo Molnar   [PATCH] sem2mutex...
29
30
  static DEFINE_MUTEX(deflate_mutex);
  static DEFINE_MUTEX(inflate_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
34
35
  static z_stream inf_strm, def_strm;
  
  #ifdef __KERNEL__ /* Linux-only */
  #include <linux/vmalloc.h>
  #include <linux/init.h>
353ab6e97   Ingo Molnar   [PATCH] sem2mutex...
36
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
  
  static int __init alloc_workspaces(void)
  {
565d76cb7   Jim Keniston   zlib: slim down z...
40
41
  	def_strm.workspace = vmalloc(zlib_deflate_workspacesize(MAX_WBITS,
  							MAX_MEM_LEVEL));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
  	if (!def_strm.workspace) {
565d76cb7   Jim Keniston   zlib: slim down z...
43
44
  		printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace
  ", zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
  		return -ENOMEM;
  	}
565d76cb7   Jim Keniston   zlib: slim down z...
47
48
  	D1(printk(KERN_DEBUG "Allocated %d bytes for deflate workspace
  ", zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
  	inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
  	if (!inf_strm.workspace) {
  		printk(KERN_WARNING "Failed to allocate %d bytes for inflate workspace
  ", zlib_inflate_workspacesize());
  		vfree(def_strm.workspace);
  		return -ENOMEM;
  	}
  	D1(printk(KERN_DEBUG "Allocated %d bytes for inflate workspace
  ", zlib_inflate_workspacesize()));
  	return 0;
  }
  
  static void free_workspaces(void)
  {
  	vfree(def_strm.workspace);
  	vfree(inf_strm.workspace);
  }
  #else
  #define alloc_workspaces() (0)
  #define free_workspaces() do { } while(0)
  #endif /* __KERNEL__ */
75c96f858   Adrian Bunk   [PATCH] make some...
70
71
  static int jffs2_zlib_compress(unsigned char *data_in,
  			       unsigned char *cpage_out,
088bd455c   Mike Frysinger   jffs2: drop unuse...
72
  			       uint32_t *sourcelen, uint32_t *dstlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
75
76
77
  {
  	int ret;
  
  	if (*dstlen <= STREAM_END_SPACE)
  		return -1;
353ab6e97   Ingo Molnar   [PATCH] sem2mutex...
78
  	mutex_lock(&deflate_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
81
82
  
  	if (Z_OK != zlib_deflateInit(&def_strm, 3)) {
  		printk(KERN_WARNING "deflateInit failed
  ");
353ab6e97   Ingo Molnar   [PATCH] sem2mutex...
83
  		mutex_unlock(&deflate_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
86
87
88
  		return -1;
  	}
  
  	def_strm.next_in = data_in;
  	def_strm.total_in = 0;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
89

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
92
93
94
95
96
97
98
99
  	def_strm.next_out = cpage_out;
  	def_strm.total_out = 0;
  
  	while (def_strm.total_out < *dstlen - STREAM_END_SPACE && def_strm.total_in < *sourcelen) {
  		def_strm.avail_out = *dstlen - (def_strm.total_out + STREAM_END_SPACE);
  		def_strm.avail_in = min((unsigned)(*sourcelen-def_strm.total_in), def_strm.avail_out);
  		D1(printk(KERN_DEBUG "calling deflate with avail_in %d, avail_out %d
  ",
  			  def_strm.avail_in, def_strm.avail_out));
  		ret = zlib_deflate(&def_strm, Z_PARTIAL_FLUSH);
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
100
101
  		D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
104
105
106
  			  def_strm.avail_in, def_strm.avail_out, def_strm.total_in, def_strm.total_out));
  		if (ret != Z_OK) {
  			D1(printk(KERN_DEBUG "deflate in loop returned %d
  ", ret));
  			zlib_deflateEnd(&def_strm);
353ab6e97   Ingo Molnar   [PATCH] sem2mutex...
107
  			mutex_unlock(&deflate_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
  			return -1;
  		}
  	}
  	def_strm.avail_out += STREAM_END_SPACE;
  	def_strm.avail_in = 0;
  	ret = zlib_deflate(&def_strm, Z_FINISH);
  	zlib_deflateEnd(&def_strm);
  
  	if (ret != Z_STREAM_END) {
  		D1(printk(KERN_DEBUG "final deflate returned %d
  ", ret));
  		ret = -1;
  		goto out;
  	}
  
  	if (def_strm.total_out >= def_strm.total_in) {
  		D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld; failing
  ",
  			  def_strm.total_in, def_strm.total_out));
  		ret = -1;
  		goto out;
  	}
  
  	D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld
  ",
  		  def_strm.total_in, def_strm.total_out));
  
  	*dstlen = def_strm.total_out;
  	*sourcelen = def_strm.total_in;
  	ret = 0;
   out:
353ab6e97   Ingo Molnar   [PATCH] sem2mutex...
139
  	mutex_unlock(&deflate_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
  	return ret;
  }
75c96f858   Adrian Bunk   [PATCH] make some...
142
143
  static int jffs2_zlib_decompress(unsigned char *data_in,
  				 unsigned char *cpage_out,
088bd455c   Mike Frysinger   jffs2: drop unuse...
144
  				 uint32_t srclen, uint32_t destlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
  {
  	int ret;
  	int wbits = MAX_WBITS;
353ab6e97   Ingo Molnar   [PATCH] sem2mutex...
148
  	mutex_lock(&inflate_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
151
152
  
  	inf_strm.next_in = data_in;
  	inf_strm.avail_in = srclen;
  	inf_strm.total_in = 0;
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
153

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
  	inf_strm.next_out = cpage_out;
  	inf_strm.avail_out = destlen;
  	inf_strm.total_out = 0;
  
  	/* If it's deflate, and it's got no preset dictionary, then
  	   we can tell zlib to skip the adler32 check. */
  	if (srclen > 2 && !(data_in[1] & PRESET_DICT) &&
  	    ((data_in[0] & 0x0f) == Z_DEFLATED) &&
  	    !(((data_in[0]<<8) + data_in[1]) % 31)) {
  
  		D2(printk(KERN_DEBUG "inflate skipping adler32
  "));
  		wbits = -((data_in[0] >> 4) + 8);
  		inf_strm.next_in += 2;
  		inf_strm.avail_in -= 2;
  	} else {
  		/* Let this remain D1 for now -- it should never happen */
  		D1(printk(KERN_DEBUG "inflate not skipping adler32
  "));
  	}
  
  
  	if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) {
  		printk(KERN_WARNING "inflateInit failed
  ");
353ab6e97   Ingo Molnar   [PATCH] sem2mutex...
179
  		mutex_unlock(&inflate_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
183
184
185
186
187
188
189
  		return 1;
  	}
  
  	while((ret = zlib_inflate(&inf_strm, Z_FINISH)) == Z_OK)
  		;
  	if (ret != Z_STREAM_END) {
  		printk(KERN_NOTICE "inflate returned %d
  ", ret);
  	}
  	zlib_inflateEnd(&inf_strm);
353ab6e97   Ingo Molnar   [PATCH] sem2mutex...
190
  	mutex_unlock(&inflate_mutex);
ef53cb02f   David Woodhouse   [JFFS2] Whitespac...
191
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
  }
  
  static struct jffs2_compressor jffs2_zlib_comp = {
      .priority = JFFS2_ZLIB_PRIORITY,
      .name = "zlib",
      .compr = JFFS2_COMPR_ZLIB,
      .compress = &jffs2_zlib_compress,
      .decompress = &jffs2_zlib_decompress,
  #ifdef JFFS2_ZLIB_DISABLED
      .disabled = 1,
  #else
      .disabled = 0,
  #endif
  };
  
  int __init jffs2_zlib_init(void)
  {
      int ret;
  
      ret = alloc_workspaces();
      if (ret)
ef53cb02f   David Woodhouse   [JFFS2] Whitespac...
213
  	    return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
215
216
  
      ret = jffs2_register_compressor(&jffs2_zlib_comp);
      if (ret)
ef53cb02f   David Woodhouse   [JFFS2] Whitespac...
217
  	    free_workspaces();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
220
221
222
223
224
225
226
  
      return ret;
  }
  
  void jffs2_zlib_exit(void)
  {
      jffs2_unregister_compressor(&jffs2_zlib_comp);
      free_workspaces();
  }