aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorStefan Behrens <sbehrens@giantdisaster.de>2012-11-06 07:15:27 -0500
committerJosef Bacik <jbacik@fusionio.com>2012-12-12 17:15:42 -0500
commit8dabb7420f014ab0f9f04afae8ae046c0f48b270 (patch)
tree6342f353ac71003d749a776dd6dc6a18b1bd959b /fs
parente93c89c1aaaaaec3487c4c18dd02360371790722 (diff)
Btrfs: change core code of btrfs to support the device replace operations
This commit contains all the essential changes to the core code of Btrfs for support of the device replace procedure. Signed-off-by: Stefan Behrens <sbehrens@giantdisaster.de> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/disk-io.c24
-rw-r--r--fs/btrfs/reada.c17
-rw-r--r--fs/btrfs/scrub.c7
-rw-r--r--fs/btrfs/super.c13
-rw-r--r--fs/btrfs/transaction.c7
-rw-r--r--fs/btrfs/volumes.c54
-rw-r--r--fs/btrfs/volumes.h3
7 files changed, 111 insertions, 14 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 0e410478ad2..76b82506bf9 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -45,6 +45,7 @@
45#include "inode-map.h" 45#include "inode-map.h"
46#include "check-integrity.h" 46#include "check-integrity.h"
47#include "rcu-string.h" 47#include "rcu-string.h"
48#include "dev-replace.h"
48 49
49#ifdef CONFIG_X86 50#ifdef CONFIG_X86
50#include <asm/cpufeature.h> 51#include <asm/cpufeature.h>
@@ -2438,7 +2439,11 @@ int open_ctree(struct super_block *sb,
2438 goto fail_tree_roots; 2439 goto fail_tree_roots;
2439 } 2440 }
2440 2441
2441 btrfs_close_extra_devices(fs_devices); 2442 /*
2443 * keep the device that is marked to be the target device for the
2444 * dev_replace procedure
2445 */
2446 btrfs_close_extra_devices(fs_info, fs_devices, 0);
2442 2447
2443 if (!fs_devices->latest_bdev) { 2448 if (!fs_devices->latest_bdev) {
2444 printk(KERN_CRIT "btrfs: failed to read devices on %s\n", 2449 printk(KERN_CRIT "btrfs: failed to read devices on %s\n",
@@ -2510,6 +2515,14 @@ retry_root_backup:
2510 goto fail_block_groups; 2515 goto fail_block_groups;
2511 } 2516 }
2512 2517
2518 ret = btrfs_init_dev_replace(fs_info);
2519 if (ret) {
2520 pr_err("btrfs: failed to init dev_replace: %d\n", ret);
2521 goto fail_block_groups;
2522 }
2523
2524 btrfs_close_extra_devices(fs_info, fs_devices, 1);
2525
2513 ret = btrfs_init_space_info(fs_info); 2526 ret = btrfs_init_space_info(fs_info);
2514 if (ret) { 2527 if (ret) {
2515 printk(KERN_ERR "Failed to initial space info: %d\n", ret); 2528 printk(KERN_ERR "Failed to initial space info: %d\n", ret);
@@ -2658,6 +2671,13 @@ retry_root_backup:
2658 return ret; 2671 return ret;
2659 } 2672 }
2660 2673
2674 ret = btrfs_resume_dev_replace_async(fs_info);
2675 if (ret) {
2676 pr_warn("btrfs: failed to resume dev_replace\n");
2677 close_ctree(tree_root);
2678 return ret;
2679 }
2680
2661 return 0; 2681 return 0;
2662 2682
2663fail_qgroup: 2683fail_qgroup:
@@ -3300,6 +3320,8 @@ int close_ctree(struct btrfs_root *root)
3300 /* pause restriper - we want to resume on mount */ 3320 /* pause restriper - we want to resume on mount */
3301 btrfs_pause_balance(fs_info); 3321 btrfs_pause_balance(fs_info);
3302 3322
3323 btrfs_dev_replace_suspend_for_unmount(fs_info);
3324
3303 btrfs_scrub_cancel(fs_info); 3325 btrfs_scrub_cancel(fs_info);
3304 3326
3305 /* wait for any defraggers to finish */ 3327 /* wait for any defraggers to finish */
diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c
index 9f363e17ec7..c705a48e676 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
@@ -331,6 +332,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
331 int nzones = 0; 332 int nzones = 0;
332 int i; 333 int i;
333 unsigned long index = logical >> PAGE_CACHE_SHIFT; 334 unsigned long index = logical >> PAGE_CACHE_SHIFT;
335 int dev_replace_is_ongoing;
334 336
335 spin_lock(&fs_info->reada_lock); 337 spin_lock(&fs_info->reada_lock);
336 re = radix_tree_lookup(&fs_info->reada_tree, index); 338 re = radix_tree_lookup(&fs_info->reada_tree, index);
@@ -392,6 +394,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
392 } 394 }
393 395
394 /* insert extent in reada_tree + all per-device trees, all or nothing */ 396 /* insert extent in reada_tree + all per-device trees, all or nothing */
397 btrfs_dev_replace_lock(&fs_info->dev_replace);
395 spin_lock(&fs_info->reada_lock); 398 spin_lock(&fs_info->reada_lock);
396 ret = radix_tree_insert(&fs_info->reada_tree, index, re); 399 ret = radix_tree_insert(&fs_info->reada_tree, index, re);
397 if (ret == -EEXIST) { 400 if (ret == -EEXIST) {
@@ -399,13 +402,17 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
399 BUG_ON(!re_exist); 402 BUG_ON(!re_exist);
400 re_exist->refcnt++; 403 re_exist->refcnt++;
401 spin_unlock(&fs_info->reada_lock); 404 spin_unlock(&fs_info->reada_lock);
405 btrfs_dev_replace_unlock(&fs_info->dev_replace);
402 goto error; 406 goto error;
403 } 407 }
404 if (ret) { 408 if (ret) {
405 spin_unlock(&fs_info->reada_lock); 409 spin_unlock(&fs_info->reada_lock);
410 btrfs_dev_replace_unlock(&fs_info->dev_replace);
406 goto error; 411 goto error;
407 } 412 }
408 prev_dev = NULL; 413 prev_dev = NULL;
414 dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing(
415 &fs_info->dev_replace);
409 for (i = 0; i < nzones; ++i) { 416 for (i = 0; i < nzones; ++i) {
410 dev = bbio->stripes[i].dev; 417 dev = bbio->stripes[i].dev;
411 if (dev == prev_dev) { 418 if (dev == prev_dev) {
@@ -422,6 +429,14 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
422 /* cannot read ahead on missing device */ 429 /* cannot read ahead on missing device */
423 continue; 430 continue;
424 } 431 }
432 if (dev_replace_is_ongoing &&
433 dev == fs_info->dev_replace.tgtdev) {
434 /*
435 * as this device is selected for reading only as
436 * a last resort, skip it for read ahead.
437 */
438 continue;
439 }
425 prev_dev = dev; 440 prev_dev = dev;
426 ret = radix_tree_insert(&dev->reada_extents, index, re); 441 ret = radix_tree_insert(&dev->reada_extents, index, re);
427 if (ret) { 442 if (ret) {
@@ -434,10 +449,12 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
434 BUG_ON(fs_info == NULL); 449 BUG_ON(fs_info == NULL);
435 radix_tree_delete(&fs_info->reada_tree, index); 450 radix_tree_delete(&fs_info->reada_tree, index);
436 spin_unlock(&fs_info->reada_lock); 451 spin_unlock(&fs_info->reada_lock);
452 btrfs_dev_replace_unlock(&fs_info->dev_replace);
437 goto error; 453 goto error;
438 } 454 }
439 } 455 }
440 spin_unlock(&fs_info->reada_lock); 456 spin_unlock(&fs_info->reada_lock);
457 btrfs_dev_replace_unlock(&fs_info->dev_replace);
441 458
442 kfree(bbio); 459 kfree(bbio);
443 return re; 460 return re;
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 61157a26cf2..30cbf6921c0 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -2843,12 +2843,17 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
2843 return -EIO; 2843 return -EIO;
2844 } 2844 }
2845 2845
2846 if (dev->scrub_device) { 2846 btrfs_dev_replace_lock(&fs_info->dev_replace);
2847 if (dev->scrub_device ||
2848 (!is_dev_replace &&
2849 btrfs_dev_replace_is_ongoing(&fs_info->dev_replace))) {
2850 btrfs_dev_replace_unlock(&fs_info->dev_replace);
2847 mutex_unlock(&fs_info->scrub_lock); 2851 mutex_unlock(&fs_info->scrub_lock);
2848 mutex_unlock(&fs_info->fs_devices->device_list_mutex); 2852 mutex_unlock(&fs_info->fs_devices->device_list_mutex);
2849 scrub_workers_put(fs_info); 2853 scrub_workers_put(fs_info);
2850 return -EINPROGRESS; 2854 return -EINPROGRESS;
2851 } 2855 }
2856 btrfs_dev_replace_unlock(&fs_info->dev_replace);
2852 sctx = scrub_setup_ctx(dev, is_dev_replace); 2857 sctx = scrub_setup_ctx(dev, is_dev_replace);
2853 if (IS_ERR(sctx)) { 2858 if (IS_ERR(sctx)) {
2854 mutex_unlock(&fs_info->scrub_lock); 2859 mutex_unlock(&fs_info->scrub_lock);
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index ad4380684b9..def4f24b58d 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -55,6 +55,7 @@
55#include "export.h" 55#include "export.h"
56#include "compression.h" 56#include "compression.h"
57#include "rcu-string.h" 57#include "rcu-string.h"
58#include "dev-replace.h"
58 59
59#define CREATE_TRACE_POINTS 60#define CREATE_TRACE_POINTS
60#include <trace/events/btrfs.h> 61#include <trace/events/btrfs.h>
@@ -1225,8 +1226,15 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
1225 return 0; 1226 return 0;
1226 1227
1227 if (*flags & MS_RDONLY) { 1228 if (*flags & MS_RDONLY) {
1229 /*
1230 * this also happens on 'umount -rf' or on shutdown, when
1231 * the filesystem is busy.
1232 */
1228 sb->s_flags |= MS_RDONLY; 1233 sb->s_flags |= MS_RDONLY;
1229 1234
1235 btrfs_dev_replace_suspend_for_unmount(fs_info);
1236 btrfs_scrub_cancel(fs_info);
1237
1230 ret = btrfs_commit_super(root); 1238 ret = btrfs_commit_super(root);
1231 if (ret) 1239 if (ret)
1232 goto restore; 1240 goto restore;
@@ -1263,6 +1271,11 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
1263 if (ret) 1271 if (ret)
1264 goto restore; 1272 goto restore;
1265 1273
1274 ret = btrfs_resume_dev_replace_async(fs_info);
1275 if (ret) {
1276 pr_warn("btrfs: failed to resume dev_replace\n");
1277 goto restore;
1278 }
1266 sb->s_flags &= ~MS_RDONLY; 1279 sb->s_flags &= ~MS_RDONLY;
1267 } 1280 }
1268 1281
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 7b297354e73..bcc6b65be3b 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -30,6 +30,7 @@
30#include "tree-log.h" 30#include "tree-log.h"
31#include "inode-map.h" 31#include "inode-map.h"
32#include "volumes.h" 32#include "volumes.h"
33#include "dev-replace.h"
33 34
34#define BTRFS_ROOT_TRANS_TAG 0 35#define BTRFS_ROOT_TRANS_TAG 0
35 36
@@ -845,7 +846,9 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
845 return ret; 846 return ret;
846 847
847 ret = btrfs_run_dev_stats(trans, root->fs_info); 848 ret = btrfs_run_dev_stats(trans, root->fs_info);
848 BUG_ON(ret); 849 WARN_ON(ret);
850 ret = btrfs_run_dev_replace(trans, root->fs_info);
851 WARN_ON(ret);
849 852
850 ret = btrfs_run_qgroups(trans, root->fs_info); 853 ret = btrfs_run_qgroups(trans, root->fs_info);
851 BUG_ON(ret); 854 BUG_ON(ret);
@@ -868,6 +871,8 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
868 switch_commit_root(fs_info->extent_root); 871 switch_commit_root(fs_info->extent_root);
869 up_write(&fs_info->extent_commit_sem); 872 up_write(&fs_info->extent_commit_sem);
870 873
874 btrfs_after_dev_replace_commit(fs_info);
875
871 return 0; 876 return 0;
872} 877}
873 878
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 5777e6a9aab..a4e0963bf45 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -36,6 +36,7 @@
36#include "check-integrity.h" 36#include "check-integrity.h"
37#include "rcu-string.h" 37#include "rcu-string.h"
38#include "math.h" 38#include "math.h"
39#include "dev-replace.h"
39 40
40static int init_first_rw_device(struct btrfs_trans_handle *trans, 41static int init_first_rw_device(struct btrfs_trans_handle *trans,
41 struct btrfs_root *root, 42 struct btrfs_root *root,
@@ -505,7 +506,8 @@ error:
505 return ERR_PTR(-ENOMEM); 506 return ERR_PTR(-ENOMEM);
506} 507}
507 508
508void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices) 509void btrfs_close_extra_devices(struct btrfs_fs_info *fs_info,
510 struct btrfs_fs_devices *fs_devices, int step)
509{ 511{
510 struct btrfs_device *device, *next; 512 struct btrfs_device *device, *next;
511 513
@@ -528,6 +530,21 @@ again:
528 continue; 530 continue;
529 } 531 }
530 532
533 if (device->devid == BTRFS_DEV_REPLACE_DEVID) {
534 /*
535 * In the first step, keep the device which has
536 * the correct fsid and the devid that is used
537 * for the dev_replace procedure.
538 * In the second step, the dev_replace state is
539 * read from the device tree and it is known
540 * whether the procedure is really active or
541 * not, which means whether this device is
542 * used or whether it should be removed.
543 */
544 if (step == 0 || device->is_tgtdev_for_dev_replace) {
545 continue;
546 }
547 }
531 if (device->bdev) { 548 if (device->bdev) {
532 blkdev_put(device->bdev, device->mode); 549 blkdev_put(device->bdev, device->mode);
533 device->bdev = NULL; 550 device->bdev = NULL;
@@ -536,7 +553,8 @@ again:
536 if (device->writeable) { 553 if (device->writeable) {
537 list_del_init(&device->dev_alloc_list); 554 list_del_init(&device->dev_alloc_list);
538 device->writeable = 0; 555 device->writeable = 0;
539 fs_devices->rw_devices--; 556 if (!device->is_tgtdev_for_dev_replace)
557 fs_devices->rw_devices--;
540 } 558 }
541 list_del_init(&device->dev_list); 559 list_del_init(&device->dev_list);
542 fs_devices->num_devices--; 560 fs_devices->num_devices--;
@@ -594,7 +612,7 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
594 if (device->bdev) 612 if (device->bdev)
595 fs_devices->open_devices--; 613 fs_devices->open_devices--;
596 614
597 if (device->writeable) { 615 if (device->writeable && !device->is_tgtdev_for_dev_replace) {
598 list_del_init(&device->dev_alloc_list); 616 list_del_init(&device->dev_alloc_list);
599 fs_devices->rw_devices--; 617 fs_devices->rw_devices--;
600 } 618 }
@@ -718,7 +736,7 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
718 fs_devices->rotating = 1; 736 fs_devices->rotating = 1;
719 737
720 fs_devices->open_devices++; 738 fs_devices->open_devices++;
721 if (device->writeable) { 739 if (device->writeable && !device->is_tgtdev_for_dev_replace) {
722 fs_devices->rw_devices++; 740 fs_devices->rw_devices++;
723 list_add(&device->dev_alloc_list, 741 list_add(&device->dev_alloc_list,
724 &fs_devices->alloc_list); 742 &fs_devices->alloc_list);
@@ -1350,16 +1368,22 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
1350 root->fs_info->avail_system_alloc_bits | 1368 root->fs_info->avail_system_alloc_bits |
1351 root->fs_info->avail_metadata_alloc_bits; 1369 root->fs_info->avail_metadata_alloc_bits;
1352 1370
1353 if ((all_avail & BTRFS_BLOCK_GROUP_RAID10) && 1371 num_devices = root->fs_info->fs_devices->num_devices;
1354 root->fs_info->fs_devices->num_devices <= 4) { 1372 btrfs_dev_replace_lock(&root->fs_info->dev_replace);
1373 if (btrfs_dev_replace_is_ongoing(&root->fs_info->dev_replace)) {
1374 WARN_ON(num_devices < 1);
1375 num_devices--;
1376 }
1377 btrfs_dev_replace_unlock(&root->fs_info->dev_replace);
1378
1379 if ((all_avail & BTRFS_BLOCK_GROUP_RAID10) && num_devices <= 4) {
1355 printk(KERN_ERR "btrfs: unable to go below four devices " 1380 printk(KERN_ERR "btrfs: unable to go below four devices "
1356 "on raid10\n"); 1381 "on raid10\n");
1357 ret = -EINVAL; 1382 ret = -EINVAL;
1358 goto out; 1383 goto out;
1359 } 1384 }
1360 1385
1361 if ((all_avail & BTRFS_BLOCK_GROUP_RAID1) && 1386 if ((all_avail & BTRFS_BLOCK_GROUP_RAID1) && num_devices <= 2) {
1362 root->fs_info->fs_devices->num_devices <= 2) {
1363 printk(KERN_ERR "btrfs: unable to go below two " 1387 printk(KERN_ERR "btrfs: unable to go below two "
1364 "devices on raid1\n"); 1388 "devices on raid1\n");
1365 ret = -EINVAL; 1389 ret = -EINVAL;
@@ -2935,6 +2959,7 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
2935 u64 allowed; 2959 u64 allowed;
2936 int mixed = 0; 2960 int mixed = 0;
2937 int ret; 2961 int ret;
2962 u64 num_devices;
2938 2963
2939 if (btrfs_fs_closing(fs_info) || 2964 if (btrfs_fs_closing(fs_info) ||
2940 atomic_read(&fs_info->balance_pause_req) || 2965 atomic_read(&fs_info->balance_pause_req) ||
@@ -2963,10 +2988,17 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
2963 } 2988 }
2964 } 2989 }
2965 2990
2991 num_devices = fs_info->fs_devices->num_devices;
2992 btrfs_dev_replace_lock(&fs_info->dev_replace);
2993 if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace)) {
2994 BUG_ON(num_devices < 1);
2995 num_devices--;
2996 }
2997 btrfs_dev_replace_unlock(&fs_info->dev_replace);
2966 allowed = BTRFS_AVAIL_ALLOC_BIT_SINGLE; 2998 allowed = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
2967 if (fs_info->fs_devices->num_devices == 1) 2999 if (num_devices == 1)
2968 allowed |= BTRFS_BLOCK_GROUP_DUP; 3000 allowed |= BTRFS_BLOCK_GROUP_DUP;
2969 else if (fs_info->fs_devices->num_devices < 4) 3001 else if (num_devices < 4)
2970 allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1); 3002 allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1);
2971 else 3003 else
2972 allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | 3004 allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
@@ -3591,6 +3623,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
3591 devices_info[ndevs].total_avail = total_avail; 3623 devices_info[ndevs].total_avail = total_avail;
3592 devices_info[ndevs].dev = device; 3624 devices_info[ndevs].dev = device;
3593 ++ndevs; 3625 ++ndevs;
3626 WARN_ON(ndevs > fs_devices->rw_devices);
3594 } 3627 }
3595 3628
3596 /* 3629 /*
@@ -4773,6 +4806,7 @@ static void fill_device_from_item(struct extent_buffer *leaf,
4773 device->io_align = btrfs_device_io_align(leaf, dev_item); 4806 device->io_align = btrfs_device_io_align(leaf, dev_item);
4774 device->io_width = btrfs_device_io_width(leaf, dev_item); 4807 device->io_width = btrfs_device_io_width(leaf, dev_item);
4775 device->sector_size = btrfs_device_sector_size(leaf, dev_item); 4808 device->sector_size = btrfs_device_sector_size(leaf, dev_item);
4809 WARN_ON(device->devid == BTRFS_DEV_REPLACE_DEVID);
4776 device->is_tgtdev_for_dev_replace = 0; 4810 device->is_tgtdev_for_dev_replace = 0;
4777 4811
4778 ptr = (unsigned long)btrfs_device_uuid(dev_item); 4812 ptr = (unsigned long)btrfs_device_uuid(dev_item);
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 58d79375dea..37d0157167b 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -268,7 +268,8 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
268int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, 268int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
269 struct btrfs_fs_devices **fs_devices_ret); 269 struct btrfs_fs_devices **fs_devices_ret);
270int btrfs_close_devices(struct btrfs_fs_devices *fs_devices); 270int btrfs_close_devices(struct btrfs_fs_devices *fs_devices);
271void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices); 271void btrfs_close_extra_devices(struct btrfs_fs_info *fs_info,
272 struct btrfs_fs_devices *fs_devices, int step);
272int btrfs_find_device_missing_or_by_path(struct btrfs_root *root, 273int btrfs_find_device_missing_or_by_path(struct btrfs_root *root,
273 char *device_path, 274 char *device_path,
274 struct btrfs_device **device); 275 struct btrfs_device **device);