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