diff options
author | Josef Bacik <josef@redhat.com> | 2011-06-08 14:45:50 -0400 |
---|---|---|
committer | Arne Jansen <sensille@gmx.net> | 2011-06-10 06:14:12 -0400 |
commit | ad3e34bba4b64ab8e1f5ea1a17768e1a0d9648ea (patch) | |
tree | 46f2081646866cea4f89d8f20c5f632f14e3bc2a /fs/btrfs | |
parent | aa0467d8d2a00e75b2bb6a56a4ee6d70c5d1928f (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/btrfs')
-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 | } |