Btrfs: add missing read locks in backref.c
iref_to_path and iterate_irefs both increment the eb's refcount to use it after releasing the path. Both depend on consistent data remaining in the extent buffer and need a read lock to protect it. Signed-off-by: Jan Schmidt <list.btrfs@jan-o-sch.net>
This commit is contained in:
parent
aefc1eb13e
commit
b916a59adf
|
@ -22,6 +22,7 @@
|
||||||
#include "ulist.h"
|
#include "ulist.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
#include "delayed-ref.h"
|
#include "delayed-ref.h"
|
||||||
|
#include "locking.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* this structure records all encountered refs on the way up to the root
|
* this structure records all encountered refs on the way up to the root
|
||||||
|
@ -893,18 +894,22 @@ static char *iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
|
||||||
s64 bytes_left = size - 1;
|
s64 bytes_left = size - 1;
|
||||||
struct extent_buffer *eb = eb_in;
|
struct extent_buffer *eb = eb_in;
|
||||||
struct btrfs_key found_key;
|
struct btrfs_key found_key;
|
||||||
|
int leave_spinning = path->leave_spinning;
|
||||||
|
|
||||||
if (bytes_left >= 0)
|
if (bytes_left >= 0)
|
||||||
dest[bytes_left] = '\0';
|
dest[bytes_left] = '\0';
|
||||||
|
|
||||||
|
path->leave_spinning = 1;
|
||||||
while (1) {
|
while (1) {
|
||||||
len = btrfs_inode_ref_name_len(eb, iref);
|
len = btrfs_inode_ref_name_len(eb, iref);
|
||||||
bytes_left -= len;
|
bytes_left -= len;
|
||||||
if (bytes_left >= 0)
|
if (bytes_left >= 0)
|
||||||
read_extent_buffer(eb, dest + bytes_left,
|
read_extent_buffer(eb, dest + bytes_left,
|
||||||
(unsigned long)(iref + 1), len);
|
(unsigned long)(iref + 1), len);
|
||||||
if (eb != eb_in)
|
if (eb != eb_in) {
|
||||||
|
btrfs_tree_read_unlock_blocking(eb);
|
||||||
free_extent_buffer(eb);
|
free_extent_buffer(eb);
|
||||||
|
}
|
||||||
ret = inode_ref_info(parent, 0, fs_root, path, &found_key);
|
ret = inode_ref_info(parent, 0, fs_root, path, &found_key);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
|
@ -919,8 +924,11 @@ static char *iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
|
||||||
slot = path->slots[0];
|
slot = path->slots[0];
|
||||||
eb = path->nodes[0];
|
eb = path->nodes[0];
|
||||||
/* make sure we can use eb after releasing the path */
|
/* make sure we can use eb after releasing the path */
|
||||||
if (eb != eb_in)
|
if (eb != eb_in) {
|
||||||
atomic_inc(&eb->refs);
|
atomic_inc(&eb->refs);
|
||||||
|
btrfs_tree_read_lock(eb);
|
||||||
|
btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
|
||||||
|
}
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
|
|
||||||
iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref);
|
iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref);
|
||||||
|
@ -931,6 +939,7 @@ static char *iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
|
path->leave_spinning = leave_spinning;
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
|
@ -1260,6 +1269,7 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
|
||||||
struct btrfs_key found_key;
|
struct btrfs_key found_key;
|
||||||
|
|
||||||
while (!ret) {
|
while (!ret) {
|
||||||
|
path->leave_spinning = 1;
|
||||||
ret = inode_ref_info(inum, parent ? parent+1 : 0, fs_root, path,
|
ret = inode_ref_info(inum, parent ? parent+1 : 0, fs_root, path,
|
||||||
&found_key);
|
&found_key);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -1275,6 +1285,8 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
|
||||||
eb = path->nodes[0];
|
eb = path->nodes[0];
|
||||||
/* make sure we can use eb after releasing the path */
|
/* make sure we can use eb after releasing the path */
|
||||||
atomic_inc(&eb->refs);
|
atomic_inc(&eb->refs);
|
||||||
|
btrfs_tree_read_lock(eb);
|
||||||
|
btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
|
|
||||||
item = btrfs_item_nr(eb, slot);
|
item = btrfs_item_nr(eb, slot);
|
||||||
|
@ -1293,6 +1305,7 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
|
||||||
len = sizeof(*iref) + name_len;
|
len = sizeof(*iref) + name_len;
|
||||||
iref = (struct btrfs_inode_ref *)((char *)iref + len);
|
iref = (struct btrfs_inode_ref *)((char *)iref + len);
|
||||||
}
|
}
|
||||||
|
btrfs_tree_read_unlock_blocking(eb);
|
||||||
free_extent_buffer(eb);
|
free_extent_buffer(eb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue