Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

btrfs: assert we have a write lock when removing and replacing extent maps

Removing or replacing an extent map requires holding a write lock on the
extent map's tree. We currently do that everywhere, except in one of the
self tests, where it's harmless since there's no concurrency.

In order to catch possible races in the future, assert that we are holding
a write lock on the extent map tree before removing or replacing an extent
map in the tree, and update the self test to obtain a write lock before
removing extent maps.

Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>

authored by

Filipe Manana and committed by
David Sterba
6d3b050e ad3fc794

+6
+4
fs/btrfs/extent_map.c
··· 492 492 */ 493 493 void remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em) 494 494 { 495 + lockdep_assert_held_write(&tree->lock); 496 + 495 497 WARN_ON(test_bit(EXTENT_FLAG_PINNED, &em->flags)); 496 498 rb_erase_cached(&em->rb_node, &tree->map); 497 499 if (!test_bit(EXTENT_FLAG_LOGGING, &em->flags)) ··· 508 506 struct extent_map *new, 509 507 int modified) 510 508 { 509 + lockdep_assert_held_write(&tree->lock); 510 + 511 511 WARN_ON(test_bit(EXTENT_FLAG_PINNED, &cur->flags)); 512 512 ASSERT(extent_map_in_tree(cur)); 513 513 if (!test_bit(EXTENT_FLAG_LOGGING, &cur->flags))
+2
fs/btrfs/tests/extent-map-tests.c
··· 15 15 struct extent_map *em; 16 16 struct rb_node *node; 17 17 18 + write_lock(&em_tree->lock); 18 19 while (!RB_EMPTY_ROOT(&em_tree->map.rb_root)) { 19 20 node = rb_first_cached(&em_tree->map); 20 21 em = rb_entry(node, struct extent_map, rb_node); ··· 33 32 #endif 34 33 free_extent_map(em); 35 34 } 35 + write_unlock(&em_tree->lock); 36 36 } 37 37 38 38 /*