Skip to content

Commit

Permalink
btrfs: fix possible deadlock by clearing __GFP_FS flag
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Miao Xie authored and root committed Mar 28, 2011
1 parent c055e99 commit 1561ded
Show file tree
Hide file tree
Showing 2 changed files with 4 additions and 1 deletion.
2 changes: 2 additions & 0 deletions fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 1561ded

Please sign in to comment.