diff options
author | Yan Zheng <zheng.yan@oracle.com> | 2009-07-22 09:59:00 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2009-07-22 09:59:00 -0400 |
commit | 33c66f430bfa3a033e70470e4c93f967156b696d (patch) | |
tree | 5af7edc4564aa3f32033b364495828eb32b690a7 /fs/btrfs/relocation.c | |
parent | e457afec60fdbd86b963d36f4a8a9285088c6043 (diff) | |
download | op-kernel-dev-33c66f430bfa3a033e70470e4c93f967156b696d.zip op-kernel-dev-33c66f430bfa3a033e70470e4c93f967156b696d.tar.gz |
Btrfs: fix locking issue in btrfs_find_next_key
When walking up the tree, btrfs_find_next_key assumes the upper level tree
block is properly locked. This isn't always true even path->keep_locks is 1.
This is because btrfs_find_next_key may advance path->slots[] several times
instead of only once.
When 'path->slots[level] >= btrfs_header_nritems(path->nodes[level])' is found,
we can't guarantee the original value of 'path->slots[level]' is
'btrfs_header_nritems(path->nodes[level]) - 1'. If it's not, the tree block at
'level + 1' isn't locked.
This patch fixes the issue by explicitly checking the locking state,
re-searching the tree if it's not locked.
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/relocation.c')
-rw-r--r-- | fs/btrfs/relocation.c | 3 |
1 files changed, 3 insertions, 0 deletions
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 0083979..e71264d 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -670,6 +670,8 @@ again: err = ret; goto out; } + if (ret > 0 && path2->slots[level] > 0) + path2->slots[level]--; eb = path2->nodes[level]; WARN_ON(btrfs_node_blockptr(eb, path2->slots[level]) != @@ -1609,6 +1611,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc, BUG_ON(level == 0); path->lowest_level = level; ret = btrfs_search_slot(NULL, reloc_root, &key, path, 0, 0); + path->lowest_level = 0; if (ret < 0) { btrfs_free_path(path); return ret; |