block: remove i_bdev
[linux-2.6-microblaze.git] / fs / btrfs / volumes.c
index 214856c..fbc4b58 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <linux/sched.h>
  */
 
 #include <linux/sched.h>
+#include <linux/sched/mm.h>
 #include <linux/bio.h>
 #include <linux/slab.h>
 #include <linux/blkdev.h>
 #include <linux/bio.h>
 #include <linux/slab.h>
 #include <linux/blkdev.h>
@@ -290,8 +291,8 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info,
  *   balance_mutex
  *
  *
  *   balance_mutex
  *
  *
- * Exclusive operations, BTRFS_FS_EXCL_OP
- * ======================================
+ * Exclusive operations
+ * ====================
  *
  * Maintains the exclusivity of the following operations that apply to the
  * whole filesystem and cannot run in parallel.
  *
  * Maintains the exclusivity of the following operations that apply to the
  * whole filesystem and cannot run in parallel.
@@ -317,11 +318,11 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info,
  * - system power-cycle and filesystem mounted as read-only
  * - filesystem or device errors leading to forced read-only
  *
  * - system power-cycle and filesystem mounted as read-only
  * - filesystem or device errors leading to forced read-only
  *
- * BTRFS_FS_EXCL_OP flag is set and cleared using atomic operations.
- * During the course of Paused state, the BTRFS_FS_EXCL_OP remains set.
+ * The status of exclusive operation is set and cleared atomically.
+ * During the course of Paused state, fs_info::exclusive_operation remains set.
  * A device operation in Paused or Running state can be canceled or resumed
  * either by ioctl (Balance only) or when remounted as read-write.
  * A device operation in Paused or Running state can be canceled or resumed
  * either by ioctl (Balance only) or when remounted as read-write.
- * BTRFS_FS_EXCL_OP flag is cleared when the device operation is canceled or
+ * The exclusive status is cleared when the device operation is canceled or
  * completed.
  */
 
  * completed.
  */
 
@@ -355,6 +356,7 @@ static struct btrfs_fs_devices *alloc_fs_devices(const u8 *fsid,
        INIT_LIST_HEAD(&fs_devs->devices);
        INIT_LIST_HEAD(&fs_devs->alloc_list);
        INIT_LIST_HEAD(&fs_devs->fs_list);
        INIT_LIST_HEAD(&fs_devs->devices);
        INIT_LIST_HEAD(&fs_devs->alloc_list);
        INIT_LIST_HEAD(&fs_devs->fs_list);
+       INIT_LIST_HEAD(&fs_devs->seed_list);
        if (fsid)
                memcpy(fs_devs->fsid, fsid, BTRFS_FSID_SIZE);
 
        if (fsid)
                memcpy(fs_devs->fsid, fsid, BTRFS_FSID_SIZE);
 
@@ -405,7 +407,7 @@ void __exit btrfs_cleanup_fs_uuids(void)
  * Returned struct is not linked onto any lists and must be destroyed using
  * btrfs_free_device.
  */
  * Returned struct is not linked onto any lists and must be destroyed using
  * btrfs_free_device.
  */
-static struct btrfs_device *__alloc_device(void)
+static struct btrfs_device *__alloc_device(struct btrfs_fs_info *fs_info)
 {
        struct btrfs_device *dev;
 
 {
        struct btrfs_device *dev;
 
@@ -429,10 +431,11 @@ static struct btrfs_device *__alloc_device(void)
 
        atomic_set(&dev->reada_in_flight, 0);
        atomic_set(&dev->dev_stats_ccnt, 0);
 
        atomic_set(&dev->reada_in_flight, 0);
        atomic_set(&dev->dev_stats_ccnt, 0);
-       btrfs_device_data_ordered_init(dev);
+       btrfs_device_data_ordered_init(dev, fs_info);
        INIT_RADIX_TREE(&dev->reada_zones, GFP_NOFS & ~__GFP_DIRECT_RECLAIM);
        INIT_RADIX_TREE(&dev->reada_extents, GFP_NOFS & ~__GFP_DIRECT_RECLAIM);
        INIT_RADIX_TREE(&dev->reada_zones, GFP_NOFS & ~__GFP_DIRECT_RECLAIM);
        INIT_RADIX_TREE(&dev->reada_extents, GFP_NOFS & ~__GFP_DIRECT_RECLAIM);
-       extent_io_tree_init(NULL, &dev->alloc_state, 0, NULL);
+       extent_io_tree_init(fs_info, &dev->alloc_state,
+                           IO_TREE_DEVICE_ALLOC_STATE, NULL);
 
        return dev;
 }
 
        return dev;
 }
@@ -592,8 +595,6 @@ static int btrfs_free_stale_devices(const char *path,
                        btrfs_free_device(device);
 
                        ret = 0;
                        btrfs_free_device(device);
 
                        ret = 0;
-                       if (fs_devices->num_devices == 0)
-                               break;
                }
                mutex_unlock(&fs_devices->device_list_mutex);
 
                }
                mutex_unlock(&fs_devices->device_list_mutex);
 
