summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/volumes.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r--fs/btrfs/volumes.c197
1 files changed, 102 insertions, 95 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 035efce..71a60cc 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -859,7 +859,7 @@ static void btrfs_close_bdev(struct btrfs_device *device)
blkdev_put(device->bdev, device->mode);
}
-static void btrfs_close_one_device(struct btrfs_device *device)
+static void btrfs_prepare_close_one_device(struct btrfs_device *device)
{
struct btrfs_fs_devices *fs_devices = device->fs_devices;
struct btrfs_device *new_device;
@@ -877,8 +877,6 @@ static void btrfs_close_one_device(struct btrfs_device *device)
if (device->missing)
fs_devices->missing_devices--;
- btrfs_close_bdev(device);
-
new_device = btrfs_alloc_device(NULL, &device->devid,
device->uuid);
BUG_ON(IS_ERR(new_device)); /* -ENOMEM */
@@ -892,23 +890,39 @@ static void btrfs_close_one_device(struct btrfs_device *device)
list_replace_rcu(&device->dev_list, &new_device->dev_list);
new_device->fs_devices = device->fs_devices;
-
- call_rcu(&device->rcu, free_device);
}
static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
{
struct btrfs_device *device, *tmp;
+ struct list_head pending_put;
+
+ INIT_LIST_HEAD(&pending_put);
if (--fs_devices->opened > 0)
return 0;
mutex_lock(&fs_devices->device_list_mutex);
list_for_each_entry_safe(device, tmp, &fs_devices->devices, dev_list) {
- btrfs_close_one_device(device);
+ btrfs_prepare_close_one_device(device);
+ list_add(&device->dev_list, &pending_put);
}
mutex_unlock(&fs_devices->device_list_mutex);
+ /*
+ * btrfs_show_devname() is using the device_list_mutex,
+ * sometimes call to blkdev_put() leads vfs calling
+ * into this func. So do put outside of device_list_mutex,
+ * as of now.
+ */
+ while (!list_empty(&pending_put)) {
+ device = list_first_entry(&pending_put,
+ struct btrfs_device, dev_list);
+ list_del(&device->dev_list);
+ btrfs_close_bdev(device);
+ call_rcu(&device->rcu, free_device);
+ }
+
WARN_ON(fs_devices->open_devices);
WARN_ON(fs_devices->rw_devices);
fs_devices->opened = 0;
@@ -1140,12 +1154,12 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
ret = device_list_add(path, disk_super, devid, fs_devices_ret);
if (ret > 0) {
if (disk_super->label[0]) {
- printk(KERN_INFO "BTRFS: device label %s ", disk_super->label);
+ pr_info("BTRFS: device label %s ", disk_super->label);
} else {
- printk(KERN_INFO "BTRFS: device fsid %pU ", disk_super->fsid);
+ pr_info("BTRFS: device fsid %pU ", disk_super->fsid);
}
- printk(KERN_CONT "devid %llu transid %llu %s\n", devid, transid, path);
+ pr_cont("devid %llu transid %llu %s\n", devid, transid, path);
ret = 0;
}
if (!ret && fs_devices_ret)
@@ -1846,7 +1860,6 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid)
u64 num_devices;
int ret = 0;
bool clear_super = false;
- char *dev_name = NULL;
mutex_lock(&uuid_mutex);
@@ -1882,11 +1895,6 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid)
list_del_init(&device->dev_alloc_list);
device->fs_devices->rw_devices--;
unlock_chunks(root);
- dev_name = kstrdup(device->name->str, GFP_KERNEL);
- if (!dev_name) {
- ret = -ENOMEM;
- goto error_undo;
- }
clear_super = true;
}
@@ -1936,14 +1944,21 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid)
btrfs_sysfs_rm_device_link(root->fs_info->fs_devices, device);
}
- btrfs_close_bdev(device);
-
- call_rcu(&device->rcu, free_device);
-
num_devices = btrfs_super_num_devices(root->fs_info->super_copy) - 1;
btrfs_set_super_num_devices(root->fs_info->super_copy, num_devices);
mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+ /*
+ * at this point, the device is zero sized and detached from
+ * the devices list. All that's left is to zero out the old
+ * supers and free the device.
+ */
+ if (device->writeable)
+ btrfs_scratch_superblocks(device->bdev, device->name->str);
+
+ btrfs_close_bdev(device);
+ call_rcu(&device->rcu, free_device);
+
if (cur_devices->open_devices == 0) {
struct btrfs_fs_devices *fs_devices;
fs_devices = root->fs_info->fs_devices;
@@ -1962,24 +1977,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid)
root->fs_info->num_tolerated_disk_barrier_failures =
btrfs_calc_num_tolerated_disk_barrier_failures(root->fs_info);
- /*
- * at this point, the device is zero sized. We want to
- * remove it from the devices list and zero out the old super
- */
- if (clear_super) {
- struct block_device *bdev;
-
- bdev = blkdev_get_by_path(dev_name, FMODE_READ | FMODE_EXCL,
- root->fs_info->bdev_holder);
- if (!IS_ERR(bdev)) {
- btrfs_scratch_superblocks(bdev, dev_name);
- blkdev_put(bdev, FMODE_READ | FMODE_EXCL);
- }
- }
-
out:
- kfree(dev_name);
-
mutex_unlock(&uuid_mutex);
return ret;
@@ -2494,9 +2492,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
ret = btrfs_relocate_sys_chunks(root);
if (ret < 0)
btrfs_handle_fs_error(root->fs_info, ret,
- "Failed to relocate sys chunks after "
- "device initialization. This can be fixed "
- "using the \"btrfs balance\" command.");
+ "Failed to relocate sys chunks after device initialization. This can be fixed using the \"btrfs balance\" command.");
trans = btrfs_attach_transaction(root);
if (IS_ERR(trans)) {
if (PTR_ERR(trans) == -ENOENT)
@@ -2555,7 +2551,8 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
devices = &fs_info->fs_devices->devices;
list_for_each_entry(device, devices, dev_list) {
if (device->bdev == bdev) {
- btrfs_err(fs_info, "target device is in the filesystem!");
+ btrfs_err(fs_info,
+ "target device is in the filesystem!");
ret = -EEXIST;
goto error;
}
@@ -2564,7 +2561,8 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
if (i_size_read(bdev->bd_inode) <
btrfs_device_get_total_bytes(srcdev)) {
- btrfs_err(fs_info, "target device is smaller than source device!");
+ btrfs_err(fs_info,
+ "target device is smaller than source device!");
ret = -EINVAL;
goto error;
}
@@ -3698,7 +3696,7 @@ error:
btrfs_free_path(path);
if (enospc_errors) {
btrfs_info(fs_info, "%d enospc errors during balance",
- enospc_errors);
+ enospc_errors);
if (!ret)
ret = -ENOSPC;
}
@@ -3792,8 +3790,8 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
if (!(bctl->flags & BTRFS_BALANCE_DATA) ||
!(bctl->flags & BTRFS_BALANCE_METADATA) ||
memcmp(&bctl->data, &bctl->meta, sizeof(bctl->data))) {
- btrfs_err(fs_info, "with mixed groups data and "
- "metadata balance options must be the same");
+ btrfs_err(fs_info,
+ "with mixed groups data and metadata balance options must be the same");
ret = -EINVAL;
goto out;
}
@@ -3815,23 +3813,23 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
allowed |= (BTRFS_BLOCK_GROUP_RAID10 |
BTRFS_BLOCK_GROUP_RAID6);
if (validate_convert_profile(&bctl->data, allowed)) {
- btrfs_err(fs_info, "unable to start balance with target "
- "data profile %llu",
- bctl->data.target);
+ btrfs_err(fs_info,
+ "unable to start balance with target data profile %llu",
+ bctl->data.target);
ret = -EINVAL;
goto out;
}
if (validate_convert_profile(&bctl->meta, allowed)) {
btrfs_err(fs_info,
- "unable to start balance with target metadata profile %llu",
- bctl->meta.target);
+ "unable to start balance with target metadata profile %llu",
+ bctl->meta.target);
ret = -EINVAL;
goto out;
}
if (validate_convert_profile(&bctl->sys, allowed)) {
btrfs_err(fs_info,
- "unable to start balance with target system profile %llu",
- bctl->sys.target);
+ "unable to start balance with target system profile %llu",
+ bctl->sys.target);
ret = -EINVAL;
goto out;
}
@@ -3851,10 +3849,11 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
(fs_info->avail_metadata_alloc_bits & allowed) &&
!(bctl->meta.target & allowed))) {
if (bctl->flags & BTRFS_BALANCE_FORCE) {
- btrfs_info(fs_info, "force reducing metadata integrity");
+ btrfs_info(fs_info,
+ "force reducing metadata integrity");
} else {
- btrfs_err(fs_info, "balance will reduce metadata "
- "integrity, use force if you want this");
+ btrfs_err(fs_info,
+ "balance will reduce metadata integrity, use force if you want this");
ret = -EINVAL;
goto out;
}
@@ -3864,8 +3863,8 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
if (btrfs_get_num_tolerated_disk_barrier_failures(bctl->meta.target) <
btrfs_get_num_tolerated_disk_barrier_failures(bctl->data.target)) {
btrfs_warn(fs_info,
- "metadata profile 0x%llx has lower redundancy than data profile 0x%llx",
- bctl->meta.target, bctl->data.target);
+ "metadata profile 0x%llx has lower redundancy than data profile 0x%llx",
+ bctl->meta.target, bctl->data.target);
}
if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) {
@@ -4221,7 +4220,7 @@ out:
if (ret)
btrfs_warn(fs_info, "btrfs_uuid_scan_kthread failed %d", ret);
else
- fs_info->update_uuid_tree_gen = 1;
+ set_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags);
up(&fs_info->uuid_tree_rescan_sem);
return 0;
}
@@ -4913,15 +4912,16 @@ int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans,
read_unlock(&em_tree->lock);
if (!em) {
- btrfs_crit(extent_root->fs_info, "unable to find logical "
- "%Lu len %Lu", chunk_offset, chunk_size);
+ btrfs_crit(extent_root->fs_info,
+ "unable to find logical %Lu len %Lu",
+ chunk_offset, chunk_size);
return -EINVAL;
}
if (em->start != chunk_offset || em->len != chunk_size) {
- btrfs_crit(extent_root->fs_info, "found a bad mapping, wanted"
- " %Lu-%Lu, found %Lu-%Lu", chunk_offset,
- chunk_size, em->start, em->len);
+ btrfs_crit(extent_root->fs_info,
+ "found a bad mapping, wanted %Lu-%Lu, found %Lu-%Lu",
+ chunk_offset, chunk_size, em->start, em->len);
free_extent_map(em);
return -EINVAL;
}
@@ -5154,9 +5154,9 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len)
}
if (em->start > logical || em->start + em->len < logical) {
- btrfs_crit(fs_info, "Invalid mapping for %Lu-%Lu, got "
- "%Lu-%Lu", logical, logical+len, em->start,
- em->start + em->len);
+ btrfs_crit(fs_info, "Invalid mapping for %Lu-%Lu, got %Lu-%Lu",
+ logical, logical+len, em->start,
+ em->start + em->len);
free_extent_map(em);
return 1;
}
@@ -5370,9 +5370,9 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int op,
}
if (em->start > logical || em->start + em->len < logical) {
- btrfs_crit(fs_info, "found a bad mapping, wanted %Lu, "
- "found %Lu-%Lu", logical, em->start,
- em->start + em->len);
+ btrfs_crit(fs_info,
+ "found a bad mapping, wanted %Lu, found %Lu-%Lu",
+ logical, em->start, em->start + em->len);
free_extent_map(em);
return -EINVAL;
}
@@ -5390,9 +5390,8 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int op,
stripe_offset = stripe_nr * stripe_len;
if (offset < stripe_offset) {
- btrfs_crit(fs_info, "stripe math has gone wrong, "
- "stripe_offset=%llu, offset=%llu, start=%llu, "
- "logical=%llu, stripe_len=%llu",
+ btrfs_crit(fs_info,
+ "stripe math has gone wrong, stripe_offset=%llu, offset=%llu, start=%llu, logical=%llu, stripe_len=%llu",
stripe_offset, offset, em->start, logical,
stripe_len);
free_extent_map(em);
@@ -5642,8 +5641,8 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int op,
mirror_num = stripe_index + 1;
}
if (stripe_index >= map->num_stripes) {
- btrfs_crit(fs_info, "stripe index math went horribly wrong, "
- "got stripe_index=%u, num_stripes=%u",
+ btrfs_crit(fs_info,
+ "stripe index math went horribly wrong, got stripe_index=%u, num_stripes=%u",
stripe_index, map->num_stripes);
ret = -EINVAL;
goto out;
@@ -5907,10 +5906,11 @@ int btrfs_map_sblock(struct btrfs_fs_info *fs_info, int op,
mirror_num, need_raid_map);
}
-int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
+int btrfs_rmap_block(struct btrfs_fs_info *fs_info,
u64 chunk_start, u64 physical, u64 devid,
u64 **logical, int *naddrs, int *stripe_len)
{
+ struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
struct extent_map_tree *em_tree = &map_tree->map_tree;
struct extent_map *em;
struct map_lookup *map;
@@ -5926,13 +5926,13 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
read_unlock(&em_tree->lock);
if (!em) {
- printk(KERN_ERR "BTRFS: couldn't find em for chunk %Lu\n",
- chunk_start);
+ btrfs_err(fs_info, "couldn't find em for chunk %Lu",
+ chunk_start);
return -EIO;
}
if (em->start != chunk_start) {
- printk(KERN_ERR "BTRFS: bad chunk start, em=%Lu, wanted=%Lu\n",
+ btrfs_err(fs_info, "bad chunk start, em=%Lu, wanted=%Lu",
em->start, chunk_start);
free_extent_map(em);
return -EIO;
@@ -6137,10 +6137,12 @@ static void submit_stripe_bio(struct btrfs_root *root, struct btrfs_bio *bbio,
rcu_read_lock();
name = rcu_dereference(dev->name);
- pr_debug("btrfs_map_bio: rw %d 0x%x, sector=%llu, dev=%lu "
- "(%s id %llu), size=%u\n", bio_op(bio), bio->bi_opf,
- (u64)bio->bi_iter.bi_sector, (u_long)dev->bdev->bd_dev,
- name->str, dev->devid, bio->bi_iter.bi_size);
+ btrfs_debug(fs_info,
+ "btrfs_map_bio: rw %d 0x%x, sector=%llu, dev=%lu (%s id %llu), size=%u",
+ bio_op(bio), bio->bi_opf,
+ (u64)bio->bi_iter.bi_sector,
+ (u_long)dev->bdev->bd_dev, name->str, dev->devid,
+ bio->bi_iter.bi_size);
rcu_read_unlock();
}
#endif
@@ -6215,8 +6217,9 @@ int btrfs_map_bio(struct btrfs_root *root, struct bio *bio,
}
if (map_length < length) {
- btrfs_crit(root->fs_info, "mapping failed logical %llu bio len %llu len %llu",
- logical, length, map_length);
+ btrfs_crit(root->fs_info,
+ "mapping failed logical %llu bio len %llu len %llu",
+ logical, length, map_length);
BUG();
}
@@ -6483,8 +6486,9 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
free_extent_map(em);
return -EIO;
}
- btrfs_warn(root->fs_info, "devid %llu uuid %pU is missing",
- devid, uuid);
+ btrfs_warn(root->fs_info,
+ "devid %llu uuid %pU is missing",
+ devid, uuid);
}
map->stripes[i].dev->in_fs_metadata = 1;
}
@@ -6661,7 +6665,8 @@ static int read_one_dev(struct btrfs_root *root,
int btrfs_read_sys_array(struct btrfs_root *root)
{
- struct btrfs_super_block *super_copy = root->fs_info->super_copy;
+ struct btrfs_fs_info *fs_info = root->fs_info;
+ struct btrfs_super_block *super_copy = fs_info->super_copy;
struct extent_buffer *sb;
struct btrfs_disk_key *disk_key;
struct btrfs_chunk *chunk;
@@ -6732,8 +6737,8 @@ int btrfs_read_sys_array(struct btrfs_root *root)
num_stripes = btrfs_chunk_num_stripes(sb, chunk);
if (!num_stripes) {
- printk(KERN_ERR
- "BTRFS: invalid number of stripes %u in sys_array at offset %u\n",
+ btrfs_err(fs_info,
+ "invalid number of stripes %u in sys_array at offset %u",
num_stripes, cur_offset);
ret = -EIO;
break;
@@ -6741,7 +6746,7 @@ int btrfs_read_sys_array(struct btrfs_root *root)
type = btrfs_chunk_type(sb, chunk);
if ((type & BTRFS_BLOCK_GROUP_SYSTEM) == 0) {
- btrfs_err(root->fs_info,
+ btrfs_err(fs_info,
"invalid chunk type %llu in sys_array at offset %u",
type, cur_offset);
ret = -EIO;
@@ -6756,9 +6761,9 @@ int btrfs_read_sys_array(struct btrfs_root *root)
if (ret)
break;
} else {
- printk(KERN_ERR
- "BTRFS: unexpected item type %u in sys_array at offset %u\n",
- (u32)key.type, cur_offset);
+ btrfs_err(fs_info,
+ "unexpected item type %u in sys_array at offset %u",
+ (u32)key.type, cur_offset);
ret = -EIO;
break;
}
@@ -6771,7 +6776,7 @@ int btrfs_read_sys_array(struct btrfs_root *root)
return ret;
out_short_read:
- printk(KERN_ERR "BTRFS: sys_array too short to read %u bytes at offset %u\n",
+ btrfs_err(fs_info, "sys_array too short to read %u bytes at offset %u",
len, cur_offset);
clear_extent_buffer_uptodate(sb);
free_extent_buffer_stale(sb);
@@ -7095,10 +7100,12 @@ int btrfs_get_dev_stats(struct btrfs_root *root,
mutex_unlock(&fs_devices->device_list_mutex);
if (!dev) {
- btrfs_warn(root->fs_info, "get dev_stats failed, device not found");
+ btrfs_warn(root->fs_info,
+ "get dev_stats failed, device not found");
return -ENODEV;
} else if (!dev->dev_stats_valid) {
- btrfs_warn(root->fs_info, "get dev_stats failed, not yet valid");
+ btrfs_warn(root->fs_info,
+ "get dev_stats failed, not yet valid");
return -ENODEV;
} else if (stats->flags & BTRFS_DEV_STATS_RESET) {
for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++) {
OpenPOWER on IntegriCloud