Blame view

fs/btrfs/zlib.c 10.5 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
27
28
29
30
31
32
  /*
   * 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>
  #include <linux/vmalloc.h>
  #include <linux/init.h>
  #include <linux/err.h>
  #include <linux/sched.h>
  #include <linux/pagemap.h>
  #include <linux/bio.h>
b2950863c   Christoph Hellwig   Btrfs: make thing...
33
  #include "compression.h"
c8b978188   Chris Mason   Btrfs: Add zlib c...
34

c8b978188   Chris Mason   Btrfs: Add zlib c...
35
  struct workspace {
788099134   Sergey Senozhatsky   btrfs compression...
36
  	z_stream strm;
c8b978188   Chris Mason   Btrfs: Add zlib c...
37
38
39
  	char *buf;
  	struct list_head list;
  };
261507a02   Li Zefan   btrfs: Allow to a...
40
41
42
  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...
43

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

c8b978188   Chris Mason   Btrfs: Add zlib c...
54
  	workspace = kzalloc(sizeof(*workspace), GFP_NOFS);
261507a02   Li Zefan   btrfs: Allow to a...
55
56
  	if (!workspace)
  		return ERR_PTR(-ENOMEM);
c8b978188   Chris Mason   Btrfs: Add zlib c...
57

788099134   Sergey Senozhatsky   btrfs compression...
58
59
60
  	workspacesize = max(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL),
  			zlib_inflate_workspacesize());
  	workspace->strm.workspace = vmalloc(workspacesize);
c8b978188   Chris Mason   Btrfs: Add zlib c...
61
  	workspace->buf = kmalloc(PAGE_CACHE_SIZE, GFP_NOFS);
788099134   Sergey Senozhatsky   btrfs compression...
62
  	if (!workspace->strm.workspace || !workspace->buf)
261507a02   Li Zefan   btrfs: Allow to a...
63
  		goto fail;
c8b978188   Chris Mason   Btrfs: Add zlib c...
64

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

261507a02   Li Zefan   btrfs: Allow to a...
67
68
69
70
  	return &workspace->list;
  fail:
  	zlib_free_workspace(&workspace->list);
  	return ERR_PTR(-ENOMEM);
c8b978188   Chris Mason   Btrfs: Add zlib c...
71
  }
261507a02   Li Zefan   btrfs: Allow to a...
72
73
74
75
76
77
78
79
80
  static int zlib_compress_pages(struct list_head *ws,
  			       struct address_space *mapping,
  			       u64 start, unsigned long len,
  			       struct page **pages,
  			       unsigned long nr_dest_pages,
  			       unsigned long *out_pages,
  			       unsigned long *total_in,
  			       unsigned long *total_out,
  			       unsigned long max_out)
c8b978188   Chris Mason   Btrfs: Add zlib c...
81
  {
261507a02   Li Zefan   btrfs: Allow to a...
82
  	struct workspace *workspace = list_entry(ws, struct workspace, list);
c8b978188   Chris Mason   Btrfs: Add zlib c...
83
  	int ret;
c8b978188   Chris Mason   Btrfs: Add zlib c...
84
85
86
87
88
  	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...
89
90
91
92
93
  	unsigned long bytes_left;
  
  	*out_pages = 0;
  	*total_out = 0;
  	*total_in = 0;
788099134   Sergey Senozhatsky   btrfs compression...
94
  	if (Z_OK != zlib_deflateInit(&workspace->strm, 3)) {
efe120a06   Frank Holton   Btrfs: convert pr...
95
96
  		printk(KERN_WARNING "BTRFS: deflateInit failed
  ");
60e1975ac   Zach Brown   btrfs: return err...
97
  		ret = -EIO;
c8b978188   Chris Mason   Btrfs: Add zlib c...
98
99
  		goto out;
  	}
788099134   Sergey Senozhatsky   btrfs compression...
100
101
  	workspace->strm.total_in = 0;
  	workspace->strm.total_out = 0;
c8b978188   Chris Mason   Btrfs: Add zlib c...
102
103
104
105
106
  
  	in_page = find_get_page(mapping, start >> PAGE_CACHE_SHIFT);
  	data_in = kmap(in_page);
  
  	out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
4b72029dc   Li Zefan   btrfs: Fix error ...
107
  	if (out_page == NULL) {
60e1975ac   Zach Brown   btrfs: return err...
108
  		ret = -ENOMEM;
4b72029dc   Li Zefan   btrfs: Fix error ...
109
110
  		goto out;
  	}
c8b978188   Chris Mason   Btrfs: Add zlib c...
111
112
113
  	cpage_out = kmap(out_page);
  	pages[0] = out_page;
  	nr_pages = 1;
788099134   Sergey Senozhatsky   btrfs compression...
114
115
116
117
  	workspace->strm.next_in = data_in;
  	workspace->strm.next_out = cpage_out;
  	workspace->strm.avail_out = PAGE_CACHE_SIZE;
  	workspace->strm.avail_in = min(len, PAGE_CACHE_SIZE);
c8b978188   Chris Mason   Btrfs: Add zlib c...
118

788099134   Sergey Senozhatsky   btrfs compression...
119
120
  	while (workspace->strm.total_in < len) {
  		ret = zlib_deflate(&workspace->strm, Z_SYNC_FLUSH);
c8b978188   Chris Mason   Btrfs: Add zlib c...
121
  		if (ret != Z_OK) {
efe120a06   Frank Holton   Btrfs: convert pr...
122
123
  			printk(KERN_DEBUG "BTRFS: deflate in loop returned %d
  ",
c8b978188   Chris Mason   Btrfs: Add zlib c...
124
  			       ret);
788099134   Sergey Senozhatsky   btrfs compression...
125
  			zlib_deflateEnd(&workspace->strm);
60e1975ac   Zach Brown   btrfs: return err...
126
  			ret = -EIO;
c8b978188   Chris Mason   Btrfs: Add zlib c...
127
128
129
130
  			goto out;
  		}
  
  		/* we're making it bigger, give up */
