btrfs: optionally extend i_size in cow_file_range_inline()
authorOmar Sandoval <osandov@fb.com>
Thu, 7 Nov 2019 23:19:16 +0000 (15:19 -0800)
committerDavid Sterba <dsterba@suse.com>
Mon, 14 Mar 2022 12:13:51 +0000 (13:13 +0100)
Currently, an inline extent is always created after i_size is extended
from btrfs_dirty_pages(). However, for encoded writes, we only want to
update i_size after we successfully created the inline extent. Add an
update_i_size parameter to cow_file_range_inline() and
insert_inline_extent() and pass in the size of the extent rather than
determining it from i_size.

Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Omar Sandoval <osandov@fb.com>
Reviewed-by: David Sterba <dsterba@suse.com>
[ reformat comment ]
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/inode.c

index c0b2421..004d2dd 100644 (file)
@@ -243,7 +243,8 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans,
                                struct btrfs_inode *inode, bool extent_inserted,
                                size_t size, size_t compressed_size,
                                int compress_type,
-                               struct page **compressed_pages)
+                               struct page **compressed_pages,
+                               bool update_i_size)
 {
        struct btrfs_root *root = inode->root;
        struct extent_buffer *leaf;
@@ -253,6 +254,7 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans,
        struct btrfs_file_extent_item *ei;
        int ret;
        size_t cur_size = size;
+       u64 i_size;
 
        ASSERT((compressed_size > 0 && compressed_pages) ||
               (compressed_size == 0 && !compressed_pages));
@@ -323,15 +325,18 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans,
                goto fail;
 
        /*
-        * we're an inline extent, so nobody can
-        * extend the file past i_size without locking
-        * a page we already have locked.
+        * We're an inline extent, so nobody can extend the file past i_size
+        * without locking a page we already have locked.
         *
-        * We must do any isize and inode updates
-        * before we unlock the pages.  Otherwise we
-        * could end up racing with unlink.
+        * We must do any i_size and inode updates before we unlock the pages.
+        * Otherwise we could end up racing with unlink.
         */
-       inode->disk_i_size = i_size_read(&inode->vfs_inode);
+       i_size = i_size_read(&inode->vfs_inode);
+       if (update_i_size && size > i_size) {
+               i_size_write(&inode->vfs_inode, size);
+               i_size = size;
+       }
+       inode->disk_i_size = i_size;
 
 fail:
        return ret;
@@ -346,7 +351,8 @@ fail:
 static noinline int cow_file_range_inline(struct btrfs_inode *inode, u64 size,
                                          size_t compressed_size,
                                          int compress_type,
-                                         struct page **compressed_pages)
+                                         struct page **compressed_pages,
+                                         bool update_i_size)
 {
        struct btrfs_drop_extents_args drop_args = { 0 };
        struct btrfs_root *root = inode->root;
@@ -393,7 +399,7 @@ static noinline int cow_file_range_inline(struct btrfs_inode *inode, u64 size,
 
        ret = insert_inline_extent(trans, path, inode, drop_args.extent_inserted,
                                   size, compressed_size, compress_type,
-                                  compressed_pages);
+                                  compressed_pages, update_i_size);
        if (ret && ret != -ENOSPC) {
                btrfs_abort_transaction(trans, ret);
                goto out;
@@ -725,12 +731,13 @@ cont:
                         */
                        ret = cow_file_range_inline(BTRFS_I(inode), actual_end,
                                                    0, BTRFS_COMPRESS_NONE,
-                                                   NULL);
+                                                   NULL, false);
                } else {
                        /* try making a compressed inline extent */
                        ret = cow_file_range_inline(BTRFS_I(inode), actual_end,
                                                    total_compressed,
-                                                   compress_type, pages);
+                                                   compress_type, pages,
+                                                   false);
                }
                if (ret <= 0) {
                        unsigned long clear_flags = EXTENT_DELALLOC |
@@ -1148,7 +1155,7 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
 
                /* lets try to make an inline extent */
                ret = cow_file_range_inline(inode, actual_end, 0,
-                                           BTRFS_COMPRESS_NONE, NULL);
+                                           BTRFS_COMPRESS_NONE, NULL, false);
                if (ret == 0) {
                        /*
                         * We use DO_ACCOUNTING here because we need the