1c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason/*
2c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason * Copyright (C) 2008 Oracle.  All rights reserved.
3c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason *
4c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason * This program is free software; you can redistribute it and/or
5c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason * modify it under the terms of the GNU General Public
6c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason * License v2 as published by the Free Software Foundation.
7c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason *
8c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason * This program is distributed in the hope that it will be useful,
9c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason * but WITHOUT ANY WARRANTY; without even the implied warranty of
10c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason * General Public License for more details.
12c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason *
13c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason * You should have received a copy of the GNU General Public
14c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason * License along with this program; if not, write to the
15c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason * Boston, MA 021110-1307, USA.
17c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason *
18c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason * Based on jffs2 zlib code:
19c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason * Copyright © 2001-2007 Red Hat, Inc.
20c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason * Created by David Woodhouse <dwmw2@infradead.org>
21c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason */
22c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
23c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason#include <linux/kernel.h>
24c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason#include <linux/slab.h>
25c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason#include <linux/zlib.h>
26c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason#include <linux/zutil.h>
27c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason#include <linux/vmalloc.h>
28c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason#include <linux/init.h>
29c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason#include <linux/err.h>
30c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason#include <linux/sched.h>
31c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason#include <linux/pagemap.h>
32c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason#include <linux/bio.h>
33b2950863c61bc24cf0f63bc05947d9d50663c4c0Christoph Hellwig#include "compression.h"
34c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
35c8b978188c9a0fd3d535c13debd19d522b726f1fChris Masonstruct workspace {
367880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	z_stream strm;
37c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	char *buf;
38c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	struct list_head list;
39c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason};
40c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
41261507a02ccba9afda919852263b6bc1581ce1efLi Zefanstatic void zlib_free_workspace(struct list_head *ws)
42261507a02ccba9afda919852263b6bc1581ce1efLi Zefan{
43261507a02ccba9afda919852263b6bc1581ce1efLi Zefan	struct workspace *workspace = list_entry(ws, struct workspace, list);
44c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
457880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	vfree(workspace->strm.workspace);
46261507a02ccba9afda919852263b6bc1581ce1efLi Zefan	kfree(workspace->buf);
47261507a02ccba9afda919852263b6bc1581ce1efLi Zefan	kfree(workspace);
48261507a02ccba9afda919852263b6bc1581ce1efLi Zefan}
49261507a02ccba9afda919852263b6bc1581ce1efLi Zefan
50261507a02ccba9afda919852263b6bc1581ce1efLi Zefanstatic struct list_head *zlib_alloc_workspace(void)
51c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason{
52c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	struct workspace *workspace;
537880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	int workspacesize;
548844355df7f4e091b03cc131e1549631238b397bLi Zefan
55c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	workspace = kzalloc(sizeof(*workspace), GFP_NOFS);
56261507a02ccba9afda919852263b6bc1581ce1efLi Zefan	if (!workspace)
57261507a02ccba9afda919852263b6bc1581ce1efLi Zefan		return ERR_PTR(-ENOMEM);
58c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
597880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspacesize = max(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL),
607880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky			zlib_inflate_workspacesize());
617880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.workspace = vmalloc(workspacesize);
62c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	workspace->buf = kmalloc(PAGE_CACHE_SIZE, GFP_NOFS);
637880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	if (!workspace->strm.workspace || !workspace->buf)
64261507a02ccba9afda919852263b6bc1581ce1efLi Zefan		goto fail;
65c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
66261507a02ccba9afda919852263b6bc1581ce1efLi Zefan	INIT_LIST_HEAD(&workspace->list);
67c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
68261507a02ccba9afda919852263b6bc1581ce1efLi Zefan	return &workspace->list;
69261507a02ccba9afda919852263b6bc1581ce1efLi Zefanfail:
70261507a02ccba9afda919852263b6bc1581ce1efLi Zefan	zlib_free_workspace(&workspace->list);
71261507a02ccba9afda919852263b6bc1581ce1efLi Zefan	return ERR_PTR(-ENOMEM);
72c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason}
73c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
74261507a02ccba9afda919852263b6bc1581ce1efLi Zefanstatic int zlib_compress_pages(struct list_head *ws,
75261507a02ccba9afda919852263b6bc1581ce1efLi Zefan			       struct address_space *mapping,
76261507a02ccba9afda919852263b6bc1581ce1efLi Zefan			       u64 start, unsigned long len,
77261507a02ccba9afda919852263b6bc1581ce1efLi Zefan			       struct page **pages,
78261507a02ccba9afda919852263b6bc1581ce1efLi Zefan			       unsigned long nr_dest_pages,
79261507a02ccba9afda919852263b6bc1581ce1efLi Zefan			       unsigned long *out_pages,
80261507a02ccba9afda919852263b6bc1581ce1efLi Zefan			       unsigned long *total_in,
81261507a02ccba9afda919852263b6bc1581ce1efLi Zefan			       unsigned long *total_out,
82261507a02ccba9afda919852263b6bc1581ce1efLi Zefan			       unsigned long max_out)
83c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason{
84261507a02ccba9afda919852263b6bc1581ce1efLi Zefan	struct workspace *workspace = list_entry(ws, struct workspace, list);
85c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	int ret;
86c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	char *data_in;
87c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	char *cpage_out;
88c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	int nr_pages = 0;
89c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	struct page *in_page = NULL;
90c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	struct page *out_page = NULL;
91c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	unsigned long bytes_left;
92c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
93c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	*out_pages = 0;
94c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	*total_out = 0;
95c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	*total_in = 0;
96c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
977880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	if (Z_OK != zlib_deflateInit(&workspace->strm, 3)) {
98efe120a067c8674a8ae21b194f0e68f098b61ee2Frank Holton		printk(KERN_WARNING "BTRFS: deflateInit failed\n");
9960e1975acb48fc3d74a3422b21dde74c977ac3d5Zach Brown		ret = -EIO;
100c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		goto out;
101c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	}
102c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
1037880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.total_in = 0;
1047880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.total_out = 0;
105c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
106c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	in_page = find_get_page(mapping, start >> PAGE_CACHE_SHIFT);
107c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	data_in = kmap(in_page);
108c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
109c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
1104b72029dc3fd6ba7dc45ccd1cf0aa0ebfa209bd3Li Zefan	if (out_page == NULL) {
11160e1975acb48fc3d74a3422b21dde74c977ac3d5Zach Brown		ret = -ENOMEM;
1124b72029dc3fd6ba7dc45ccd1cf0aa0ebfa209bd3Li Zefan		goto out;
1134b72029dc3fd6ba7dc45ccd1cf0aa0ebfa209bd3Li Zefan	}
114c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	cpage_out = kmap(out_page);
115c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	pages[0] = out_page;
116c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	nr_pages = 1;
117c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
1187880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.next_in = data_in;
1197880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.next_out = cpage_out;
1207880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.avail_out = PAGE_CACHE_SIZE;
1217880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.avail_in = min(len, PAGE_CACHE_SIZE);
122c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
1237880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	while (workspace->strm.total_in < len) {
1247880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		ret = zlib_deflate(&workspace->strm, Z_SYNC_FLUSH);
125c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		if (ret != Z_OK) {
126efe120a067c8674a8ae21b194f0e68f098b61ee2Frank Holton			printk(KERN_DEBUG "BTRFS: deflate in loop returned %d\n",
127c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			       ret);
1287880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky			zlib_deflateEnd(&workspace->strm);
12960e1975acb48fc3d74a3422b21dde74c977ac3d5Zach Brown			ret = -EIO;
130c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			goto out;
131c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		}
132c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
133c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		/* we're making it bigger, give up */
1347880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		if (workspace->strm.total_in > 8192 &&
1357880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		    workspace->strm.total_in <
1367880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		    workspace->strm.total_out) {
137130d5b415a091e493ac1508b9d27bbb85ba7b8c0David Sterba			ret = -E2BIG;
138c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			goto out;
139c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		}
140c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		/* we need another page for writing out.  Test this
141c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		 * before the total_in so we will pull in a new page for
142c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		 * the stream end if required
143c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		 */
1447880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		if (workspace->strm.avail_out == 0) {
145c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			kunmap(out_page);
146c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			if (nr_pages == nr_dest_pages) {
147c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason				out_page = NULL;
14860e1975acb48fc3d74a3422b21dde74c977ac3d5Zach Brown				ret = -E2BIG;
149c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason				goto out;
150c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			}
151c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
1524b72029dc3fd6ba7dc45ccd1cf0aa0ebfa209bd3Li Zefan			if (out_page == NULL) {
15360e1975acb48fc3d74a3422b21dde74c977ac3d5Zach Brown				ret = -ENOMEM;
1544b72029dc3fd6ba7dc45ccd1cf0aa0ebfa209bd3Li Zefan				goto out;
1554b72029dc3fd6ba7dc45ccd1cf0aa0ebfa209bd3Li Zefan			}
156c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			cpage_out = kmap(out_page);
157c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			pages[nr_pages] = out_page;
158c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			nr_pages++;
1597880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky			workspace->strm.avail_out = PAGE_CACHE_SIZE;
1607880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky			workspace->strm.next_out = cpage_out;
161c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		}
162c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		/* we're all done */
1637880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		if (workspace->strm.total_in >= len)
164c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			break;
165c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
166c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		/* we've read in a full page, get a new one */
1677880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		if (workspace->strm.avail_in == 0) {
1687880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky			if (workspace->strm.total_out > max_out)
169c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason				break;
170c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
1717880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky			bytes_left = len - workspace->strm.total_in;
172c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			kunmap(in_page);
173c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			page_cache_release(in_page);
174c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
175c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			start += PAGE_CACHE_SIZE;
176c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			in_page = find_get_page(mapping,
177c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason						start >> PAGE_CACHE_SHIFT);
178c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			data_in = kmap(in_page);
1797880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky			workspace->strm.avail_in = min(bytes_left,
180c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason							   PAGE_CACHE_SIZE);
1817880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky			workspace->strm.next_in = data_in;
182c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		}
183c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	}
1847880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.avail_in = 0;
1857880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	ret = zlib_deflate(&workspace->strm, Z_FINISH);
1867880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	zlib_deflateEnd(&workspace->strm);
187c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
188c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	if (ret != Z_STREAM_END) {
18960e1975acb48fc3d74a3422b21dde74c977ac3d5Zach Brown		ret = -EIO;
190c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		goto out;
191c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	}
192c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
1937880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	if (workspace->strm.total_out >= workspace->strm.total_in) {
19460e1975acb48fc3d74a3422b21dde74c977ac3d5Zach Brown		ret = -E2BIG;
195c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		goto out;
196c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	}
197c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
198c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	ret = 0;
1997880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	*total_out = workspace->strm.total_out;
2007880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	*total_in = workspace->strm.total_in;
201c8b978188c9a0fd3d535c13debd19d522b726f1fChris Masonout:
202c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	*out_pages = nr_pages;
203c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	if (out_page)
204c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		kunmap(out_page);
205c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
206c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	if (in_page) {
207c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		kunmap(in_page);
208c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		page_cache_release(in_page);
209c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	}
210c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	return ret;
211c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason}
212c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
213261507a02ccba9afda919852263b6bc1581ce1efLi Zefanstatic int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
214261507a02ccba9afda919852263b6bc1581ce1efLi Zefan				  u64 disk_start,
215261507a02ccba9afda919852263b6bc1581ce1efLi Zefan				  struct bio_vec *bvec,
216261507a02ccba9afda919852263b6bc1581ce1efLi Zefan				  int vcnt,
217261507a02ccba9afda919852263b6bc1581ce1efLi Zefan				  size_t srclen)
218c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason{
219261507a02ccba9afda919852263b6bc1581ce1efLi Zefan	struct workspace *workspace = list_entry(ws, struct workspace, list);
2203a39c18d63fec35f49df577d4b2a4e29c2212f22Li Zefan	int ret = 0, ret2;
221c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	int wbits = MAX_WBITS;
222c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	char *data_in;
223c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	size_t total_out = 0;
224c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	unsigned long page_in_index = 0;
225c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	unsigned long page_out_index = 0;
226ed6078f70335f158ca79790a0d0708ce558a6e9aDavid Sterba	unsigned long total_pages_in = DIV_ROUND_UP(srclen, PAGE_CACHE_SIZE);
227c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	unsigned long buf_start;
228c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	unsigned long pg_offset;
229c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
230c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	data_in = kmap(pages_in[page_in_index]);
2317880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.next_in = data_in;
2327880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.avail_in = min_t(size_t, srclen, PAGE_CACHE_SIZE);
2337880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.total_in = 0;
234c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
2357880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.total_out = 0;
2367880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.next_out = workspace->buf;
2377880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.avail_out = PAGE_CACHE_SIZE;
238c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	pg_offset = 0;
239c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
240c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	/* If it's deflate, and it's got no preset dictionary, then
241c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	   we can tell zlib to skip the adler32 check. */
242c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	if (srclen > 2 && !(data_in[1] & PRESET_DICT) &&
243c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	    ((data_in[0] & 0x0f) == Z_DEFLATED) &&
244c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	    !(((data_in[0]<<8) + data_in[1]) % 31)) {
245c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
246c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		wbits = -((data_in[0] >> 4) + 8);
2477880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		workspace->strm.next_in += 2;
2487880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		workspace->strm.avail_in -= 2;
249c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	}
250c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
2517880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	if (Z_OK != zlib_inflateInit2(&workspace->strm, wbits)) {
252efe120a067c8674a8ae21b194f0e68f098b61ee2Frank Holton		printk(KERN_WARNING "BTRFS: inflateInit failed\n");
25360e1975acb48fc3d74a3422b21dde74c977ac3d5Zach Brown		return -EIO;
254c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	}
2557880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	while (workspace->strm.total_in < srclen) {
2567880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		ret = zlib_inflate(&workspace->strm, Z_NO_FLUSH);
257d397712bcc6a759a560fd247e6053ecae091f958Chris Mason		if (ret != Z_OK && ret != Z_STREAM_END)
258c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			break;
259c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
2603a39c18d63fec35f49df577d4b2a4e29c2212f22Li Zefan		buf_start = total_out;
2617880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		total_out = workspace->strm.total_out;
262c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
2633a39c18d63fec35f49df577d4b2a4e29c2212f22Li Zefan		/* we didn't make progress in this inflate call, we're done */
2643a39c18d63fec35f49df577d4b2a4e29c2212f22Li Zefan		if (buf_start == total_out)
265c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			break;
266c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
2673a39c18d63fec35f49df577d4b2a4e29c2212f22Li Zefan		ret2 = btrfs_decompress_buf2page(workspace->buf, buf_start,
2683a39c18d63fec35f49df577d4b2a4e29c2212f22Li Zefan						 total_out, disk_start,
2693a39c18d63fec35f49df577d4b2a4e29c2212f22Li Zefan						 bvec, vcnt,
2703a39c18d63fec35f49df577d4b2a4e29c2212f22Li Zefan						 &page_out_index, &pg_offset);
2713a39c18d63fec35f49df577d4b2a4e29c2212f22Li Zefan		if (ret2 == 0) {
2723a39c18d63fec35f49df577d4b2a4e29c2212f22Li Zefan			ret = 0;
2733a39c18d63fec35f49df577d4b2a4e29c2212f22Li Zefan			goto done;
274c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		}
2753a39c18d63fec35f49df577d4b2a4e29c2212f22Li Zefan
2767880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		workspace->strm.next_out = workspace->buf;
2777880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		workspace->strm.avail_out = PAGE_CACHE_SIZE;
278c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
2797880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		if (workspace->strm.avail_in == 0) {
280c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			unsigned long tmp;
281c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			kunmap(pages_in[page_in_index]);
282c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			page_in_index++;
283c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			if (page_in_index >= total_pages_in) {
284c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason				data_in = NULL;
285c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason				break;
286c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			}
287c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			data_in = kmap(pages_in[page_in_index]);
2887880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky			workspace->strm.next_in = data_in;
2897880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky			tmp = srclen - workspace->strm.total_in;
2907880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky			workspace->strm.avail_in = min(tmp,
291c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason							   PAGE_CACHE_SIZE);
292c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		}
293c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	}
294d397712bcc6a759a560fd247e6053ecae091f958Chris Mason	if (ret != Z_STREAM_END)
29560e1975acb48fc3d74a3422b21dde74c977ac3d5Zach Brown		ret = -EIO;
296d397712bcc6a759a560fd247e6053ecae091f958Chris Mason	else
297c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		ret = 0;
298c8b978188c9a0fd3d535c13debd19d522b726f1fChris Masondone:
2997880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	zlib_inflateEnd(&workspace->strm);
300c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	if (data_in)
301c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		kunmap(pages_in[page_in_index]);
3022f19cad94cee3c9bd52d0c9ca584ef506302fb7cChris Mason	if (!ret)
3032f19cad94cee3c9bd52d0c9ca584ef506302fb7cChris Mason		btrfs_clear_biovec_end(bvec, vcnt, page_out_index, pg_offset);
304c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	return ret;
305c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason}
306c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
307261507a02ccba9afda919852263b6bc1581ce1efLi Zefanstatic int zlib_decompress(struct list_head *ws, unsigned char *data_in,
308261507a02ccba9afda919852263b6bc1581ce1efLi Zefan			   struct page *dest_page,
309261507a02ccba9afda919852263b6bc1581ce1efLi Zefan			   unsigned long start_byte,
310261507a02ccba9afda919852263b6bc1581ce1efLi Zefan			   size_t srclen, size_t destlen)
311c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason{
312261507a02ccba9afda919852263b6bc1581ce1efLi Zefan	struct workspace *workspace = list_entry(ws, struct workspace, list);
313c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	int ret = 0;
314c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	int wbits = MAX_WBITS;
3152f19cad94cee3c9bd52d0c9ca584ef506302fb7cChris Mason	unsigned long bytes_left;
316c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	unsigned long total_out = 0;
3172f19cad94cee3c9bd52d0c9ca584ef506302fb7cChris Mason	unsigned long pg_offset = 0;
318c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	char *kaddr;
319c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
3202f19cad94cee3c9bd52d0c9ca584ef506302fb7cChris Mason	destlen = min_t(unsigned long, destlen, PAGE_SIZE);
3212f19cad94cee3c9bd52d0c9ca584ef506302fb7cChris Mason	bytes_left = destlen;
3222f19cad94cee3c9bd52d0c9ca584ef506302fb7cChris Mason
3237880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.next_in = data_in;
3247880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.avail_in = srclen;
3257880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.total_in = 0;
326c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
3277880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.next_out = workspace->buf;
3287880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.avail_out = PAGE_CACHE_SIZE;
3297880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	workspace->strm.total_out = 0;
330c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	/* If it's deflate, and it's got no preset dictionary, then
331c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	   we can tell zlib to skip the adler32 check. */
332c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	if (srclen > 2 && !(data_in[1] & PRESET_DICT) &&
333c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	    ((data_in[0] & 0x0f) == Z_DEFLATED) &&
334c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	    !(((data_in[0]<<8) + data_in[1]) % 31)) {
335c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
336c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		wbits = -((data_in[0] >> 4) + 8);
3377880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		workspace->strm.next_in += 2;
3387880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		workspace->strm.avail_in -= 2;
339c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	}
340c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
3417880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	if (Z_OK != zlib_inflateInit2(&workspace->strm, wbits)) {
342efe120a067c8674a8ae21b194f0e68f098b61ee2Frank Holton		printk(KERN_WARNING "BTRFS: inflateInit failed\n");
34360e1975acb48fc3d74a3422b21dde74c977ac3d5Zach Brown		return -EIO;
344c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	}
345c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
346d397712bcc6a759a560fd247e6053ecae091f958Chris Mason	while (bytes_left > 0) {
347c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		unsigned long buf_start;
348c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		unsigned long buf_offset;
349c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		unsigned long bytes;
350c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
3517880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		ret = zlib_inflate(&workspace->strm, Z_NO_FLUSH);
352d397712bcc6a759a560fd247e6053ecae091f958Chris Mason		if (ret != Z_OK && ret != Z_STREAM_END)
353c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			break;
354c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
355c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		buf_start = total_out;
3567880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		total_out = workspace->strm.total_out;
357c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
358c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		if (total_out == buf_start) {
35960e1975acb48fc3d74a3422b21dde74c977ac3d5Zach Brown			ret = -EIO;
360c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			break;
361c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		}
362c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
363d397712bcc6a759a560fd247e6053ecae091f958Chris Mason		if (total_out <= start_byte)
364c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			goto next;
365c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
366d397712bcc6a759a560fd247e6053ecae091f958Chris Mason		if (total_out > start_byte && buf_start < start_byte)
367c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			buf_offset = start_byte - buf_start;
368d397712bcc6a759a560fd247e6053ecae091f958Chris Mason		else
369c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			buf_offset = 0;
370c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
371c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		bytes = min(PAGE_CACHE_SIZE - pg_offset,
372c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason			    PAGE_CACHE_SIZE - buf_offset);
373c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		bytes = min(bytes, bytes_left);
374c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
3757ac687d9e047b3fa335f04e18c7188db6a170334Cong Wang		kaddr = kmap_atomic(dest_page);
376c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		memcpy(kaddr + pg_offset, workspace->buf + buf_offset, bytes);
3777ac687d9e047b3fa335f04e18c7188db6a170334Cong Wang		kunmap_atomic(kaddr);
378c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
379c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		pg_offset += bytes;
380c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		bytes_left -= bytes;
381c8b978188c9a0fd3d535c13debd19d522b726f1fChris Masonnext:
3827880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		workspace->strm.next_out = workspace->buf;
3837880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky		workspace->strm.avail_out = PAGE_CACHE_SIZE;
384c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	}
385d397712bcc6a759a560fd247e6053ecae091f958Chris Mason
386d397712bcc6a759a560fd247e6053ecae091f958Chris Mason	if (ret != Z_STREAM_END && bytes_left != 0)
38760e1975acb48fc3d74a3422b21dde74c977ac3d5Zach Brown		ret = -EIO;
388d397712bcc6a759a560fd247e6053ecae091f958Chris Mason	else
389c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason		ret = 0;
390d397712bcc6a759a560fd247e6053ecae091f958Chris Mason
3917880991344f73647fa2222b198cf5cfc10805ac2Sergey Senozhatsky	zlib_inflateEnd(&workspace->strm);
3922f19cad94cee3c9bd52d0c9ca584ef506302fb7cChris Mason
3932f19cad94cee3c9bd52d0c9ca584ef506302fb7cChris Mason	/*
3942f19cad94cee3c9bd52d0c9ca584ef506302fb7cChris Mason	 * this should only happen if zlib returned fewer bytes than we
3952f19cad94cee3c9bd52d0c9ca584ef506302fb7cChris Mason	 * expected.  btrfs_get_block is responsible for zeroing from the
3962f19cad94cee3c9bd52d0c9ca584ef506302fb7cChris Mason	 * end of the inline extent (destlen) to the end of the page
3972f19cad94cee3c9bd52d0c9ca584ef506302fb7cChris Mason	 */
3982f19cad94cee3c9bd52d0c9ca584ef506302fb7cChris Mason	if (pg_offset < destlen) {
3992f19cad94cee3c9bd52d0c9ca584ef506302fb7cChris Mason		kaddr = kmap_atomic(dest_page);
4002f19cad94cee3c9bd52d0c9ca584ef506302fb7cChris Mason		memset(kaddr + pg_offset, 0, destlen - pg_offset);
4012f19cad94cee3c9bd52d0c9ca584ef506302fb7cChris Mason		kunmap_atomic(kaddr);
4022f19cad94cee3c9bd52d0c9ca584ef506302fb7cChris Mason	}
403c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason	return ret;
404c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason}
405c8b978188c9a0fd3d535c13debd19d522b726f1fChris Mason
406261507a02ccba9afda919852263b6bc1581ce1efLi Zefanstruct btrfs_compress_op btrfs_zlib_compress = {
407261507a02ccba9afda919852263b6bc1581ce1efLi Zefan	.alloc_workspace	= zlib_alloc_workspace,
408261507a02ccba9afda919852263b6bc1581ce1efLi Zefan	.free_workspace		= zlib_free_workspace,
409261507a02ccba9afda919852263b6bc1581ce1efLi Zefan	.compress_pages		= zlib_compress_pages,
410261507a02ccba9afda919852263b6bc1581ce1efLi Zefan	.decompress_biovec	= zlib_decompress_biovec,
411261507a02ccba9afda919852263b6bc1581ce1efLi Zefan	.decompress		= zlib_decompress,
412261507a02ccba9afda919852263b6bc1581ce1efLi Zefan};
413