From patchwork Wed Mar 3 15:57:43 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: jim owens X-Patchwork-Id: 83364 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o23G3Q3l027167 for ; Wed, 3 Mar 2010 16:03:27 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753367Ab0CCQDZ (ORCPT ); Wed, 3 Mar 2010 11:03:25 -0500 Received: from mail-qy0-f198.google.com ([209.85.221.198]:57425 "EHLO mail-qy0-f198.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752695Ab0CCQDY (ORCPT ); Wed, 3 Mar 2010 11:03:24 -0500 X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Wed, 03 Mar 2010 16:03:27 +0000 (UTC) X-Greylist: delayed 338 seconds by postgrey-1.27 at vger.kernel.org; Wed, 03 Mar 2010 11:03:24 EST Received: by qyk36 with SMTP id 36so1040572qyk.19 for ; Wed, 03 Mar 2010 08:03:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:message-id:date:from :user-agent:mime-version:to:subject:content-type :content-transfer-encoding; bh=1qr/VNL8JplotwUOn5yF8go9Ndy6jL6iye+PE+XHo98=; b=v4mha+ByxAtyZny4g6Ih3nKYzT7dUMICInIW9HHf1MnUfIKdsA2+D1iNY6j8N2Y08z tez3U9vSrVN4z1Zx8irVJ0JVHAe1M0Gai/t3hodQ0yJfMpXUlVF8Q2eFRtq8821gzb7e R8wFlBS5Dcgd9lxDWU0vKIYxMW7qe7c1JWsmU= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:from:user-agent:mime-version:to:subject :content-type:content-transfer-encoding; b=TbPwdrqD6FtThI1PKvGGCL7cC6bmPmMbDIAicGkPLvJLroWTp4+PBEyDTWQ5BaktLl rJVu8vAfAri64AmlXSyJVG5AbUVqipS/CFrxnQ186brEwvCC7Kra1hNiHpYwB2jwiQWP 9f67ztrgUCbYqvmvihVElVyJeWt+CzO/j7CE0= Received: by 10.224.52.98 with SMTP id h34mr1017116qag.104.1267631865244; Wed, 03 Mar 2010 07:57:45 -0800 (PST) Received: from ?192.168.0.99? (c-24-147-40-65.hsd1.nh.comcast.net [24.147.40.65]) by mx.google.com with ESMTPS id 22sm4156576qyk.10.2010.03.03.07.57.44 (version=TLSv1/SSLv3 cipher=RC4-MD5); Wed, 03 Mar 2010 07:57:44 -0800 (PST) Message-ID: <4B8E86F7.3000600@gmail.com> Date: Wed, 03 Mar 2010 10:57:43 -0500 From: jim owens User-Agent: Thunderbird 2.0.0.23 (X11/20090817) MIME-Version: 1.0 To: linux-btrfs Subject: [PATCH V2] Btrfs: add decompression code for direct I/O. Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org diff --git a/fs/btrfs/compression.h b/fs/btrfs/compression.h index 421f5b4..afd262d 100644 --- a/fs/btrfs/compression.h +++ b/fs/btrfs/compression.h @@ -19,6 +19,26 @@ #ifndef __BTRFS_COMPRESSION_ #define __BTRFS_COMPRESSION_ +#include +struct workspace { + z_stream z_strm; + char *buf; + struct list_head list; +}; + +struct btrfs_inflate { + struct workspace *workspace; + int (*get_next_in)(struct bio_vec *vec, struct btrfs_inflate *icb); + int (*get_next_out)(struct bio_vec *vec, struct btrfs_inflate *icb); + void (*done_with_out)(struct bio_vec *vec, struct btrfs_inflate *icb); + u32 out_start; + u32 out_len; +}; + +struct workspace *find_zlib_workspace(void); +int free_workspace(struct workspace *workspace); +int btrfs_zlib_inflate(struct btrfs_inflate *icb); + int btrfs_zlib_decompress(unsigned char *data_in, struct page *dest_page, unsigned long start_byte, diff --git a/fs/btrfs/zlib.c b/fs/btrfs/zlib.c index d7bdce5..ea601e6 100644 --- a/fs/btrfs/zlib.c +++ b/fs/btrfs/zlib.c @@ -41,12 +41,6 @@ */ #define STREAM_END_SPACE 12 -struct workspace { - z_stream z_strm; - char *buf; - struct list_head list; -}; - static LIST_HEAD(idle_workspace); static DEFINE_SPINLOCK(workspace_lock); static unsigned long num_workspace; @@ -57,7 +51,7 @@ static DECLARE_WAIT_QUEUE_HEAD(workspace_wait); * this finds an available zlib workspace or allocates a new one * NULL or an ERR_PTR is returned if things go bad. */ -static struct workspace *find_zlib_workspace(void) +struct workspace *find_zlib_workspace(void) { struct workspace *workspace; int ret; @@ -117,7 +111,7 @@ fail: * put a workspace struct back on the list or free it if we have enough * idle ones sitting around */ -static int free_workspace(struct workspace *workspace) +int free_workspace(struct workspace *workspace) { spin_lock(&workspace_lock); if (num_workspace < num_online_cpus()) { @@ -622,3 +616,135 @@ void btrfs_zlib_exit(void) { free_workspaces(); } + +/* inflate compressed data for one contiguous file range from directio */ +int btrfs_zlib_inflate(struct btrfs_inflate *icb) +{ + struct workspace *workspace = icb->workspace; + unsigned long out_start = icb->out_start; + unsigned long total_len = icb->out_len + out_start; + struct bio_vec ivec; + struct bio_vec ovec; + char *in; + char *out; + int err; + int wbits; + + icb->out_len = 0; + ivec.bv_len = 0; + ovec.bv_len = 0; + if (!workspace) { + workspace = find_zlib_workspace(); + if (IS_ERR(workspace)) + return -ENOMEM; + } + + err = icb->get_next_in(&ivec, icb); + if (err) + goto fail; + in = kmap_atomic(ivec.bv_page, KM_USER0); + workspace->z_strm.next_in = in + ivec.bv_offset; + workspace->z_strm.avail_in = ivec.bv_len; + workspace->z_strm.total_in = 0; + workspace->z_strm.total_out = 0; + workspace->z_strm.next_out = workspace->buf; + workspace->z_strm.avail_out = PAGE_CACHE_SIZE; + + /* with no preset dictionary, tell zlib to skip the adler32 check */ + if (!(in[ivec.bv_offset+1] & PRESET_DICT) && + ((in[ivec.bv_offset] & 0x0f) == Z_DEFLATED) && + !(((in[ivec.bv_offset]<<8) + in[ivec.bv_offset+1]) % 31)) { + + wbits = -((in[ivec.bv_offset] >> 4) + 8); + workspace->z_strm.next_in += 2; + workspace->z_strm.avail_in -= 2; + } else { + wbits = MAX_WBITS; + } + + err = zlib_inflateInit2(&workspace->z_strm, wbits); + if (err) { + kunmap_atomic(in, KM_USER0); + goto fail; + } + + ivec.bv_len = workspace->z_strm.avail_in; + ivec.bv_offset = (char *)workspace->z_strm.next_in - in; + kunmap_atomic(in, KM_USER0); + + /* use temp buf to toss everything before the real data we want */ + while (workspace->z_strm.total_out < out_start) { + workspace->z_strm.next_out = workspace->buf; + workspace->z_strm.avail_out = min(PAGE_CACHE_SIZE, + out_start - workspace->z_strm.total_out); + + if (!ivec.bv_len) { + err = icb->get_next_in(&ivec, icb); + if (err) + goto fail; + } + in = kmap_atomic(ivec.bv_page, KM_USER0); + workspace->z_strm.next_in = in + ivec.bv_offset; + workspace->z_strm.avail_in = ivec.bv_len; + + err = zlib_inflate(&workspace->z_strm, Z_NO_FLUSH); + + ivec.bv_len = workspace->z_strm.avail_in; + ivec.bv_offset = (char *)workspace->z_strm.next_in - in; + kunmap_atomic(in, KM_USER0); + + if (err != Z_OK) /* Z_STREAM_END is no-user-data failure here */ + goto fail; + cond_resched(); + } + + while (workspace->z_strm.total_out < total_len) { + if (!ivec.bv_len) { + err = icb->get_next_in(&ivec, icb); + if (err) + goto fail; + } + if (!ovec.bv_len) { + err = icb->get_next_out(&ovec, icb); + if (err) + goto fail; + } + + in = kmap_atomic(ivec.bv_page, KM_USER0); + workspace->z_strm.next_in = in + ivec.bv_offset; + workspace->z_strm.avail_in = ivec.bv_len; + + out = kmap_atomic(ovec.bv_page, KM_USER1); + workspace->z_strm.next_out = out + ovec.bv_offset; + workspace->z_strm.avail_out = ovec.bv_len; + + err = zlib_inflate(&workspace->z_strm, Z_NO_FLUSH); + + icb->out_len += (ovec.bv_len - workspace->z_strm.avail_out); + ovec.bv_len = workspace->z_strm.avail_out; + ovec.bv_offset = (char *)workspace->z_strm.next_out - out; + kunmap_atomic(out, KM_USER1); + + ivec.bv_len = workspace->z_strm.avail_in; + ivec.bv_offset = (char *)workspace->z_strm.next_in - in; + kunmap_atomic(in, KM_USER0); + + if (!ovec.bv_len) + icb->done_with_out(&ovec, icb); + else + flush_dcache_page(ovec.bv_page); + + if (err != Z_OK) + goto fail; + cond_resched(); + } + +fail: + if (ovec.bv_len) + icb->done_with_out(&ovec, icb); + if (!icb->workspace) + free_workspace(workspace); + if (err == Z_OK || err == Z_STREAM_END) + return 0; + return err; +}