Blame view

fs/btrfs/zlib.c 9.92 KB
c1d7c514f   David Sterba   btrfs: replace GP...
1
  // SPDX-License-Identifier: GPL-2.0
c8b978188   Chris Mason   Btrfs: Add zlib c...
2
3
4
  /*
   * Copyright (C) 2008 Oracle.  All rights reserved.
   *
c8b978188   Chris Mason   Btrfs: Add zlib c...
5
6
7
8
9
10
11
12
13
   * Based on jffs2 zlib code:
   * Copyright © 2001-2007 Red Hat, Inc.
   * Created by David Woodhouse <dwmw2@infradead.org>
   */
  
  #include <linux/kernel.h>
  #include <linux/slab.h>
  #include <linux/zlib.h>
  #include <linux/zutil.h>
6acafd1ef   David Sterba   btrfs: switch to ...
14
  #include <linux/mm.h>
c8b978188   Chris Mason   Btrfs: Add zlib c...
15
16
17
18
19
  #include <linux/init.h>
  #include <linux/err.h>
  #include <linux/sched.h>
  #include <linux/pagemap.h>
  #include <linux/bio.h>
e1ddce71d   Anand Jain   btrfs: reduce arg...
20
  #include <linux/refcount.h>
b2950863c   Christoph Hellwig   Btrfs: make thing...
21
  #include "compression.h"
c8b978188   Chris Mason   Btrfs: Add zlib c...
22

c8b978188   Chris Mason   Btrfs: Add zlib c...
23
  struct workspace {
788099134   Sergey Senozhatsky   btrfs compression...
24
  	z_stream strm;
c8b978188   Chris Mason   Btrfs: Add zlib c...
25
26
  	char *buf;
  	struct list_head list;
f51d2b591   David Sterba   btrfs: allow to s...
27
  	int level;
c8b978188   Chris Mason   Btrfs: Add zlib c...
28
  };
92ee55303   Dennis Zhou   btrfs: move to fu...
29
  static struct workspace_manager wsm;
d20f395f9   David Sterba   btrfs: compressio...
30
  struct list_head *zlib_get_workspace(unsigned int level)
92ee55303   Dennis Zhou   btrfs: move to fu...
31
  {
5907a9bb1   David Sterba   btrfs: compressio...
32
  	struct list_head *ws = btrfs_get_workspace(BTRFS_COMPRESS_ZLIB, level);
d0ab62ce2   Dennis Zhou   btrfs: change set...
33
34
35
36
37
  	struct workspace *workspace = list_entry(ws, struct workspace, list);
  
  	workspace->level = level;
  
  	return ws;
92ee55303   Dennis Zhou   btrfs: move to fu...
38
  }
d20f395f9   David Sterba   btrfs: compressio...
39
  void zlib_free_workspace(struct list_head *ws)
261507a02   Li Zefan   btrfs: Allow to a...
40
41
  {
  	struct workspace *workspace = list_entry(ws, struct workspace, list);
c8b978188   Chris Mason   Btrfs: Add zlib c...
42

6acafd1ef   David Sterba   btrfs: switch to ...
43
  	kvfree(workspace->strm.workspace);
261507a02   Li Zefan   btrfs: Allow to a...
44
45
46
  	kfree(workspace->buf);
  	kfree(workspace);
  }
d20f395f9   David Sterba   btrfs: compressio...
47
  struct list_head *zlib_alloc_workspace(unsigned int level)
c8b978188   Chris Mason   Btrfs: Add zlib c...
48
49
  {
  	struct workspace *workspace;
788099134   Sergey Senozhatsky   btrfs compression...
50
  	int workspacesize;
8844355df   Li Zefan   btrfs: Fix bugs i...
51

389a6cfc2   David Sterba   btrfs: switch kma...
52
  	workspace = kzalloc(sizeof(*workspace), GFP_KERNEL);
261507a02   Li Zefan   btrfs: Allow to a...
53
54
  	if (!workspace)
  		return ERR_PTR(-ENOMEM);
c8b978188   Chris Mason   Btrfs: Add zlib c...
55

788099134   Sergey Senozhatsky   btrfs compression...
56
57
  	workspacesize = max(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL),
  			zlib_inflate_workspacesize());