@@ -928,28 +929,29 @@ static noinline struct btrfs_device *device_list_add(const char *path,
                 * make sure it's the same device if the device is mounted
                 */
                if (device->bdev) {
                 * make sure it's the same device if the device is mounted
                 */
                if (device->bdev) {
-                       struct block_device *path_bdev;
+                       int error;
+                       dev_t path_dev;
 
 
-                       path_bdev = lookup_bdev(path);
-                       if (IS_ERR(path_bdev)) {
+                       error = lookup_bdev(path, &path_dev);
+                       if (error) {
                                mutex_unlock(&fs_devices->device_list_mutex);
                                mutex_unlock(&fs_devices->device_list_mutex);
-                               return ERR_CAST(path_bdev);
+                               return ERR_PTR(error);
                        }
 
                        }
 
-                       if (device->bdev != path_bdev) {
-                               bdput(path_bdev);
+                       if (device->bdev->bd_dev != path_dev) {
                                mutex_unlock(&fs_devices->device_list_mutex);
                                btrfs_warn_in_rcu(device->fs_info,
                                mutex_unlock(&fs_devices->device_list_mutex);
                                btrfs_warn_in_rcu(device->fs_info,
-                       "duplicate device fsid:devid for %pU:%llu old:%s new:%s",
-                                       disk_super->fsid, devid,
-                                       rcu_str_deref(device->name), path);
+       "duplicate device %s devid %llu generation %llu scanned by %s (%d)",
+                                                 path, devid, found_transid,
+                                                 current->comm,
+                                                 task_pid_nr(current));
                                return ERR_PTR(-EEXIST);
                        }
                                return ERR_PTR(-EEXIST);
                        }
-                       bdput(path_bdev);
                        btrfs_info_in_rcu(device->fs_info,
                        btrfs_info_in_rcu(device->fs_info,
-                               "device fsid %pU devid %llu moved old:%s new:%s",
-                               disk_super->fsid, devid,
-                               rcu_str_deref(device->name), path);
+       "devid %llu device path %s changed to %s scanned by %s (%d)",
+                                         devid, rcu_str_deref(device->name),
+                                         path, current->comm,
+                                         task_pid_nr(current));
                }
 
                name = rcu_string_strdup(path, GFP_NOFS);
                }
 
                name = rcu_string_strdup(path, GFP_NOFS);
@@ -1034,48 +1036,32 @@ error:
        return ERR_PTR(ret);
 }
 
        return ERR_PTR(ret);
 }
 
-/*
- * After we have read the system tree and know devids belonging to
- * this filesystem, remove the device which does not belong there.
- */
-void btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices, int step)
+static void __btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices,
+                                     int step, struct btrfs_device **latest_dev)
 {
        struct btrfs_device *device, *next;
 {
        struct btrfs_device *device, *next;
-       struct btrfs_device *latest_dev = NULL;
 
 
-       mutex_lock(&uuid_mutex);
-again:
        /* This is the initialized path, it is safe to release the devices. */
        list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) {
        /* This is the initialized path, it is safe to release the devices. */
        list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) {
-               if (test_bit(BTRFS_DEV_STATE_IN_FS_METADATA,
-                                                       &device->dev_state)) {
+               if (test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state)) {
                        if (!test_bit(BTRFS_DEV_STATE_REPLACE_TGT,
                        if (!test_bit(BTRFS_DEV_STATE_REPLACE_TGT,
-                            &device->dev_state) &&
+                                     &device->dev_state) &&
                            !test_bit(BTRFS_DEV_STATE_MISSING,
                                      &device->dev_state) &&
                            !test_bit(BTRFS_DEV_STATE_MISSING,
                                      &device->dev_state) &&
-                            (!latest_dev ||
-                             device->generation > latest_dev->generation)) {
-                               latest_dev = device;
+                           (!*latest_dev ||
+                            device->generation > (*latest_dev)->generation)) {
+                               *latest_dev = device;
                        }
                        continue;
                }
 
                        }
                        continue;
                }
 
-               if (device->devid == BTRFS_DEV_REPLACE_DEVID) {
-                       /*
-                        * In the first step, keep the device which has
-                        * the correct fsid and the devid that is used
-                        * for the dev_replace procedure.
-                        * In the second step, the dev_replace state is
-                        * read from the device tree and it is known
-                        * whether the procedure is really active or
-                        * not, which means whether this device is
-                        * used or whether it should be removed.
-                        */
-                       if (step == 0 || test_bit(BTRFS_DEV_STATE_REPLACE_TGT,
-                                                 &device->dev_state)) {
-                               continue;
-                       }
-               }
+               /*
+                * We have already validated the presence of BTRFS_DEV_REPLACE_DEVID,
+                * in btrfs_init_dev_replace() so just continue.
+                */
+               if (device->devid == BTRFS_DEV_REPLACE_DEVID)
+                       continue;
+
                if (device->bdev) {
                        blkdev_put(device->bdev, device->mode);
                        device->bdev = NULL;
                if (device->bdev) {
                        blkdev_put(device->bdev, device->mode);
                        device->bdev = NULL;
@@ -1084,19 +1070,28 @@ again:
                if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) {
                        list_del_init(&device->dev_alloc_list);
                        clear_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state);
                if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) {
                        list_del_init(&device->dev_alloc_list);
                        clear_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state);
-                       if (!test_bit(BTRFS_DEV_STATE_REPLACE_TGT,
-                                     &device->dev_state))
-                               fs_devices->rw_devices--;
                }
                list_del_init(&device->dev_list);
                fs_devices->num_devices--;
                btrfs_free_device(device);
        }
 
                }
                list_del_init(&device->dev_list);
                fs_devices->num_devices--;
                btrfs_free_device(device);
        }
 
-       if (fs_devices->seed) {
-               fs_devices = fs_devices->seed;
-               goto again;
-       }
+}
+
+/*
+ * After we have read the system tree and know devids belonging to this
+ * filesystem, remove the device which does not belong there.
+ */
+void btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices, int step)
+{
+       struct btrfs_device *latest_dev = NULL;
+       struct btrfs_fs_devices *seed_dev;
+
+       mutex_lock(&uuid_mutex);
+       __btrfs_free_extra_devids(fs_devices, step, &latest_dev);
+
+       list_for_each_entry(seed_dev, &fs_devices->seed_list, seed_list)
+               __btrfs_free_extra_devids(seed_dev, step, &latest_dev);
 
        fs_devices->latest_bdev = latest_dev->bdev;
 
 
        fs_devices->latest_bdev = latest_dev->bdev;
 
@@ -1148,47 +1143,41 @@ static void btrfs_close_one_device(struct btrfs_device *device)
        ASSERT(atomic_read(&device->reada_in_flight) == 0);
 }
 
        ASSERT(atomic_read(&device->reada_in_flight) == 0);
 }
 
