mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Chao Yu <yuchao0@huawei.com>
To: Nick Terrell <terrelln@fb.com>
Cc: Nick Terrell <nickrterrell@gmail.com>,
	"linux-f2fs-devel@lists.sourceforge.net" 
	<linux-f2fs-devel@lists.sourceforge.net>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	Kernel Team <Kernel-team@fb.com>, Chris Mason <clm@fb.com>,
	Petr Malat <oss@malat.biz>, Johannes Weiner <jweiner@fb.com>,
	Niket Agarwal <niketa@fb.com>, Yann Collet <cyan@fb.com>
Subject: Re: [PATCH 6/9] f2fs: zstd: Switch to the zstd-1.4.6 API
Date: Fri, 18 Sep 2020 09:47:32 +0800	[thread overview]
Message-ID: <a8b6e21d-fb51-1a50-8f2a-045f3a496c12@huawei.com> (raw)
In-Reply-To: <9589E483-A94B-4AF6-8C03-B0763715B40A@fb.com>

On 2020/9/18 3:34, Nick Terrell wrote:
> 
> 
>> On Sep 17, 2020, at 11:00 AM, Nick Terrell <terrelln@fb.com> wrote:
>>
>>
>>
>>> On Sep 16, 2020, at 11:31 PM, Chao Yu <yuchao0@huawei.com> wrote:
>>>
>>> Hi Nick,
>>>
>>> On 2020/9/17 2:39, Nick Terrell wrote:
>>>>> On Sep 15, 2020, at 11:31 PM, Chao Yu <yuchao0@huawei.com> wrote:
>>>>>
>>>>> Hi Nick,
>>>>>
>>>>> remove not related mailing list.
>>>>>
>>>>> On 2020/9/16 11:43, Nick Terrell wrote:
>>>>>> From: Nick Terrell <terrelln@fb.com>
>>>>>> Move away from the compatibility wrapper to the zstd-1.4.6 API. This
>>>>>> code is more efficient because it uses the single-pass API instead of
>>>>>> the streaming API. The streaming API is not necessary because the whole
>>>>>> input and output buffers are available. This saves memory because we
>>>>>> don't need to allocate a buffer for the window. It is also more
>>>>>> efficient because it saves unnecessary memcpy calls.
>>>>>> I've had problems testing this code because I see data truncation before
>>>>>> and after this patchset. Help testing this patch would be much
>>>>>> appreciated.
>>>>>
>>>>> Can you please explain more about data truncation? I'm a little confused...
>>>>>
>>>>> Do you mean that f2fs doesn't allocate enough memory for zstd compression,
>>>>> so that compression is not finished actually, the compressed data is truncated
>>>>> at dst buffer?
>>>> Hi Chao,
>>>> I’ve tested F2FS using a benchmark I adapted from testing BtrFS [0]. It is possible
>>>> that the script I’m using is buggy or is exposing an edge case in F2FS. The files
>>>> that I copy to F2FS and compress end up truncated with a hole at the end.
>>>
>>> Thanks for your explanation. :)
>>>
>>>> It is based off of upstream commit ab29a807a7.
>>>> E.g. the end of the copied file looks like this, but the original file has non-zero data
>>>> In the end. Until the hole at the end the file is correct.
>>>> od dickens | tail -n 5
>>>>> 46667760 067502 066167 020056 040440 020163 023511 006555 060412
>>>>> 46670000 000000 000000 000000 000000 000000 000000 000000 000000
>>>>> *
>>>>> 46703060 000000 000000 000000 000000 000000 000000 000000
>>>>> 46703076
>>>> [0] https://gist.github.com/terrelln/7dd2919937dfbdb8e839e4ad11c81db4
>>>
>>> Shouldn't we just get sha1 value by flitering sha1sum output?
>>>
>>>                asha=`sha1sum $BENCHMARK_DIR/$file |awk {'print $1'}`
>>>                bsha=`sha1sum $MP/$i/$file |awk {'print $1'}`
>>
>> Probably, but it was just a quick one-off script.
> 
> Ah, never mind, you are right.
> 
>>> I can't reproduce this issue by using simple data sample, could you share
>>> that 'dickens' file or other smaller-sized sample if you have?
>>
>> The /tmp/silesia directory in the example is populated with all the files from
>> this website. It is a popular data compression benchmark corpus. You can
>> click on the “total” link to download a zip archive of all the files.
>>
>> http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia
>>
>> -Nick
> 
> I’ve spent some time minimizing the test case. This script [0] is the minimized
> test case that doesn’t require any input files, it builds its own.
> 
> Several observations:
> * The input file needs to be 7700481 bytes large, smaller files don’t trigger the bug.
> * You have to `chattr +c` the file after copying it otherwise the bug doesn’t occur.
> * After `chattr +c` you have to unmount and remount the filesystem to trigger the bug.
> 
> I’ve reproduced on v5.9-rc5 (856deb866d16e). I’ve also reproduced on my host machine
> running 5.8.5-arch1-1.
> 
> [0] https://gist.github.com/terrelln/4bba325abdfa3a6f014e9911ac92a185