788099134   Sergey Senozhatsky   btrfs compression...
131
132
133
  		if (workspace->strm.total_in > 8192 &&
  		    workspace->strm.total_in <
  		    workspace->strm.total_out) {
130d5b415   David Sterba   btrfs: use E2BIG ...
134
  			ret = -E2BIG;
c8b978188   Chris Mason   Btrfs: Add zlib c...
135
136
137
138
139
140
  			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...
141
  		if (workspace->strm.avail_out == 0) {
c8b978188   Chris Mason   Btrfs: Add zlib c...
142
143
144
  			kunmap(out_page);
  			if (nr_pages == nr_dest_pages) {
  				out_page = NULL;
60e1975ac   Zach Brown   btrfs: return err...
145
  				ret = -E2BIG;
c8b978188   Chris Mason   Btrfs: Add zlib c...
146
147
148
  				goto out;
  			}
  			out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
4b72029dc   Li Zefan   btrfs: Fix error ...
149
  			if (out_page == NULL) {
60e1975ac   Zach Brown   btrfs: return err...
150
  				ret = -ENOMEM;
4b72029dc   Li Zefan   btrfs: Fix error ...
151
152
  				goto out;
  			}
c8b978188   Chris Mason   Btrfs: Add zlib c...
153
154
155
  			cpage_out = kmap(out_page);
  			pages[nr_pages] = out_page;
  			nr_pages++;
788099134   Sergey Senozhatsky   btrfs compression...
156
157
  			workspace->strm.avail_out = PAGE_CACHE_SIZE;
  			workspace->strm.next_out = cpage_out;
c8b978188   Chris Mason   Btrfs: Add zlib c...
158
159
  		}
  		/* we're all done */
788099134   Sergey Senozhatsky   btrfs compression...
160
  		if (workspace->strm.total_in >= len)
c8b978188   Chris Mason   Btrfs: Add zlib c...
161
162
163
  			break;
  
  		/* we've read in a full page, get a new one */
788099134   Sergey Senozhatsky   btrfs compression...
164
165
  		if (workspace->strm.avail_in == 0) {
  			if (workspace->strm.total_out > max_out)
c8b978188   Chris Mason   Btrfs: Add zlib c...
166
  				break;
788099134   Sergey Senozhatsky   btrfs compression...
167
  			bytes_left = len - workspace->strm.total_in;
c8b978188   Chris Mason   Btrfs: Add zlib c...
168
169
170
171
172
173
174
  			kunmap(in_page);
  			page_cache_release(in_page);
  
  			start += PAGE_CACHE_SIZE;
  			in_page = find_get_page(mapping,
  						start >> PAGE_CACHE_SHIFT);
  			data_in = kmap(in_page);
788099134   Sergey Senozhatsky   btrfs compression...
175
  			workspace->strm.avail_in = min(bytes_left,
c8b978188   Chris Mason   Btrfs: Add zlib c...
176
  							   PAGE_CACHE_SIZE);
788099134   Sergey Senozhatsky   btrfs compression...
177
  			workspace->strm.next_in = data_in;
c8b978188   Chris Mason   Btrfs: Add zlib c...
178
179
  		}
  	}
