Skip to content

Commit

Permalink
Btrfs: add inodes before dropping the extent lock in find_all_leafs
Browse files Browse the repository at this point in the history
We must build up the inode list with the extent lock held after following
indirect refs.

This also requires an extension to ulists, which allows to modify the stored
aux value in case a key already exists in the list.

Signed-off-by: Jan Schmidt <[email protected]>
  • Loading branch information
Jan Schmidt committed May 31, 2012
1 parent 95a0607 commit 3301958
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 6 deletions.
36 changes: 31 additions & 5 deletions fs/btrfs/backref.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ struct __prelim_ref {
struct btrfs_key key_for_search;
int level;
int count;
struct extent_inode_elem *inode_list;
u64 parent;
u64 wanted_disk_byte;
};
Expand Down Expand Up @@ -166,6 +167,7 @@ static int __add_prelim_ref(struct list_head *head, u64 root_id,
else
memset(&ref->key_for_search, 0, sizeof(ref->key_for_search));

ref->inode_list = NULL;
ref->level = level;
ref->count = count;
ref->parent = parent;
Expand All @@ -181,14 +183,21 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
const u64 *extent_item_pos)
{
int ret;
int slot;
int slot = path->slots[level];
struct extent_buffer *eb = path->nodes[level];
struct btrfs_file_extent_item *fi;
struct extent_inode_elem *eie = NULL;
u64 disk_byte;
u64 wanted_objectid = key->objectid;

add_parent:
ret = ulist_add(parents, eb->start, 0, GFP_NOFS);
if (level == 0 && extent_item_pos) {
fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item);
ret = check_extent_in_eb(key, eb, fi, *extent_item_pos, &eie);
if (ret < 0)
return ret;
}
ret = ulist_add(parents, eb->start, (unsigned long)eie, GFP_NOFS);
if (ret < 0)
return ret;

Expand All @@ -202,6 +211,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
* repeat this until we don't find any additional EXTENT_DATA items.
*/
while (1) {
eie = NULL;
ret = btrfs_next_leaf(root, path);
if (ret < 0)
return ret;
Expand Down Expand Up @@ -346,6 +356,8 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
ULIST_ITER_INIT(&uiter);
node = ulist_next(parents, &uiter);
ref->parent = node ? node->val : 0;
ref->inode_list =
node ? (struct extent_inode_elem *)node->aux : 0;

/* additional parents require new refs being added here */
while ((node = ulist_next(parents, &uiter))) {
Expand All @@ -356,6 +368,8 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
}
memcpy(new_ref, ref, sizeof(*ref));
new_ref->parent = node->val;
new_ref->inode_list =
(struct extent_inode_elem *)node->aux;
list_add(&new_ref->list, &ref->list);
}
ulist_reinit(parents);
Expand Down Expand Up @@ -879,7 +893,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
}
if (ref->count && ref->parent) {
struct extent_inode_elem *eie = NULL;
if (extent_item_pos) {
if (extent_item_pos && !ref->inode_list) {
u32 bsz;
struct extent_buffer *eb;
bsz = btrfs_level_size(fs_info->extent_root,
Expand All @@ -889,10 +903,22 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
BUG_ON(!eb);
ret = find_extent_in_eb(eb, bytenr,
*extent_item_pos, &eie);
ref->inode_list = eie;
free_extent_buffer(eb);
}
ret = ulist_add(refs, ref->parent,
(unsigned long)eie, GFP_NOFS);
ret = ulist_add_merge(refs, ref->parent,
(unsigned long)ref->inode_list,
(unsigned long *)&eie, GFP_NOFS);
if (!ret && extent_item_pos) {
/*
* we've recorded that parent, so we must extend
* its inode list here
*/
BUG_ON(!eie);
while (eie->next)
eie = eie->next;
eie->next = ref->inode_list;
}
BUG_ON(ret < 0);
}
kfree(ref);
Expand Down
11 changes: 10 additions & 1 deletion fs/btrfs/ulist.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,21 @@ EXPORT_SYMBOL(ulist_free);
*/
int ulist_add(struct ulist *ulist, u64 val, unsigned long aux,
unsigned long gfp_mask)
{
return ulist_add_merge(ulist, val, aux, NULL, gfp_mask);
}

int ulist_add_merge(struct ulist *ulist, u64 val, unsigned long aux,
unsigned long *old_aux, unsigned long gfp_mask)
{
int i;

for (i = 0; i < ulist->nnodes; ++i) {
if (ulist->nodes[i].val == val)
if (ulist->nodes[i].val == val) {
if (old_aux)
*old_aux = ulist->nodes[i].aux;
return 0;
}
}

if (ulist->nnodes >= ulist->nodes_alloced) {
Expand Down
2 changes: 2 additions & 0 deletions fs/btrfs/ulist.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ struct ulist *ulist_alloc(unsigned long gfp_mask);
void ulist_free(struct ulist *ulist);
int ulist_add(struct ulist *ulist, u64 val, unsigned long aux,
unsigned long gfp_mask);
int ulist_add_merge(struct ulist *ulist, u64 val, unsigned long aux,
unsigned long *old_aux, unsigned long gfp_mask);
struct ulist_node *ulist_next(struct ulist *ulist,
struct ulist_iterator *uiter);

Expand Down

0 comments on commit 3301958

Please sign in to comment.