All of lore.kernel.org
 help / color / mirror / Atom feed
From: Qu Wenruo <quwenruo.btrfs@gmx.com>
To: fdmanana@kernel.org, linux-btrfs@vger.kernel.org
Subject: Re: [PATCH v2] btrfs: send: fix missing hole punching during incremental send
Date: Fri, 23 Oct 2026 17:09:16 +1030	[thread overview]
Message-ID: <31e4e491-c331-43fa-bbf5-7459860834de@gmx.com> (raw)
In-Reply-To: <087634ad0970d81654b2f1cc72cd35bbde47df97.1792618636.git.fdmanana@suse.com>



在 2026/10/22 08:11, fdmanana@kernel.org 写道:
> From: Filipe Manana <fdmanana@suse.com>
> 
> When using the no-holes feature (enabled by default since btrfs-progs
> v5.15) and doing an incremental send, we can miss issuing a hole punching
> command when the following conditions happen:
> 
> 1) A hole is punched in a tail section of a file extent item that happens
>     to be the last item in a leaf (for example the extent covers the file
>     range [1M, 3M) and a hole is punched in the range [2M, 3M)). Between
>     the end of this file extent item's range and the i_size, there are
>     other file extent items;
> 
> 2) The next leaf was not modified in the send snapshot, remaining shared
>     with the parent snapshot.
> 
> In this scenario we are unable to detect a hole was punched and never
> issue a hole punch command because with no-holes there we don't have an
> exlicit file extent item to mark a hole.
> 
> Fix this by teaching maybe_send_hole() to detect such case.
> A test case for fstests will follow soon.
> 
> Reported-by: Tristan Elvers <tristanelvers@gmail.com>
> Link: https://lore.kernel.org/linux-btrfs/CAFoLKK+aErV4p6ZJPnVeH5SHQ5++0f=8ZgxPWe-E-CkeKBs8PA@mail.gmail.com/
> Fixes: 16e7549f045d ("Btrfs: incompatible format change to remove hole extents")
> Signed-off-by: Filipe Manana <fdmanana@suse.com>
> ---
> 
> V2: Address a couple issues pointed by sashiko, simplify a few things.
> 
>   fs/btrfs/send.c | 62 +++++++++++++++++++++++++++++++++++++++++++++----
>   1 file changed, 58 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
> index c523bf950c89..cec1aae5ce14 100644
> --- a/fs/btrfs/send.c
> +++ b/fs/btrfs/send.c
> @@ -6371,6 +6371,8 @@ static int range_is_hole_in_parent(struct send_ctx *sctx,
>   static int maybe_send_hole(struct send_ctx *sctx, struct btrfs_path *path,
>   			   struct btrfs_key *key)
>   {
> +	BTRFS_PATH_AUTO_FREE(next_path);
> +	u64 next_offset;
>   	int ret = 0;
>   
>   	if (sctx->cur_ino != key->objectid || !need_send_hole(sctx))
> @@ -6397,14 +6399,66 @@ static int maybe_send_hole(struct send_ctx *sctx, struct btrfs_path *path,
>   		ret = range_is_hole_in_parent(sctx,
>   					      sctx->cur_inode_last_extent,
>   					      key->offset);
> -		if (ret < 0)
> -			return ret;
> -		else if (ret == 0)
> +		if (ret == 0)
>   			ret = send_hole(sctx, key->offset);
> -		else
> +		else if (ret == 1)
>   			ret = 0;
> +
> +		if (ret < 0)
> +			return ret;
>   	}
>   	sctx->cur_inode_last_extent = btrfs_file_extent_end(path);
> +
> +	/*
> +	 * If we are the last file extent item in a leaf, we may have had a tail
> +	 * section that got a hole punched, and if there is no change in the
> +	 * next leaf, we must find out if we have such a hole and punch it.
> +	 */
> +	if (path->slots[0] != btrfs_header_nritems(path->nodes[0]) - 1)
> +		return ret;

Just a nitpick, do we need to check NO_HOLES features? IIRC without 
NO_HOLES, we should always have a file extent covering i_size, thus 
without NO_HOLES, we should not need to check for the next leaf?

Thanks,
Qu

> +
> +	next_path = alloc_path_for_send();
> +	if (!next_path)
> +		return -ENOMEM;
> +
> +	ret = btrfs_search_slot(NULL, sctx->send_root, key, next_path, 0, 0);
> +	if (ret < 0)
> +		return ret;
> +	if (WARN_ON(ret != 0))
> +		return -EUCLEAN;
> +
> +	ret = btrfs_next_leaf(sctx->send_root, next_path);
> +	if (ret < 0) {
> +		return ret;
> +	} else if (ret > 0) {
> +		/*
> +		 * No next leaf, must punch hole to i_size and set the path back
> +		 * to where it was before.
> +		 */
> +		next_offset = sctx->cur_inode_size;
> +	} else {
> +		struct btrfs_key next_key;
> +
> +		btrfs_item_key_to_cpu(next_path->nodes[0], &next_key,
> +				      next_path->slots[0]);
> +		if (next_key.objectid != key->objectid ||
> +		    next_key.type != BTRFS_EXTENT_DATA_KEY)
> +			next_offset = sctx->cur_inode_size;
> +		else
> +			next_offset = next_key.offset;
> +	}
> +
> +	btrfs_free_path(next_path);
> +	next_path = NULL;
> +
> +	ret = range_is_hole_in_parent(sctx, sctx->cur_inode_last_extent, next_offset);
> +	if (ret == 0)
> +		ret = send_hole(sctx, next_offset);
> +	else if (ret == 1)
> +		ret = 0;
> +
> +	sctx->cur_inode_last_extent = next_offset;
> +
>   	return ret;
>   }
>   


  reply	other threads:[~2026-10-23  6:39 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-21 20:17 [PATCH] btrfs: send: fix missing hole punching during incremental send fdmanana
2026-10-21 21:41 ` [PATCH v2] " fdmanana
2026-10-23  6:39   ` Qu Wenruo [this message]
2026-10-23  8:51     ` Filipe Manana
2026-10-23  8:51 ` [PATCH v3] " fdmanana
2026-10-23  9:21   ` Qu Wenruo

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=31e4e491-c331-43fa-bbf5-7459860834de@gmx.com \
    --to=quwenruo.btrfs@gmx.com \
    --cc=fdmanana@kernel.org \
    --cc=linux-btrfs@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.