788099134   Sergey Senozhatsky   btrfs compression...
180
181
182
  	workspace->strm.avail_in = 0;
  	ret = zlib_deflate(&workspace->strm, Z_FINISH);
  	zlib_deflateEnd(&workspace->strm);
c8b978188   Chris Mason   Btrfs: Add zlib c...
183
184
  
  	if (ret != Z_STREAM_END) {
60e1975ac   Zach Brown   btrfs: return err...
185
  		ret = -EIO;
c8b978188   Chris Mason   Btrfs: Add zlib c...
186
187
  		goto out;
  	}
788099134   Sergey Senozhatsky   btrfs compression...
188
  	if (workspace->strm.total_out >= workspace->strm.total_in) {
60e1975ac   Zach Brown   btrfs: return err...
189
  		ret = -E2BIG;
c8b978188   Chris Mason   Btrfs: Add zlib c...
190
191
192
193
  		goto out;
  	}
  
  	ret = 0;
788099134   Sergey Senozhatsky   btrfs compression...
194
195
  	*total_out = workspace->strm.total_out;
  	*total_in = workspace->strm.total_in;
c8b978188   Chris Mason   Btrfs: Add zlib c...
196
197
198
199
200
201
202
203
204
  out:
  	*out_pages = nr_pages;
  	if (out_page)
  		kunmap(out_page);
  
  	if (in_page) {
  		kunmap(in_page);
  		page_cache_release(in_page);
  	}
c8b978188   Chris Mason   Btrfs: Add zlib c...
205
206
  	return ret;
  }
261507a02   Li Zefan   btrfs: Allow to a...
207
208
209
210
211
  static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
  				  u64 disk_start,
  				  struct bio_vec *bvec,
  				  int vcnt,
  				  size_t srclen)
c8b978188   Chris Mason   Btrfs: Add zlib c...
212
  {
261507a02   Li Zefan   btrfs: Allow to a...
213
  	struct workspace *workspace = list_entry(ws, struct workspace, list);
3a39c18d6   Li Zefan   btrfs: Extract du...
214
  	int ret = 0, ret2;
c8b978188   Chris Mason   Btrfs: Add zlib c...
215
  	int wbits = MAX_WBITS;
c8b978188   Chris Mason   Btrfs: Add zlib c...
216
217
  	char *data_in;
  	size_t total_out = 0;
c8b978188   Chris Mason   Btrfs: Add zlib c...
218
219
  	unsigned long page_in_index = 0;
  	unsigned long page_out_index = 0;
ed6078f70   David Sterba   btrfs: use DIV_RO...
220
  	unsigned long total_pages_in = DIV_ROUND_UP(srclen, PAGE_CACHE_SIZE);
c8b978188   Chris Mason   Btrfs: Add zlib c...
221
  	unsigned long buf_start;
c8b978188   Chris Mason   Btrfs: Add zlib c...
222
  	unsigned long pg_offset;
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
226
227
  	workspace->strm.next_in = data_in;
  	workspace->strm.avail_in = min_t(size_t, srclen, PAGE_CACHE_SIZE);
  	workspace->strm.total_in = 0;
c8b978188   Chris Mason   Btrfs: Add zlib c...
228

788099134   Sergey Senozhatsky   btrfs compression...
229
230
231
  	workspace->strm.total_out = 0;
  	workspace->strm.next_out = workspace->buf;
  	workspace->strm.avail_out = PAGE_CACHE_SIZE;
c8b978188   Chris Mason   Btrfs: Add zlib c...
232
233
234
235
236
237
238
239
240
  	pg_offset = 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)) {
  
  		wbits = -((data_in[0] >> 4) + 8);
788099134   Sergey Senozhatsky   btrfs compression...
241
242
  		workspace->strm.next_in += 2;
  		workspace->strm.avail_in -= 2;
c8b978188   Chris Mason   Btrfs: Add zlib c...
243
  	}
