Skip to content

Commit

Permalink
Merge tag 'for-5.3-rc8-tag' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/git/kdave/linux

Pull btrfs fixes from David Sterba:
 "Here are two fixes, one of them urgent fixing a bug introduced in 5.2
  and reported by many users. It took time to identify the root cause,
  catching the 5.3 release is higly desired also to push the fix to 5.2
  stable tree.

  The bug is a mess up of return values after adding proper error
  handling and honestly the kind of bug that can cause sleeping
  disorders until it's caught. My appologies to everybody who was
  affected.

  Summary of what could happen:

  1) either a hang when committing a transaction, if this happens
     there's no risk of corruption, still the hang is very inconvenient
     and can't be resolved without a reboot

  2) writeback for some btree nodes may never be started and we end up
     committing a transaction without noticing that, this is really
     serious and that will lead to the "parent transid verify failed"
     messages"

* tag 'for-5.3-rc8-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  Btrfs: fix unwritten extent buffers and hangs on future writeback attempts
  Btrfs: fix assertion failure during fsync and use of stale transaction
  • Loading branch information
Linus Torvalds committed Sep 13, 2019
2 parents 505a8ec + 18dfa71 commit 1b304a1
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 17 deletions.
35 changes: 26 additions & 9 deletions fs/btrfs/extent_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -3628,6 +3628,13 @@ void wait_on_extent_buffer_writeback(struct extent_buffer *eb)
TASK_UNINTERRUPTIBLE);
}

static void end_extent_buffer_writeback(struct extent_buffer *eb)
{
clear_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags);
smp_mb__after_atomic();
wake_up_bit(&eb->bflags, EXTENT_BUFFER_WRITEBACK);
}

/*
* Lock eb pages and flush the bio if we can't the locks
*
Expand Down Expand Up @@ -3699,8 +3706,11 @@ static noinline_for_stack int lock_extent_buffer_for_io(struct extent_buffer *eb

if (!trylock_page(p)) {
if (!flush) {
ret = flush_write_bio(epd);
if (ret < 0) {
int err;

err = flush_write_bio(epd);
if (err < 0) {
ret = err;
failed_page_nr = i;
goto err_unlock;
}
Expand All @@ -3715,16 +3725,23 @@ static noinline_for_stack int lock_extent_buffer_for_io(struct extent_buffer *eb
/* Unlock already locked pages */
for (i = 0; i < failed_page_nr; i++)
unlock_page(eb->pages[i]);
/*
* Clear EXTENT_BUFFER_WRITEBACK and wake up anyone waiting on it.
* Also set back EXTENT_BUFFER_DIRTY so future attempts to this eb can
* be made and undo everything done before.
*/
btrfs_tree_lock(eb);
spin_lock(&eb->refs_lock);
set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags);
end_extent_buffer_writeback(eb);
spin_unlock(&eb->refs_lock);
percpu_counter_add_batch(&fs_info->dirty_metadata_bytes, eb->len,
fs_info->dirty_metadata_batch);
btrfs_clear_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
btrfs_tree_unlock(eb);
return ret;
}

static void end_extent_buffer_writeback(struct extent_buffer *eb)
{
clear_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags);
smp_mb__after_atomic();
wake_up_bit(&eb->bflags, EXTENT_BUFFER_WRITEBACK);
}

static void set_btree_ioerr(struct page *page)
{
struct extent_buffer *eb = (struct extent_buffer *)page->private;
Expand Down
16 changes: 8 additions & 8 deletions fs/btrfs/tree-log.c
Original file line number Diff line number Diff line change
Expand Up @@ -4985,7 +4985,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
BTRFS_I(inode),
LOG_OTHER_INODE_ALL,
0, LLONG_MAX, ctx);
iput(inode);
btrfs_add_delayed_iput(inode);
}
}
continue;
Expand All @@ -5000,7 +5000,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
ret = btrfs_log_inode(trans, root, BTRFS_I(inode),
LOG_OTHER_INODE, 0, LLONG_MAX, ctx);
if (ret) {
iput(inode);
btrfs_add_delayed_iput(inode);
continue;
}

Expand All @@ -5009,7 +5009,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
key.offset = 0;
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0) {
iput(inode);
btrfs_add_delayed_iput(inode);
continue;
}

Expand Down Expand Up @@ -5056,7 +5056,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
}
path->slots[0]++;
}
iput(inode);
btrfs_add_delayed_iput(inode);
}

return ret;
Expand Down Expand Up @@ -5689,7 +5689,7 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans,
}

if (btrfs_inode_in_log(BTRFS_I(di_inode), trans->transid)) {
iput(di_inode);
btrfs_add_delayed_iput(di_inode);
break;
}

Expand All @@ -5701,7 +5701,7 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans,
if (!ret &&
btrfs_must_commit_transaction(trans, BTRFS_I(di_inode)))
ret = 1;
iput(di_inode);
btrfs_add_delayed_iput(di_inode);
if (ret)
goto next_dir_inode;
if (ctx->log_new_dentries) {
Expand Down Expand Up @@ -5848,7 +5848,7 @@ static int btrfs_log_all_parents(struct btrfs_trans_handle *trans,
if (!ret && ctx && ctx->log_new_dentries)
ret = log_new_dir_dentries(trans, root,
BTRFS_I(dir_inode), ctx);
iput(dir_inode);
btrfs_add_delayed_iput(dir_inode);
if (ret)
goto out;
}
Expand Down Expand Up @@ -5891,7 +5891,7 @@ static int log_new_ancestors(struct btrfs_trans_handle *trans,
ret = btrfs_log_inode(trans, root, BTRFS_I(inode),
LOG_INODE_EXISTS,
0, LLONG_MAX, ctx);
iput(inode);
btrfs_add_delayed_iput(inode);
if (ret)
return ret;

Expand Down

0 comments on commit 1b304a1

Please sign in to comment.