-static int close_fs_devices(struct btrfs_fs_devices *fs_devices)
+static void close_fs_devices(struct btrfs_fs_devices *fs_devices)
 {
        struct btrfs_device *device, *tmp;
 
 {
        struct btrfs_device *device, *tmp;
 
+       lockdep_assert_held(&uuid_mutex);
+
        if (--fs_devices->opened > 0)
        if (--fs_devices->opened > 0)
-               return 0;
+               return;
 
 
-       mutex_lock(&fs_devices->device_list_mutex);
-       list_for_each_entry_safe(device, tmp, &fs_devices->devices, dev_list) {
+       list_for_each_entry_safe(device, tmp, &fs_devices->devices, dev_list)
                btrfs_close_one_device(device);
                btrfs_close_one_device(device);
-       }
-       mutex_unlock(&fs_devices->device_list_mutex);
 
        WARN_ON(fs_devices->open_devices);
        WARN_ON(fs_devices->rw_devices);
        fs_devices->opened = 0;
        fs_devices->seeding = false;
 
        WARN_ON(fs_devices->open_devices);
        WARN_ON(fs_devices->rw_devices);
        fs_devices->opened = 0;
        fs_devices->seeding = false;
-
-       return 0;
+       fs_devices->fs_info = NULL;
 }
 
 }
 
