diff mbox series

[3/4] btrfs: extract the space reservation code from btrfs_buffered_write()

Message ID 522bfb923444f08b2c68c51a05cb5ca8b3ac7a77.1742443383.git.wqu@suse.com (mailing list archive)
State New
Headers show
Series btrfs: refactor btrfs_buffered_write() for the incoming large data folios | expand

Commit Message

Qu Wenruo March 20, 2025, 5:34 a.m. UTC
Inside the main loop of btrfs_buffered_write(), we have a complex data
and metadata space reservation code, which tries to reserve space for
a COW write, if failed then fallback to check if we can do a NOCOW
write.

Extract that part of code into a dedicated helper, reserve_space(), to
make the main loop a little easier to read.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/file.c | 108 ++++++++++++++++++++++++++++--------------------
 1 file changed, 63 insertions(+), 45 deletions(-)

Comments

Johannes Thumshirn March 21, 2025, 9:49 a.m. UTC | #1
Looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Filipe Manana March 21, 2025, 12:20 p.m. UTC | #2
On Thu, Mar 20, 2025 at 5:37 AM Qu Wenruo <wqu@suse.com> wrote:
>
> Inside the main loop of btrfs_buffered_write(), we have a complex data
> and metadata space reservation code, which tries to reserve space for
> a COW write, if failed then fallback to check if we can do a NOCOW
> write.
>
> Extract that part of code into a dedicated helper, reserve_space(), to
> make the main loop a little easier to read.
>
> Signed-off-by: Qu Wenruo <wqu@suse.com>
> ---
>  fs/btrfs/file.c | 108 ++++++++++++++++++++++++++++--------------------
>  1 file changed, 63 insertions(+), 45 deletions(-)
>
> diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
> index f68846c14ed5..99580ef906a6 100644
> --- a/fs/btrfs/file.c
> +++ b/fs/btrfs/file.c
> @@ -1095,6 +1095,64 @@ static void release_space(struct btrfs_inode *inode,
>         }
>  }
>
> +/*
> + * Reserve data and metadata space for the this buffered write range.

"for the this" -> for this

> + *
> + * Return >0 for the number of bytes reserved, which is always block aligned.
> + * Return <0 for error.
> + */
> +static ssize_t reserve_space(struct btrfs_inode *inode,
> +                        struct extent_changeset **data_reserved,
> +                        u64 start, size_t *len, bool nowait,
> +                        bool *only_release_metadata)
> +{
> +       const struct btrfs_fs_info *fs_info = inode->root->fs_info;
> +       unsigned int block_offset = start & (fs_info->sectorsize - 1);

block_offset can also be const.

> +       size_t reserve_bytes;
> +       int ret;
> +
> +       ret = btrfs_check_data_free_space(inode, data_reserved, start, *len,
> +                                         nowait);
> +       if (ret < 0) {
> +               int can_nocow;
> +
> +               if (nowait && (ret == -ENOSPC || ret == -EAGAIN))
> +                       return -EAGAIN;
> +
> +               /*
> +                * If we don't have to COW at the offset, reserve
> +                * metadata only. write_bytes may get smaller than
> +                * requested here.

While here, we can make the line width closer to the 80 characters
limit, as these are a bit too short.

> +                */
> +               can_nocow = btrfs_check_nocow_lock(inode, start, len, nowait);
> +               if (can_nocow < 0)
> +                       ret = can_nocow;
> +               if (can_nocow > 0)
> +                       ret = 0;
> +               if (ret)
> +                       return ret;
> +               *only_release_metadata = true;
> +       }
> +
> +       reserve_bytes = round_up(*len + block_offset,
> +                                fs_info->sectorsize);

There's no need for line splitting here, it all fits within 75 characters.

Otherwise it looks good, and with these minor changes:

Reviewed-by: Filipe Manana <fdmanana@suse.com>

Thanks.

> +       WARN_ON(reserve_bytes == 0);
> +       ret = btrfs_delalloc_reserve_metadata(inode, reserve_bytes,
> +                                             reserve_bytes, nowait);
> +       if (ret) {
> +               if (!*only_release_metadata)
> +                       btrfs_free_reserved_data_space(inode,
> +                                       *data_reserved, start, *len);
> +               else
> +                       btrfs_check_nocow_unlock(inode);
> +
> +               if (nowait && ret == -ENOSPC)
> +                       ret = -EAGAIN;
> +               return ret;
> +       }
> +       return reserve_bytes;
> +}
> +
>  ssize_t btrfs_buffered_write(struct kiocb *iocb, struct iov_iter *i)
>  {
>         struct file *file = iocb->ki_filp;
> @@ -1160,52 +1218,12 @@ ssize_t btrfs_buffered_write(struct kiocb *iocb, struct iov_iter *i)
>                 sector_offset = pos & (fs_info->sectorsize - 1);
>
>                 extent_changeset_release(data_reserved);
> -               ret = btrfs_check_data_free_space(BTRFS_I(inode),
> -                                                 &data_reserved, pos,
> -                                                 write_bytes, nowait);
> -               if (ret < 0) {
> -                       int can_nocow;
> -
> -                       if (nowait && (ret == -ENOSPC || ret == -EAGAIN)) {
> -                               ret = -EAGAIN;
> -                               break;
> -                       }
> -
> -                       /*
> -                        * If we don't have to COW at the offset, reserve
> -                        * metadata only. write_bytes may get smaller than
> -                        * requested here.
> -                        */
> -                       can_nocow = btrfs_check_nocow_lock(BTRFS_I(inode), pos,
> -                                                          &write_bytes, nowait);
> -                       if (can_nocow < 0)
> -                               ret = can_nocow;
> -                       if (can_nocow > 0)
> -                               ret = 0;
> -                       if (ret)
> -                               break;
> -                       only_release_metadata = true;
> -               }
> -
> -               reserve_bytes = round_up(write_bytes + sector_offset,
> -                                        fs_info->sectorsize);
> -               WARN_ON(reserve_bytes == 0);
> -               ret = btrfs_delalloc_reserve_metadata(BTRFS_I(inode),
> -                                                     reserve_bytes,
> -                                                     reserve_bytes, nowait);
> -               if (ret) {
> -                       if (!only_release_metadata)
> -                               btrfs_free_reserved_data_space(BTRFS_I(inode),
> -                                               data_reserved, pos,
> -                                               write_bytes);
> -                       else
> -                               btrfs_check_nocow_unlock(BTRFS_I(inode));
> -
> -                       if (nowait && ret == -ENOSPC)
> -                               ret = -EAGAIN;
> +               ret = reserve_space(BTRFS_I(inode), &data_reserved, pos,
> +                                   &write_bytes, nowait,
> +                                   &only_release_metadata);
> +               if (ret < 0)
>                         break;
> -               }
> -
> +               reserve_bytes = ret;
>                 release_bytes = reserve_bytes;
>  again:
>                 ret = balance_dirty_pages_ratelimited_flags(inode->i_mapping, bdp_flags);
> --
> 2.49.0
>
>
diff mbox series

Patch

diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index f68846c14ed5..99580ef906a6 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1095,6 +1095,64 @@  static void release_space(struct btrfs_inode *inode,
 	}
 }
 
