aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/extent-tree.c17
-rw-r--r--fs/btrfs/volumes.c20
-rw-r--r--fs/btrfs/volumes.h2
3 files changed, 36 insertions, 3 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 41133b064d72..4be231e0d2bd 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -3044,7 +3044,13 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
3044 3044
3045u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags) 3045u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
3046{ 3046{
3047 u64 num_devices = root->fs_info->fs_devices->rw_devices; 3047 /*
3048 * we add in the count of missing devices because we want
3049 * to make sure that any RAID levels on a degraded FS
3050 * continue to be honored.
3051 */
3052 u64 num_devices = root->fs_info->fs_devices->rw_devices +
3053 root->fs_info->fs_devices->missing_devices;
3048 3054
3049 if (num_devices == 1) 3055 if (num_devices == 1)
3050 flags &= ~(BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID0); 3056 flags &= ~(BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID0);
@@ -7891,7 +7897,14 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags)
7891 u64 stripped = BTRFS_BLOCK_GROUP_RAID0 | 7897 u64 stripped = BTRFS_BLOCK_GROUP_RAID0 |
7892 BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10; 7898 BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10;
7893 7899
7894 num_devices = root->fs_info->fs_devices->rw_devices; 7900 /*
7901 * we add in the count of missing devices because we want
7902 * to make sure that any RAID levels on a degraded FS
7903 * continue to be honored.
7904 */
7905 num_devices = root->fs_info->fs_devices->rw_devices +
7906 root->fs_info->fs_devices->missing_devices;
7907
7895 if (num_devices == 1) { 7908 if (num_devices == 1) {
7896 stripped |= BTRFS_BLOCK_GROUP_DUP; 7909 stripped |= BTRFS_BLOCK_GROUP_DUP;
7897 stripped = flags & ~stripped; 7910 stripped = flags & ~stripped;
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 91851b555e2e..177b73179590 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -413,12 +413,16 @@ static noinline int device_list_add(const char *path,
413 413
414 device->fs_devices = fs_devices; 414 device->fs_devices = fs_devices;
415 fs_devices->num_devices++; 415 fs_devices->num_devices++;
416 } else if (strcmp(device->name, path)) { 416 } else if (!device->name || strcmp(device->name, path)) {
417 name = kstrdup(path, GFP_NOFS); 417 name = kstrdup(path, GFP_NOFS);
418 if (!name) 418 if (!name)
419 return -ENOMEM; 419 return -ENOMEM;
420 kfree(device->name); 420 kfree(device->name);
421 device->name = name; 421 device->name = name;
422 if (device->missing) {
423 fs_devices->missing_devices--;
424 device->missing = 0;
425 }
422 } 426 }
423 427
424 if (found_transid > fs_devices->latest_trans) { 428 if (found_transid > fs_devices->latest_trans) {
@@ -1238,6 +1242,9 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
1238 1242
1239 device->fs_devices->num_devices--; 1243 device->fs_devices->num_devices--;
1240 1244
1245 if (device->missing)
1246 root->fs_info->fs_devices->missing_devices--;
1247
1241 next_device = list_entry(root->fs_info->fs_devices->devices.next, 1248 next_device = list_entry(root->fs_info->fs_devices->devices.next,
1242 struct btrfs_device, dev_list); 1249 struct btrfs_device, dev_list);
1243 if (device->bdev == root->fs_info->sb->s_bdev) 1250 if (device->bdev == root->fs_info->sb->s_bdev)
@@ -3084,7 +3091,9 @@ static struct btrfs_device *add_missing_dev(struct btrfs_root *root,
3084 device->devid = devid; 3091 device->devid = devid;
3085 device->work.func = pending_bios_fn; 3092 device->work.func = pending_bios_fn;
3086 device->fs_devices = fs_devices; 3093 device->fs_devices = fs_devices;
3094 device->missing = 1;
3087 fs_devices->num_devices++; 3095 fs_devices->num_devices++;
3096 fs_devices->missing_devices++;
3088 spin_lock_init(&device->io_lock); 3097 spin_lock_init(&device->io_lock);
3089 INIT_LIST_HEAD(&device->dev_alloc_list); 3098 INIT_LIST_HEAD(&device->dev_alloc_list);
3090 memcpy(device->uuid, dev_uuid, BTRFS_UUID_SIZE); 3099 memcpy(device->uuid, dev_uuid, BTRFS_UUID_SIZE);
@@ -3282,6 +3291,15 @@ static int read_one_dev(struct btrfs_root *root,
3282 device = add_missing_dev(root, devid, dev_uuid); 3291 device = add_missing_dev(root, devid, dev_uuid);
3283 if (!device) 3292 if (!device)
3284 return -ENOMEM; 3293 return -ENOMEM;
3294 } else if (!device->missing) {
3295 /*
3296 * this happens when a device that was properly setup
3297 * in the device info lists suddenly goes bad.
3298 * device->bdev is NULL, and so we have to set
3299 * device->missing to one here
3300 */
3301 root->fs_info->fs_devices->missing_devices++;
3302 device->missing = 1;
3285 } 3303 }
3286 } 3304 }
3287 3305
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 31b0fabdd2ea..a668c0116982 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -45,6 +45,7 @@ struct btrfs_device {
45 int barriers; 45 int barriers;
46 int writeable; 46 int writeable;
47 int in_fs_metadata; 47 int in_fs_metadata;
48 int missing;
48 49
49 spinlock_t io_lock; 50 spinlock_t io_lock;
50 51
@@ -94,6 +95,7 @@ struct btrfs_fs_devices {
94 u64 num_devices; 95 u64 num_devices;
95 u64 open_devices; 96 u64 open_devices;
96 u64 rw_devices; 97 u64 rw_devices;
98 u64 missing_devices;
97 u64 total_rw_bytes; 99 u64 total_rw_bytes;
98 struct block_device *latest_bdev; 100 struct block_device *latest_bdev;
99 101