-int btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
+void btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
 {
 {
-       struct btrfs_fs_devices *seed_devices = NULL;
-       int ret;
+       LIST_HEAD(list);
+       struct btrfs_fs_devices *tmp;
 
        mutex_lock(&uuid_mutex);
 
        mutex_lock(&uuid_mutex);
-       ret = close_fs_devices(fs_devices);
-       if (!fs_devices->opened) {
-               seed_devices = fs_devices->seed;
-               fs_devices->seed = NULL;
-       }
-       mutex_unlock(&uuid_mutex);
+       close_fs_devices(fs_devices);
+       if (!fs_devices->opened)
+               list_splice_init(&fs_devices->seed_list, &list);
 
 
-       while (seed_devices) {
-               fs_devices = seed_devices;
-               seed_devices = fs_devices->seed;
+       list_for_each_entry_safe(fs_devices, tmp, &list, seed_list) {
                close_fs_devices(fs_devices);
                close_fs_devices(fs_devices);
+               list_del(&fs_devices->seed_list);
                free_fs_devices(fs_devices);
        }
                free_fs_devices(fs_devices);
        }
-       return ret;
+       mutex_unlock(&uuid_mutex);
 }
 
 static int open_fs_devices(struct btrfs_fs_devices *fs_devices,
 }
 
 static int open_fs_devices(struct btrfs_fs_devices *fs_devices,
@@ -1196,17 +1185,23 @@ static int open_fs_devices(struct btrfs_fs_devices *fs_devices,
 {
        struct btrfs_device *device;
        struct btrfs_device *latest_dev = NULL;
 {
        struct btrfs_device *device;
        struct btrfs_device *latest_dev = NULL;
+       struct btrfs_device *tmp_device;
 
        flags |= FMODE_EXCL;
 
 
        flags |= FMODE_EXCL;
 
-       list_for_each_entry(device, &fs_devices->devices, dev_list) {
-               /* Just open everything we can; ignore failures here */
-               if (btrfs_open_one_device(fs_devices, device, flags, holder))
-                       continue;
+       list_for_each_entry_safe(device, tmp_device, &fs_devices->devices,
+                                dev_list) {
+               int ret;
 
 
-               if (!latest_dev ||
-                   device->generation > latest_dev->generation)
+               ret = btrfs_open_one_device(fs_devices, device, flags, holder);
+               if (ret == 0 &&
+                   (!latest_dev || device->generation > latest_dev->generation)) {
                        latest_dev = device;
                        latest_dev = device;
+               } else if (ret == -ENODATA) {
+                       fs_devices->num_devices--;
+                       list_del(&device->dev_list);
+                       btrfs_free_device(device);
+               }
        }
        if (fs_devices->open_devices == 0)
                return -EINVAL;
        }
        if (fs_devices->open_devices == 0)
                return -EINVAL;
@@ -1960,16 +1955,13 @@ static struct btrfs_device * btrfs_find_next_active_device(
  * this_dev) which is active.
  */
 void __cold btrfs_assign_next_active_device(struct btrfs_device *device,
  * this_dev) which is active.
  */
 void __cold btrfs_assign_next_active_device(struct btrfs_device *device,
-                                    struct btrfs_device *this_dev)
+                                           struct btrfs_device *next_device)
 {
        struct btrfs_fs_info *fs_info = device->fs_info;
 {
        struct btrfs_fs_info *fs_info = device->fs_info;
-       struct btrfs_device *next_device;
 
 
-       if (this_dev)
-               next_device = this_dev;
-       else
+       if (!next_device)
                next_device = btrfs_find_next_active_device(fs_info->fs_devices,
                next_device = btrfs_find_next_active_device(fs_info->fs_devices,
-                                                               device);
+                                                           device);
        ASSERT(next_device);
 
        if (fs_info->sb->s_bdev &&
        ASSERT(next_device);
 
        if (fs_info->sb->s_bdev &&
@@ -1998,9 +1990,9 @@ static u64 btrfs_num_devices(struct btrfs_fs_info *fs_info)
        return num_devices;
 }
 
        return num_devices;
 }
 
-static void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,
-                                     struct block_device *bdev,
-                                     const char *device_path)
+void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,
+                              struct block_device *bdev,
+                              const char *device_path)
 {
        struct btrfs_super_block *disk_super;
        int copy_num;
 {
        struct btrfs_super_block *disk_super;
        int copy_num;
@@ -2039,7 +2031,7 @@ static void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,
 }
 
 int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
 }
 
 int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
-               u64 devid)
+                   u64 devid)
 {
        struct btrfs_device *device;
        struct btrfs_fs_devices *cur_devices;
 {
        struct btrfs_device *device;
        struct btrfs_fs_devices *cur_devices;
@@ -2094,6 +2086,8 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
 
        mutex_unlock(&uuid_mutex);
        ret = btrfs_shrink_device(device, 0);
 
        mutex_unlock(&uuid_mutex);
        ret = btrfs_shrink_device(device, 0);
+       if (!ret)
+               btrfs_reada_remove_dev(device);
        mutex_lock(&uuid_mutex);
        if (ret)
                goto error_undo;
        mutex_lock(&uuid_mutex);
        if (ret)
                goto error_undo;
@@ -2143,7 +2137,7 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
        if (device->bdev) {
                cur_devices->open_devices--;
                /* remove sysfs entry */
        if (device->bdev) {
                cur_devices->open_devices--;
                /* remove sysfs entry */
-               btrfs_sysfs_remove_devices_dir(fs_devices, device);
+               btrfs_sysfs_remove_device(device);
        }
 
        num_devices = btrfs_super_num_devices(fs_info->super_copy) - 1;
        }
 
        num_devices = btrfs_super_num_devices(fs_info->super_copy) - 1;
@@ -2164,14 +2158,7 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
        btrfs_free_device(device);
 
        if (cur_devices->open_devices == 0) {
        btrfs_free_device(device);
 
        if (cur_devices->open_devices == 0) {
-               while (fs_devices) {
-                       if (fs_devices->seed == cur_devices) {
-                               fs_devices->seed = cur_devices->seed;
-                               break;
-                       }
-                       fs_devices = fs_devices->seed;
-               }
-               cur_devices->seed = NULL;
+               list_del_init(&cur_devices->seed_list);
                close_fs_devices(cur_devices);
                free_fs_devices(cur_devices);
        }
                close_fs_devices(cur_devices);
                free_fs_devices(cur_devices);
        }
@@ -2181,6 +2168,7 @@ out:
        return ret;
 
 error_undo:
        return ret;
 
 error_undo:
+       btrfs_reada_undo_remove_dev(device);
        if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) {
                mutex_lock(&fs_info->chunk_mutex);
                list_add(&device->dev_alloc_list,
        if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) {
                mutex_lock(&fs_info->chunk_mutex);
                list_add(&device->dev_alloc_list,
@@ -2220,14 +2208,9 @@ void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_device *srcdev)
 
 void btrfs_rm_dev_replace_free_srcdev(struct btrfs_device *srcdev)
 {
 
 void btrfs_rm_dev_replace_free_srcdev(struct btrfs_device *srcdev)
 {
-       struct btrfs_fs_info *fs_info = srcdev->fs_info;
        struct btrfs_fs_devices *fs_devices = srcdev->fs_devices;
 
        struct btrfs_fs_devices *fs_devices = srcdev->fs_devices;
 
-       if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &srcdev->dev_state)) {
-               /* zero out the old super if it is writable */
-               btrfs_scratch_superblocks(fs_info, srcdev->bdev,
-                                         srcdev->name->str);
-       }
+       mutex_lock(&uuid_mutex);
 
        btrfs_close_bdev(srcdev);
        synchronize_rcu();
 
        btrfs_close_bdev(srcdev);
        synchronize_rcu();
@@ -2235,8 +2218,6 @@ void btrfs_rm_dev_replace_free_srcdev(struct btrfs_device *srcdev)
 
        /* if this is no devs we rather delete the fs_devices */
        if (!fs_devices->num_devices) {
 
        /* if this is no devs we rather delete the fs_devices */
        if (!fs_devices->num_devices) {
-               struct btrfs_fs_devices *tmp_fs_devices;
-
                /*
                 * On a mounted FS, num_devices can't be zero unless it's a
                 * seed. In case of a seed device being replaced, the replace
                /*
                 * On a mounted FS, num_devices can't be zero unless it's a
                 * seed. In case of a seed device being replaced, the replace
@@ -2245,18 +2226,11 @@ void btrfs_rm_dev_replace_free_srcdev(struct btrfs_device *srcdev)
                 */
                ASSERT(fs_devices->seeding);
 
                 */
                ASSERT(fs_devices->seeding);
 
-               tmp_fs_devices = fs_info->fs_devices;
-               while (tmp_fs_devices) {
-                       if (tmp_fs_devices->seed == fs_devices) {
-                               tmp_fs_devices->seed = fs_devices->seed;
-                               break;
-                       }
-                       tmp_fs_devices = tmp_fs_devices->seed;
-               }
-               fs_devices->seed = NULL;
+               list_del_init(&fs_devices->seed_list);
                close_fs_devices(fs_devices);
                free_fs_devices(fs_devices);
        }
                close_fs_devices(fs_devices);
                free_fs_devices(fs_devices);
        }
+       mutex_unlock(&uuid_mutex);
 }
 
 void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev)
 }
 
 void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev)
@@ -2265,7 +2239,7 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev)
 
        mutex_lock(&fs_devices->device_list_mutex);
 
 
        mutex_lock(&fs_devices->device_list_mutex);
 
-       btrfs_sysfs_remove_devices_dir(fs_devices, tgtdev);
+       btrfs_sysfs_remove_device(tgtdev);
 
        if (tgtdev->bdev)
                fs_devices->open_devices--;
 
        if (tgtdev->bdev)
                fs_devices->open_devices--;
@@ -2374,10 +2348,20 @@ static int btrfs_prepare_sprout(struct btrfs_fs_info *fs_info)
        if (!fs_devices->seeding)
                return -EINVAL;
 
        if (!fs_devices->seeding)
                return -EINVAL;
 
+       /*
+        * Private copy of the seed devices, anchored at
+        * fs_info->fs_devices->seed_list
+        */
        seed_devices = alloc_fs_devices(NULL, NULL);
        if (IS_ERR(seed_devices))
                return PTR_ERR(seed_devices);
 
        seed_devices = alloc_fs_devices(NULL, NULL);
        if (IS_ERR(seed_devices))
                return PTR_ERR(seed_devices);
 
