btrfs: fix possible deadlock by clearing __GFP_FS flag
Using the GFP_HIGHUSER_MOVABLE flag to allocate the metadata's page may cause deadlock. Task1 open() ... btrfs_search_slot() ... btrfs_cow_block() ... alloc_page() wait for reclaiming shrink_slab() ... shrink_icache_memory() ... btrfs_evict_inode() ... btrfs_search_slot() If the path is locked by task1, the deadlock happens. So the btree's page cache is different with the file's page cache, it can not allocate pages by GFP_HIGHUSER_MOVABLE flag, we must clear __GFP_FS flag in GFP_HIGHUSER_MOVABLE flag. Reported-by: Itaru Kitayama <kitayama@cl.bb4u.ne.jp> Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
parent
c055e99eea
commit
1561deda68
@ -1724,6 +1724,8 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
|||||||
goto fail_bdi;
|
goto fail_bdi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fs_info->btree_inode->i_mapping->flags &= ~__GFP_FS;
|
||||||
|
|
||||||
INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
|
INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
|
||||||
INIT_LIST_HEAD(&fs_info->trans_list);
|
INIT_LIST_HEAD(&fs_info->trans_list);
|
||||||
INIT_LIST_HEAD(&fs_info->dead_roots);
|
INIT_LIST_HEAD(&fs_info->dead_roots);
|
||||||
|
@ -2536,6 +2536,8 @@ static void btrfs_read_locked_inode(struct inode *inode)
|
|||||||
BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item);
|
BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item);
|
||||||
|
|
||||||
alloc_group_block = btrfs_inode_block_group(leaf, inode_item);
|
alloc_group_block = btrfs_inode_block_group(leaf, inode_item);
|
||||||
|
if (location.objectid == BTRFS_FREE_SPACE_OBJECTID)
|
||||||
|
inode->i_mapping->flags &= ~__GFP_FS;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* try to precache a NULL acl entry for files that don't have
|
* try to precache a NULL acl entry for files that don't have
|
||||||
@ -4084,7 +4086,6 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
|
|||||||
BTRFS_I(inode)->root = root;
|
BTRFS_I(inode)->root = root;
|
||||||
memcpy(&BTRFS_I(inode)->location, location, sizeof(*location));
|
memcpy(&BTRFS_I(inode)->location, location, sizeof(*location));
|
||||||
btrfs_read_locked_inode(inode);
|
btrfs_read_locked_inode(inode);
|
||||||
|
|
||||||
inode_tree_add(inode);
|
inode_tree_add(inode);
|
||||||
unlock_new_inode(inode);
|
unlock_new_inode(inode);
|
||||||
if (new)
|
if (new)
|
||||||
|
Loading…
Reference in New Issue
Block a user