aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/volumes.c
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2014-09-03 09:35:32 -0400
committerChris Mason <clm@fb.com>2014-09-17 16:38:31 -0400
commit1c43366d3b3f0fa6c6e81aaf3aa18e0550245dad (patch)
treee5800ddfd965032bcd139ff4595e64d3868a6a5c /fs/btrfs/volumes.c
parentc7662111c741bc04a7192f2a00aad608cbc0b205 (diff)
Btrfs: fix unprotected assignment of the target device
We didn't protect the assignment of the target device, it might cause the problem that the super block update was skipped because we might find wrong size of the target device during the assignment. Fix it by moving the assignment sentences into the initialization function of the target device. And there is another merit that we can check if the target device is suitable more early. Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r--fs/btrfs/volumes.c23
1 files changed, 19 insertions, 4 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 483fc6d45299..1646659f2800 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -2295,6 +2295,7 @@ error:
2295} 2295}
2296 2296
2297int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path, 2297int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
2298 struct btrfs_device *srcdev,
2298 struct btrfs_device **device_out) 2299 struct btrfs_device **device_out)
2299{ 2300{
2300 struct request_queue *q; 2301 struct request_queue *q;
@@ -2307,24 +2308,37 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
2307 int ret = 0; 2308 int ret = 0;
2308 2309
2309 *device_out = NULL; 2310 *device_out = NULL;
2310 if (fs_info->fs_devices->seeding) 2311 if (fs_info->fs_devices->seeding) {
2312 btrfs_err(fs_info, "the filesystem is a seed filesystem!");
2311 return -EINVAL; 2313 return -EINVAL;
2314 }
2312 2315
2313 bdev = blkdev_get_by_path(device_path, FMODE_WRITE | FMODE_EXCL, 2316 bdev = blkdev_get_by_path(device_path, FMODE_WRITE | FMODE_EXCL,
2314 fs_info->bdev_holder); 2317 fs_info->bdev_holder);
2315 if (IS_ERR(bdev)) 2318 if (IS_ERR(bdev)) {
2319 btrfs_err(fs_info, "target device %s is invalid!", device_path);
2316 return PTR_ERR(bdev); 2320 return PTR_ERR(bdev);
2321 }
2317 2322
2318 filemap_write_and_wait(bdev->bd_inode->i_mapping); 2323 filemap_write_and_wait(bdev->bd_inode->i_mapping);
2319 2324
2320 devices = &fs_info->fs_devices->devices; 2325 devices = &fs_info->fs_devices->devices;
2321 list_for_each_entry(device, devices, dev_list) { 2326 list_for_each_entry(device, devices, dev_list) {
2322 if (device->bdev == bdev) { 2327 if (device->bdev == bdev) {
2328 btrfs_err(fs_info, "target device is in the filesystem!");
2323 ret = -EEXIST; 2329 ret = -EEXIST;
2324 goto error; 2330 goto error;
2325 } 2331 }
2326 } 2332 }
2327 2333
2334
2335 if (i_size_read(bdev->bd_inode) < srcdev->total_bytes) {
2336 btrfs_err(fs_info, "target device is smaller than source device!");
2337 ret = -EINVAL;
2338 goto error;
2339 }
2340
2341
2328 device = btrfs_alloc_device(NULL, &devid, NULL); 2342 device = btrfs_alloc_device(NULL, &devid, NULL);
2329 if (IS_ERR(device)) { 2343 if (IS_ERR(device)) {
2330 ret = PTR_ERR(device); 2344 ret = PTR_ERR(device);
@@ -2348,8 +2362,9 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
2348 device->io_width = root->sectorsize; 2362 device->io_width = root->sectorsize;
2349 device->io_align = root->sectorsize; 2363 device->io_align = root->sectorsize;
2350 device->sector_size = root->sectorsize; 2364 device->sector_size = root->sectorsize;
2351 device->total_bytes = i_size_read(bdev->bd_inode); 2365 device->total_bytes = srcdev->total_bytes;
2352 device->disk_total_bytes = device->total_bytes; 2366 device->disk_total_bytes = srcdev->disk_total_bytes;
2367 device->bytes_used = srcdev->bytes_used;
2353 device->dev_root = fs_info->dev_root; 2368 device->dev_root = fs_info->dev_root;
2354 device->bdev = bdev; 2369 device->bdev = bdev;
2355 device->in_fs_metadata = 1; 2370 device->in_fs_metadata = 1;