Blame view

fs/btrfs/zlib.c 10.4 KB
c8b978188   Chris Mason   Btrfs: Add zlib c...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  /*
   * Copyright (C) 2008 Oracle.  All rights reserved.
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public
   * License v2 as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * General Public License for more details.
   *
   * You should have received a copy of the GNU General Public
   * License along with this program; if not, write to the
   * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   * Boston, MA 021110-1307, USA.
   *
   * 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 ...
27
  #include <linux/mm.h>
c8b978188   Chris Mason   Btrfs: Add zlib c...
28
29
30
31
32
  #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...
33
  #include <linux/refcount.h>
b2950863c   Christoph Hellwig   Btrfs: make thing...
34
  #include "compression.h"
c8b978188   Chris Mason   Btrfs: Add zlib c...
35

c8b978188   Chris Mason   Btrfs: Add zlib c...
36
  struct workspace {
788099134   Sergey Senozhatsky   btrfs compression...
37
  	z_stream strm;
c8b978188   Chris Mason   Btrfs: Add zlib c...
38
39
40
  	char *buf;
  	struct list_head list;
  };
261507a02   Li Zefan   btrfs: Allow to a...
41
42
43
  static void zlib_free_workspace(struct list_head *ws)
  {
  	struct workspace *workspace = list_entry(ws, struct workspace, list);
c8b978188   Chris Mason   Btrfs: Add zlib c...
44

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

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

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

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

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

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

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

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

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

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

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

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

3a39c18d6   Li Zefan   btrfs: Extract du...
261
262
  		ret2 = btrfs_decompress_buf2page(workspace->buf, buf_start,
  						 total_out, disk_start,
974b1adc3   Christoph Hellwig   btrfs: use bio it...
263
  						 orig_bio);
3a39c18d6   Li Zefan   btrfs: Extract du...
264
265
266
  		if (ret2 == 0) {
  			ret = 0;
  			goto done;
c8b978188   Chris Mason   Btrfs: Add zlib c...
267
  		}
3a39c18d6   Li Zefan   btrfs: Extract du...
268

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

788099134   Sergey Senozhatsky   btrfs compression...
272
  		if (workspace->strm.avail_in == 0) {
c8b978188   Chris Mason   Btrfs: Add zlib c...
273
274
275
276
277
278
279
280
  			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...
281
282
283
  			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...
284
  							   PAGE_SIZE);
c8b978188   Chris Mason   Btrfs: Add zlib c...
285
286
  		}
  	}
d397712bc   Chris Mason   Btrfs: Fix checkp...
287
  	if (ret != Z_STREAM_END)
60e1975ac   Zach Brown   btrfs: return err...
288
  		ret = -EIO;
d397712bc   Chris Mason   Btrfs: Fix checkp...
289
  	else
c8b978188   Chris Mason   Btrfs: Add zlib c...
290
  		ret = 0;
c8b978188   Chris Mason   Btrfs: Add zlib c...
291
  done:
788099134   Sergey Senozhatsky   btrfs compression...
292
  	zlib_inflateEnd(&workspace->strm);
c8b978188   Chris Mason   Btrfs: Add zlib c...
293
294
  	if (data_in)
  		kunmap(pages_in[page_in_index]);
2f19cad94   Chris Mason   btrfs: zero out l...
295
  	if (!ret)
974b1adc3   Christoph Hellwig   btrfs: use bio it...
296
  		zero_fill_bio(orig_bio);
c8b978188   Chris Mason   Btrfs: Add zlib c...
297
298
  	return ret;
  }
261507a02   Li Zefan   btrfs: Allow to a...
299
300
301
302
  static 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...
303
  {
261507a02   Li Zefan   btrfs: Allow to a...
304
  	struct workspace *workspace = list_entry(ws, struct workspace, list);
c8b978188   Chris Mason   Btrfs: Add zlib c...
305
306
  	int ret = 0;
  	int wbits = MAX_WBITS;
2f19cad94   Chris Mason   btrfs: zero out l...
307
  	unsigned long bytes_left;
c8b978188   Chris Mason   Btrfs: Add zlib c...
308
  	unsigned long total_out = 0;
2f19cad94   Chris Mason   btrfs: zero out l...
309
  	unsigned long pg_offset = 0;
c8b978188   Chris Mason   Btrfs: Add zlib c...
310
  	char *kaddr;
2f19cad94   Chris Mason   btrfs: zero out l...
311
312
  	destlen = min_t(unsigned long, destlen, PAGE_SIZE);
  	bytes_left = destlen;
788099134   Sergey Senozhatsky   btrfs compression...
313
314
315
  	workspace->strm.next_in = data_in;
  	workspace->strm.avail_in = srclen;
  	workspace->strm.total_in = 0;
c8b978188   Chris Mason   Btrfs: Add zlib c...
316

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

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

d397712bc   Chris Mason   Btrfs: Fix checkp...
354
  		if (total_out > start_byte && buf_start < start_byte)
c8b978188   Chris Mason   Btrfs: Add zlib c...
355
  			buf_offset = start_byte - buf_start;
d397712bc   Chris Mason   Btrfs: Fix checkp...
356
  		else
c8b978188   Chris Mason   Btrfs: Add zlib c...
357
  			buf_offset = 0;
c8b978188   Chris Mason   Btrfs: Add zlib c...
358

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

788099134   Sergey Senozhatsky   btrfs compression...
378
  	zlib_inflateEnd(&workspace->strm);
2f19cad94   Chris Mason   btrfs: zero out l...
379
380
381
382
383
384
385
386
387
388
389
  
  	/*
  	 * 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...
390
391
  	return ret;
  }
e8c9f1860   David Sterba   btrfs: constify s...
392
  const struct btrfs_compress_op btrfs_zlib_compress = {
261507a02   Li Zefan   btrfs: Allow to a...
393
394
395
  	.alloc_workspace	= zlib_alloc_workspace,
  	.free_workspace		= zlib_free_workspace,
  	.compress_pages		= zlib_compress_pages,
974b1adc3   Christoph Hellwig   btrfs: use bio it...
396
  	.decompress_bio		= zlib_decompress_bio,
261507a02   Li Zefan   btrfs: Allow to a...
397
398
  	.decompress		= zlib_decompress,
  };