+       /*
+        * It's necessary to retain a copy of the original seed fs_devices in
+        * fs_uuids so that filesystems which have been seeded can successfully
+        * reference the seed device from open_seed_devices. This also supports
+        * multiple fs seed.
+        */
        old_devices = clone_fs_devices(fs_devices);
        if (IS_ERR(old_devices)) {
                kfree(seed_devices);
        old_devices = clone_fs_devices(fs_devices);
        if (IS_ERR(old_devices)) {
                kfree(seed_devices);
@@ -2398,16 +2382,12 @@ static int btrfs_prepare_sprout(struct btrfs_fs_info *fs_info)
        list_for_each_entry(device, &seed_devices->devices, dev_list)
                device->fs_devices = seed_devices;
 
        list_for_each_entry(device, &seed_devices->devices, dev_list)
                device->fs_devices = seed_devices;
 
-       mutex_lock(&fs_info->chunk_mutex);
-       list_splice_init(&fs_devices->alloc_list, &seed_devices->alloc_list);
-       mutex_unlock(&fs_info->chunk_mutex);
-
        fs_devices->seeding = false;
        fs_devices->num_devices = 0;
        fs_devices->open_devices = 0;
        fs_devices->missing_devices = 0;
        fs_devices->rotating = false;
        fs_devices->seeding = false;
        fs_devices->num_devices = 0;
        fs_devices->open_devices = 0;
        fs_devices->missing_devices = 0;
        fs_devices->rotating = false;
-       fs_devices->seed = seed_devices;
+       list_add(&seed_devices->seed_list, &fs_devices->seed_list);
 
        generate_random_uuid(fs_devices->fsid);
        memcpy(fs_devices->metadata_uuid, fs_devices->fsid, BTRFS_FSID_SIZE);
 
        generate_random_uuid(fs_devices->fsid);
        memcpy(fs_devices->metadata_uuid, fs_devices->fsid, BTRFS_FSID_SIZE);
@@ -2510,7 +2490,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
        u64 orig_super_num_devices;
        int seeding_dev = 0;
        int ret = 0;
        u64 orig_super_num_devices;
        int seeding_dev = 0;
        int ret = 0;
-       bool unlocked = false;
+       bool locked = false;
 
        if (sb_rdonly(sb) && !fs_devices->seeding)
                return -EROFS;
 
        if (sb_rdonly(sb) && !fs_devices->seeding)
                return -EROFS;
@@ -2524,20 +2504,20 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
                seeding_dev = 1;
                down_write(&sb->s_umount);
                mutex_lock(&uuid_mutex);
                seeding_dev = 1;
                down_write(&sb->s_umount);
                mutex_lock(&uuid_mutex);
+               locked = true;
        }
 
        }
 
-       filemap_write_and_wait(bdev->bd_inode->i_mapping);
+       sync_blockdev(bdev);
 
 
-       mutex_lock(&fs_devices->device_list_mutex);
-       list_for_each_entry(device, &fs_devices->devices, dev_list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(device, &fs_devices->devices, dev_list) {
                if (device->bdev == bdev) {
                        ret = -EEXIST;
                if (device->bdev == bdev) {
                        ret = -EEXIST;
-                       mutex_unlock(
-                               &fs_devices->device_list_mutex);
+                       rcu_read_unlock();
                        goto error;
                }
        }
                        goto error;
                }
        }
-       mutex_unlock(&fs_devices->device_list_mutex);
+       rcu_read_unlock();
 
        device = btrfs_alloc_device(fs_info, NULL, NULL);
        if (IS_ERR(device)) {
 
        device = btrfs_alloc_device(fs_info, NULL, NULL);
        if (IS_ERR(device)) {
@@ -2612,9 +2592,6 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
        btrfs_set_super_num_devices(fs_info->super_copy,
                                    orig_super_num_devices + 1);
 
        btrfs_set_super_num_devices(fs_info->super_copy,
                                    orig_super_num_devices + 1);
 
-       /* add sysfs device entry */
-       btrfs_sysfs_add_devices_dir(fs_devices, device);
-
        /*
         * we've got more storage, clear any full flags on the space
         * infos
        /*
         * we've got more storage, clear any full flags on the space
         * infos
@@ -2622,6 +2599,10 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
        btrfs_clear_space_info_full(fs_info);
 
        mutex_unlock(&fs_info->chunk_mutex);
        btrfs_clear_space_info_full(fs_info);
 
        mutex_unlock(&fs_info->chunk_mutex);
+
+       /* Add sysfs device entry */
+       btrfs_sysfs_add_device(device);
+
        mutex_unlock(&fs_devices->device_list_mutex);
 
        if (seeding_dev) {
        mutex_unlock(&fs_devices->device_list_mutex);
 
        if (seeding_dev) {
@@ -2647,8 +2628,11 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
                        goto error_sysfs;
                }
 
                        goto error_sysfs;
                }
 
-               btrfs_sysfs_update_sprout_fsid(fs_devices,
-                               fs_info->fs_devices->fsid);
+               /*
+                * fs_devices now represents the newly sprouted filesystem and
+                * its fsid has been changed by btrfs_prepare_sprout
+                */
+               btrfs_sysfs_update_sprout_fsid(fs_devices);
        }
 
        ret = btrfs_commit_transaction(trans);
        }
 
        ret = btrfs_commit_transaction(trans);