Ah, I got it.

Step of enabling compressed inode is not correct, we should touch an empty file, and
then use 'chattr +c' on that file to enable compression, otherwise the race condition
could be complicated to handle. So we need below diff to disallow setting compression
flag on an non-empty file:

diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 8a422400e824..b462db7898fd 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -1836,6 +1836,8 @@ static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask)
  		if (iflags & F2FS_COMPR_FL) {
  			if (!f2fs_may_compress(inode))
  				return -EINVAL;
+			if (get_dirty_pages(inode) || fi->i_compr_blocks)
+				return  -EINVAL;

  			set_compress_context(inode);
  		}

Could you adjust your script and retest?

touch $DST_FILE
chattr +c $DST_FILE
cp $SRC_FILE $DST_FILE

Thanks,

> 
> Best,
> Nick
> 
>>> Thanks,
>>>
>>>> Best,
>>>> Nick
>>>>> Thanks,
>>>>>
>>>>>> Signed-off-by: Nick Terrell <terrelln@fb.com>
>>>>>> ---
>>>>>> fs/f2fs/compress.c | 102 +++++++++++++++++----------------------------
>>>>>> 1 file changed, 38 insertions(+), 64 deletions(-)
>>>>>> diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
>>>>>> index e056f3a2b404..b79efce81651 100644
>>>>>> --- a/fs/f2fs/compress.c
>>>>>> +++ b/fs/f2fs/compress.c
>>>>>> @@ -11,7 +11,8 @@
>>>>>> #include <linux/backing-dev.h>
>>>>>> #include <linux/lzo.h>
>>>>>> #include <linux/lz4.h>
>>>>>> -#include <linux/zstd_compat.h>
>>>>>> +#include <linux/zstd.h>
>>>>>> +#include <linux/zstd_errors.h>
>>>>>>    #include "f2fs.h"
>>>>>> #include "node.h"
>>>>>> @@ -298,21 +299,21 @@ static const struct f2fs_compress_ops f2fs_lz4_ops = {
>>>>>> static int zstd_init_compress_ctx(struct compress_ctx *cc)
>>>>>> {
>>>>>> 	ZSTD_parameters params;
>>>>>> -	ZSTD_CStream *stream;
>>>>>> +	ZSTD_CCtx *ctx;
>>>>>> 	void *workspace;
>>>>>> 	unsigned int workspace_size;
>>>>>>    	params = ZSTD_getParams(F2FS_ZSTD_DEFAULT_CLEVEL, cc->rlen, 0);
>>>>>> -	workspace_size = ZSTD_CStreamWorkspaceBound(params.cParams);
>>>>>> +	workspace_size = ZSTD_estimateCCtxSize_usingCParams(params.cParams);
>>>>>>    	workspace = f2fs_kvmalloc(F2FS_I_SB(cc->inode),
>>>>>> 					workspace_size, GFP_NOFS);
>>>>>> 	if (!workspace)
>>>>>> 		return -ENOMEM;
>>>>>> -	stream = ZSTD_initCStream(params, 0, workspace, workspace_size);
>>>>>> -	if (!stream) {
>>>>>> -		printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_initCStream failed\n",
>>>>>> +	ctx = ZSTD_initStaticCCtx(workspace, workspace_size);
>>>>>> +	if (!ctx) {
>>>>>> +		printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_inittaticCStream failed\n",
>>>>>> 				KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id,
>>>>>> 				__func__);
>>>>>> 		kvfree(workspace);
>>>>>> @@ -320,7 +321,7 @@ static int zstd_init_compress_ctx(struct compress_ctx *cc)
>>>>>> 	}
>>>>>>    	cc->private = workspace;
>>>>>> -	cc->private2 = stream;
>>>>>> +	cc->private2 = ctx;
>>>>>>    	cc->clen = cc->rlen - PAGE_SIZE - COMPRESS_HEADER_SIZE;
>>>>>> 	return 0;
>>>>>> @@ -335,65 +336,48 @@ static void zstd_destroy_compress_ctx(struct compress_ctx *cc)
>>>>>>    static int zstd_compress_pages(struct compress_ctx *cc)
>>>>>> {
>>>>>> -	ZSTD_CStream *stream = cc->private2;
>>>>>> -	ZSTD_inBuffer inbuf;
>>>>>> -	ZSTD_outBuffer outbuf;
>>>>>> -	int src_size = cc->rlen;
>>>>>> -	int dst_size = src_size - PAGE_SIZE - COMPRESS_HEADER_SIZE;
>>>>>> -	int ret;
>>>>>> -
>>>>>> -	inbuf.pos = 0;
>>>>>> -	inbuf.src = cc->rbuf;
>>>>>> -	inbuf.size = src_size;
>>>>>> -
>>>>>> -	outbuf.pos = 0;
>>>>>> -	outbuf.dst = cc->cbuf->cdata;
>>>>>> -	outbuf.size = dst_size;
>>>>>> -
>>>>>> -	ret = ZSTD_compressStream(stream, &outbuf, &inbuf);
>>>>>> -	if (ZSTD_isError(ret)) {
>>>>>> -		printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_compressStream failed, ret: %d\n",
>>>>>> -				KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id,
>>>>>> -				__func__, ZSTD_getErrorCode(ret));
>>>>>> -		return -EIO;
>>>>>> -	}
>>>>>> -
>>>>>> -	ret = ZSTD_endStream(stream, &outbuf);
>>>>>> +	ZSTD_CCtx *ctx = cc->private2;
>>>>>> +	const size_t src_size = cc->rlen;
>>>>>> +	const size_t dst_size = src_size - PAGE_SIZE - COMPRESS_HEADER_SIZE;
>>>>>> +	ZSTD_parameters params = ZSTD_getParams(F2FS_ZSTD_DEFAULT_CLEVEL, src_size, 0);
>>>>>> +	size_t ret;
>>>>>> +
>>>>>> +	ret = ZSTD_compress_advanced(
>>>>>> +			ctx, cc->cbuf->cdata, dst_size, cc->rbuf, src_size, NULL, 0, params);
>>>>>> 	if (ZSTD_isError(ret)) {
>>>>>> -		printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_endStream returned %d\n",
>>>>>> +		/*
>>>>>> +		 * there is compressed data remained in intermediate buffer due to
>>>>>> +		 * no more space in cbuf.cdata
>>>>>> +		 */
>>>>>> +		if (ZSTD_getErrorCode(ret) == ZSTD_error_dstSize_tooSmall)
>>>>>> +			return -EAGAIN;
>>>>>> +		/* other compression errors return -EIO */
>>>>>> +		printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_compress_advanced failed, err: %s\n",
>>>>>> 				KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id,
>>>>>> -				__func__, ZSTD_getErrorCode(ret));
>>>>>> +				__func__, ZSTD_getErrorName(ret));
>>>>>> 		return -EIO;
>>>>>> 	}
>>>>>> -	/*
>>>>>> -	 * there is compressed data remained in intermediate buffer due to
>>>>>> -	 * no more space in cbuf.cdata
>>>>>> -	 */
>>>>>> -	if (ret)
>>>>>> -		return -EAGAIN;
>>>>>> -
>>>>>> -	cc->clen = outbuf.pos;
>>>>>> +	cc->clen = ret;
>>>>>> 	return 0;
>>>>>> }
>>>>>>    static int zstd_init_decompress_ctx(struct decompress_io_ctx *dic)
>>>>>> {
>>>>>> -	ZSTD_DStream *stream;
>>>>>> +	ZSTD_DCtx *ctx;
>>>>>> 	void *workspace;
>>>>>> 	unsigned int workspace_size;
>>>>>> -	workspace_size = ZSTD_DStreamWorkspaceBound(MAX_COMPRESS_WINDOW_SIZE);
>>>>>> +	workspace_size = ZSTD_estimateDCtxSize();
>>>>>>    	workspace = f2fs_kvmalloc(F2FS_I_SB(dic->inode),
>>>>>> 					workspace_size, GFP_NOFS);
>>>>>> 	if (!workspace)
>>>>>> 		return -ENOMEM;
>>>>>> -	stream = ZSTD_initDStream(MAX_COMPRESS_WINDOW_SIZE,
>>>>>> -					workspace, workspace_size);
>>>>>> -	if (!stream) {
>>>>>> -		printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_initDStream failed\n",
>>>>>> +	ctx = ZSTD_initStaticDCtx(workspace, workspace_size);
>>>>>> +	if (!ctx) {
>>>>>> +		printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_initStaticDCtx failed\n",
>>>>>> 				KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id,
>>>>>> 				__func__);
>>>>>> 		kvfree(workspace);
>>>>>> @@ -401,7 +385,7 @@ static int zstd_init_decompress_ctx(struct decompress_io_ctx *dic)
>>>>>> 	}
>>>>>>    	dic->private = workspace;
>>>>>> -	dic->private2 = stream;
>>>>>> +	dic->private2 = ctx;
>>>>>>    	return 0;
>>>>>> }
>>>>>> @@ -415,28 +399,18 @@ static void zstd_destroy_decompress_ctx(struct decompress_io_ctx *dic)
>>>>>>    static int zstd_decompress_pages(struct decompress_io_ctx *dic)
>>>>>> {
>>>>>> -	ZSTD_DStream *stream = dic->private2;
>>>>>> -	ZSTD_inBuffer inbuf;
>>>>>> -	ZSTD_outBuffer outbuf;
>>>>>> -	int ret;
>>>>>> -
>>>>>> -	inbuf.pos = 0;
>>>>>> -	inbuf.src = dic->cbuf->cdata;
>>>>>> -	inbuf.size = dic->clen;
>>>>>> -
>>>>>> -	outbuf.pos = 0;
>>>>>> -	outbuf.dst = dic->rbuf;
>>>>>> -	outbuf.size = dic->rlen;
>>>>>> +	ZSTD_DCtx *ctx = dic->private2;
>>>>>> +	size_t ret;
>>>>>> -	ret = ZSTD_decompressStream(stream, &outbuf, &inbuf);
>>>>>> +	ret = ZSTD_decompressDCtx(ctx, dic->rbuf, dic->rlen, dic->cbuf->cdata, dic->clen);
>>>>>> 	if (ZSTD_isError(ret)) {
>>>>>> -		printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_compressStream failed, ret: %d\n",
>>>>>> +		printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_decompressDCtx failed, err: %s\n",
>>>>>> 				KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id,
>>>>>> -				__func__, ZSTD_getErrorCode(ret));
>>>>>> +				__func__, ZSTD_getErrorName(ret));
>>>>>> 		return -EIO;
>>>>>> 	}
>>>>>> -	if (dic->rlen != outbuf.pos) {
>>>>>> +	if (dic->rlen != ret) {
>>>>>> 		printk_ratelimited("%sF2FS-fs (%s): %s ZSTD invalid rlen:%zu, "
>>>>>> 				"expected:%lu\n", KERN_ERR,
>>>>>> 				F2FS_I_SB(dic->inode)->sb->s_id,
> 

  reply	other threads:[~2020-09-18  1:47 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-09-16  3:42 [PATCH 0/9] Update to zstd-1.4.6 Nick Terrell
2020-09-16  3:42 ` [PATCH 1/9] lib: zstd: Add zstd compatibility wrapper Nick Terrell
2020-09-16  8:48   ` Christoph Hellwig
2020-09-16 20:21     ` Nick Terrell
2020-09-16  3:42 ` [PATCH 2/9] lib: zstd: Add decompress_sources.h for decompress_unzstd Nick Terrell
2020-09-16  3:42 ` [PATCH 3/9] lib: zstd: Upgrade to latest upstream zstd version 1.4.6 Nick Terrell
2020-09-16  8:01   ` kernel test robot
2020-09-16 20:53   ` Nick Terrell
2020-09-16 20:53     ` Nick Terrell
2020-09-16  3:42 ` [PATCH 4/9] crypto: zstd: Switch to zstd-1.4.6 API Nick Terrell
2020-09-16  8:49   ` Christoph Hellwig
2020-09-16  3:42 ` [PATCH 5/9] btrfs: zstd: Switch to the " Nick Terrell
2020-09-16  8:49   ` Christoph Hellwig
2020-09-16 14:20     ` Chris Mason
2020-09-16 14:30       ` Christoph Hellwig
2020-09-16 14:43         ` Chris Mason
2020-09-16 14:46           ` Christoph Hellwig
2020-09-16 15:01             ` Chris Mason
2020-09-16 18:27             ` Eric Biggers
2020-09-16 19:18             ` Nick Terrell
2020-09-17  1:35               ` Rik van Riel
2020-09-17 10:04                 ` Christoph Hellwig
2020-09-17 14:28                   ` Chris Mason
2020-09-17 17:57                     ` Nick Terrell
2020-09-16  3:43 ` [PATCH 6/9] f2fs: " Nick Terrell
2020-09-16  6:31   ` Chao Yu
2020-09-16 18:39     ` Nick Terrell
2020-09-16 18:39       ` Nick Terrell
2020-09-17  6:31       ` Chao Yu
2020-09-17 18:00         ` Nick Terrell
2020-09-17 19:34           ` Nick Terrell
2020-09-18  1:47             ` Chao Yu [this message]
2020-09-18  2:56               ` Eric Biggers
2020-09-18  2:58                 ` Chao Yu
2020-09-18  5:39               ` Nick Terrell
2020-09-18  1:41           ` Chao Yu
2020-09-16  3:43 ` [PATCH 7/9] squashfs: " Nick Terrell
2020-09-16  3:43 ` [PATCH 8/9] lib: unzstd: " Nick Terrell
2020-09-16  3:43 ` [PATCH 9/9] lib: zstd: Remove zstd compatibility wrapper Nick Terrell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=a8b6e21d-fb51-1a50-8f2a-045f3a496c12@huawei.com \
    --to=yuchao0@huawei.com \
    --cc=Kernel-team@fb.com \
    --cc=clm@fb.com \
    --cc=cyan@fb.com \
    --cc=jweiner@fb.com \
    --cc=linux-f2fs-devel@lists.sourceforge.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nickrterrell@gmail.com \
    --cc=niketa@fb.com \
    --cc=oss@malat.biz \
    --cc=terrelln@fb.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®