btrfs: calculate num_pages, reserve_bytes once in btrfs_buffered_write
authorGoldwyn Rodrigues <rgoldwyn@suse.com>
Fri, 25 Sep 2020 20:36:38 +0000 (15:36 -0500)
committerDavid Sterba <dsterba@suse.com>
Tue, 8 Dec 2020 14:53:37 +0000 (15:53 +0100)
write_bytes can change in btrfs_check_nocow_lock(). Calculate variables
such as num_pages and reserve_bytes once we are sure of the value of
write_bytes so there is no need to re-calculate.

Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/file.c

index 4373da7..7c5e3d4 100644 (file)
@@ -1591,8 +1591,7 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb,
                size_t write_bytes = min(iov_iter_count(i),
                                         nrptrs * (size_t)PAGE_SIZE -
                                         offset);
-               size_t num_pages = DIV_ROUND_UP(write_bytes + offset,
-                                               PAGE_SIZE);
+               size_t num_pages;
                size_t reserve_bytes;
                size_t dirty_pages;
                size_t copied;
@@ -1600,8 +1599,6 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb,
                size_t num_sectors;
                int extents_locked;
 
-               WARN_ON(num_pages > nrptrs);
-
                /*
                 * Fault pages before locking them in prepare_pages
                 * to avoid recursive lock
@@ -1613,35 +1610,28 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb,
 
                only_release_metadata = false;
                sector_offset = pos & (fs_info->sectorsize - 1);
-               reserve_bytes = round_up(write_bytes + sector_offset,
-                               fs_info->sectorsize);
 
                extent_changeset_release(data_reserved);
                ret = btrfs_check_data_free_space(BTRFS_I(inode),
                                                  &data_reserved, pos,
                                                  write_bytes);
                if (ret < 0) {
+                       /*
+                        * If we don't have to COW at the offset, reserve
+                        * metadata only. write_bytes may get smaller than
+                        * requested here.
+                        */
                        if (btrfs_check_nocow_lock(BTRFS_I(inode), pos,
-                                                  &write_bytes) > 0) {
-                               /*
-                                * For nodata cow case, no need to reserve
-                                * data space.
-                                */
+                                                  &write_bytes) > 0)
                                only_release_metadata = true;
-                               /*
-                                * our prealloc extent may be smaller than
-                                * write_bytes, so scale down.
-                                */
-                               num_pages = DIV_ROUND_UP(write_bytes + offset,
-                                                        PAGE_SIZE);
-                               reserve_bytes = round_up(write_bytes +
-                                                        sector_offset,
-                                                        fs_info->sectorsize);
-                       } else {
+                       else
                                break;
-                       }
                }
 
+               num_pages = DIV_ROUND_UP(write_bytes + offset, PAGE_SIZE);
+               WARN_ON(num_pages > nrptrs);
+               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);