aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Schmidt <list.btrfs@jan-o-sch.net>2012-04-13 06:28:08 -0400
committerDavid Sterba <dsterba@suse.cz>2012-04-18 13:22:23 -0400
commitb916a59adfdc875381b68ced258694b434cf43ae (patch)
tree7c73c9326cd558e9a5ae34381a6450e354a65a9d
parentaefc1eb13ebbb86c5ffade8a9e2425cd71032d7e (diff)
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>
-rw-r--r--fs/btrfs/backref.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index fb56bcc80377..bcec06750232 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -22,6 +22,7 @@
22#include "ulist.h" 22#include "ulist.h"
23#include "transaction.h" 23#include "transaction.h"
24#include "delayed-ref.h" 24#include "delayed-ref.h"
25#include "locking.h"
25 26
26/* 27/*
27 * this structure records all encountered refs on the way up to the root 28 * 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,
893 s64 bytes_left = size - 1; 894 s64 bytes_left = size - 1;
894 struct extent_buffer *eb = eb_in; 895 struct extent_buffer *eb = eb_in;
895 struct btrfs_key found_key; 896 struct btrfs_key found_key;
897 int leave_spinning = path->leave_spinning;
896 898
897 if (bytes_left >= 0) 899 if (bytes_left >= 0)
898 dest[bytes_left] = '\0'; 900 dest[bytes_left] = '\0';
899 901
902 path->leave_spinning = 1;
900 while (1) { 903 while (1) {
901 len = btrfs_inode_ref_name_len(eb, iref); 904 len = btrfs_inode_ref_name_len(eb, iref);
902 bytes_left -= len; 905 bytes_left -= len;
903 if (bytes_left >= 0) 906 if (bytes_left >= 0)
904 read_extent_buffer(eb, dest + bytes_left, 907 read_extent_buffer(eb, dest + bytes_left,
905 (unsigned long)(iref + 1), len); 908 (unsigned long)(iref + 1), len);
906 if (eb != eb_in) 909 if (eb != eb_in) {
910 btrfs_tree_read_unlock_blocking(eb);
907 free_extent_buffer(eb); 911 free_extent_buffer(eb);
912 }
908 ret = inode_ref_info(parent, 0, fs_root, path, &found_key); 913 ret = inode_ref_info(parent, 0, fs_root, path, &found_key);
909 if (ret > 0) 914 if (ret > 0)
910 ret = -ENOENT; 915 ret = -ENOENT;
@@ -919,8 +924,11 @@ static char *iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
919 slot = path->slots[0]; 924 slot = path->slots[0];
920 eb = path->nodes[0]; 925 eb = path->nodes[0];
921 /* make sure we can use eb after releasing the path */ 926 /* make sure we can use eb after releasing the path */
922 if (eb != eb_in) 927 if (eb != eb_in) {
923 atomic_inc(&eb->refs); 928 atomic_inc(&eb->refs);
929 btrfs_tree_read_lock(eb);
930 btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
931 }
924 btrfs_release_path(path); 932 btrfs_release_path(path);
925 933
926 iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref); 934 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,
931 } 939 }
932 940
933 btrfs_release_path(path); 941 btrfs_release_path(path);
942 path->leave_spinning = leave_spinning;
934 943
935 if (ret) 944 if (ret)
936 return ERR_PTR(ret); 945 return ERR_PTR(ret);
@@ -1260,6 +1269,7 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
1260 struct btrfs_key found_key; 1269 struct btrfs_key found_key;
1261 1270
1262 while (!ret) { 1271 while (!ret) {
1272 path->leave_spinning = 1;
1263 ret = inode_ref_info(inum, parent ? parent+1 : 0, fs_root, path, 1273 ret = inode_ref_info(inum, parent ? parent+1 : 0, fs_root, path,
1264 &found_key); 1274 &found_key);
1265 if (ret < 0) 1275 if (ret < 0)
@@ -1275,6 +1285,8 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
1275 eb = path->nodes[0]; 1285 eb = path->nodes[0];
1276 /* make sure we can use eb after releasing the path */ 1286 /* make sure we can use eb after releasing the path */
1277 atomic_inc(&eb->refs); 1287 atomic_inc(&eb->refs);
1288 btrfs_tree_read_lock(eb);
1289 btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
1278 btrfs_release_path(path); 1290 btrfs_release_path(path);
1279 1291
1280 item = btrfs_item_nr(eb, slot); 1292 item = btrfs_item_nr(eb, slot);
@@ -1293,6 +1305,7 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
1293 len = sizeof(*iref) + name_len; 1305 len = sizeof(*iref) + name_len;
1294 iref = (struct btrfs_inode_ref *)((char *)iref + len); 1306 iref = (struct btrfs_inode_ref *)((char *)iref + len);
1295 } 1307 }
1308 btrfs_tree_read_unlock_blocking(eb);
1296 free_extent_buffer(eb); 1309 free_extent_buffer(eb);
1297 } 1310 }
1298 1311