From patchwork Mon Mar 22 03:30:46 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: jim owens X-Patchwork-Id: 87345 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 o2M3Unhw019477 for ; Mon, 22 Mar 2010 03:30:50 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753923Ab0CVDat (ORCPT ); Sun, 21 Mar 2010 23:30:49 -0400 Received: from qw-out-2122.google.com ([74.125.92.26]:65476 "EHLO qw-out-2122.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753711Ab0CVDas (ORCPT ); Sun, 21 Mar 2010 23:30:48 -0400 Received: by qw-out-2122.google.com with SMTP id 8so1063870qwh.37 for ; Sun, 21 Mar 2010 20:30:47 -0700 (PDT) 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=27XhAZwLZlHtnffWLgJzjdDMH2mjqFx0pEQ6KI5zrFo=; b=h2tB1u6HgOofnfCBGd3lfNyMUglDxuuZDVjy0xMz/pEUhugkFWhtLfAW9LtahNw4rc fZ0oSHYI4dJapQNkCN31Bot8HriMuiK0uT3R2423hgZz9v7iRtyG7d+u3Yby7iazsJLU t7xR7vCVrzbVmx3jdOypH4eMJYOFqSlGy8yts= 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=Y7xS190an1bcLWFU8eWLlzjtdhI9J3EGVzUlwYRyxPctv0h7ksm5FLTyabG6p3oV36 0oJ+pGb/4LFVztpLBa/fz1YJgL8lekAIKSzhG5LyygFh7Wl/rtgEE7RlK0d6V00LDVGD tsx3U7LHZY7lDl1G/pyWOE3RoCaIgJuwzh+MA= Received: by 10.224.94.73 with SMTP id y9mr2099106qam.90.1269228647569; Sun, 21 Mar 2010 20:30:47 -0700 (PDT) Received: from [192.168.0.97] (c-24-147-40-65.hsd1.nh.comcast.net [24.147.40.65]) by mx.google.com with ESMTPS id 6sm6033171qwk.22.2010.03.21.20.30.46 (version=TLSv1/SSLv3 cipher=RC4-MD5); Sun, 21 Mar 2010 20:30:46 -0700 (PDT) Message-ID: <4BA6E466.9080906@gmail.com> Date: Sun, 21 Mar 2010 23:30:46 -0400 From: jim owens User-Agent: Thunderbird 2.0.0.24 (X11/20100317) MIME-Version: 1.0 To: linux-btrfs Subject: [PATCH V3 13/18] 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 X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Mon, 22 Mar 2010 03:30:50 +0000 (UTC) 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; +}