From patchwork Mon Sep 22 08:29:28 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gui Hecheng X-Patchwork-Id: 4946081 Return-Path: X-Original-To: patchwork-linux-btrfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id D90109F313 for ; Mon, 22 Sep 2014 08:30:29 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 3039C2018E for ; Mon, 22 Sep 2014 08:30:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D799E20109 for ; Mon, 22 Sep 2014 08:30:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753397AbaIVIaU (ORCPT ); Mon, 22 Sep 2014 04:30:20 -0400 Received: from cn.fujitsu.com ([59.151.112.132]:49743 "EHLO heian.cn.fujitsu.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1753249AbaIVIaT (ORCPT ); Mon, 22 Sep 2014 04:30:19 -0400 X-IronPort-AV: E=Sophos;i="5.04,570,1406563200"; d="scan'208";a="36268590" Received: from unknown (HELO edo.cn.fujitsu.com) ([10.167.33.5]) by heian.cn.fujitsu.com with ESMTP; 22 Sep 2014 16:27:17 +0800 Received: from G08CNEXCHPEKD01.g08.fujitsu.local (localhost.localdomain [127.0.0.1]) by edo.cn.fujitsu.com (8.14.3/8.13.1) with ESMTP id s8M8UMVr016143; Mon, 22 Sep 2014 16:30:22 +0800 Received: from localhost.localdomain (10.167.226.111) by G08CNEXCHPEKD01.g08.fujitsu.local (10.167.33.89) with Microsoft SMTP Server (TLS) id 14.3.181.6; Mon, 22 Sep 2014 16:30:21 +0800 From: Gui Hecheng To: CC: , Gui Hecheng Subject: [PATCH v2] btrfs-progs: fix page align issue for lzo compress in restore Date: Mon, 22 Sep 2014 16:29:28 +0800 Message-ID: <1411374568-8542-1-git-send-email-guihc.fnst@cn.fujitsu.com> X-Mailer: git-send-email 1.8.1.4 In-Reply-To: <1411031454.25255.11.camel@localhost.localdomain> References: <1411031454.25255.11.camel@localhost.localdomain> MIME-Version: 1.0 X-Originating-IP: [10.167.226.111] Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Spam-Status: No, score=-7.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP When runing restore under lzo compression, "bad compress length" problems are encountered. It is because there is a page align problem with the @decompress_lzo, as follows: |------| |----|-| |------|...|------| page ^ page page | 3 bytes left When lzo compress pages im RAM, lzo will ensure that the 4 bytes len will be in one page as a whole. There is a situation that 3 (or less) bytes are left at the end of a page, and then the 4 bytes len is stored at the start of the next page. But the @decompress_lzo doesn't goto the start of the next page and continue to read the next 4 bytes which is across two pages, so a random value is fetched as a "bad compress length". So we check page alignment every time before we are going to fetch the next @len and after the former piece of data is decompressed. If the current page that we reach has less than 4 bytes left, then we should fetch the next @len at the start of next page. Signed-off-by: Marc Dietrich Signed-off-by: Gui Hecheng --- changelog v1->v2: adopt alignment check method suggested by Marc --- cmds-restore.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/cmds-restore.c b/cmds-restore.c index 38a131e..974f45d 100644 --- a/cmds-restore.c +++ b/cmds-restore.c @@ -57,6 +57,9 @@ static int dry_run = 0; #define LZO_LEN 4 #define PAGE_CACHE_SIZE 4096 +#define PAGE_CACHE_MASK (~(PAGE_CACHE_SIZE - 1)) +#define PAGE_CACHE_ALIGN(addr) (((addr) + PAGE_CACHE_SIZE - 1) \ + & PAGE_CACHE_MASK) #define lzo1x_worst_compress(x) ((x) + ((x) / 16) + 64 + 3) static int decompress_zlib(char *inbuf, char *outbuf, u64 compress_len, @@ -93,6 +96,28 @@ static inline size_t read_compress_length(unsigned char *buf) return le32_to_cpu(dlen); } +static void align_if_need(size_t *tot_in, size_t *in_len) +{ + int tot_in_aligned; + int bytes_left; + + tot_in_aligned = PAGE_CACHE_ALIGN(*tot_in); + bytes_left = tot_in_aligned - *tot_in; + + if (bytes_left >= LZO_LEN) + return; + + /* + * The LZO_LEN bytes is guaranteed to be + * in one page as a whole, so if a page + * has fewer than LZO_LEN bytes left, + * the LZO_LEN bytes should be fetched + * at the start of the next page + */ + *in_len += tot_in_aligned - *tot_in; + *tot_in = tot_in_aligned; +} + static int decompress_lzo(unsigned char *inbuf, char *outbuf, u64 compress_len, u64 *decompress_len) { @@ -135,8 +160,8 @@ static int decompress_lzo(unsigned char *inbuf, char *outbuf, u64 compress_len, } out_len += new_len; outbuf += new_len; + align_if_need(&tot_in, &in_len); inbuf += in_len; - tot_in += in_len; } *decompress_len = out_len;