Merge tag 'for-5.7-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 3 May 2020 18:30:08 +0000 (11:30 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 3 May 2020 18:30:08 +0000 (11:30 -0700)
Pull more btrfs fixes from David Sterba:
 "A few more stability fixes, minor build warning fixes and git url
  fixup:

   - fix partial loss of prealloc extent past i_size after fsync

   - fix potential deadlock due to wrong transaction handle passing via
     journal_info

   - fix gcc 4.8 struct intialization warning

   - update git URL in MAINTAINERS entry"

* tag 'for-5.7-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  MAINTAINERS: btrfs: fix git repo URL
  btrfs: fix gcc-4.8 build warning for struct initializer
  btrfs: transaction: Avoid deadlock due to bad initialization timing of fs_info::journal_info
  btrfs: fix partial loss of prealloc extent past i_size after fsync

MAINTAINERS
fs/btrfs/backref.c
fs/btrfs/transaction.c
fs/btrfs/tree-log.c

index 26f281d9f32a4ad35d744a90353c93177b309287..2926327e497665ecacffdb4b89f438c14432e434 100644 (file)
@@ -3657,7 +3657,7 @@ L:        linux-btrfs@vger.kernel.org
 S:     Maintained
 W:     http://btrfs.wiki.kernel.org/
 Q:     http://patchwork.kernel.org/project/linux-btrfs/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git
 F:     Documentation/filesystems/btrfs.rst
 F:     fs/btrfs/
 F:     include/linux/btrfs*
index 9c380e7edf629155af9a351873f4b7c615888bfb..0cc02577577bc98ddc3a68f53be308f4a6fcf62c 100644 (file)
@@ -391,7 +391,7 @@ static int is_shared_data_backref(struct preftrees *preftrees, u64 bytenr)
        struct rb_node **p = &preftrees->direct.root.rb_root.rb_node;
        struct rb_node *parent = NULL;
        struct prelim_ref *ref = NULL;
-       struct prelim_ref target = {0};
+       struct prelim_ref target = {};
        int result;
 
        target.parent = bytenr;
index 8cede6eb9843c73f432325dbfd98af132c2563ba..2d5498136e5ef82798ece5a9230e3b72204b3513 100644 (file)
@@ -662,10 +662,19 @@ again:
        }
 
 got_it:
-       btrfs_record_root_in_trans(h, root);
-
        if (!current->journal_info)
                current->journal_info = h;
+
+       /*
+        * btrfs_record_root_in_trans() needs to alloc new extents, and may
+        * call btrfs_join_transaction() while we're also starting a
+        * transaction.
+        *
+        * Thus it need to be called after current->journal_info initialized,
+        * or we can deadlock.
+        */
+       btrfs_record_root_in_trans(h, root);
+
        return h;
 
 join_fail:
index ec36a7c6ba3de86b65b54739d71ecc47a5e42c4b..02ebdd9edc193512ba58b29002d0d53e86fa4510 100644 (file)
@@ -4226,6 +4226,9 @@ static int btrfs_log_prealloc_extents(struct btrfs_trans_handle *trans,
        const u64 ino = btrfs_ino(inode);
        struct btrfs_path *dst_path = NULL;
        bool dropped_extents = false;
+       u64 truncate_offset = i_size;
+       struct extent_buffer *leaf;
+       int slot;
        int ins_nr = 0;
        int start_slot;
        int ret;
@@ -4240,9 +4243,43 @@ static int btrfs_log_prealloc_extents(struct btrfs_trans_handle *trans,
        if (ret < 0)
                goto out;
 
+       /*
+        * We must check if there is a prealloc extent that starts before the
+        * i_size and crosses the i_size boundary. This is to ensure later we
+        * truncate down to the end of that extent and not to the i_size, as
+        * otherwise we end up losing part of the prealloc extent after a log
+        * replay and with an implicit hole if there is another prealloc extent
+        * that starts at an offset beyond i_size.
+        */
+       ret = btrfs_previous_item(root, path, ino, BTRFS_EXTENT_DATA_KEY);
+       if (ret < 0)
+               goto out;
+
+       if (ret == 0) {
+               struct btrfs_file_extent_item *ei;
+
+               leaf = path->nodes[0];
+               slot = path->slots[0];
+               ei = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
+
+               if (btrfs_file_extent_type(leaf, ei) ==
+                   BTRFS_FILE_EXTENT_PREALLOC) {
+                       u64 extent_end;
+
+                       btrfs_item_key_to_cpu(leaf, &key, slot);
+                       extent_end = key.offset +
+                               btrfs_file_extent_num_bytes(leaf, ei);
+
+                       if (extent_end > i_size)
+                               truncate_offset = extent_end;
+               }
+       } else {
+               ret = 0;
+       }
+
        while (true) {
-               struct extent_buffer *leaf = path->nodes[0];
-               int slot = path->slots[0];
+               leaf = path->nodes[0];
+               slot = path->slots[0];
 
                if (slot >= btrfs_header_nritems(leaf)) {
                        if (ins_nr > 0) {
@@ -4280,7 +4317,7 @@ static int btrfs_log_prealloc_extents(struct btrfs_trans_handle *trans,
                                ret = btrfs_truncate_inode_items(trans,
                                                         root->log_root,
                                                         &inode->vfs_inode,
-                                                        i_size,
+                                                        truncate_offset,
                                                         BTRFS_EXTENT_DATA_KEY);
                        } while (ret == -EAGAIN);
                        if (ret)