diff options
author | Jeff Mahoney <jeffm@suse.com> | 2014-03-26 14:11:26 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2014-04-07 12:08:40 -0400 |
commit | ed55b6ac077fe7f9c6490ff55172c4b563562d7c (patch) | |
tree | a126c4cdc858dc1886aa0e56c0b97a8dee32546f /fs | |
parent | 3f8a18cc53bd1be26eb5b5247e1386ad0e21b623 (diff) |
btrfs: fix lockdep warning with reclaim lock inversion
When encountering memory pressure, testers have run into the following
lockdep warning. It was caused by __link_block_group calling kobject_add
with the groups_sem held. kobject_add calls kvasprintf with GFP_KERNEL,
which gets us into reclaim context. The kobject doesn't actually need
to be added under the lock -- it just needs to ensure that it's only
added for the first block group to be linked.
=========================================================
[ INFO: possible irq lock inversion dependency detected ]
3.14.0-rc8-default #1 Not tainted
---------------------------------------------------------
kswapd0/169 just changed the state of lock:
(&delayed_node->mutex){+.+.-.}, at: [<ffffffffa018baea>] __btrfs_release_delayed_node+0x3a/0x200 [btrfs]
but this lock took another, RECLAIM_FS-unsafe lock in the past:
(&found->groups_sem){+++++.}
and interrupts could create inverse lock ordering between them.
other info that might help us debug this:
Possible interrupt unsafe locking scenario:
CPU0 CPU1
---- ----
lock(&found->groups_sem);
local_irq_disable();
lock(&delayed_node->mutex);
lock(&found->groups_sem);
<Interrupt>
lock(&delayed_node->mutex);
*** DEADLOCK ***
2 locks held by kswapd0/169:
#0: (shrinker_rwsem){++++..}, at: [<ffffffff81159e8a>] shrink_slab+0x3a/0x160
#1: (&type->s_umount_key#27){++++..}, at: [<ffffffff811bac6f>] grab_super_passive+0x3f/0x90
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/extent-tree.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 4d2508bbf6f0..1341163abe68 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -8337,9 +8337,15 @@ static void __link_block_group(struct btrfs_space_info *space_info, | |||
8337 | struct btrfs_block_group_cache *cache) | 8337 | struct btrfs_block_group_cache *cache) |
8338 | { | 8338 | { |
8339 | int index = get_block_group_index(cache); | 8339 | int index = get_block_group_index(cache); |
8340 | bool first = false; | ||
8340 | 8341 | ||
8341 | down_write(&space_info->groups_sem); | 8342 | down_write(&space_info->groups_sem); |
8342 | if (list_empty(&space_info->block_groups[index])) { | 8343 | if (list_empty(&space_info->block_groups[index])) |
8344 | first = true; | ||
8345 | list_add_tail(&cache->list, &space_info->block_groups[index]); | ||
8346 | up_write(&space_info->groups_sem); | ||
8347 | |||
8348 | if (first) { | ||
8343 | struct kobject *kobj = &space_info->block_group_kobjs[index]; | 8349 | struct kobject *kobj = &space_info->block_group_kobjs[index]; |
8344 | int ret; | 8350 | int ret; |
8345 | 8351 | ||
@@ -8351,8 +8357,6 @@ static void __link_block_group(struct btrfs_space_info *space_info, | |||
8351 | kobject_put(&space_info->kobj); | 8357 | kobject_put(&space_info->kobj); |
8352 | } | 8358 | } |
8353 | } | 8359 | } |
8354 | list_add_tail(&cache->list, &space_info->block_groups[index]); | ||
8355 | up_write(&space_info->groups_sem); | ||
8356 | } | 8360 | } |
8357 | 8361 | ||
8358 | static struct btrfs_block_group_cache * | 8362 | static struct btrfs_block_group_cache * |