From: Miao Xie Date: Sun, 27 Mar 2011 08:07:36 +0000 (+0800) Subject: btrfs: fix possible deadlock by clearing __GFP_FS flag X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=1561deda687eef0e95065f1268d680ddc5976ee7;p=openwrt%2Fstaging%2Fblogic.git 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 Signed-off-by: Miao Xie Signed-off-by: Chris Mason --- diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index b3fc8475870f..5cf3aa7b125c 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1724,6 +1724,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, goto fail_bdi; } + fs_info->btree_inode->i_mapping->flags &= ~__GFP_FS; + INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC); INIT_LIST_HEAD(&fs_info->trans_list); INIT_LIST_HEAD(&fs_info->dead_roots); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 04babaf31a33..06274186b290 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -2536,6 +2536,8 @@ static void btrfs_read_locked_inode(struct inode *inode) BTRFS_I(inode)->flags = btrfs_inode_flags(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 @@ -4084,7 +4086,6 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location, BTRFS_I(inode)->root = root; memcpy(&BTRFS_I(inode)->location, location, sizeof(*location)); btrfs_read_locked_inode(inode); - inode_tree_add(inode); unlock_new_inode(inode); if (new)