Skip to content

Commit b916a59

Browse files
Jan Schmidtkdave
authored andcommitted
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>
1 parent aefc1eb commit b916a59

File tree

1 file changed

+15
-2
lines changed

1 file changed

+15
-2
lines changed

fs/btrfs/backref.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "ulist.h"
2323
#include "transaction.h"
2424
#include "delayed-ref.h"
25+
#include "locking.h"
2526

2627
/*
2728
* 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,
893894
s64 bytes_left = size - 1;
894895
struct extent_buffer *eb = eb_in;
895896
struct btrfs_key found_key;
897+
int leave_spinning = path->leave_spinning;
896898

897899
if (bytes_left >= 0)
898900
dest[bytes_left] = '\0';
899901

902+
path->leave_spinning = 1;
900903
while (1) {
901904
len = btrfs_inode_ref_name_len(eb, iref);
902905
bytes_left -= len;
903906
if (bytes_left >= 0)
904907
read_extent_buffer(eb, dest + bytes_left,
905908
(unsigned long)(iref + 1), len);
906-
if (eb != eb_in)
909+
if (eb != eb_in) {
910+
btrfs_tree_read_unlock_blocking(eb);
907911
free_extent_buffer(eb);
912+
}
908913
ret = inode_ref_info(parent, 0, fs_root, path, &found_key);
909914
if (ret > 0)
910915
ret = -ENOENT;
@@ -919,8 +924,11 @@ static char *iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
919924
slot = path->slots[0];
920925
eb = path->nodes[0];
921926
/* make sure we can use eb after releasing the path */
922-
if (eb != eb_in)
927+
if (eb != eb_in) {
923928
atomic_inc(&eb->refs);
929+
btrfs_tree_read_lock(eb);
930+
btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
931+
}
924932
btrfs_release_path(path);
925933

926934
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,
931939
}
932940

933941
btrfs_release_path(path);
942+
path->leave_spinning = leave_spinning;
934943

935944
if (ret)
936945
return ERR_PTR(ret);
@@ -1260,6 +1269,7 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
12601269
struct btrfs_key found_key;
12611270

12621271
while (!ret) {
1272+
path->leave_spinning = 1;
12631273
ret = inode_ref_info(inum, parent ? parent+1 : 0, fs_root, path,
12641274
&found_key);
12651275
if (ret < 0)
@@ -1275,6 +1285,8 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
12751285
eb = path->nodes[0];
12761286
/* make sure we can use eb after releasing the path */
12771287
atomic_inc(&eb->refs);
1288+
btrfs_tree_read_lock(eb);
1289+
btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
12781290
btrfs_release_path(path);
12791291

12801292
item = btrfs_item_nr(eb, slot);
@@ -1293,6 +1305,7 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
12931305
len = sizeof(*iref) + name_len;
12941306
iref = (struct btrfs_inode_ref *)((char *)iref + len);
12951307
}
1308+
btrfs_tree_read_unlock_blocking(eb);
12961309
free_extent_buffer(eb);
12971310
}
12981311

0 commit comments

Comments
 (0)