788099134   Sergey Senozhatsky   btrfs compression...
244
  	if (Z_OK != zlib_inflateInit2(&workspace->strm, wbits)) {
efe120a06   Frank Holton   Btrfs: convert pr...
245
246
  		printk(KERN_WARNING "BTRFS: inflateInit failed
  ");
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
263
264
265
266
267
  		ret2 = btrfs_decompress_buf2page(workspace->buf, buf_start,
  						 total_out, disk_start,
  						 bvec, vcnt,
  						 &page_out_index, &pg_offset);
  		if (ret2 == 0) {
  			ret = 0;
  			goto done;
c8b978188   Chris Mason   Btrfs: Add zlib c...
268
  		}
3a39c18d6   Li Zefan   btrfs: Extract du...
269

788099134   Sergey Senozhatsky   btrfs compression...
270
271
  		workspace->strm.next_out = workspace->buf;
  		workspace->strm.avail_out = PAGE_CACHE_SIZE;
c8b978188   Chris Mason   Btrfs: Add zlib c...
272

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

788099134   Sergey Senozhatsky   btrfs compression...
318
319
320
  	workspace->strm.next_out = workspace->buf;
  	workspace->strm.avail_out = PAGE_CACHE_SIZE;
  	workspace->strm.total_out = 0;
c8b978188   Chris Mason   Btrfs: Add zlib c...
321
322
323
324
325
326
327
  	/* 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...
328
329
  		workspace->strm.next_in += 2;
  		workspace->strm.avail_in -= 2;
c8b978188   Chris Mason   Btrfs: Add zlib c...
330
  	}
788099134   Sergey Senozhatsky   btrfs compression...
331
  	if (Z_OK != zlib_inflateInit2(&workspace->strm, wbits)) {
efe120a06   Frank Holton   Btrfs: convert pr...
332
333
  		printk(KERN_WARNING "BTRFS: inflateInit failed
  ");
60e1975ac   Zach Brown   btrfs: return err...
334
  		return -EIO;
c8b978188   Chris Mason   Btrfs: Add zlib c...
335
  	}
d397712bc   Chris Mason   Btrfs: Fix checkp...
336
  	while (bytes_left > 0) {
c8b978188   Chris Mason   Btrfs: Add zlib c...
337
338
339
  		unsigned long buf_start;
  		unsigned long buf_offset;
  		unsigned long bytes;
c8b978188   Chris Mason   Btrfs: Add zlib c...
340

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

d397712bc   Chris Mason   Btrfs: Fix checkp...
355
  		if (total_out > start_byte && buf_start < start_byte)
c8b978188   Chris Mason   Btrfs: Add zlib c...
356
  			buf_offset = start_byte - buf_start;
d397712bc   Chris Mason   Btrfs: Fix checkp...
357
  		else
c8b978188   Chris Mason   Btrfs: Add zlib c...
358
  			buf_offset = 0;
c8b978188   Chris Mason   Btrfs: Add zlib c...
359
360
361
362
  
  		bytes = min(PAGE_CACHE_SIZE - pg_offset,
  			    PAGE_CACHE_SIZE - buf_offset);
  		bytes = min(bytes, bytes_left);
7ac687d9e   Cong Wang   btrfs: remove the...
363
  		kaddr = kmap_atomic(dest_page);
c8b978188   Chris Mason   Btrfs: Add zlib c...
364
  		memcpy(kaddr + pg_offset, workspace->buf + buf_offset, bytes);
7ac687d9e   Cong Wang   btrfs: remove the...
365
  		kunmap_atomic(kaddr);
c8b978188   Chris Mason   Btrfs: Add zlib c...
366
367
368
369
  
  		pg_offset += bytes;
  		bytes_left -= bytes;
  next:
788099134   Sergey Senozhatsky   btrfs compression...
370
371
  		workspace->strm.next_out = workspace->buf;
  		workspace->strm.avail_out = PAGE_CACHE_SIZE;
c8b978188   Chris Mason   Btrfs: Add zlib c...
372
  	}
d397712bc   Chris Mason   Btrfs: Fix checkp...
373
374
  
  	if (ret != Z_STREAM_END && bytes_left != 0)
60e1975ac   Zach Brown   btrfs: return err...
375
  		ret = -EIO;
d397712bc   Chris Mason   Btrfs: Fix checkp...
376
  	else
c8b978188   Chris Mason   Btrfs: Add zlib c...
377
  		ret = 0;
d397712bc   Chris Mason   Btrfs: Fix checkp...
378

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