diff options
author | Josef Bacik <josef@redhat.com> | 2011-06-08 14:36:54 -0400 |
---|---|---|
committer | Josef Bacik <josef@redhat.com> | 2011-06-09 10:12:07 -0400 |
commit | 25b8b936ed44814a5ce6fc3b2a21401f33cd56f6 (patch) | |
tree | 3f95ff0f54340bf63885e1d38766cf52a05d3029 /fs | |
parent | f6a398298d34af66ec3a2d82a44a4dbc5277357d (diff) |
Btrfs: don't map extent buffer if path->skip_locking is set
Arne's scrub stuff exposed a problem with mapping the extent buffer in
reada_for_search. He searches the commit root with multiple threads and with
skip_locking set, so we can race and overwrite node->map_token since node isn't
locked. So fix this so that we only map the extent buffer if we don't already
have a map_token and skip_locking isn't set. Without this patch scrub would
panic almost immediately, with the patch it doesn't panic anymore. Thanks,
Reported-by: Arne Jansen <sensille@gmx.net>
Signed-off-by: Josef Bacik <josef@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index d84089349c82..2e667868e0d2 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -1228,6 +1228,7 @@ static void reada_for_search(struct btrfs_root *root, | |||
1228 | u32 nr; | 1228 | u32 nr; |
1229 | u32 blocksize; | 1229 | u32 blocksize; |
1230 | u32 nscan = 0; | 1230 | u32 nscan = 0; |
1231 | bool map = true; | ||
1231 | 1232 | ||
1232 | if (level != 1) | 1233 | if (level != 1) |
1233 | return; | 1234 | return; |
@@ -1249,8 +1250,11 @@ static void reada_for_search(struct btrfs_root *root, | |||
1249 | 1250 | ||
1250 | nritems = btrfs_header_nritems(node); | 1251 | nritems = btrfs_header_nritems(node); |
1251 | nr = slot; | 1252 | nr = slot; |
1253 | if (node->map_token || path->skip_locking) | ||
1254 | map = false; | ||
1255 | |||
1252 | while (1) { | 1256 | while (1) { |
1253 | if (!node->map_token) { | 1257 | if (map && !node->map_token) { |
1254 | unsigned long offset = btrfs_node_key_ptr_offset(nr); | 1258 | unsigned long offset = btrfs_node_key_ptr_offset(nr); |
1255 | map_private_extent_buffer(node, offset, | 1259 | map_private_extent_buffer(node, offset, |
1256 | sizeof(struct btrfs_key_ptr), | 1260 | sizeof(struct btrfs_key_ptr), |
@@ -1277,7 +1281,7 @@ static void reada_for_search(struct btrfs_root *root, | |||
1277 | if ((search <= target && target - search <= 65536) || | 1281 | if ((search <= target && target - search <= 65536) || |
1278 | (search > target && search - target <= 65536)) { | 1282 | (search > target && search - target <= 65536)) { |
1279 | gen = btrfs_node_ptr_generation(node, nr); | 1283 | gen = btrfs_node_ptr_generation(node, nr); |
1280 | if (node->map_token) { | 1284 | if (map && node->map_token) { |
1281 | unmap_extent_buffer(node, node->map_token, | 1285 | unmap_extent_buffer(node, node->map_token, |
1282 | KM_USER1); | 1286 | KM_USER1); |
1283 | node->map_token = NULL; | 1287 | node->map_token = NULL; |
@@ -1289,7 +1293,7 @@ static void reada_for_search(struct btrfs_root *root, | |||
1289 | if ((nread > 65536 || nscan > 32)) | 1293 | if ((nread > 65536 || nscan > 32)) |
1290 | break; | 1294 | break; |
1291 | } | 1295 | } |
1292 | if (node->map_token) { | 1296 | if (map && node->map_token) { |
1293 | unmap_extent_buffer(node, node->map_token, KM_USER1); | 1297 | unmap_extent_buffer(node, node->map_token, KM_USER1); |
1294 | node->map_token = NULL; | 1298 | node->map_token = NULL; |
1295 | } | 1299 | } |