1c1d7c514SDavid Sterba // SPDX-License-Identifier: GPL-2.0
2c8b97818SChris Mason /*
3c8b97818SChris Mason * Copyright (C) 2008 Oracle. All rights reserved.
4c8b97818SChris Mason *
5c8b97818SChris Mason * Based on jffs2 zlib code:
6c8b97818SChris Mason * Copyright © 2001-2007 Red Hat, Inc.
7c8b97818SChris Mason * Created by David Woodhouse <dwmw2@infradead.org>
8c8b97818SChris Mason */
9c8b97818SChris Mason
10c8b97818SChris Mason #include <linux/kernel.h>
11c8b97818SChris Mason #include <linux/slab.h>
12c8b97818SChris Mason #include <linux/zlib.h>
13c8b97818SChris Mason #include <linux/zutil.h>
146acafd1eSDavid Sterba #include <linux/mm.h>
15c8b97818SChris Mason #include <linux/init.h>
16c8b97818SChris Mason #include <linux/err.h>
17c8b97818SChris Mason #include <linux/sched.h>
18c8b97818SChris Mason #include <linux/pagemap.h>
19c8b97818SChris Mason #include <linux/bio.h>
20e1ddce71SAnand Jain #include <linux/refcount.h>
21b2950863SChristoph Hellwig #include "compression.h"
22c8b97818SChris Mason
233fd396afSMikhail Zaslonko /* workspace buffer size for s390 zlib hardware support */
243fd396afSMikhail Zaslonko #define ZLIB_DFLTCC_BUF_SIZE (4 * PAGE_SIZE)
253fd396afSMikhail Zaslonko
26c8b97818SChris Mason struct workspace {
2778809913SSergey Senozhatsky z_stream strm;
28c8b97818SChris Mason char *buf;
293fd396afSMikhail Zaslonko unsigned int buf_size;
30c8b97818SChris Mason struct list_head list;
31f51d2b59SDavid Sterba int level;
32c8b97818SChris Mason };
33c8b97818SChris Mason
3492ee5530SDennis Zhou static struct workspace_manager wsm;
3592ee5530SDennis Zhou
zlib_get_workspace(unsigned int level)36d20f395fSDavid Sterba struct list_head *zlib_get_workspace(unsigned int level)
3792ee5530SDennis Zhou {
385907a9bbSDavid Sterba struct list_head *ws = btrfs_get_workspace(BTRFS_COMPRESS_ZLIB, level);
39d0ab62ceSDennis Zhou struct workspace *workspace = list_entry(ws, struct workspace, list);
40d0ab62ceSDennis Zhou
41d0ab62ceSDennis Zhou workspace->level = level;
42d0ab62ceSDennis Zhou
43d0ab62ceSDennis Zhou return ws;
4492ee5530SDennis Zhou }
4592ee5530SDennis Zhou
zlib_free_workspace(struct list_head * ws)46d20f395fSDavid Sterba void zlib_free_workspace(struct list_head *ws)
47261507a0SLi Zefan {
48261507a0SLi Zefan struct workspace *workspace = list_entry(ws, struct workspace, list);
49c8b97818SChris Mason
506acafd1eSDavid Sterba kvfree(workspace->strm.workspace);
51261507a0SLi Zefan kfree(workspace->buf);
52261507a0SLi Zefan kfree(workspace);
53261507a0SLi Zefan }
54261507a0SLi Zefan
zlib_alloc_workspace(unsigned int level)55d20f395fSDavid Sterba struct list_head *zlib_alloc_workspace(unsigned int level)
56c8b97818SChris Mason {
57c8b97818SChris Mason struct workspace *workspace;
5878809913SSergey Senozhatsky int workspacesize;
598844355dSLi Zefan
60389a6cfcSDavid Sterba workspace = kzalloc(sizeof(*workspace), GFP_KERNEL);
61261507a0SLi Zefan if (!workspace)
62261507a0SLi Zefan return ERR_PTR(-ENOMEM);
63c8b97818SChris Mason
6478809913SSergey Senozhatsky workspacesize = max(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL),
6578809913SSergey Senozhatsky zlib_inflate_workspacesize());
668ab546bbSDavid Sterba workspace->strm.workspace = kvzalloc(workspacesize, GFP_KERNEL | __GFP_NOWARN);
677bf49943SDennis Zhou workspace->level = level;
683fd396afSMikhail Zaslonko workspace->buf = NULL;
693fd396afSMikhail Zaslonko /*
703fd396afSMikhail Zaslonko * In case of s390 zlib hardware support, allocate lager workspace
713fd396afSMikhail Zaslonko * buffer. If allocator fails, fall back to a single page buffer.
723fd396afSMikhail Zaslonko */
733fd396afSMikhail Zaslonko if (zlib_deflate_dfltcc_enabled()) {
743fd396afSMikhail Zaslonko workspace->buf = kmalloc(ZLIB_DFLTCC_BUF_SIZE,
753fd396afSMikhail Zaslonko __GFP_NOMEMALLOC | __GFP_NORETRY |
763fd396afSMikhail Zaslonko __GFP_NOWARN | GFP_NOIO);
773fd396afSMikhail Zaslonko workspace->buf_size = ZLIB_DFLTCC_BUF_SIZE;
783fd396afSMikhail Zaslonko }
793fd396afSMikhail Zaslonko if (!workspace->buf) {
80389a6cfcSDavid Sterba workspace->buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
813fd396afSMikhail Zaslonko workspace->buf_size = PAGE_SIZE;
823fd396afSMikhail Zaslonko }
8378809913SSergey Senozhatsky if (!workspace->strm.workspace || !workspace->buf)
84261507a0SLi Zefan goto fail;
85c8b97818SChris Mason
86261507a0SLi Zefan INIT_LIST_HEAD(&workspace->list);
87261507a0SLi Zefan
88261507a0SLi Zefan return &workspace->list;
89c8b97818SChris Mason fail:
90261507a0SLi Zefan zlib_free_workspace(&workspace->list);
91261507a0SLi Zefan return ERR_PTR(-ENOMEM);
92c8b97818SChris Mason }
93c8b97818SChris Mason
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)94c4bf665aSDavid Sterba int zlib_compress_pages(struct list_head *ws, struct address_space *mapping,
95c4bf665aSDavid Sterba u64 start, struct page **pages, unsigned long *out_pages,
96c4bf665aSDavid Sterba unsigned long *total_in, unsigned long *total_out)
97c8b97818SChris Mason {
98261507a0SLi Zefan struct workspace *workspace = list_entry(ws, struct workspace, list);
99c8b97818SChris Mason int ret;
100718e5855SFabio M. De Francesco char *data_in = NULL;
101c8b97818SChris Mason char *cpage_out;
102c8b97818SChris Mason int nr_pages = 0;
103c8b97818SChris Mason struct page *in_page = NULL;
104c8b97818SChris Mason struct page *out_page = NULL;
105c8b97818SChris Mason unsigned long bytes_left;
1063fd396afSMikhail Zaslonko unsigned int in_buf_pages;
10738c31464SDavid Sterba unsigned long len = *total_out;
1084d3a800eSDavid Sterba unsigned long nr_dest_pages = *out_pages;
109e5d74902SDavid Sterba const unsigned long max_out = nr_dest_pages * PAGE_SIZE;
110c8b97818SChris Mason
111c8b97818SChris Mason *out_pages = 0;
112c8b97818SChris Mason *total_out = 0;
113c8b97818SChris Mason *total_in = 0;
114c8b97818SChris Mason
115f51d2b59SDavid Sterba if (Z_OK != zlib_deflateInit(&workspace->strm, workspace->level)) {
11662e85577SJeff Mahoney pr_warn("BTRFS: deflateInit failed\n");
11760e1975aSZach Brown ret = -EIO;
118c8b97818SChris Mason goto out;
119c8b97818SChris Mason }
120c8b97818SChris Mason
12178809913SSergey Senozhatsky workspace->strm.total_in = 0;
12278809913SSergey Senozhatsky workspace->strm.total_out = 0;
123c8b97818SChris Mason
124b0ee5e1eSDavid Sterba out_page = alloc_page(GFP_NOFS);
1254b72029dSLi Zefan if (out_page == NULL) {
12660e1975aSZach Brown ret = -ENOMEM;
1274b72029dSLi Zefan goto out;
1284b72029dSLi Zefan }
129718e5855SFabio M. De Francesco cpage_out = page_address(out_page);
130c8b97818SChris Mason pages[0] = out_page;
131c8b97818SChris Mason nr_pages = 1;
132c8b97818SChris Mason
1333fd396afSMikhail Zaslonko workspace->strm.next_in = workspace->buf;
1343fd396afSMikhail Zaslonko workspace->strm.avail_in = 0;
13578809913SSergey Senozhatsky workspace->strm.next_out = cpage_out;
13609cbfeafSKirill A. Shutemov workspace->strm.avail_out = PAGE_SIZE;
137c8b97818SChris Mason
13878809913SSergey Senozhatsky while (workspace->strm.total_in < len) {
1393fd396afSMikhail Zaslonko /*
1403fd396afSMikhail Zaslonko * Get next input pages and copy the contents to
1413fd396afSMikhail Zaslonko * the workspace buffer if required.
1423fd396afSMikhail Zaslonko */
1433fd396afSMikhail Zaslonko if (workspace->strm.avail_in == 0) {
1443fd396afSMikhail Zaslonko bytes_left = len - workspace->strm.total_in;
1453fd396afSMikhail Zaslonko in_buf_pages = min(DIV_ROUND_UP(bytes_left, PAGE_SIZE),
1463fd396afSMikhail Zaslonko workspace->buf_size / PAGE_SIZE);
1473fd396afSMikhail Zaslonko if (in_buf_pages > 1) {
1483fd396afSMikhail Zaslonko int i;
1493fd396afSMikhail Zaslonko
1503fd396afSMikhail Zaslonko for (i = 0; i < in_buf_pages; i++) {
151718e5855SFabio M. De Francesco if (data_in) {
152718e5855SFabio M. De Francesco kunmap_local(data_in);
1533fd396afSMikhail Zaslonko put_page(in_page);
15455276e14SDavid Sterba }
1553fd396afSMikhail Zaslonko in_page = find_get_page(mapping,
1563fd396afSMikhail Zaslonko start >> PAGE_SHIFT);
157718e5855SFabio M. De Francesco data_in = kmap_local_page(in_page);
1589e5e6d4eSDavid Sterba copy_page(workspace->buf + i * PAGE_SIZE,
1599e5e6d4eSDavid Sterba data_in);
1603fd396afSMikhail Zaslonko start += PAGE_SIZE;
1613fd396afSMikhail Zaslonko }
1623fd396afSMikhail Zaslonko workspace->strm.next_in = workspace->buf;
1633fd396afSMikhail Zaslonko } else {
164718e5855SFabio M. De Francesco if (data_in) {
165718e5855SFabio M. De Francesco kunmap_local(data_in);
1663fd396afSMikhail Zaslonko put_page(in_page);
16755276e14SDavid Sterba }
1683fd396afSMikhail Zaslonko in_page = find_get_page(mapping,
1693fd396afSMikhail Zaslonko start >> PAGE_SHIFT);
170718e5855SFabio M. De Francesco data_in = kmap_local_page(in_page);
1713fd396afSMikhail Zaslonko start += PAGE_SIZE;
1723fd396afSMikhail Zaslonko workspace->strm.next_in = data_in;
1733fd396afSMikhail Zaslonko }
1743fd396afSMikhail Zaslonko workspace->strm.avail_in = min(bytes_left,
1753fd396afSMikhail Zaslonko (unsigned long) workspace->buf_size);
1763fd396afSMikhail Zaslonko }
1773fd396afSMikhail Zaslonko
17878809913SSergey Senozhatsky ret = zlib_deflate(&workspace->strm, Z_SYNC_FLUSH);
179c8b97818SChris Mason if (ret != Z_OK) {
18062e85577SJeff Mahoney pr_debug("BTRFS: deflate in loop returned %d\n",
181c8b97818SChris Mason ret);
18278809913SSergey Senozhatsky zlib_deflateEnd(&workspace->strm);
18360e1975aSZach Brown ret = -EIO;
184c8b97818SChris Mason goto out;
185c8b97818SChris Mason }
186c8b97818SChris Mason
187c8b97818SChris Mason /* we're making it bigger, give up */
18878809913SSergey Senozhatsky if (workspace->strm.total_in > 8192 &&
18978809913SSergey Senozhatsky workspace->strm.total_in <
19078809913SSergey Senozhatsky workspace->strm.total_out) {
191130d5b41SDavid Sterba ret = -E2BIG;
192c8b97818SChris Mason goto out;
193c8b97818SChris Mason }
194c8b97818SChris Mason /* we need another page for writing out. Test this
195c8b97818SChris Mason * before the total_in so we will pull in a new page for
196c8b97818SChris Mason * the stream end if required
197c8b97818SChris Mason */
19878809913SSergey Senozhatsky if (workspace->strm.avail_out == 0) {
199c8b97818SChris Mason if (nr_pages == nr_dest_pages) {
20060e1975aSZach Brown ret = -E2BIG;
201c8b97818SChris Mason goto out;
202c8b97818SChris Mason }
203b0ee5e1eSDavid Sterba out_page = alloc_page(GFP_NOFS);
2044b72029dSLi Zefan if (out_page == NULL) {
20560e1975aSZach Brown ret = -ENOMEM;
2064b72029dSLi Zefan goto out;
2074b72029dSLi Zefan }
208718e5855SFabio M. De Francesco cpage_out = page_address(out_page);
209c8b97818SChris Mason pages[nr_pages] = out_page;
210c8b97818SChris Mason nr_pages++;
21109cbfeafSKirill A. Shutemov workspace->strm.avail_out = PAGE_SIZE;
21278809913SSergey Senozhatsky workspace->strm.next_out = cpage_out;
213c8b97818SChris Mason }
214c8b97818SChris Mason /* we're all done */
21578809913SSergey Senozhatsky if (workspace->strm.total_in >= len)
216c8b97818SChris Mason break;
21778809913SSergey Senozhatsky if (workspace->strm.total_out > max_out)
218c8b97818SChris Mason break;
219c8b97818SChris Mason }
22078809913SSergey Senozhatsky workspace->strm.avail_in = 0;
2213fd396afSMikhail Zaslonko /*
2223fd396afSMikhail Zaslonko * Call deflate with Z_FINISH flush parameter providing more output
2233fd396afSMikhail Zaslonko * space but no more input data, until it returns with Z_STREAM_END.
2243fd396afSMikhail Zaslonko */
2253fd396afSMikhail Zaslonko while (ret != Z_STREAM_END) {
22678809913SSergey Senozhatsky ret = zlib_deflate(&workspace->strm, Z_FINISH);
2273fd396afSMikhail Zaslonko if (ret == Z_STREAM_END)
2283fd396afSMikhail Zaslonko break;
2293fd396afSMikhail Zaslonko if (ret != Z_OK && ret != Z_BUF_ERROR) {
23078809913SSergey Senozhatsky zlib_deflateEnd(&workspace->strm);
23160e1975aSZach Brown ret = -EIO;
232c8b97818SChris Mason goto out;
2333fd396afSMikhail Zaslonko } else if (workspace->strm.avail_out == 0) {
2343fd396afSMikhail Zaslonko /* get another page for the stream end */
2353fd396afSMikhail Zaslonko if (nr_pages == nr_dest_pages) {
2363fd396afSMikhail Zaslonko ret = -E2BIG;
2373fd396afSMikhail Zaslonko goto out;
238c8b97818SChris Mason }
239b0ee5e1eSDavid Sterba out_page = alloc_page(GFP_NOFS);
2403fd396afSMikhail Zaslonko if (out_page == NULL) {
2413fd396afSMikhail Zaslonko ret = -ENOMEM;
2423fd396afSMikhail Zaslonko goto out;
2433fd396afSMikhail Zaslonko }
244718e5855SFabio M. De Francesco cpage_out = page_address(out_page);
2453fd396afSMikhail Zaslonko pages[nr_pages] = out_page;
2463fd396afSMikhail Zaslonko nr_pages++;
2473fd396afSMikhail Zaslonko workspace->strm.avail_out = PAGE_SIZE;
2483fd396afSMikhail Zaslonko workspace->strm.next_out = cpage_out;
2493fd396afSMikhail Zaslonko }
2503fd396afSMikhail Zaslonko }
2513fd396afSMikhail Zaslonko zlib_deflateEnd(&workspace->strm);
252c8b97818SChris Mason
25378809913SSergey Senozhatsky if (workspace->strm.total_out >= workspace->strm.total_in) {
25460e1975aSZach Brown ret = -E2BIG;
255c8b97818SChris Mason goto out;
256c8b97818SChris Mason }
257c8b97818SChris Mason
258c8b97818SChris Mason ret = 0;
25978809913SSergey Senozhatsky *total_out = workspace->strm.total_out;
26078809913SSergey Senozhatsky *total_in = workspace->strm.total_in;
261c8b97818SChris Mason out:
262c8b97818SChris Mason *out_pages = nr_pages;
263718e5855SFabio M. De Francesco if (data_in) {
264718e5855SFabio M. De Francesco kunmap_local(data_in);
26509cbfeafSKirill A. Shutemov put_page(in_page);
26655276e14SDavid Sterba }
267718e5855SFabio M. De Francesco
268c8b97818SChris Mason return ret;
269c8b97818SChris Mason }
270c8b97818SChris Mason
zlib_decompress_bio(struct list_head * ws,struct compressed_bio * cb)271c4bf665aSDavid Sterba int zlib_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
272c8b97818SChris Mason {
273261507a0SLi Zefan struct workspace *workspace = list_entry(ws, struct workspace, list);
2743a39c18dSLi Zefan int ret = 0, ret2;
275c8b97818SChris Mason int wbits = MAX_WBITS;
276c8b97818SChris Mason char *data_in;
277c8b97818SChris Mason size_t total_out = 0;
278c8b97818SChris Mason unsigned long page_in_index = 0;
279e1ddce71SAnand Jain size_t srclen = cb->compressed_len;
28009cbfeafSKirill A. Shutemov unsigned long total_pages_in = DIV_ROUND_UP(srclen, PAGE_SIZE);
281c8b97818SChris Mason unsigned long buf_start;
282e1ddce71SAnand Jain struct page **pages_in = cb->compressed_pages;
283c8b97818SChris Mason
2845a6e6e7cSFabio M. De Francesco data_in = kmap_local_page(pages_in[page_in_index]);
28578809913SSergey Senozhatsky workspace->strm.next_in = data_in;
28609cbfeafSKirill A. Shutemov workspace->strm.avail_in = min_t(size_t, srclen, PAGE_SIZE);
28778809913SSergey Senozhatsky workspace->strm.total_in = 0;
288c8b97818SChris Mason
28978809913SSergey Senozhatsky workspace->strm.total_out = 0;
29078809913SSergey Senozhatsky workspace->strm.next_out = workspace->buf;
2913fd396afSMikhail Zaslonko workspace->strm.avail_out = workspace->buf_size;
292c8b97818SChris Mason
293c8b97818SChris Mason /* If it's deflate, and it's got no preset dictionary, then
294c8b97818SChris Mason we can tell zlib to skip the adler32 check. */
295c8b97818SChris Mason if (srclen > 2 && !(data_in[1] & PRESET_DICT) &&
296c8b97818SChris Mason ((data_in[0] & 0x0f) == Z_DEFLATED) &&
297c8b97818SChris Mason !(((data_in[0]<<8) + data_in[1]) % 31)) {
298c8b97818SChris Mason
299c8b97818SChris Mason wbits = -((data_in[0] >> 4) + 8);
30078809913SSergey Senozhatsky workspace->strm.next_in += 2;
30178809913SSergey Senozhatsky workspace->strm.avail_in -= 2;
302c8b97818SChris Mason }
303c8b97818SChris Mason
30478809913SSergey Senozhatsky if (Z_OK != zlib_inflateInit2(&workspace->strm, wbits)) {
30562e85577SJeff Mahoney pr_warn("BTRFS: inflateInit failed\n");
3065a6e6e7cSFabio M. De Francesco kunmap_local(data_in);
30760e1975aSZach Brown return -EIO;
308c8b97818SChris Mason }
30978809913SSergey Senozhatsky while (workspace->strm.total_in < srclen) {
31078809913SSergey Senozhatsky ret = zlib_inflate(&workspace->strm, Z_NO_FLUSH);
311d397712bSChris Mason if (ret != Z_OK && ret != Z_STREAM_END)
312c8b97818SChris Mason break;
313c8b97818SChris Mason
3143a39c18dSLi Zefan buf_start = total_out;
31578809913SSergey Senozhatsky total_out = workspace->strm.total_out;
316c8b97818SChris Mason
3173a39c18dSLi Zefan /* we didn't make progress in this inflate call, we're done */
3183a39c18dSLi Zefan if (buf_start == total_out)
319c8b97818SChris Mason break;
320c8b97818SChris Mason
3211c3dc173SQu Wenruo ret2 = btrfs_decompress_buf2page(workspace->buf,
3221c3dc173SQu Wenruo total_out - buf_start, cb, buf_start);
3233a39c18dSLi Zefan if (ret2 == 0) {
324c8b97818SChris Mason ret = 0;
325c8b97818SChris Mason goto done;
326c8b97818SChris Mason }
327d397712bSChris Mason
32878809913SSergey Senozhatsky workspace->strm.next_out = workspace->buf;
3293fd396afSMikhail Zaslonko workspace->strm.avail_out = workspace->buf_size;
330c8b97818SChris Mason
33178809913SSergey Senozhatsky if (workspace->strm.avail_in == 0) {
332c8b97818SChris Mason unsigned long tmp;
3335a6e6e7cSFabio M. De Francesco kunmap_local(data_in);
334c8b97818SChris Mason page_in_index++;
335c8b97818SChris Mason if (page_in_index >= total_pages_in) {
336c8b97818SChris Mason data_in = NULL;
337c8b97818SChris Mason break;
338c8b97818SChris Mason }
3395a6e6e7cSFabio M. De Francesco data_in = kmap_local_page(pages_in[page_in_index]);
34078809913SSergey Senozhatsky workspace->strm.next_in = data_in;
34178809913SSergey Senozhatsky tmp = srclen - workspace->strm.total_in;
3421c3dc173SQu Wenruo workspace->strm.avail_in = min(tmp, PAGE_SIZE);
343c8b97818SChris Mason }
344c8b97818SChris Mason }
345d397712bSChris Mason if (ret != Z_STREAM_END)
34660e1975aSZach Brown ret = -EIO;
347d397712bSChris Mason else
348c8b97818SChris Mason ret = 0;
349c8b97818SChris Mason done:
35078809913SSergey Senozhatsky zlib_inflateEnd(&workspace->strm);
35155276e14SDavid Sterba if (data_in)
3525a6e6e7cSFabio M. De Francesco kunmap_local(data_in);
353c8b97818SChris Mason return ret;
354c8b97818SChris Mason }
355c8b97818SChris Mason
zlib_decompress(struct list_head * ws,const u8 * data_in,struct page * dest_page,unsigned long dest_pgoff,size_t srclen,size_t destlen)3563e09b5b2SDavid Sterba int zlib_decompress(struct list_head *ws, const u8 *data_in,
357*56a1bf2bSQu Wenruo struct page *dest_page, unsigned long dest_pgoff, size_t srclen,
358c4bf665aSDavid Sterba size_t destlen)
359c8b97818SChris Mason {
360261507a0SLi Zefan struct workspace *workspace = list_entry(ws, struct workspace, list);
361c8b97818SChris Mason int ret = 0;
362c8b97818SChris Mason int wbits = MAX_WBITS;
363*56a1bf2bSQu Wenruo unsigned long to_copy;
3642f19cad9SChris Mason
36578809913SSergey Senozhatsky workspace->strm.next_in = data_in;
36678809913SSergey Senozhatsky workspace->strm.avail_in = srclen;
36778809913SSergey Senozhatsky workspace->strm.total_in = 0;
368c8b97818SChris Mason
36978809913SSergey Senozhatsky workspace->strm.next_out = workspace->buf;
3703fd396afSMikhail Zaslonko workspace->strm.avail_out = workspace->buf_size;
37178809913SSergey Senozhatsky workspace->strm.total_out = 0;
372c8b97818SChris Mason /* If it's deflate, and it's got no preset dictionary, then
373c8b97818SChris Mason we can tell zlib to skip the adler32 check. */
374c8b97818SChris Mason if (srclen > 2 && !(data_in[1] & PRESET_DICT) &&
375c8b97818SChris Mason ((data_in[0] & 0x0f) == Z_DEFLATED) &&
376c8b97818SChris Mason !(((data_in[0]<<8) + data_in[1]) % 31)) {
377c8b97818SChris Mason
378c8b97818SChris Mason wbits = -((data_in[0] >> 4) + 8);
37978809913SSergey Senozhatsky workspace->strm.next_in += 2;
38078809913SSergey Senozhatsky workspace->strm.avail_in -= 2;
381c8b97818SChris Mason }
382c8b97818SChris Mason
38378809913SSergey Senozhatsky if (Z_OK != zlib_inflateInit2(&workspace->strm, wbits)) {
38462e85577SJeff Mahoney pr_warn("BTRFS: inflateInit failed\n");
38560e1975aSZach Brown return -EIO;
386c8b97818SChris Mason }
387c8b97818SChris Mason
388*56a1bf2bSQu Wenruo /*
389*56a1bf2bSQu Wenruo * Everything (in/out buf) should be at most one sector, there should
390*56a1bf2bSQu Wenruo * be no need to switch any input/output buffer.
391*56a1bf2bSQu Wenruo */
392*56a1bf2bSQu Wenruo ret = zlib_inflate(&workspace->strm, Z_FINISH);
393*56a1bf2bSQu Wenruo to_copy = min(workspace->strm.total_out, destlen);
394*56a1bf2bSQu Wenruo if (ret != Z_STREAM_END)
395*56a1bf2bSQu Wenruo goto out;
396c8b97818SChris Mason
397*56a1bf2bSQu Wenruo memcpy_to_page(dest_page, dest_pgoff, workspace->buf, to_copy);
398c8b97818SChris Mason
399*56a1bf2bSQu Wenruo out:
400*56a1bf2bSQu Wenruo if (unlikely(to_copy != destlen)) {
401*56a1bf2bSQu Wenruo pr_warn_ratelimited("BTRFS: infalte failed, decompressed=%lu expected=%zu\n",
402*56a1bf2bSQu Wenruo to_copy, destlen);
40360e1975aSZach Brown ret = -EIO;
404*56a1bf2bSQu Wenruo } else {
405c8b97818SChris Mason ret = 0;
406*56a1bf2bSQu Wenruo }
407d397712bSChris Mason
40878809913SSergey Senozhatsky zlib_inflateEnd(&workspace->strm);
4092f19cad9SChris Mason
410*56a1bf2bSQu Wenruo if (unlikely(to_copy < destlen))
411*56a1bf2bSQu Wenruo memzero_page(dest_page, dest_pgoff + to_copy, destlen - to_copy);
412c8b97818SChris Mason return ret;
413c8b97818SChris Mason }
414c8b97818SChris Mason
415e8c9f186SDavid Sterba const struct btrfs_compress_op btrfs_zlib_compress = {
416be951045SDavid Sterba .workspace_manager = &wsm,
417e18333a7SDavid Sterba .max_level = 9,
418e18333a7SDavid Sterba .default_level = BTRFS_ZLIB_DEFAULT_LEVEL,
419261507a0SLi Zefan };
420