summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2010-03-18 12:23:10 -0400
committerChris Mason <chris.mason@oracle.com>2010-03-18 12:23:10 -0400
commit8ad6fcab564c5bc956bdc3dfa440ab152b6e780f (patch)
tree38670d63e5315650f3e6efe2a2a8025e945b4743 /fs
parent1b53ac4d1b75b23bdc2b54ace787b8f718a987ef (diff)
Btrfs: fix the inode ref searches done by btrfs_search_path_in_tree
This is used by the inode lookup ioctl to follow all the backrefs up to the subvol root. But the search being done would sometimes land one past the last item in the leaf instead of finding the backref. This changes the search to look for the highest possible backref and hop back one item. It also fixes a leaked path on failure to find the root. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/ioctl.c9
1 files changed, 6 insertions, 3 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 1e462de6556..2845c6ceecd 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -1147,12 +1147,13 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
root = btrfs_read_fs_root_no_name(info, &key);
if (IS_ERR(root)) {
printk(KERN_ERR "could not find root %llu\n", tree_id);
- return -ENOENT;
+ ret = -ENOENT;
+ goto out;
}
key.objectid = dirid;
key.type = BTRFS_INODE_REF_KEY;
- key.offset = 0;
+ key.offset = (u64)-1;
while(1) {
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
@@ -1161,6 +1162,8 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
l = path->nodes[0];
slot = path->slots[0];
+ if (ret > 0 && slot > 0)
+ slot--;
btrfs_item_key_to_cpu(l, &key, slot);
if (ret > 0 && (key.objectid != dirid ||
@@ -1184,7 +1187,7 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
btrfs_release_path(root, path);
key.objectid = key.offset;
- key.offset = 0;
+ key.offset = (u64)-1;
dirid = key.objectid;
}