6acafd1ef   David Sterba   btrfs: switch to ...
58
  	workspace->strm.workspace = kvmalloc(workspacesize, GFP_KERNEL);
7bf499430   Dennis Zhou   btrfs: plumb leve...
59
  	workspace->level = level;
389a6cfc2   David Sterba   btrfs: switch kma...
60
  	workspace->buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
788099134   Sergey Senozhatsky   btrfs compression...
61
  	if (!workspace->strm.workspace || !workspace->buf)
261507a02   Li Zefan   btrfs: Allow to a...
62
  		goto fail;
c8b978188   Chris Mason   Btrfs: Add zlib c...
63

261507a02   Li Zefan   btrfs: Allow to a...
64
  	INIT_LIST_HEAD(&workspace->list);
c8b978188   Chris Mason   Btrfs: Add zlib c...
65

261507a02   Li Zefan   btrfs: Allow to a...
66
67
68
69
  	return &workspace->list;
  fail:
  	zlib_free_workspace(&workspace->list);
  	return ERR_PTR(-ENOMEM);
c8b978188   Chris Mason   Btrfs: Add zlib c...
70
  }
c4bf665a3   David Sterba   btrfs: export com...
71
72
73
  int zlib_compress_pages(struct list_head *ws, struct address_space *mapping,
  		u64 start, struct page **pages, unsigned long *out_pages,
  		unsigned long *total_in, unsigned long *total_out)