@@ -2656,7 +2640,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
        if (seeding_dev) {
                mutex_unlock(&uuid_mutex);
                up_write(&sb->s_umount);
        if (seeding_dev) {
                mutex_unlock(&uuid_mutex);
                up_write(&sb->s_umount);
-               unlocked = true;
+               locked = false;
 
                if (ret) /* transaction commit */
                        return ret;
 
                if (ret) /* transaction commit */
                        return ret;
@@ -2691,7 +2675,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
        return ret;
 
 error_sysfs:
        return ret;
 
 error_sysfs:
-       btrfs_sysfs_remove_devices_dir(fs_devices, device);
+       btrfs_sysfs_remove_device(device);
        mutex_lock(&fs_info->fs_devices->device_list_mutex);
        mutex_lock(&fs_info->chunk_mutex);
        list_del_rcu(&device->dev_list);
        mutex_lock(&fs_info->fs_devices->device_list_mutex);
        mutex_lock(&fs_info->chunk_mutex);
        list_del_rcu(&device->dev_list);
@@ -2717,7 +2701,7 @@ error_free_device:
        btrfs_free_device(device);
 error:
        blkdev_put(bdev, FMODE_EXCL);
        btrfs_free_device(device);
 error:
        blkdev_put(bdev, FMODE_EXCL);
-       if (seeding_dev && !unlocked) {
+       if (locked) {
                mutex_unlock(&uuid_mutex);
                up_write(&sb->s_umount);
        }
                mutex_unlock(&uuid_mutex);
                up_write(&sb->s_umount);
        }
@@ -4044,7 +4028,7 @@ int btrfs_balance(struct btrfs_fs_info *fs_info,
 
        /*
         * rw_devices will not change at the moment, device add/delete/replace
 
        /*
         * rw_devices will not change at the moment, device add/delete/replace
-        * are excluded by EXCL_OP
+        * are exclusive
         */
        num_devices = fs_info->fs_devices->rw_devices;
 
         */
        num_devices = fs_info->fs_devices->rw_devices;
 
@@ -4180,7 +4164,7 @@ int btrfs_balance(struct btrfs_fs_info *fs_info,
        if ((ret && ret != -ECANCELED && ret != -ENOSPC) ||
            balance_need_close(fs_info)) {
                reset_balance_state(fs_info);
        if ((ret && ret != -ECANCELED && ret != -ENOSPC) ||
            balance_need_close(fs_info)) {
                reset_balance_state(fs_info);
-               clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags);
+               btrfs_exclop_finish(fs_info);
        }
 
        wake_up(&fs_info->balance_wait_q);
        }
 
        wake_up(&fs_info->balance_wait_q);
@@ -4191,7 +4175,7 @@ out:
                reset_balance_state(fs_info);
        else
                kfree(bctl);
                reset_balance_state(fs_info);
        else
                kfree(bctl);
-       clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags);
+       btrfs_exclop_finish(fs_info);
 
        return ret;
 }
 
        return ret;
 }
@@ -4293,7 +4277,7 @@ int btrfs_recover_balance(struct btrfs_fs_info *fs_info)
         * is in a paused state and must have fs_info::balance_ctl properly
         * set up.
         */
         * is in a paused state and must have fs_info::balance_ctl properly
         * set up.
         */
-       if (test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags))
+       if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_BALANCE))
                btrfs_warn(fs_info,
        "balance: cannot set exclusive op status, resume manually");
 
                btrfs_warn(fs_info,
        "balance: cannot set exclusive op status, resume manually");
 
@@ -4375,7 +4359,7 @@ int btrfs_cancel_balance(struct btrfs_fs_info *fs_info)
 
                if (fs_info->balance_ctl) {
                        reset_balance_state(fs_info);
 
                if (fs_info->balance_ctl) {
                        reset_balance_state(fs_info);
-                       clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags);
+                       btrfs_exclop_finish(fs_info);
                        btrfs_info(fs_info, "balance: canceled");
                }
        }
                        btrfs_info(fs_info, "balance: canceled");
                }
        }
