linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Liu Bo <bo.li.liu@oracle.com>
To: Filipe David Borba Manana <fdmanana@gmail.com>
Cc: linux-btrfs@vger.kernel.org
Subject: Re: [PATCH v4] Btrfs: fix clone to deal with holes when NO_HOLES feature is enabled
Date: Wed, 4 Jun 2014 16:25:13 +0800	[thread overview]
Message-ID: <20140604082512.GB17398@localhost.localdomain> (raw)
In-Reply-To: <1401583828-9230-1-git-send-email-fdmanana@gmail.com>

On Sun, Jun 01, 2014 at 01:50:28AM +0100, Filipe David Borba Manana wrote:
> If the NO_HOLES feature is enabled holes don't have file extent items in
> the btree that represent them anymore. This made the clone operation
> ignore the gaps that exist between consecutive file extent items and
> therefore not create the holes at the destination. When not using the
> NO_HOLES feature, the holes were created at the destination.
> 
> A test case for xfstests follows.

Reviewed-by: Liu Bo <bo.li.liu@oracle.com>

-liubo

> 
> Signed-off-by: Filipe David Borba Manana <fdmanana@gmail.com>
> ---
> 
> V2: Deal with holes at the boundaries of the cloning range and that
>     either overlap the boundary completely or partially.
>     Test case for xfstests updated too to test these 2 cases.
> 
> V3: Deal with the case where the cloning range overlaps (partially or
>     completely) a hole at the end of the source file, and might increase
>     the size of the target file.
>     Updated the test for xfstests to cover these cases too.
> 
> V4: Moved some duplicated code into an helper function.
> 
>  fs/btrfs/ioctl.c | 108 ++++++++++++++++++++++++++++++++++++++++++-------------
>  1 file changed, 83 insertions(+), 25 deletions(-)
> 
> diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
> index 04ece8f..95194a9 100644
> --- a/fs/btrfs/ioctl.c
> +++ b/fs/btrfs/ioctl.c
> @@ -2983,6 +2983,37 @@ out:
>  	return ret;
>  }
>  
> +static int clone_finish_inode_update(struct btrfs_trans_handle *trans,
> +				     struct inode *inode,
> +				     u64 endoff,
> +				     const u64 destoff,
> +				     const u64 olen)
> +{
> +	struct btrfs_root *root = BTRFS_I(inode)->root;
> +	int ret;
> +
> +	inode_inc_iversion(inode);
> +	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
> +	/*
> +	 * We round up to the block size at eof when determining which
> +	 * extents to clone above, but shouldn't round up the file size.
> +	 */
> +	if (endoff > destoff + olen)
> +		endoff = destoff + olen;
> +	if (endoff > inode->i_size)
> +		btrfs_i_size_write(inode, endoff);
> +
> +	ret = btrfs_update_inode(trans, root, inode);
> +	if (ret) {
> +		btrfs_abort_transaction(trans, root, ret);
> +		btrfs_end_transaction(trans, root);
> +		goto out;
> +	}
> +	ret = btrfs_end_transaction(trans, root);
> +out:
> +	return ret;
> +}
> +
>  /**
>   * btrfs_clone() - clone a range from inode file to another
>   *
> @@ -2995,7 +3026,8 @@ out:
>   * @destoff: Offset within @inode to start clone
>   */
>  static int btrfs_clone(struct inode *src, struct inode *inode,
> -		       u64 off, u64 olen, u64 olen_aligned, u64 destoff)
> +		       const u64 off, const u64 olen, const u64 olen_aligned,
> +		       const u64 destoff)
>  {
>  	struct btrfs_root *root = BTRFS_I(inode)->root;
>  	struct btrfs_path *path = NULL;
> @@ -3007,8 +3039,9 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
>  	int slot;
>  	int ret;
>  	int no_quota;
> -	u64 len = olen_aligned;
> +	const u64 len = olen_aligned;
>  	u64 last_disko = 0;
> +	u64 last_dest_end = destoff;
>  
>  	ret = -ENOMEM;
>  	buf = vmalloc(btrfs_level_size(root, 0));
> @@ -3076,7 +3109,7 @@ process_slot:
>  			u64 disko = 0, diskl = 0;
>  			u64 datao = 0, datal = 0;
>  			u8 comp;
> -			u64 endoff;
> +			u64 drop_start;
>  
>  			extent = btrfs_item_ptr(leaf, slot,
>  						struct btrfs_file_extent_item);
> @@ -3125,6 +3158,18 @@ process_slot:
>  				new_key.offset = destoff;
>  
>  			/*
> +			 * Deal with a hole that doesn't have an extent item
> +			 * that represents it (NO_HOLES feature enabled).
> +			 * This hole is either in the middle of the cloning
> +			 * range or at the beginning (fully overlaps it or
> +			 * partially overlaps it).
> +			 */
> +			if (new_key.offset != last_dest_end)
> +				drop_start = last_dest_end;
> +			else
> +				drop_start = new_key.offset;
> +
> +			/*
>  			 * 1 - adjusting old extent (we may have to split it)
>  			 * 1 - add new extent
>  			 * 1 - inode update
> @@ -3153,7 +3198,7 @@ process_slot:
>  				}
>  
>  				ret = btrfs_drop_extents(trans, root, inode,
> -							 new_key.offset,
> +							 drop_start,
>  							 new_key.offset + datal,
>  							 1);
>  				if (ret) {
> @@ -3254,7 +3299,7 @@ process_slot:
>  				aligned_end = ALIGN(new_key.offset + datal,
>  						    root->sectorsize);
>  				ret = btrfs_drop_extents(trans, root, inode,
> -							 new_key.offset,
> +							 drop_start,
>  							 aligned_end,
>  							 1);
>  				if (ret) {
> @@ -3292,27 +3337,12 @@ process_slot:
>  			btrfs_mark_buffer_dirty(leaf);
>  			btrfs_release_path(path);
>  
> -			inode_inc_iversion(inode);
> -			inode->i_mtime = inode->i_ctime = CURRENT_TIME;
> -
> -			/*
> -			 * we round up to the block size at eof when
> -			 * determining which extents to clone above,
> -			 * but shouldn't round up the file size
> -			 */
> -			endoff = new_key.offset + datal;
> -			if (endoff > destoff+olen)
> -				endoff = destoff+olen;
> -			if (endoff > inode->i_size)
> -				btrfs_i_size_write(inode, endoff);
> -
> -			ret = btrfs_update_inode(trans, root, inode);
> -			if (ret) {
> -				btrfs_abort_transaction(trans, root, ret);
> -				btrfs_end_transaction(trans, root);
> +			last_dest_end = new_key.offset + datal;
> +			ret = clone_finish_inode_update(trans, inode,
> +							last_dest_end,
> +							destoff, olen);
> +			if (ret)
>  				goto out;
> -			}
> -			ret = btrfs_end_transaction(trans, root);
>  			if (new_key.offset + datal >= destoff + len)
>  				break;
>  		}
> @@ -3321,6 +3351,34 @@ process_slot:
>  	}
>  	ret = 0;
>  
> +	if (last_dest_end < destoff + len) {
> +		/*
> +		 * We have an implicit hole (NO_HOLES feature is enabled) that
> +		 * fully or partially overlaps our cloning range at its end.
> +		 */
> +		btrfs_release_path(path);
> +
> +		/*
> +		 * 1 - remove extent(s)
> +		 * 1 - inode update
> +		 */
> +		trans = btrfs_start_transaction(root, 2);
> +		if (IS_ERR(trans)) {
> +			ret = PTR_ERR(trans);
> +			goto out;
> +		}
> +		ret = btrfs_drop_extents(trans, root, inode,
> +					 last_dest_end, destoff + len, 1);
> +		if (ret) {
> +			if (ret != -EOPNOTSUPP)
> +				btrfs_abort_transaction(trans, root, ret);
> +			btrfs_end_transaction(trans, root);
> +			goto out;
> +		}
> +		ret = clone_finish_inode_update(trans, inode, destoff + len,
> +						destoff, olen);
> +	}
> +
>  out:
>  	btrfs_free_path(path);
>  	vfree(buf);
> -- 
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

      reply	other threads:[~2014-06-04  8:25 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-05-31  1:16 [PATCH] Btrfs: fix clone to deal with holes when NO_HOLES feature is enabled Filipe David Borba Manana
2014-05-31 14:12 ` [PATCH v2] " Filipe David Borba Manana
2014-05-31 16:20 ` [PATCH v3] " Filipe David Borba Manana
2014-06-01  0:50 ` [PATCH v4] " Filipe David Borba Manana
2014-06-04  8:25   ` Liu Bo [this message]

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=20140604082512.GB17398@localhost.localdomain \
    --to=bo.li.liu@oracle.com \
    --cc=fdmanana@gmail.com \
    --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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).