c8b978188   Chris Mason   Btrfs: Add zlib c...
74
  {
261507a02   Li Zefan   btrfs: Allow to a...
75
  	struct workspace *workspace = list_entry(ws, struct workspace, list);
c8b978188   Chris Mason   Btrfs: Add zlib c...
76
  	int ret;
c8b978188   Chris Mason   Btrfs: Add zlib c...
77
78
79
80
81
  	char *data_in;
  	char *cpage_out;
  	int nr_pages = 0;
  	struct page *in_page = NULL;
  	struct page *out_page = NULL;
c8b978188   Chris Mason   Btrfs: Add zlib c...
82
  	unsigned long bytes_left;
38c314640   David Sterba   btrfs: merge leng...
83
  	unsigned long len = *total_out;
4d3a800eb   David Sterba   btrfs: merge nr_p...
84
  	unsigned long nr_dest_pages = *out_pages;
e5d749023   David Sterba   btrfs: derive max...
85
  	const unsigned long max_out = nr_dest_pages * PAGE_SIZE;
c8b978188   Chris Mason   Btrfs: Add zlib c...
86
87
88
89
  
  	*out_pages = 0;
  	*total_out = 0;
  	*total_in = 0;
f51d2b591   David Sterba   btrfs: allow to s...
90
  	if (Z_OK != zlib_deflateInit(&workspace->strm, workspace->level)) {
62e855771   Jeff Mahoney   btrfs: convert pr...
91
92
  		pr_warn("BTRFS: deflateInit failed
  ");
60e1975ac   Zach Brown   btrfs: return err...
93
  		ret = -EIO;
c8b978188   Chris Mason   Btrfs: Add zlib c...
94
95
  		goto out;
  	}
788099134   Sergey Senozhatsky   btrfs compression...
96
97
  	workspace->strm.total_in = 0;
  	workspace->strm.total_out = 0;
c8b978188   Chris Mason   Btrfs: Add zlib c...
98

09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
99
  	in_page = find_get_page(mapping, start >> PAGE_SHIFT);
c8b978188   Chris Mason   Btrfs: Add zlib c...
100
101
102
  	data_in = kmap(in_page);
  
  	out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
4b72029dc   Li Zefan   btrfs: Fix error ...
103
  	if (out_page == NULL) {
60e1975ac   Zach Brown   btrfs: return err...
104
  		ret = -ENOMEM;
4b72029dc   Li Zefan   btrfs: Fix error ...
105
106
  		goto out;
  	}
c8b978188   Chris Mason   Btrfs: Add zlib c...
107
108
109
  	cpage_out = kmap(out_page);
  	pages[0] = out_page;
  	nr_pages = 1;
788099134   Sergey Senozhatsky   btrfs compression...
110
111
  	workspace->strm.next_in = data_in;
  	workspace->strm.next_out = cpage_out;
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
112
113
  	workspace->strm.avail_out = PAGE_SIZE;
  	workspace->strm.avail_in = min(len, PAGE_SIZE);
c8b978188   Chris Mason   Btrfs: Add zlib c...
114

788099134   Sergey Senozhatsky   btrfs compression...
115
116
  	while (workspace->strm.total_in < len) {
  		ret = zlib_deflate(&workspace->strm, Z_SYNC_FLUSH);
c8b978188   Chris Mason   Btrfs: Add zlib c...
117
  		if (ret != Z_OK) {
62e855771   Jeff Mahoney   btrfs: convert pr...
118
119
  			pr_debug("BTRFS: deflate in loop returned %d
  ",
c8b978188   Chris Mason   Btrfs: Add zlib c...
120
  			       ret);
788099134   Sergey Senozhatsky   btrfs compression...
121
  			zlib_deflateEnd(&workspace->strm);
60e1975ac   Zach Brown   btrfs: return err...
122
  			ret = -EIO;
c8b978188   Chris Mason   Btrfs: Add zlib c...
123
124
125
126
  			goto out;
  		}
  
  		/* we're making it bigger, give up */
788099134   Sergey Senozhatsky   btrfs compression...
127
128
129
  		if (workspace->strm.total_in > 8192 &&
  		    workspace->strm.total_in <
  		    workspace->strm.total_out) {
130d5b415   David Sterba   btrfs: use E2BIG ...
130
  			ret = -E2BIG;
c8b978188   Chris Mason   Btrfs: Add zlib c...
131
132
133
134
135
136
  			goto out;
  		}
  		/* we need another page for writing out.  Test this
  		 * before the total_in so we will pull in a new page for
  		 * the stream end if required
  		 */
788099134   Sergey Senozhatsky   btrfs compression...
137
  		if (workspace->strm.avail_out == 0) {
c8b978188   Chris Mason   Btrfs: Add zlib c...
138
139
140
  			kunmap(out_page);
  			if (nr_pages == nr_dest_pages) {
  				out_page = NULL;
60e1975ac   Zach Brown   btrfs: return err...
141
  				ret = -E2BIG;
c8b978188   Chris Mason   Btrfs: Add zlib c...
142
143
144
  				goto out;
  			}
  			out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
4b72029dc   Li Zefan   btrfs: Fix error ...
145
  			if (out_page == NULL) {
60e1975ac   Zach Brown   btrfs: return err...
146
  				ret = -ENOMEM;
4b72029dc   Li Zefan   btrfs: Fix error ...
147
148
  				goto out;
  			}
c8b978188   Chris Mason   Btrfs: Add zlib c...
149
150
151
  			cpage_out = kmap(out_page);
  			pages[nr_pages] = out_page;
  			nr_pages++;
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
152
  			workspace->strm.avail_out = PAGE_SIZE;
788099134   Sergey Senozhatsky   btrfs compression...
153
  			workspace->strm.next_out = cpage_out;
c8b978188   Chris Mason   Btrfs: Add zlib c...
154
155
  		}
  		/* we're all done */
788099134   Sergey Senozhatsky   btrfs compression...
156
  		if (workspace->strm.total_in >= len)
c8b978188   Chris Mason   Btrfs: Add zlib c...
157
158
159
  			break;
  
  		/* we've read in a full page, get a new one */
788099134   Sergey Senozhatsky   btrfs compression...
160
161
  		if (workspace->strm.avail_in == 0) {
  			if (workspace->strm.total_out > max_out)
c8b978188   Chris Mason   Btrfs: Add zlib c...
162
  				break;
788099134   Sergey Senozhatsky   btrfs compression...
163
  			bytes_left = len - workspace->strm.total_in;
c8b978188   Chris Mason   Btrfs: Add zlib c...
164
  			kunmap(in_page);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
165
  			put_page(in_page);
c8b978188   Chris Mason   Btrfs: Add zlib c...
166

09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
167
  			start += PAGE_SIZE;
c8b978188   Chris Mason   Btrfs: Add zlib c...
168
  			in_page = find_get_page(mapping,
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
169
  						start >> PAGE_SHIFT);
c8b978188   Chris Mason   Btrfs: Add zlib c...
170
  			data_in = kmap(in_page);
788099134   Sergey Senozhatsky   btrfs compression...
171
  			workspace->strm.avail_in = min(bytes_left,
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
172
  							   PAGE_SIZE);
788099134   Sergey Senozhatsky   btrfs compression...
173
  			workspace->strm.next_in = data_in;
c8b978188   Chris Mason   Btrfs: Add zlib c...
174
175
  		}
  	}
788099134   Sergey Senozhatsky   btrfs compression...
176
177
178
  	workspace->strm.avail_in = 0;
  	ret = zlib_deflate(&workspace->strm, Z_FINISH);
  	zlib_deflateEnd(&workspace->strm);
c8b978188   Chris Mason   Btrfs: Add zlib c...
179
180
  
  	if (ret != Z_STREAM_END) {
60e1975ac   Zach Brown   btrfs: return err...
181
  		ret = -EIO;
c8b978188   Chris Mason   Btrfs: Add zlib c...
182
183
  		goto out;
  	}
788099134   Sergey Senozhatsky   btrfs compression...
184
  	if (workspace->strm.total_out >= workspace->strm.total_in) {
60e1975ac   Zach Brown   btrfs: return err...
185
  		ret = -E2BIG;
c8b978188   Chris Mason   Btrfs: Add zlib c...
186
187
188
189
  		goto out;
  	}
  
  	ret = 0;
788099134   Sergey Senozhatsky   btrfs compression...
190
191
  	*total_out = workspace->strm.total_out;
  	*total_in = workspace->strm.total_in;
c8b978188   Chris Mason   Btrfs: Add zlib c...
192
193
194
195
196
197
198
  out:
  	*out_pages = nr_pages;
  	if (out_page)
  		kunmap(out_page);
  
  	if (in_page) {
  		kunmap(in_page);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
199
  		put_page(in_page);
c8b978188   Chris Mason   Btrfs: Add zlib c...
200
  	}
c8b978188   Chris Mason   Btrfs: Add zlib c...
201
202
  	return ret;
  }
c4bf665a3   David Sterba   btrfs: export com...
203
  int zlib_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
c8b978188   Chris Mason   Btrfs: Add zlib c...
204
  {
261507a02   Li Zefan   btrfs: Allow to a...
205
  	struct workspace *workspace = list_entry(ws, struct workspace, list);
3a39c18d6   Li Zefan   btrfs: Extract du...
206
  	int ret = 0, ret2;
c8b978188   Chris Mason   Btrfs: Add zlib c...
207
  	int wbits = MAX_WBITS;
c8b978188   Chris Mason   Btrfs: Add zlib c...
208
209
  	char *data_in;
  	size_t total_out = 0;
c8b978188   Chris Mason   Btrfs: Add zlib c...
210
  	unsigned long page_in_index = 0;
e1ddce71d   Anand Jain   btrfs: reduce arg...
211
  	size_t srclen = cb->compressed_len;
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
212
  	unsigned long total_pages_in = DIV_ROUND_UP(srclen, PAGE_SIZE);
c8b978188   Chris Mason   Btrfs: Add zlib c...
213
  	unsigned long buf_start;
e1ddce71d   Anand Jain   btrfs: reduce arg...
214
215
216
  	struct page **pages_in = cb->compressed_pages;
  	u64 disk_start = cb->start;
  	struct bio *orig_bio = cb->orig_bio;
c8b978188   Chris Mason   Btrfs: Add zlib c...
217

c8b978188   Chris Mason   Btrfs: Add zlib c...
218
  	data_in = kmap(pages_in[page_in_index]);
788099134   Sergey Senozhatsky   btrfs compression...
219
  	workspace->strm.next_in = data_in;
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
220
  	workspace->strm.avail_in = min_t(size_t, srclen, PAGE_SIZE);
788099134   Sergey Senozhatsky   btrfs compression...
221
  	workspace->strm.total_in = 0;
c8b978188   Chris Mason   Btrfs: Add zlib c...
222

788099134   Sergey Senozhatsky   btrfs compression...
223
224
  	workspace->strm.total_out = 0;
  	workspace->strm.next_out = workspace->buf;
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
225
  	workspace->strm.avail_out = PAGE_SIZE;
c8b978188   Chris Mason   Btrfs: Add zlib c...
226
227
228
229
230
231
232
233
  
  	/* 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)) {
  
  		wbits = -((data_in[0] >> 4) + 8);
788099134   Sergey Senozhatsky   btrfs compression...
234
235
  		workspace->strm.next_in += 2;
  		workspace->strm.avail_in -= 2;
c8b978188   Chris Mason   Btrfs: Add zlib c...
236
  	}
788099134   Sergey Senozhatsky   btrfs compression...
237
  	if (Z_OK != zlib_inflateInit2(&workspace->strm, wbits)) {
62e855771   Jeff Mahoney   btrfs: convert pr...
238
239
  		pr_warn("BTRFS: inflateInit failed
  ");
d1111a754   Nick Terrell   btrfs: Call kunma...
240
  		kunmap(pages_in[page_in_index]);
60e1975ac   Zach Brown   btrfs: return err...
241
  		return -EIO;
c8b978188   Chris Mason   Btrfs: Add zlib c...
242
  	}
788099134   Sergey Senozhatsky   btrfs compression...
243
244
  	while (workspace->strm.total_in < srclen) {
  		ret = zlib_inflate(&workspace->strm, Z_NO_FLUSH);
d397712bc   Chris Mason   Btrfs: Fix checkp...
245
  		if (ret != Z_OK && ret != Z_STREAM_END)
c8b978188   Chris Mason   Btrfs: Add zlib c...
246
  			break;
c8b978188   Chris Mason   Btrfs: Add zlib c...
247

3a39c18d6   Li Zefan   btrfs: Extract du...
248
  		buf_start = total_out;
788099134   Sergey Senozhatsky   btrfs compression...
249
  		total_out = workspace->strm.total_out;
c8b978188   Chris Mason   Btrfs: Add zlib c...
250

3a39c18d6   Li Zefan   btrfs: Extract du...
251
252
  		/* we didn't make progress in this inflate call, we're done */
  		if (buf_start == total_out)
c8b978188   Chris Mason   Btrfs: Add zlib c...
253
  			break;
c8b978188   Chris Mason   Btrfs: Add zlib c...
254

3a39c18d6   Li Zefan   btrfs: Extract du...
255
256
  		ret2 = btrfs_decompress_buf2page(workspace->buf, buf_start,
  						 total_out, disk_start,
974b1adc3   Christoph Hellwig   btrfs: use bio it...
257
  						 orig_bio);
3a39c18d6   Li Zefan   btrfs: Extract du...
258
259
260
  		if (ret2 == 0) {
  			ret = 0;
  			goto done;
c8b978188   Chris Mason   Btrfs: Add zlib c...
261
  		}
3a39c18d6   Li Zefan   btrfs: Extract du...
262

788099134   Sergey Senozhatsky   btrfs compression...
263
  		workspace->strm.next_out = workspace->buf;
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
264
  		workspace->strm.avail_out = PAGE_SIZE;
c8b978188   Chris Mason   Btrfs: Add zlib c...
265

788099134   Sergey Senozhatsky   btrfs compression...
266
  		if (workspace->strm.avail_in == 0) {
c8b978188   Chris Mason   Btrfs: Add zlib c...
267
268
269
270
271
272
273
274
  			unsigned long tmp;
  			kunmap(pages_in[page_in_index]);
  			page_in_index++;
  			if (page_in_index >= total_pages_in) {
  				data_in = NULL;
  				break;
  			}
  			data_in = kmap(pages_in[page_in_index]);
788099134   Sergey Senozhatsky   btrfs compression...
275
276
277
  			workspace->strm.next_in = data_in;
  			tmp = srclen - workspace->strm.total_in;
  			workspace->strm.avail_in = min(tmp,
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
278
  							   PAGE_SIZE);
c8b978188   Chris Mason   Btrfs: Add zlib c...
279
280
  		}
  	}
d397712bc   Chris Mason   Btrfs: Fix checkp...
281
  	if (ret != Z_STREAM_END)
60e1975ac   Zach Brown   btrfs: return err...
282
  		ret = -EIO;
d397712bc   Chris Mason   Btrfs: Fix checkp...
283
  	else
c8b978188   Chris Mason   Btrfs: Add zlib c...
284
  		ret = 0;
c8b978188   Chris Mason   Btrfs: Add zlib c...
285
  done:
788099134   Sergey Senozhatsky   btrfs compression...
286
  	zlib_inflateEnd(&workspace->strm);
c8b978188   Chris Mason   Btrfs: Add zlib c...
287
288
  	if (data_in)
  		kunmap(pages_in[page_in_index]);
2f19cad94   Chris Mason   btrfs: zero out l...
289
  	if (!ret)
974b1adc3   Christoph Hellwig   btrfs: use bio it...
290
  		zero_fill_bio(orig_bio);
c8b978188   Chris Mason   Btrfs: Add zlib c...
291
292
  	return ret;
  }