@@ -6460,11 +6444,21 @@ struct btrfs_device *btrfs_find_device(struct btrfs_fs_devices *fs_devices,
                                       bool seed)
 {
        struct btrfs_device *device;
                                       bool seed)
 {
        struct btrfs_device *device;
+       struct btrfs_fs_devices *seed_devs;
+
+       if (!fsid || !memcmp(fs_devices->metadata_uuid, fsid, BTRFS_FSID_SIZE)) {
+               list_for_each_entry(device, &fs_devices->devices, dev_list) {
+                       if (device->devid == devid &&
+                           (!uuid || memcmp(device->uuid, uuid,
+                                            BTRFS_UUID_SIZE) == 0))
+                               return device;
+               }
+       }
 
 
-       while (fs_devices) {
+       list_for_each_entry(seed_devs, &fs_devices->seed_list, seed_list) {
                if (!fsid ||
                if (!fsid ||
-                   !memcmp(fs_devices->metadata_uuid, fsid, BTRFS_FSID_SIZE)) {
-                       list_for_each_entry(device, &fs_devices->devices,
+                   !memcmp(seed_devs->metadata_uuid, fsid, BTRFS_FSID_SIZE)) {
+                       list_for_each_entry(device, &seed_devs->devices,
                                            dev_list) {
                                if (device->devid == devid &&
                                    (!uuid || memcmp(device->uuid, uuid,
                                            dev_list) {
                                if (device->devid == devid &&
                                    (!uuid || memcmp(device->uuid, uuid,
@@ -6472,11 +6466,8 @@ struct btrfs_device *btrfs_find_device(struct btrfs_fs_devices *fs_devices,
                                        return device;
                        }
                }
                                        return device;
                        }
                }
-               if (seed)
-                       fs_devices = fs_devices->seed;
-               else
-                       return NULL;
        }
        }
+
        return NULL;
 }
 
        return NULL;
 }
 
@@ -6484,8 +6475,17 @@ static struct btrfs_device *add_missing_dev(struct btrfs_fs_devices *fs_devices,
                                            u64 devid, u8 *dev_uuid)
 {
        struct btrfs_device *device;
                                            u64 devid, u8 *dev_uuid)
 {
        struct btrfs_device *device;
+       unsigned int nofs_flag;
 
 
+       /*
+        * We call this under the chunk_mutex, so we want to use NOFS for this
+        * allocation, however we don't want to change btrfs_alloc_device() to
+        * always do NOFS because we use it in a lot of other GFP_KERNEL safe
+        * places.
+        */
+       nofs_flag = memalloc_nofs_save();
        device = btrfs_alloc_device(NULL, &devid, dev_uuid);
        device = btrfs_alloc_device(NULL, &devid, dev_uuid);
+       memalloc_nofs_restore(nofs_flag);
        if (IS_ERR(device))
                return device;
 
        if (IS_ERR(device))
                return device;
 
@@ -6522,7 +6522,7 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
        if (WARN_ON(!devid && !fs_info))
                return ERR_PTR(-EINVAL);
 
        if (WARN_ON(!devid && !fs_info))
                return ERR_PTR(-EINVAL);
 
-       dev = __alloc_device();
+       dev = __alloc_device(fs_info);
        if (IS_ERR(dev))
                return dev;
 
        if (IS_ERR(dev))
                return dev;
 
@@ -6718,13 +6718,11 @@ static struct btrfs_fs_devices *open_seed_devices(struct btrfs_fs_info *fs_info,
        lockdep_assert_held(&uuid_mutex);
        ASSERT(fsid);
 
        lockdep_assert_held(&uuid_mutex);
        ASSERT(fsid);
 
-       fs_devices = fs_info->fs_devices->seed;
-       while (fs_devices) {
+       /* This will match only for multi-device seed fs */
+       list_for_each_entry(fs_devices, &fs_info->fs_devices->seed_list, seed_list)
                if (!memcmp(fs_devices->fsid, fsid, BTRFS_FSID_SIZE))
                        return fs_devices;
 
                if (!memcmp(fs_devices->fsid, fsid, BTRFS_FSID_SIZE))
                        return fs_devices;
 
-               fs_devices = fs_devices->seed;
-       }
 
        fs_devices = find_fsid(fsid, NULL);
        if (!fs_devices) {
 
        fs_devices = find_fsid(fsid, NULL);
        if (!fs_devices) {
@@ -6740,6 +6738,10 @@ static struct btrfs_fs_devices *open_seed_devices(struct btrfs_fs_info *fs_info,
                return fs_devices;
        }
 
                return fs_devices;
        }
 
+       /*
+        * Upon first call for a seed fs fsid, just create a private copy of the
+        * respective fs_devices and anchor it at fs_info->fs_devices->seed_list
+        */
        fs_devices = clone_fs_devices(fs_devices);
        if (IS_ERR(fs_devices))
                return fs_devices;
        fs_devices = clone_fs_devices(fs_devices);
        if (IS_ERR(fs_devices))
                return fs_devices;
@@ -6747,20 +6749,17 @@ static struct btrfs_fs_devices *open_seed_devices(struct btrfs_fs_info *fs_info,
        ret = open_fs_devices(fs_devices, FMODE_READ, fs_info->bdev_holder);
        if (ret) {
                free_fs_devices(fs_devices);
        ret = open_fs_devices(fs_devices, FMODE_READ, fs_info->bdev_holder);
        if (ret) {
                free_fs_devices(fs_devices);
-               fs_devices = ERR_PTR(ret);
-               goto out;
+               return ERR_PTR(ret);
        }
 
        if (!fs_devices->seeding) {
                close_fs_devices(fs_devices);
                free_fs_devices(fs_devices);
        }
 
        if (!fs_devices->seeding) {
                close_fs_devices(fs_devices);
                free_fs_devices(fs_devices);
-               fs_devices = ERR_PTR(-EINVAL);
-               goto out;
+               return ERR_PTR(-EINVAL);
        }
 
        }
 
-       fs_devices->seed = fs_info->fs_devices->seed;
-       fs_info->fs_devices->seed = fs_devices;
-out:
+       list_add(&fs_devices->seed_list, &fs_info->fs_devices->seed_list);
+
        return fs_devices;
 }
 
        return fs_devices;
 }
 
@@ -7179,17 +7178,22 @@ error:
 
 void btrfs_init_devices_late(struct btrfs_fs_info *fs_info)
 {
 
 void btrfs_init_devices_late(struct btrfs_fs_info *fs_info)
 {
-       struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
+       struct btrfs_fs_devices *fs_devices = fs_info->fs_devices, *seed_devs;
        struct btrfs_device *device;
 
        struct btrfs_device *device;
 
-       while (fs_devices) {
-               mutex_lock(&fs_devices->device_list_mutex);
-               list_for_each_entry(device, &fs_devices->devices, dev_list)
+       fs_devices->fs_info = fs_info;
+
+       mutex_lock(&fs_devices->device_list_mutex);
+       list_for_each_entry(device, &fs_devices->devices, dev_list)
+               device->fs_info = fs_info;
+
+       list_for_each_entry(seed_devs, &fs_devices->seed_list, seed_list) {
+               list_for_each_entry(device, &seed_devs->devices, dev_list)
                        device->fs_info = fs_info;
                        device->fs_info = fs_info;
-               mutex_unlock(&fs_devices->device_list_mutex);
 
 
-               fs_devices = fs_devices->seed;
+               seed_devs->fs_info = fs_info;
        }
        }
+       mutex_unlock(&fs_devices->device_list_mutex);
 }
 
 static u64 btrfs_dev_stats_value(const struct extent_buffer *eb,
 }
 
 static u64 btrfs_dev_stats_value(const struct extent_buffer *eb,
@@ -7215,17 +7219,53 @@ static void btrfs_set_dev_stats_value(struct extent_buffer *eb,
                            sizeof(val));
 }
 
                            sizeof(val));
 }
 
-int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info)
+static int btrfs_device_init_dev_stats(struct btrfs_device *device,
+                                      struct btrfs_path *path)
 {
 {
-       struct btrfs_key key;
-       struct btrfs_root *dev_root = fs_info->dev_root;
-       struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
+       struct btrfs_dev_stats_item *ptr;
        struct extent_buffer *eb;
        struct extent_buffer *eb;
-       int slot;
-       int ret = 0;
+       struct btrfs_key key;
+       int item_size;
+       int i, ret, slot;
+
+       key.objectid = BTRFS_DEV_STATS_OBJECTID;
+       key.type = BTRFS_PERSISTENT_ITEM_KEY;
+       key.offset = device->devid;
+       ret = btrfs_search_slot(NULL, device->fs_info->dev_root, &key, path, 0, 0);
+       if (ret) {
+               for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++)
+                       btrfs_dev_stat_set(device, i, 0);
+               device->dev_stats_valid = 1;
+               btrfs_release_path(path);
+               return ret < 0 ? ret : 0;
+       }
+       slot = path->slots[0];
+       eb = path->nodes[0];
+       item_size = btrfs_item_size_nr(eb, slot);
+
+       ptr = btrfs_item_ptr(eb, slot, struct btrfs_dev_stats_item);
+
+       for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++) {
+               if (item_size >= (1 + i) * sizeof(__le64))
+                       btrfs_dev_stat_set(device, i,
+                                          btrfs_dev_stats_value(eb, ptr, i));
+               else
+                       btrfs_dev_stat_set(device, i, 0);
+       }
+
+       device->dev_stats_valid = 1;
+       btrfs_dev_stat_print_on_load(device);
+       btrfs_release_path(path);
+
+       return 0;
+}
+
+int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_fs_devices *fs_devices = fs_info->fs_devices, *seed_devs;
        struct btrfs_device *device;
        struct btrfs_path *path = NULL;
        struct btrfs_device *device;
        struct btrfs_path *path = NULL;
-       int i;
+       int ret = 0;
 
        path = btrfs_alloc_path();
        if (!path)
 
        path = btrfs_alloc_path();
        if (!path)
@@ -7233,43 +7273,22 @@ int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info)
 
        mutex_lock(&fs_devices->device_list_mutex);
        list_for_each_entry(device, &fs_devices->devices, dev_list) {
 
        mutex_lock(&fs_devices->device_list_mutex);
        list_for_each_entry(device, &fs_devices->devices, dev_list) {
-               int item_size;
-               struct btrfs_dev_stats_item *ptr;
-
-               key.objectid = BTRFS_DEV_STATS_OBJECTID;
-               key.type = BTRFS_PERSISTENT_ITEM_KEY;
-               key.offset = device->devid;
-               ret = btrfs_search_slot(NULL, dev_root, &key, path, 0, 0);
-               if (ret) {
-                       for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++)
-                               btrfs_dev_stat_set(device, i, 0);
-                       device->dev_stats_valid = 1;
-                       btrfs_release_path(path);
-                       continue;
-               }
-               slot = path->slots[0];
-               eb = path->nodes[0];
-               item_size = btrfs_item_size_nr(eb, slot);
-
-               ptr = btrfs_item_ptr(eb, slot,
-                                    struct btrfs_dev_stats_item);
-
-               for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++) {
-                       if (item_size >= (1 + i) * sizeof(__le64))
-                               btrfs_dev_stat_set(device, i,
-                                       btrfs_dev_stats_value(eb, ptr, i));
-                       else
-                               btrfs_dev_stat_set(device, i, 0);
+               ret = btrfs_device_init_dev_stats(device, path);
+               if (ret)
+                       goto out;
+       }
+       list_for_each_entry(seed_devs, &fs_devices->seed_list, seed_list) {
+               list_for_each_entry(device, &seed_devs->devices, dev_list) {
+                       ret = btrfs_device_init_dev_stats(device, path);
+                       if (ret)
+                               goto out;
                }
                }
-
-               device->dev_stats_valid = 1;
-               btrfs_dev_stat_print_on_load(device);
-               btrfs_release_path(path);
        }
        }
+out:
        mutex_unlock(&fs_devices->device_list_mutex);
 
        btrfs_free_path(path);
        mutex_unlock(&fs_devices->device_list_mutex);
 
        btrfs_free_path(path);
-       return ret < 0 ? ret : 0;
+       return ret;
 }
 
 static int update_dev_stat_item(struct btrfs_trans_handle *trans,
 }
 
 static int update_dev_stat_item(struct btrfs_trans_handle *trans,
@@ -7486,24 +7505,6 @@ void btrfs_commit_device_sizes(struct btrfs_transaction *trans)
        mutex_unlock(&trans->fs_info->chunk_mutex);
 }
 
        mutex_unlock(&trans->fs_info->chunk_mutex);
 }
 
