aboutsummaryrefslogtreecommitdiff
path: root/fs/btrfs/volumes.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r--fs/btrfs/volumes.c296
1 files changed, 149 insertions, 147 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 002aa318da67..c188256a367c 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -152,7 +152,15 @@ struct list_head *btrfs_get_fs_uuids(void)
return &fs_uuids;
}
-static struct btrfs_fs_devices *__alloc_fs_devices(void)
+/*
+ * alloc_fs_devices - allocate struct btrfs_fs_devices
+ * @fsid: if not NULL, copy the uuid to fs_devices::fsid
+ *
+ * Return a pointer to a new struct btrfs_fs_devices on success, or ERR_PTR().
+ * The returned struct is not linked onto any lists and can be destroyed with
+ * kfree() right away.
+ */
+static struct btrfs_fs_devices *alloc_fs_devices(const u8 *fsid)
{
struct btrfs_fs_devices *fs_devs;
@@ -166,31 +174,8 @@ static struct btrfs_fs_devices *__alloc_fs_devices(void)
INIT_LIST_HEAD(&fs_devs->resized_devices);
INIT_LIST_HEAD(&fs_devs->alloc_list);
INIT_LIST_HEAD(&fs_devs->list);
-
- return fs_devs;
-}
-
-/**
- * alloc_fs_devices - allocate struct btrfs_fs_devices
- * @fsid: a pointer to UUID for this FS. If NULL a new UUID is
- * generated.
- *
- * Return: a pointer to a new &struct btrfs_fs_devices on success;
- * ERR_PTR() on error. Returned struct is not linked onto any lists and
- * can be destroyed with kfree() right away.
- */
-static struct btrfs_fs_devices *alloc_fs_devices(const u8 *fsid)
-{
- struct btrfs_fs_devices *fs_devs;
-
- fs_devs = __alloc_fs_devices();
- if (IS_ERR(fs_devs))
- return fs_devs;
-
if (fsid)
memcpy(fs_devs->fsid, fsid, BTRFS_FSID_SIZE);
- else
- generate_random_uuid(fs_devs->fsid);
return fs_devs;
}
@@ -269,9 +254,17 @@ static struct btrfs_device *__alloc_device(void)
return dev;
}
-static noinline struct btrfs_device *__find_device(struct list_head *head,
- u64 devid, u8 *uuid)
+/*
+ * Find a device specified by @devid or @uuid in the list of @fs_devices, or
+ * return NULL.
+ *
+ * If devid and uuid are both specified, the match must be exact, otherwise
+ * only devid is used.
+ */
+static struct btrfs_device *find_device(struct btrfs_fs_devices *fs_devices,
+ u64 devid, const u8 *uuid)
{
+ struct list_head *head = &fs_devices->devices;
struct btrfs_device *dev;
list_for_each_entry(dev, head, dev_list) {
@@ -310,7 +303,7 @@ btrfs_get_bdev_and_sb(const char *device_path, fmode_t flags, void *holder,
if (flush)
filemap_write_and_wait((*bdev)->bd_inode->i_mapping);
- ret = set_blocksize(*bdev, 4096);
+ ret = set_blocksize(*bdev, BTRFS_BDEV_BLOCKSIZE);
if (ret) {
blkdev_put(*bdev, flags);
goto error;
@@ -636,8 +629,8 @@ static noinline int device_list_add(const char *path,
device = NULL;
} else {
- device = __find_device(&fs_devices->devices, devid,
- disk_super->dev_item.uuid);
+ device = find_device(fs_devices, devid,
+ disk_super->dev_item.uuid);
}
if (!device) {
@@ -1578,7 +1571,6 @@ out:
static int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
struct btrfs_device *device,
- u64 chunk_tree, u64 chunk_objectid,
u64 chunk_offset, u64 start, u64 num_bytes)
{
int ret;
@@ -1606,12 +1598,12 @@ static int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
leaf = path->nodes[0];
extent = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_dev_extent);
- btrfs_set_dev_extent_chunk_tree(leaf, extent, chunk_tree);
- btrfs_set_dev_extent_chunk_objectid(leaf, extent, chunk_objectid);
+ btrfs_set_dev_extent_chunk_tree(leaf, extent,
+ BTRFS_CHUNK_TREE_OBJECTID);
+ btrfs_set_dev_extent_chunk_objectid(leaf, extent,
+ BTRFS_FIRST_CHUNK_TREE_OBJECTID);
btrfs_set_dev_extent_chunk_offset(leaf, extent, chunk_offset);
- write_extent_buffer_chunk_tree_uuid(leaf, fs_info->chunk_tree_uuid);
-
btrfs_set_dev_extent_length(leaf, extent, num_bytes);
btrfs_mark_buffer_dirty(leaf);
out:
@@ -1726,7 +1718,7 @@ static int btrfs_add_device(struct btrfs_trans_handle *trans,
ptr = btrfs_device_uuid(dev_item);
write_extent_buffer(leaf, device->uuid, ptr, BTRFS_UUID_SIZE);
ptr = btrfs_device_fsid(dev_item);
- write_extent_buffer(leaf, fs_info->fsid, ptr, BTRFS_UUID_SIZE);
+ write_extent_buffer(leaf, fs_info->fsid, ptr, BTRFS_FSID_SIZE);
btrfs_mark_buffer_dirty(leaf);
ret = 0;
@@ -1872,7 +1864,6 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
struct btrfs_fs_devices *cur_devices;
u64 num_devices;
int ret = 0;
- bool clear_super = false;
mutex_lock(&uuid_mutex);
@@ -1908,7 +1899,6 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
list_del_init(&device->dev_alloc_list);
device->fs_devices->rw_devices--;
mutex_unlock(&fs_info->chunk_mutex);
- clear_super = true;
}
mutex_unlock(&uuid_mutex);
@@ -1987,9 +1977,6 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
free_fs_devices(cur_devices);
}
- fs_info->num_tolerated_disk_barrier_failures =
- btrfs_calc_num_tolerated_disk_barrier_failures(fs_info);
-
out:
mutex_unlock(&uuid_mutex);
return ret;
@@ -2202,7 +2189,7 @@ static int btrfs_prepare_sprout(struct btrfs_fs_info *fs_info)
if (!fs_devices->seeding)
return -EINVAL;
- seed_devices = __alloc_fs_devices();
+ seed_devices = alloc_fs_devices(NULL);
if (IS_ERR(seed_devices))
return PTR_ERR(seed_devices);
@@ -2261,7 +2248,7 @@ static int btrfs_finish_sprout(struct btrfs_trans_handle *trans,
struct btrfs_dev_item *dev_item;
struct btrfs_device *device;
struct btrfs_key key;
- u8 fs_uuid[BTRFS_UUID_SIZE];
+ u8 fs_uuid[BTRFS_FSID_SIZE];
u8 dev_uuid[BTRFS_UUID_SIZE];
u64 devid;
int ret;
@@ -2304,7 +2291,7 @@ next_slot:
read_extent_buffer(leaf, dev_uuid, btrfs_device_uuid(dev_item),
BTRFS_UUID_SIZE);
read_extent_buffer(leaf, fs_uuid, btrfs_device_fsid(dev_item),
- BTRFS_UUID_SIZE);
+ BTRFS_FSID_SIZE);
device = btrfs_find_device(fs_info, devid, dev_uuid, fs_uuid);
BUG_ON(!device); /* Logic error */
@@ -2407,7 +2394,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
device->is_tgtdev_for_dev_replace = 0;
device->mode = FMODE_EXCL;
device->dev_stats_valid = 1;
- set_blocksize(device->bdev, 4096);
+ set_blocksize(device->bdev, BTRFS_BDEV_BLOCKSIZE);
if (seeding_dev) {
sb->s_flags &= ~MS_RDONLY;
@@ -2487,8 +2474,6 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
"sysfs: failed to create fsid for sprout");
}
- fs_info->num_tolerated_disk_barrier_failures =
- btrfs_calc_num_tolerated_disk_barrier_failures(fs_info);
ret = btrfs_commit_transaction(trans);
if (seeding_dev) {
@@ -2612,7 +2597,7 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
device->is_tgtdev_for_dev_replace = 1;
device->mode = FMODE_EXCL;
device->dev_stats_valid = 1;
- set_blocksize(device->bdev, 4096);
+ set_blocksize(device->bdev, BTRFS_BDEV_BLOCKSIZE);
device->fs_devices = fs_info->fs_devices;
list_add(&device->dev_list, &fs_info->fs_devices->devices);
fs_info->fs_devices->num_devices++;
@@ -2728,8 +2713,7 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans,
}
static int btrfs_free_chunk(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info, u64 chunk_objectid,
- u64 chunk_offset)
+ struct btrfs_fs_info *fs_info, u64 chunk_offset)
{
struct btrfs_root *root = fs_info->chunk_root;
int ret;
@@ -2740,7 +2724,7 @@ static int btrfs_free_chunk(struct btrfs_trans_handle *trans,
if (!path)
return -ENOMEM;
- key.objectid = chunk_objectid;
+ key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
key.offset = chunk_offset;
key.type = BTRFS_CHUNK_ITEM_KEY;
@@ -2763,8 +2747,7 @@ out:
return ret;
}
-static int btrfs_del_sys_chunk(struct btrfs_fs_info *fs_info,
- u64 chunk_objectid, u64 chunk_offset)
+static int btrfs_del_sys_chunk(struct btrfs_fs_info *fs_info, u64 chunk_offset)
{
struct btrfs_super_block *super_copy = fs_info->super_copy;
struct btrfs_disk_key *disk_key;
@@ -2797,7 +2780,7 @@ static int btrfs_del_sys_chunk(struct btrfs_fs_info *fs_info,
ret = -EIO;
break;
}
- if (key.objectid == chunk_objectid &&
+ if (key.objectid == BTRFS_FIRST_CHUNK_TREE_OBJECTID &&
key.offset == chunk_offset) {
memmove(ptr, ptr + len, array_size - (cur + len));
array_size -= len;
@@ -2846,7 +2829,6 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans,
struct extent_map *em;
struct map_lookup *map;
u64 dev_extent_len = 0;
- u64 chunk_objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
int i, ret = 0;
struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
@@ -2902,7 +2884,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans,
}
mutex_unlock(&fs_devices->device_list_mutex);
- ret = btrfs_free_chunk(trans, fs_info, chunk_objectid, chunk_offset);
+ ret = btrfs_free_chunk(trans, fs_info, chunk_offset);
if (ret) {
btrfs_abort_transaction(trans, ret);
goto out;
@@ -2911,8 +2893,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans,
trace_btrfs_chunk_free(fs_info, map, chunk_offset, em->len);
if (map->type & BTRFS_BLOCK_GROUP_SYSTEM) {
- ret = btrfs_del_sys_chunk(fs_info, chunk_objectid,
- chunk_offset);
+ ret = btrfs_del_sys_chunk(fs_info, chunk_offset);
if (ret) {
btrfs_abort_transaction(trans, ret);
goto out;
@@ -3312,7 +3293,6 @@ static int chunk_devid_filter(struct extent_buffer *leaf,
/* [pstart, pend) */
static int chunk_drange_filter(struct extent_buffer *leaf,
struct btrfs_chunk *chunk,
- u64 chunk_offset,
struct btrfs_balance_args *bargs)
{
struct btrfs_stripe *stripe;
@@ -3439,7 +3419,7 @@ static int should_balance_chunk(struct btrfs_fs_info *fs_info,
/* drange filter, makes sense only with devid filter */
if ((bargs->flags & BTRFS_BALANCE_ARGS_DRANGE) &&
- chunk_drange_filter(leaf, chunk, chunk_offset, bargs)) {
+ chunk_drange_filter(leaf, chunk, bargs)) {
return 0;
}
@@ -3898,13 +3878,6 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
meta_target, data_target);
}
- if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) {
- fs_info->num_tolerated_disk_barrier_failures = min(
- btrfs_calc_num_tolerated_disk_barrier_failures(fs_info),
- btrfs_get_num_tolerated_disk_barrier_failures(
- bctl->sys.target));
- }
-
ret = insert_balance_item(fs_info, bctl);
if (ret && ret != -EEXIST)
goto out;
@@ -3927,11 +3900,6 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
mutex_lock(&fs_info->balance_mutex);
atomic_dec(&fs_info->balance_running);
- if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) {
- fs_info->num_tolerated_disk_barrier_failures =
- btrfs_calc_num_tolerated_disk_barrier_failures(fs_info);
- }
-
if (bargs) {
memset(bargs, 0, sizeof(*bargs));
update_ioctl_balance_args(fs_info, 0, bargs);
@@ -4127,7 +4095,6 @@ static int btrfs_uuid_scan_kthread(void *data)
struct btrfs_fs_info *fs_info = data;
struct btrfs_root *root = fs_info->tree_root;
struct btrfs_key key;
- struct btrfs_key max_key;
struct btrfs_path *path = NULL;
int ret = 0;
struct extent_buffer *eb;
@@ -4146,10 +4113,6 @@ static int btrfs_uuid_scan_kthread(void *data)
key.type = BTRFS_ROOT_ITEM_KEY;
key.offset = 0;
- max_key.objectid = (u64)-1;
- max_key.type = BTRFS_ROOT_ITEM_KEY;
- max_key.offset = (u64)-1;
-
while (1) {
ret = btrfs_search_forward(root, &key, path, 0);
if (ret) {
@@ -4601,12 +4564,6 @@ static int btrfs_cmp_device_info(const void *a, const void *b)
return 0;
}
-static u32 find_raid56_stripe_len(u32 data_devices, u32 dev_stripe_target)
-{
- /* TODO allow them to set a preferred stripe size */
- return SZ_64K;
-}
-
static void check_raid56_incompat_flag(struct btrfs_fs_info *info, u64 type)
{
if (!(type & BTRFS_BLOCK_GROUP_RAID56_MASK))
@@ -4629,7 +4586,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
{
struct btrfs_fs_info *info = trans->fs_info;
struct btrfs_fs_devices *fs_devices = info->fs_devices;
- struct list_head *cur;
+ struct btrfs_device *device;
struct map_lookup *map = NULL;
struct extent_map_tree *em_tree;
struct extent_map *em;
@@ -4649,7 +4606,6 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
u64 max_chunk_size;
u64 stripe_size;
u64 num_bytes;
- u64 raid_stripe_len = BTRFS_STRIPE_LEN;
int ndevs;
int i;
int j;
@@ -4703,22 +4659,15 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
if (!devices_info)
return -ENOMEM;
- cur = fs_devices->alloc_list.next;
-
/*
* in the first pass through the devices list, we gather information
* about the available holes on each device.
*/
ndevs = 0;
- while (cur != &fs_devices->alloc_list) {
- struct btrfs_device *device;
+ list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) {
u64 max_avail;
u64 dev_offset;
- device = list_entry(cur, struct btrfs_device, dev_alloc_list);
-
- cur = cur->next;
-
if (!device->writeable) {
WARN(1, KERN_ERR
"BTRFS: read-only device in alloc_list\n");
@@ -4769,15 +4718,15 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
btrfs_cmp_device_info, NULL);
/* round down to number of usable stripes */
- ndevs -= ndevs % devs_increment;
+ ndevs = round_down(ndevs, devs_increment);
if (ndevs < devs_increment * sub_stripes || ndevs < devs_min) {
ret = -ENOSPC;
goto error;
}
- if (devs_max && ndevs > devs_max)
- ndevs = devs_max;
+ ndevs = min(ndevs, devs_max);
+
/*
* the primary goal is to maximize the number of stripes, so use as many
* devices as possible, even if the stripes are not maximum sized.
@@ -4791,16 +4740,11 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
*/
data_stripes = num_stripes / ncopies;
- if (type & BTRFS_BLOCK_GROUP_RAID5) {
- raid_stripe_len = find_raid56_stripe_len(ndevs - 1,
- info->stripesize);
+ if (type & BTRFS_BLOCK_GROUP_RAID5)
data_stripes = num_stripes - 1;
- }
- if (type & BTRFS_BLOCK_GROUP_RAID6) {
- raid_stripe_len = find_raid56_stripe_len(ndevs - 2,
- info->stripesize);
+
+ if (type & BTRFS_BLOCK_GROUP_RAID6)
data_stripes = num_stripes - 2;
- }
/*
* Use the number of data stripes to figure out how big this chunk
@@ -4825,8 +4769,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
stripe_size = div_u64(stripe_size, dev_stripes);
/* align to BTRFS_STRIPE_LEN */
- stripe_size = div64_u64(stripe_size, raid_stripe_len);
- stripe_size *= raid_stripe_len;
+ stripe_size = round_down(stripe_size, BTRFS_STRIPE_LEN);
map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
if (!map) {
@@ -4843,10 +4786,9 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
j * stripe_size;
}
}
- map->sector_size = info->sectorsize;
- map->stripe_len = raid_stripe_len;
- map->io_align = raid_stripe_len;
- map->io_width = raid_stripe_len;
+ map->stripe_len = BTRFS_STRIPE_LEN;
+ map->io_align = BTRFS_STRIPE_LEN;
+ map->io_width = BTRFS_STRIPE_LEN;
map->type = type;
map->sub_stripes = sub_stripes;
@@ -4881,9 +4823,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
goto error;
}
- ret = btrfs_make_block_group(trans, info, 0, type,
- BTRFS_FIRST_CHUNK_TREE_OBJECTID,
- start, num_bytes);
+ ret = btrfs_make_block_group(trans, info, 0, type, start, num_bytes);
if (ret)
goto error_del_extent;
@@ -4963,11 +4903,8 @@ int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans,
ret = btrfs_update_device(trans, device);
if (ret)
break;
- ret = btrfs_alloc_dev_extent(trans, device,
- chunk_root->root_key.objectid,
- BTRFS_FIRST_CHUNK_TREE_OBJECTID,
- chunk_offset, dev_offset,
- stripe_size);
+ ret = btrfs_alloc_dev_extent(trans, device, chunk_offset,
+ dev_offset, stripe_size);
if (ret)
break;
}
@@ -5172,7 +5109,6 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len)
}
unsigned long btrfs_full_stripe_len(struct btrfs_fs_info *fs_info,
- struct btrfs_mapping_tree *map_tree,
u64 logical)
{
struct extent_map *em;
@@ -5180,29 +5116,30 @@ unsigned long btrfs_full_stripe_len(struct btrfs_fs_info *fs_info,
unsigned long len = fs_info->sectorsize;
em = get_chunk_map(fs_info, logical, len);
- WARN_ON(IS_ERR(em));
- map = em->map_lookup;
- if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
- len = map->stripe_len * nr_data_stripes(map);
- free_extent_map(em);
+ if (!WARN_ON(IS_ERR(em))) {
+ map = em->map_lookup;
+ if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
+ len = map->stripe_len * nr_data_stripes(map);
+ free_extent_map(em);
+ }
return len;
}
-int btrfs_is_parity_mirror(struct btrfs_fs_info *fs_info,
- u64 logical, u64 len, int mirror_num)
+int btrfs_is_parity_mirror(struct btrfs_fs_info *fs_info, u64 logical, u64 len)
{
struct extent_map *em;
struct map_lookup *map;
int ret = 0;
em = get_chunk_map(fs_info, logical, len);
- WARN_ON(IS_ERR(em));
- map = em->map_lookup;
- if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
- ret = 1;
- free_extent_map(em);
+ if(!WARN_ON(IS_ERR(em))) {
+ map = em->map_lookup;
+ if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
+ ret = 1;
+ free_extent_map(em);
+ }
return ret;
}
@@ -6295,9 +6232,8 @@ struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid,
cur_devices = fs_info->fs_devices;
while (cur_devices) {
if (!fsid ||
- !memcmp(cur_devices->fsid, fsid, BTRFS_UUID_SIZE)) {
- device = __find_device(&cur_devices->devices,
- devid, uuid);
+ !memcmp(cur_devices->fsid, fsid, BTRFS_FSID_SIZE)) {
+ device = find_device(cur_devices, devid, uuid);
if (device)
return device;
}
@@ -6450,7 +6386,6 @@ static int read_one_chunk(struct btrfs_fs_info *fs_info, struct btrfs_key *key,
struct extent_map *em;
u64 logical;
u64 length;
- u64 stripe_len;
u64 devid;
u8 uuid[BTRFS_UUID_SIZE];
int num_stripes;
@@ -6459,7 +6394,6 @@ static int read_one_chunk(struct btrfs_fs_info *fs_info, struct btrfs_key *key,
logical = key->offset;
length = btrfs_chunk_length(leaf, chunk);
- stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
ret = btrfs_check_chunk_valid(fs_info, leaf, chunk, logical);
@@ -6498,7 +6432,6 @@ static int read_one_chunk(struct btrfs_fs_info *fs_info, struct btrfs_key *key,
map->num_stripes = num_stripes;
map->io_width = btrfs_chunk_io_width(leaf, chunk);
map->io_align = btrfs_chunk_io_align(leaf, chunk);
- map->sector_size = btrfs_chunk_sector_size(leaf, chunk);
map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
map->type = btrfs_chunk_type(leaf, chunk);
map->sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk);
@@ -6514,6 +6447,7 @@ static int read_one_chunk(struct btrfs_fs_info *fs_info, struct btrfs_key *key,
if (!map->stripes[i].dev &&
!btrfs_test_opt(fs_info, DEGRADED)) {
free_extent_map(em);
+ btrfs_report_missing_device(fs_info, devid, uuid);
return -EIO;
}
if (!map->stripes[i].dev) {
@@ -6524,8 +6458,7 @@ static int read_one_chunk(struct btrfs_fs_info *fs_info, struct btrfs_key *key,
free_extent_map(em);
return -EIO;
}
- btrfs_warn(fs_info, "devid %llu uuid %pU is missing",
- devid, uuid);
+ btrfs_report_missing_device(fs_info, devid, uuid);
}
map->stripes[i].dev->in_fs_metadata = 1;
}
@@ -6569,10 +6502,11 @@ static struct btrfs_fs_devices *open_seed_devices(struct btrfs_fs_info *fs_info,
int ret;
BUG_ON(!mutex_is_locked(&uuid_mutex));
+ ASSERT(fsid);
fs_devices = fs_info->fs_devices->seed;
while (fs_devices) {
- if (!memcmp(fs_devices->fsid, fsid, BTRFS_UUID_SIZE))
+ if (!memcmp(fs_devices->fsid, fsid, BTRFS_FSID_SIZE))
return fs_devices;
fs_devices = fs_devices->seed;
@@ -6625,16 +6559,16 @@ static int read_one_dev(struct btrfs_fs_info *fs_info,
struct btrfs_device *device;
u64 devid;
int ret;
- u8 fs_uuid[BTRFS_UUID_SIZE];
+ u8 fs_uuid[BTRFS_FSID_SIZE];
u8 dev_uuid[BTRFS_UUID_SIZE];
devid = btrfs_device_id(leaf, dev_item);
read_extent_buffer(leaf, dev_uuid, btrfs_device_uuid(dev_item),
BTRFS_UUID_SIZE);
read_extent_buffer(leaf, fs_uuid, btrfs_device_fsid(dev_item),
- BTRFS_UUID_SIZE);
+ BTRFS_FSID_SIZE);
- if (memcmp(fs_uuid, fs_info->fsid, BTRFS_UUID_SIZE)) {
+ if (memcmp(fs_uuid, fs_info->fsid, BTRFS_FSID_SIZE)) {
fs_devices = open_seed_devices(fs_info, fs_uuid);
if (IS_ERR(fs_devices))
return PTR_ERR(fs_devices);
@@ -6642,17 +6576,21 @@ static int read_one_dev(struct btrfs_fs_info *fs_info,
device = btrfs_find_device(fs_info, devid, dev_uuid, fs_uuid);
if (!device) {
- if (!btrfs_test_opt(fs_info, DEGRADED))
+ if (!btrfs_test_opt(fs_info, DEGRADED)) {
+ btrfs_report_missing_device(fs_info, devid, dev_uuid);
return -EIO;
+ }
device = add_missing_dev(fs_devices, devid, dev_uuid);
if (!device)
return -ENOMEM;
- btrfs_warn(fs_info, "devid %llu uuid %pU missing",
- devid, dev_uuid);
+ btrfs_report_missing_device(fs_info, devid, dev_uuid);
} else {
- if (!device->bdev && !btrfs_test_opt(fs_info, DEGRADED))
- return -EIO;
+ if (!device->bdev) {
+ btrfs_report_missing_device(fs_info, devid, dev_uuid);
+ if (!btrfs_test_opt(fs_info, DEGRADED))
+ return -EIO;
+ }
if(!device->bdev && !device->missing) {
/*
@@ -6818,6 +6756,70 @@ out_short_read:
return -EIO;
}
+void btrfs_report_missing_device(struct btrfs_fs_info *fs_info, u64 devid,
+ u8 *uuid)
+{
+ btrfs_warn_rl(fs_info, "devid %llu uuid %pU is missing", devid, uuid);
+}
+
+/*
+ * Check if all chunks in the fs are OK for read-write degraded mount
+ *
+ * Return true if all chunks meet the minimal RW mount requirements.
+ * Return false if any chunk doesn't meet the minimal RW mount requirements.
+ */
+bool btrfs_check_rw_degradable(struct btrfs_fs_info *fs_info)
+{
+ struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
+ struct extent_map *em;
+ u64 next_start = 0;
+ bool ret = true;
+
+ read_lock(&map_tree->map_tree.lock);
+ em = lookup_extent_mapping(&map_tree->map_tree, 0, (u64)-1);
+ read_unlock(&map_tree->map_tree.lock);
+ /* No chunk at all? Return false anyway */
+ if (!em) {
+ ret = false;
+ goto out;
+ }
+ while (em) {
+ struct map_lookup *map;
+ int missing = 0;
+ int max_tolerated;
+ int i;
+
+ map = em->map_lookup;
+ max_tolerated =
+ btrfs_get_num_tolerated_disk_barrier_failures(
+ map->type);
+ for (i = 0; i < map->num_stripes; i++) {
+ struct btrfs_device *dev = map->stripes[i].dev;
+
+ if (!dev || !dev->bdev || dev->missing ||
+ dev->last_flush_error)
+ missing++;
+ }
+ if (missing > max_tolerated) {
+ btrfs_warn(fs_info,
+ "chunk %llu missing %d devices, max tolerance is %d for writeable mount",
+ em->start, missing, max_tolerated);
+ free_extent_map(em);
+ ret = false;
+ goto out;
+ }
+ next_start = extent_map_end(em);
+ free_extent_map(em);
+
+ read_lock(&map_tree->map_tree.lock);
+ em = lookup_extent_mapping(&map_tree->map_tree, next_start,
+ (u64)(-1) - next_start);
+ read_unlock(&map_tree->map_tree.lock);
+ }
+out:
+ return ret;
+}
+
int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info)
{
struct btrfs_root *root = fs_info->chunk_root;