c4bf665a3   David Sterba   btrfs: export com...
293
294
295
  int zlib_decompress(struct list_head *ws, unsigned char *data_in,
  		struct page *dest_page, unsigned long start_byte, size_t srclen,
  		size_t destlen)
c8b978188   Chris Mason   Btrfs: Add zlib c...
296
  {
261507a02   Li Zefan   btrfs: Allow to a...
297
  	struct workspace *workspace = list_entry(ws, struct workspace, list);
c8b978188   Chris Mason   Btrfs: Add zlib c...
298
299
  	int ret = 0;
  	int wbits = MAX_WBITS;
2f19cad94   Chris Mason   btrfs: zero out l...
300
  	unsigned long bytes_left;
c8b978188   Chris Mason   Btrfs: Add zlib c...
301
  	unsigned long total_out = 0;
2f19cad94   Chris Mason   btrfs: zero out l...
302
  	unsigned long pg_offset = 0;
c8b978188   Chris Mason   Btrfs: Add zlib c...
303
  	char *kaddr;
2f19cad94   Chris Mason   btrfs: zero out l...
304
305
  	destlen = min_t(unsigned long, destlen, PAGE_SIZE);
  	bytes_left = destlen;
788099134   Sergey Senozhatsky   btrfs compression...
306
307
308
  	workspace->strm.next_in = data_in;
  	workspace->strm.avail_in = srclen;
  	workspace->strm.total_in = 0;
c8b978188   Chris Mason   Btrfs: Add zlib c...
309

788099134   Sergey Senozhatsky   btrfs compression...
310
  	workspace->strm.next_out = workspace->buf;
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
311
  	workspace->strm.avail_out = PAGE_SIZE;
788099134   Sergey Senozhatsky   btrfs compression...
312
  	workspace->strm.total_out = 0;
c8b978188   Chris Mason   Btrfs: Add zlib c...
313
314
315
316
317
318
319
  	/* 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)) {
  
  		wbits = -((data_in[0] >> 4) + 8);
788099134   Sergey Senozhatsky   btrfs compression...
320
321
  		workspace->strm.next_in += 2;
  		workspace->strm.avail_in -= 2;
c8b978188   Chris Mason   Btrfs: Add zlib c...
322
  	}
788099134   Sergey Senozhatsky   btrfs compression...
323
  	if (Z_OK != zlib_inflateInit2(&workspace->strm, wbits)) {
62e855771   Jeff Mahoney   btrfs: convert pr...
324
325
  		pr_warn("BTRFS: inflateInit failed
  ");
60e1975ac   Zach Brown   btrfs: return err...
326
  		return -EIO;
c8b978188   Chris Mason   Btrfs: Add zlib c...
327
  	}
d397712bc   Chris Mason   Btrfs: Fix checkp...
328
  	while (bytes_left > 0) {
c8b978188   Chris Mason   Btrfs: Add zlib c...
329
330
331
  		unsigned long buf_start;
  		unsigned long buf_offset;
  		unsigned long bytes;
c8b978188   Chris Mason   Btrfs: Add zlib c...
332

788099134   Sergey Senozhatsky   btrfs compression...
333
  		ret = zlib_inflate(&workspace->strm, Z_NO_FLUSH);
d397712bc   Chris Mason   Btrfs: Fix checkp...
334
  		if (ret != Z_OK && ret != Z_STREAM_END)
c8b978188   Chris Mason   Btrfs: Add zlib c...
335
  			break;
c8b978188   Chris Mason   Btrfs: Add zlib c...
336
337
  
  		buf_start = total_out;
788099134   Sergey Senozhatsky   btrfs compression...
338
  		total_out = workspace->strm.total_out;
c8b978188   Chris Mason   Btrfs: Add zlib c...
339
340
  
  		if (total_out == buf_start) {
60e1975ac   Zach Brown   btrfs: return err...
341
  			ret = -EIO;
c8b978188   Chris Mason   Btrfs: Add zlib c...
342
343
  			break;
  		}
d397712bc   Chris Mason   Btrfs: Fix checkp...
344
  		if (total_out <= start_byte)
c8b978188   Chris Mason   Btrfs: Add zlib c...
345
  			goto next;
c8b978188   Chris Mason   Btrfs: Add zlib c...
346

d397712bc   Chris Mason   Btrfs: Fix checkp...
347
  		if (total_out > start_byte && buf_start < start_byte)
c8b978188   Chris Mason   Btrfs: Add zlib c...
348
  			buf_offset = start_byte - buf_start;
d397712bc   Chris Mason   Btrfs: Fix checkp...
349
  		else
c8b978188   Chris Mason   Btrfs: Add zlib c...
350
  			buf_offset = 0;
c8b978188   Chris Mason   Btrfs: Add zlib c...
351

09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
352
353
  		bytes = min(PAGE_SIZE - pg_offset,
  			    PAGE_SIZE - buf_offset);
c8b978188   Chris Mason   Btrfs: Add zlib c...
354
  		bytes = min(bytes, bytes_left);
7ac687d9e   Cong Wang   btrfs: remove the...
355
  		kaddr = kmap_atomic(dest_page);
c8b978188   Chris Mason   Btrfs: Add zlib c...
356
  		memcpy(kaddr + pg_offset, workspace->buf + buf_offset, bytes);
7ac687d9e   Cong Wang   btrfs: remove the...
357
  		kunmap_atomic(kaddr);
c8b978188   Chris Mason   Btrfs: Add zlib c...
358
359
360
361
  
  		pg_offset += bytes;
  		bytes_left -= bytes;
  next:
788099134   Sergey Senozhatsky   btrfs compression...
362
  		workspace->strm.next_out = workspace->buf;
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
363
  		workspace->strm.avail_out = PAGE_SIZE;
c8b978188   Chris Mason   Btrfs: Add zlib c...
364
  	}
d397712bc   Chris Mason   Btrfs: Fix checkp...
365
366
  
  	if (ret != Z_STREAM_END && bytes_left != 0)
60e1975ac   Zach Brown   btrfs: return err...
367
  		ret = -EIO;
d397712bc   Chris Mason   Btrfs: Fix checkp...
368
  	else
c8b978188   Chris Mason   Btrfs: Add zlib c...
369
  		ret = 0;
d397712bc   Chris Mason   Btrfs: Fix checkp...
370

788099134   Sergey Senozhatsky   btrfs compression...
371
  	zlib_inflateEnd(&workspace->strm);
2f19cad94   Chris Mason   btrfs: zero out l...
372
373
374
375
376
377
378
379
380
381
382
  
  	/*
  	 * this should only happen if zlib returned fewer bytes than we
  	 * expected.  btrfs_get_block is responsible for zeroing from the
  	 * end of the inline extent (destlen) to the end of the page
  	 */
  	if (pg_offset < destlen) {
  		kaddr = kmap_atomic(dest_page);
  		memset(kaddr + pg_offset, 0, destlen - pg_offset);
  		kunmap_atomic(kaddr);
  	}
c8b978188   Chris Mason   Btrfs: Add zlib c...
383
384
  	return ret;
  }
e8c9f1860   David Sterba   btrfs: constify s...
385
  const struct btrfs_compress_op btrfs_zlib_compress = {
be9510453   David Sterba   btrfs: compressio...
386
  	.workspace_manager	= &wsm,
e18333a7c   David Sterba   btrfs: define com...
387
388
  	.max_level		= 9,
  	.default_level		= BTRFS_ZLIB_DEFAULT_LEVEL,
261507a02   Li Zefan   btrfs: Allow to a...
389
  };