+/*
+ * Reserve data and metadata space for the this buffered write range.
+ *
+ * Return >0 for the number of bytes reserved, which is always block aligned.
+ * Return <0 for error.
+ */
+static ssize_t reserve_space(struct btrfs_inode *inode,
+			 struct extent_changeset **data_reserved,
+			 u64 start, size_t *len, bool nowait,
+			 bool *only_release_metadata)
+{
+	const struct btrfs_fs_info *fs_info = inode->root->fs_info;
+	unsigned int block_offset = start & (fs_info->sectorsize - 1);
+	size_t reserve_bytes;
+	int ret;
+
+	ret = btrfs_check_data_free_space(inode, data_reserved, start, *len,
+					  nowait);
+	if (ret < 0) {
+		int can_nocow;
+
+		if (nowait && (ret == -ENOSPC || ret == -EAGAIN))
+			return -EAGAIN;
+
+		/*
+		 * If we don't have to COW at the offset, reserve
+		 * metadata only. write_bytes may get smaller than
+		 * requested here.
+		 */
+		can_nocow = btrfs_check_nocow_lock(inode, start, len, nowait);
+		if (can_nocow < 0)
+			ret = can_nocow;
+		if (can_nocow > 0)
+			ret = 0;
+		if (ret)
+			return ret;
+		*only_release_metadata = true;
+	}
+
+	reserve_bytes = round_up(*len + block_offset,
+				 fs_info->sectorsize);
+	WARN_ON(reserve_bytes == 0);
+	ret = btrfs_delalloc_reserve_metadata(inode, reserve_bytes,
+					      reserve_bytes, nowait);
+	if (ret) {
+		if (!*only_release_metadata)
+			btrfs_free_reserved_data_space(inode,
+					*data_reserved, start, *len);
+		else
+			btrfs_check_nocow_unlock(inode);
+
+		if (nowait && ret == -ENOSPC)
+			ret = -EAGAIN;
+		return ret;
+	}
+	return reserve_bytes;
+}
+
 ssize_t btrfs_buffered_write(struct kiocb *iocb, struct iov_iter *i)
 {
 	struct file *file = iocb->ki_filp;
@@ -1160,52 +1218,12 @@  ssize_t btrfs_buffered_write(struct kiocb *iocb, struct iov_iter *i)
 		sector_offset = pos & (fs_info->sectorsize - 1);
 
 		extent_changeset_release(data_reserved);
-		ret = btrfs_check_data_free_space(BTRFS_I(inode),
-						  &data_reserved, pos,
-						  write_bytes, nowait);
-		if (ret < 0) {
-			int can_nocow;
-
-			if (nowait && (ret == -ENOSPC || ret == -EAGAIN)) {
-				ret = -EAGAIN;
-				break;
-			}
-
-			/*
-			 * If we don't have to COW at the offset, reserve
-			 * metadata only. write_bytes may get smaller than
-			 * requested here.
-			 */
-			can_nocow = btrfs_check_nocow_lock(BTRFS_I(inode), pos,
-							   &write_bytes, nowait);
-			if (can_nocow < 0)
-				ret = can_nocow;
-			if (can_nocow > 0)
-				ret = 0;
-			if (ret)
-				break;
-			only_release_metadata = true;
-		}
-
-		reserve_bytes = round_up(write_bytes + sector_offset,
-					 fs_info->sectorsize);
-		WARN_ON(reserve_bytes == 0);
-		ret = btrfs_delalloc_reserve_metadata(BTRFS_I(inode),
-						      reserve_bytes,
-						      reserve_bytes, nowait);
-		if (ret) {
-			if (!only_release_metadata)
-				btrfs_free_reserved_data_space(BTRFS_I(inode),
-						data_reserved, pos,
-						write_bytes);
-			else
-				btrfs_check_nocow_unlock(BTRFS_I(inode));
-
-			if (nowait && ret == -ENOSPC)
-				ret = -EAGAIN;
+		ret = reserve_space(BTRFS_I(inode), &data_reserved, pos,
+				    &write_bytes, nowait,
+				    &only_release_metadata);
+		if (ret < 0)
 			break;
-		}
-
+		reserve_bytes = ret;
 		release_bytes = reserve_bytes;
 again:
 		ret = balance_dirty_pages_ratelimited_flags(inode->i_mapping, bdp_flags);