]> git.hungrycats.org Git - linux/commit
Btrfs: fix unprotected list operations at btrfs_write_dirty_block_groups
authorFilipe Manana <fdmanana@suse.com>
Fri, 18 Dec 2015 03:02:48 +0000 (03:02 +0000)
committerZygo Blaxell <zblaxell@serenity.furryterror.org>
Tue, 19 Jan 2016 05:21:49 +0000 (00:21 -0500)
commitd8485dfcd1cb10dd5f0250e76397ec03b8d8a795
tree6169dd42793e3a2471ace92d1387101827149563
parent891656e91f47aa4d24276b72b76f10a8f6ecab5a
Btrfs: fix unprotected list operations at btrfs_write_dirty_block_groups

We call btrfs_write_dirty_block_groups() in the critical section of a
transaction's commit, when no other tasks can joing the transaction and
add more block groups to the transaction's list of dirty block groups,
so we not taking the dirty block groups spinlock when checking for the
list's emptyness, grabbing its first element or deleting elements from
it.

However there's a special and rare case where we can have a concurrent
task adding elements to this list. We trigger writeback for space
caches before at btrfs_start_dirty_block_groups() and in past iterations
of the loop at btrfs_write_dirty_block_groups(), this means that when
the writeback finishes (which happens asynchronously) it creates a
task ran in endio free space worke queue that executes
btrfs_finish_ordered_io() - this function is able to join the transaction,
through btrfs_join_transaction_nolock(), and update the free space cache's
inode item in the root tree, which can result in COWing nodes of this tree
and therefore allocation of a new block group, which gets added to the
transaction's list of dirty block groups.

So fix this by taking the dirty block groups spinlock before doing
operations on the dirty block groups list at
btrfs_write_dirty_block_groups().

Signed-off-by: Filipe Manana <fdmanana@suse.com>
(cherry picked from commit d87be5165a27016e5e5c285bb5d605f13c60bdb5)
(cherry picked from commit d7d572a4c88ea8dd65db745bc139cf0d03a64a74)
fs/btrfs/extent-tree.c