-void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info)
-{
-       struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
-       while (fs_devices) {
-               fs_devices->fs_info = fs_info;
-               fs_devices = fs_devices->seed;
-       }
-}
-
-void btrfs_reset_fs_info_ptr(struct btrfs_fs_info *fs_info)
-{
-       struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
-       while (fs_devices) {
-               fs_devices->fs_info = NULL;
-               fs_devices = fs_devices->seed;
-       }
-}
-
 /*
  * Multiplicity factor for simple profiles: DUP, RAID1-like and RAID10.
  */
 /*
  * Multiplicity factor for simple profiles: DUP, RAID1-like and RAID10.
  */
@@ -7584,8 +7585,11 @@ static int verify_one_dev_extent(struct btrfs_fs_info *fs_info,
 
        /* It's possible this device is a dummy for seed device */
        if (dev->disk_total_bytes == 0) {
 
        /* It's possible this device is a dummy for seed device */
        if (dev->disk_total_bytes == 0) {
-               dev = btrfs_find_device(fs_info->fs_devices->seed, devid, NULL,
-                                       NULL, false);
+               struct btrfs_fs_devices *devs;
+
+               devs = list_first_entry(&fs_info->fs_devices->seed_list,
+                                       struct btrfs_fs_devices, seed_list);
+               dev = btrfs_find_device(devs, devid, NULL, NULL, false);
                if (!dev) {
                        btrfs_err(fs_info, "failed to find seed devid %llu",
                                  devid);
                if (!dev) {
                        btrfs_err(fs_info, "failed to find seed devid %llu",
                                  devid);