From: Jaegeuk Kim <jaegeuk@kernel.org>
To: Yangtao Li <frank.li@vivo.com>
Cc: hanqi@vivo.com, linux-kernel@vger.kernel.org,
linux-f2fs-devel@lists.sourceforge.net
Subject: Re: [f2fs-dev] [PATCH] f2fs: fix to release compress file for F2FS_IOC_RESERVE_COMPRESS_BLOCKS when has no space
Date: Fri, 10 Feb 2023 13:30:19 -0800 [thread overview]
Message-ID: <Y+a3a0eSkhVUh/RG@google.com> (raw)
In-Reply-To: <20230210102019.61193-1-frank.li@vivo.com>
On 02/10, Yangtao Li wrote:
> When the released file is reserving and the space is insufficient,
> the fsck flag is set incorrectly, and lead to the file cannot be
> reserved and released normally.
>
> $ mount -t f2fs -o compress_extension=*,compress_mode=user /mnt/9p/f2fs.img
> /mnt/f2fs/
> $ dd if=/dev/zero of=/mnt/f2fs/800M bs=1M count=800
> $ dd if=/dev/zero of=/mnt/f2fs/60M bs=1M count=60
> $ f2fs_io compress /mnt/f2fs/60M
> $ ./mnt/9p/my_f2fs_io release_cblocks /mnt/f2fs/60M
> 11520
> $ dd if=/dev/zero of=/mnt/f2fs/30M bs=1M count=30
> $ f2fs_io reserve_cblocks /mnt/f2fs/60M
> [ 56.399712] F2FS-fs (loop0): f2fs_reserve_compress_blocks: partial blocks
> were released i_ino=cf iblocks=76104, reserved=5220, compr_blocks=5655,
> run fsck to fix.
> F2FS_IOC_RESERVE_COMPRESS_BLOCKS failed: No space left on device
>
> $ ./mnt/9p/my_f2fs_io reserve_cblocks /mnt/f2fs/60M
> 0
> $ ./mnt/9p/my_f2fs_io release_cblocks /mnt/f2fs/60M
> F2FS_IOC_RELEASE_COMPRESS_BLOCKS failed: Invalid argument
>
> $ rm /mnt/f2fs/30M
> $ ./mnt/9p/my_f2fs_io reserve_cblocks /mnt/f2fs/60M
> 0
> $ ./mnt/9p/my_f2fs_io release_cblocks /mnt/f2fs/60M
> F2FS_IOC_RELEASE_COMPRESS_BLOCKS failed: Invalid argument
>
> In this case, let's release back the reserved part of the compressed file.
>
> Fixes: c75488fb4d82 ("f2fs: introduce F2FS_IOC_RESERVE_COMPRESS_BLOCKS")
> Signed-off-by: Qi Han <hanqi@vivo.com>
> Signed-off-by: Yangtao Li <frank.li@vivo.com>
> ---
> fs/f2fs/file.c | 97 ++++++++++++++++++++++++++++++++------------------
> 1 file changed, 63 insertions(+), 34 deletions(-)
>
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index 300eae8b5415..8f3f55ac153a 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -3427,11 +3427,52 @@ static int release_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
> return released_blocks;
> }
>
> +static int f2fs_do_release_compress_blocks(struct inode *inode,
> + pgoff_t page_count, unsigned int *released_blocks)
> +{
> + pgoff_t page_idx = 0;
> + int ret;
> +
> + while (page_idx < page_count) {
> + struct dnode_of_data dn;
> + pgoff_t end_offset, count;
> +
> + set_new_dnode(&dn, inode, NULL, NULL, 0);
> + ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE);
> + if (ret) {
> + if (ret == -ENOENT) {
> + page_idx = f2fs_get_next_page_offset(&dn,
> + page_idx);
> + ret = 0;
> + continue;
> + }
> + break;
> + }
> +
> + end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
> + count = min(end_offset - dn.ofs_in_node, page_count - page_idx);
> + count = round_up(count, F2FS_I(inode)->i_cluster_size);
> +
> + ret = release_compress_blocks(&dn, count);
> +
> + f2fs_put_dnode(&dn);
> +
> + if (ret < 0)
> + break;
> +
> + page_idx += count;
> + if (released_blocks)
> + *released_blocks += ret;
> + }
> +
> + return ret;
> +}
> +
> static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg)
> {
> struct inode *inode = file_inode(filp);
> struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
> - pgoff_t page_idx = 0, last_idx;
> + pgoff_t last_idx;
> unsigned int released_blocks = 0;
> int ret;
> int writecount;
> @@ -3481,36 +3522,7 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg)
>
> last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
>
> - while (page_idx < last_idx) {
> - struct dnode_of_data dn;
> - pgoff_t end_offset, count;
> -
> - set_new_dnode(&dn, inode, NULL, NULL, 0);
> - ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE);
> - if (ret) {
> - if (ret == -ENOENT) {
> - page_idx = f2fs_get_next_page_offset(&dn,
> - page_idx);
> - ret = 0;
> - continue;
> - }
> - break;
> - }
> -
> - end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
> - count = min(end_offset - dn.ofs_in_node, last_idx - page_idx);
> - count = round_up(count, F2FS_I(inode)->i_cluster_size);
> -
> - ret = release_compress_blocks(&dn, count);
> -
> - f2fs_put_dnode(&dn);
> -
> - if (ret < 0)
> - break;
> -
> - page_idx += count;
> - released_blocks += ret;
> - }
> + ret = f2fs_do_release_compress_blocks(inode, last_idx, &released_blocks);
>
> filemap_invalidate_unlock(inode->i_mapping);
> f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
> @@ -3585,8 +3597,22 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
> if (ret)
> return ret;
>
> - if (reserved != cluster_size - compr_blocks)
> - return -ENOSPC;
> + if (reserved != cluster_size - compr_blocks) {
> + dec_valid_block_count(sbi, dn->inode, reserved);
This looks breaking the consistency?
> +
> + for (i = cluster_size - 1; i > 0; i--) {
> + dn->ofs_in_node--;
> + blkaddr = f2fs_data_blkaddr(dn);
> +
> + if (__is_valid_data_blkaddr(blkaddr)) {
> + dn->ofs_in_node -= i;
> + return -ENOSPC;
> + }
> +
> + dn->data_blkaddr = NULL_ADDR;
> + f2fs_set_data_blkaddr(dn);
> + }
> + }
>
> f2fs_i_compr_blocks_update(dn->inode, compr_blocks, true);
>
> @@ -3604,6 +3630,7 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
> struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
> pgoff_t page_idx = 0, last_idx;
> unsigned int reserved_blocks = 0;
> + struct dnode_of_data dn;
> int ret;
>
> if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
> @@ -3637,7 +3664,6 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
> last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
>
> while (page_idx < last_idx) {
> - struct dnode_of_data dn;
> pgoff_t end_offset, count;
>
> set_new_dnode(&dn, inode, NULL, NULL, 0);
> @@ -3667,6 +3693,9 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
> reserved_blocks += ret;
> }
>
> + if (ret == -ENOSPC)
> + f2fs_do_release_compress_blocks(inode, page_idx + dn.ofs_in_node, NULL);
> +
> filemap_invalidate_unlock(inode->i_mapping);
> f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
>
> --
> 2.25.1
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
WARNING: multiple messages have this Message-ID (diff)
From: Jaegeuk Kim <jaegeuk@kernel.org>
To: Yangtao Li <frank.li@vivo.com>
Cc: chao@kernel.org, linux-f2fs-devel@lists.sourceforge.net,
linux-kernel@vger.kernel.org, hanqi@vivo.com
Subject: Re: [PATCH] f2fs: fix to release compress file for F2FS_IOC_RESERVE_COMPRESS_BLOCKS when has no space
Date: Fri, 10 Feb 2023 13:30:19 -0800 [thread overview]
Message-ID: <Y+a3a0eSkhVUh/RG@google.com> (raw)
In-Reply-To: <20230210102019.61193-1-frank.li@vivo.com>
On 02/10, Yangtao Li wrote:
> When the released file is reserving and the space is insufficient,
> the fsck flag is set incorrectly, and lead to the file cannot be
> reserved and released normally.
>
> $ mount -t f2fs -o compress_extension=*,compress_mode=user /mnt/9p/f2fs.img
> /mnt/f2fs/
> $ dd if=/dev/zero of=/mnt/f2fs/800M bs=1M count=800
> $ dd if=/dev/zero of=/mnt/f2fs/60M bs=1M count=60
> $ f2fs_io compress /mnt/f2fs/60M
> $ ./mnt/9p/my_f2fs_io release_cblocks /mnt/f2fs/60M
> 11520
> $ dd if=/dev/zero of=/mnt/f2fs/30M bs=1M count=30
> $ f2fs_io reserve_cblocks /mnt/f2fs/60M
> [ 56.399712] F2FS-fs (loop0): f2fs_reserve_compress_blocks: partial blocks
> were released i_ino=cf iblocks=76104, reserved=5220, compr_blocks=5655,
> run fsck to fix.
> F2FS_IOC_RESERVE_COMPRESS_BLOCKS failed: No space left on device
>
> $ ./mnt/9p/my_f2fs_io reserve_cblocks /mnt/f2fs/60M
> 0
> $ ./mnt/9p/my_f2fs_io release_cblocks /mnt/f2fs/60M
> F2FS_IOC_RELEASE_COMPRESS_BLOCKS failed: Invalid argument
>
> $ rm /mnt/f2fs/30M
> $ ./mnt/9p/my_f2fs_io reserve_cblocks /mnt/f2fs/60M
> 0
> $ ./mnt/9p/my_f2fs_io release_cblocks /mnt/f2fs/60M
> F2FS_IOC_RELEASE_COMPRESS_BLOCKS failed: Invalid argument
>
> In this case, let's release back the reserved part of the compressed file.
>
> Fixes: c75488fb4d82 ("f2fs: introduce F2FS_IOC_RESERVE_COMPRESS_BLOCKS")
> Signed-off-by: Qi Han <hanqi@vivo.com>
> Signed-off-by: Yangtao Li <frank.li@vivo.com>
> ---
> fs/f2fs/file.c | 97 ++++++++++++++++++++++++++++++++------------------
> 1 file changed, 63 insertions(+), 34 deletions(-)
>
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index 300eae8b5415..8f3f55ac153a 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -3427,11 +3427,52 @@ static int release_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
> return released_blocks;
> }
>
> +static int f2fs_do_release_compress_blocks(struct inode *inode,
> + pgoff_t page_count, unsigned int *released_blocks)
> +{
> + pgoff_t page_idx = 0;
> + int ret;
> +
> + while (page_idx < page_count) {
> + struct dnode_of_data dn;
> + pgoff_t end_offset, count;
> +
> + set_new_dnode(&dn, inode, NULL, NULL, 0);
> + ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE);
> + if (ret) {
> + if (ret == -ENOENT) {
> + page_idx = f2fs_get_next_page_offset(&dn,
> + page_idx);
> + ret = 0;
> + continue;
> + }
> + break;
> + }
> +
> + end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
> + count = min(end_offset - dn.ofs_in_node, page_count - page_idx);
> + count = round_up(count, F2FS_I(inode)->i_cluster_size);
> +
> + ret = release_compress_blocks(&dn, count);
> +
> + f2fs_put_dnode(&dn);
> +
> + if (ret < 0)
> + break;
> +
> + page_idx += count;
> + if (released_blocks)
> + *released_blocks += ret;
> + }
> +
> + return ret;
> +}
> +
> static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg)
> {
> struct inode *inode = file_inode(filp);
> struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
> - pgoff_t page_idx = 0, last_idx;
> + pgoff_t last_idx;
> unsigned int released_blocks = 0;
> int ret;
> int writecount;
> @@ -3481,36 +3522,7 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg)
>
> last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
>
> - while (page_idx < last_idx) {
> - struct dnode_of_data dn;
> - pgoff_t end_offset, count;
> -
> - set_new_dnode(&dn, inode, NULL, NULL, 0);
> - ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE);
> - if (ret) {
> - if (ret == -ENOENT) {
> - page_idx = f2fs_get_next_page_offset(&dn,
> - page_idx);
> - ret = 0;
> - continue;
> - }
> - break;
> - }
> -
> - end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
> - count = min(end_offset - dn.ofs_in_node, last_idx - page_idx);
> - count = round_up(count, F2FS_I(inode)->i_cluster_size);
> -
> - ret = release_compress_blocks(&dn, count);
> -
> - f2fs_put_dnode(&dn);
> -
> - if (ret < 0)
> - break;
> -
> - page_idx += count;
> - released_blocks += ret;
> - }
> + ret = f2fs_do_release_compress_blocks(inode, last_idx, &released_blocks);
>
> filemap_invalidate_unlock(inode->i_mapping);
> f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
> @@ -3585,8 +3597,22 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
> if (ret)
> return ret;
>
> - if (reserved != cluster_size - compr_blocks)
> - return -ENOSPC;
> + if (reserved != cluster_size - compr_blocks) {
> + dec_valid_block_count(sbi, dn->inode, reserved);
This looks breaking the consistency?
> +
> + for (i = cluster_size - 1; i > 0; i--) {
> + dn->ofs_in_node--;
> + blkaddr = f2fs_data_blkaddr(dn);
> +
> + if (__is_valid_data_blkaddr(blkaddr)) {
> + dn->ofs_in_node -= i;
> + return -ENOSPC;
> + }
> +
> + dn->data_blkaddr = NULL_ADDR;
> + f2fs_set_data_blkaddr(dn);
> + }
> + }
>
> f2fs_i_compr_blocks_update(dn->inode, compr_blocks, true);
>
> @@ -3604,6 +3630,7 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
> struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
> pgoff_t page_idx = 0, last_idx;
> unsigned int reserved_blocks = 0;
> + struct dnode_of_data dn;
> int ret;
>
> if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
> @@ -3637,7 +3664,6 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
> last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
>
> while (page_idx < last_idx) {
> - struct dnode_of_data dn;
> pgoff_t end_offset, count;
>
> set_new_dnode(&dn, inode, NULL, NULL, 0);
> @@ -3667,6 +3693,9 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
> reserved_blocks += ret;
> }
>
> + if (ret == -ENOSPC)
> + f2fs_do_release_compress_blocks(inode, page_idx + dn.ofs_in_node, NULL);
> +
> filemap_invalidate_unlock(inode->i_mapping);
> f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
>
> --
> 2.25.1
next prev parent reply other threads:[~2023-02-10 21:30 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-02-10 10:20 [f2fs-dev] [PATCH] f2fs: fix to release compress file for F2FS_IOC_RESERVE_COMPRESS_BLOCKS when has no space Yangtao Li via Linux-f2fs-devel
2023-02-10 10:20 ` Yangtao Li
2023-02-10 21:30 ` Jaegeuk Kim [this message]
2023-02-10 21:30 ` Jaegeuk Kim
2023-02-13 14:28 ` [f2fs-dev] " Yangtao Li via Linux-f2fs-devel
2023-02-13 14:28 ` Yangtao Li
2023-02-15 15:13 ` [f2fs-dev] " Yangtao Li via Linux-f2fs-devel
2023-02-15 15:13 ` Yangtao Li
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=Y+a3a0eSkhVUh/RG@google.com \
--to=jaegeuk@kernel.org \
--cc=frank.li@vivo.com \
--cc=hanqi@vivo.com \
--cc=linux-f2fs-devel@lists.sourceforge.net \
--cc=linux-kernel@vger.kernel.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.