diff options
Diffstat (limited to 'fs/btrfs/reada.c')
-rw-r--r-- | fs/btrfs/reada.c | 31 |
1 files changed, 28 insertions, 3 deletions
diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c index a955669519a2..96b93daa0bbb 100644 --- a/fs/btrfs/reada.c +++ b/fs/btrfs/reada.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include "volumes.h" | 27 | #include "volumes.h" |
28 | #include "disk-io.h" | 28 | #include "disk-io.h" |
29 | #include "transaction.h" | 29 | #include "transaction.h" |
30 | #include "dev-replace.h" | ||
30 | 31 | ||
31 | #undef DEBUG | 32 | #undef DEBUG |
32 | 33 | ||
@@ -323,7 +324,6 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, | |||
323 | struct reada_extent *re = NULL; | 324 | struct reada_extent *re = NULL; |
324 | struct reada_extent *re_exist = NULL; | 325 | struct reada_extent *re_exist = NULL; |
325 | struct btrfs_fs_info *fs_info = root->fs_info; | 326 | struct btrfs_fs_info *fs_info = root->fs_info; |
326 | struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; | ||
327 | struct btrfs_bio *bbio = NULL; | 327 | struct btrfs_bio *bbio = NULL; |
328 | struct btrfs_device *dev; | 328 | struct btrfs_device *dev; |
329 | struct btrfs_device *prev_dev; | 329 | struct btrfs_device *prev_dev; |
@@ -332,6 +332,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, | |||
332 | int nzones = 0; | 332 | int nzones = 0; |
333 | int i; | 333 | int i; |
334 | unsigned long index = logical >> PAGE_CACHE_SHIFT; | 334 | unsigned long index = logical >> PAGE_CACHE_SHIFT; |
335 | int dev_replace_is_ongoing; | ||
335 | 336 | ||
336 | spin_lock(&fs_info->reada_lock); | 337 | spin_lock(&fs_info->reada_lock); |
337 | re = radix_tree_lookup(&fs_info->reada_tree, index); | 338 | re = radix_tree_lookup(&fs_info->reada_tree, index); |
@@ -358,7 +359,8 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, | |||
358 | * map block | 359 | * map block |
359 | */ | 360 | */ |
360 | length = blocksize; | 361 | length = blocksize; |
361 | ret = btrfs_map_block(map_tree, REQ_WRITE, logical, &length, &bbio, 0); | 362 | ret = btrfs_map_block(fs_info, REQ_GET_READ_MIRRORS, logical, &length, |
363 | &bbio, 0); | ||
362 | if (ret || !bbio || length < blocksize) | 364 | if (ret || !bbio || length < blocksize) |
363 | goto error; | 365 | goto error; |
364 | 366 | ||
@@ -393,6 +395,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, | |||
393 | } | 395 | } |
394 | 396 | ||
395 | /* insert extent in reada_tree + all per-device trees, all or nothing */ | 397 | /* insert extent in reada_tree + all per-device trees, all or nothing */ |
398 | btrfs_dev_replace_lock(&fs_info->dev_replace); | ||
396 | spin_lock(&fs_info->reada_lock); | 399 | spin_lock(&fs_info->reada_lock); |
397 | ret = radix_tree_insert(&fs_info->reada_tree, index, re); | 400 | ret = radix_tree_insert(&fs_info->reada_tree, index, re); |
398 | if (ret == -EEXIST) { | 401 | if (ret == -EEXIST) { |
@@ -400,13 +403,17 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, | |||
400 | BUG_ON(!re_exist); | 403 | BUG_ON(!re_exist); |
401 | re_exist->refcnt++; | 404 | re_exist->refcnt++; |
402 | spin_unlock(&fs_info->reada_lock); | 405 | spin_unlock(&fs_info->reada_lock); |
406 | btrfs_dev_replace_unlock(&fs_info->dev_replace); | ||
403 | goto error; | 407 | goto error; |
404 | } | 408 | } |
405 | if (ret) { | 409 | if (ret) { |
406 | spin_unlock(&fs_info->reada_lock); | 410 | spin_unlock(&fs_info->reada_lock); |
411 | btrfs_dev_replace_unlock(&fs_info->dev_replace); | ||
407 | goto error; | 412 | goto error; |
408 | } | 413 | } |
409 | prev_dev = NULL; | 414 | prev_dev = NULL; |
415 | dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing( | ||
416 | &fs_info->dev_replace); | ||
410 | for (i = 0; i < nzones; ++i) { | 417 | for (i = 0; i < nzones; ++i) { |
411 | dev = bbio->stripes[i].dev; | 418 | dev = bbio->stripes[i].dev; |
412 | if (dev == prev_dev) { | 419 | if (dev == prev_dev) { |
@@ -419,21 +426,36 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, | |||
419 | */ | 426 | */ |
420 | continue; | 427 | continue; |
421 | } | 428 | } |
429 | if (!dev->bdev) { | ||
430 | /* cannot read ahead on missing device */ | ||
431 | continue; | ||
432 | } | ||
433 | if (dev_replace_is_ongoing && | ||
434 | dev == fs_info->dev_replace.tgtdev) { | ||
435 | /* | ||
436 | * as this device is selected for reading only as | ||
437 | * a last resort, skip it for read ahead. | ||
438 | */ | ||
439 | continue; | ||
440 | } | ||
422 | prev_dev = dev; | 441 | prev_dev = dev; |
423 | ret = radix_tree_insert(&dev->reada_extents, index, re); | 442 | ret = radix_tree_insert(&dev->reada_extents, index, re); |
424 | if (ret) { | 443 | if (ret) { |
425 | while (--i >= 0) { | 444 | while (--i >= 0) { |
426 | dev = bbio->stripes[i].dev; | 445 | dev = bbio->stripes[i].dev; |
427 | BUG_ON(dev == NULL); | 446 | BUG_ON(dev == NULL); |
447 | /* ignore whether the entry was inserted */ | ||
428 | radix_tree_delete(&dev->reada_extents, index); | 448 | radix_tree_delete(&dev->reada_extents, index); |
429 | } | 449 | } |
430 | BUG_ON(fs_info == NULL); | 450 | BUG_ON(fs_info == NULL); |
431 | radix_tree_delete(&fs_info->reada_tree, index); | 451 | radix_tree_delete(&fs_info->reada_tree, index); |
432 | spin_unlock(&fs_info->reada_lock); | 452 | spin_unlock(&fs_info->reada_lock); |
453 | btrfs_dev_replace_unlock(&fs_info->dev_replace); | ||
433 | goto error; | 454 | goto error; |
434 | } | 455 | } |
435 | } | 456 | } |
436 | spin_unlock(&fs_info->reada_lock); | 457 | spin_unlock(&fs_info->reada_lock); |
458 | btrfs_dev_replace_unlock(&fs_info->dev_replace); | ||
437 | 459 | ||
438 | kfree(bbio); | 460 | kfree(bbio); |
439 | return re; | 461 | return re; |
@@ -915,7 +937,10 @@ struct reada_control *btrfs_reada_add(struct btrfs_root *root, | |||
915 | generation = btrfs_header_generation(node); | 937 | generation = btrfs_header_generation(node); |
916 | free_extent_buffer(node); | 938 | free_extent_buffer(node); |
917 | 939 | ||
918 | reada_add_block(rc, start, &max_key, level, generation); | 940 | if (reada_add_block(rc, start, &max_key, level, generation)) { |
941 | kfree(rc); | ||
942 | return ERR_PTR(-ENOMEM); | ||
943 | } | ||
919 | 944 | ||
920 | reada_start_machine(root->fs_info); | 945 | reada_start_machine(root->fs_info); |
921 | 946 | ||