aboutsummaryrefslogtreecommitdiffstats
path: root/fs
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
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')
-rw-r--r--fs/btrfs/dev-replace.c32
-rw-r--r--fs/btrfs/volumes.c23
-rw-r--r--fs/btrfs/volumes.h1
3 files changed, 28 insertions, 28 deletions
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
index 10dfb41f4c22..72dc02e82945 100644
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -330,29 +330,19 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
330 return -EINVAL; 330 return -EINVAL;
331 331
332 mutex_lock(&fs_info->volume_mutex); 332 mutex_lock(&fs_info->volume_mutex);
333 ret = btrfs_init_dev_replace_tgtdev(root, args->start.tgtdev_name,
334 &tgt_device);
335 if (ret) {
336 btrfs_err(fs_info, "target device %s is invalid!",
337 args->start.tgtdev_name);
338 mutex_unlock(&fs_info->volume_mutex);
339 return -EINVAL;
340 }
341
342 ret = btrfs_dev_replace_find_srcdev(root, args->start.srcdevid, 333 ret = btrfs_dev_replace_find_srcdev(root, args->start.srcdevid,
343 args->start.srcdev_name, 334 args->start.srcdev_name,
344 &src_device); 335 &src_device);
345 mutex_unlock(&fs_info->volume_mutex);
346 if (ret) { 336 if (ret) {
347 ret = -EINVAL; 337 mutex_unlock(&fs_info->volume_mutex);
348 goto leave_no_lock; 338 return ret;
349 } 339 }
350 340
351 if (tgt_device->total_bytes < src_device->total_bytes) { 341 ret = btrfs_init_dev_replace_tgtdev(root, args->start.tgtdev_name,
352 btrfs_err(fs_info, "target device is smaller than source device!"); 342 src_device, &tgt_device);
353 ret = -EINVAL; 343 mutex_unlock(&fs_info->volume_mutex);
354 goto leave_no_lock; 344 if (ret)
355 } 345 return ret;
356 346
357 btrfs_dev_replace_lock(dev_replace); 347 btrfs_dev_replace_lock(dev_replace);
358 switch (dev_replace->replace_state) { 348 switch (dev_replace->replace_state) {
@@ -380,10 +370,6 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
380 src_device->devid, 370 src_device->devid,
381 rcu_str_deref(tgt_device->name)); 371 rcu_str_deref(tgt_device->name));
382 372
383 tgt_device->total_bytes = src_device->total_bytes;
384 tgt_device->disk_total_bytes = src_device->disk_total_bytes;
385 tgt_device->bytes_used = src_device->bytes_used;
386
387 /* 373 /*
388 * from now on, the writes to the srcdev are all duplicated to 374 * from now on, the writes to the srcdev are all duplicated to
389 * go to the tgtdev as well (refer to btrfs_map_block()). 375 * go to the tgtdev as well (refer to btrfs_map_block()).
@@ -426,9 +412,7 @@ leave:
426 dev_replace->srcdev = NULL; 412 dev_replace->srcdev = NULL;
427 dev_replace->tgtdev = NULL; 413 dev_replace->tgtdev = NULL;
428 btrfs_dev_replace_unlock(dev_replace); 414 btrfs_dev_replace_unlock(dev_replace);
429leave_no_lock: 415 btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device);
430 if (tgt_device)
431 btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device);
432 return ret; 416 return ret;
433} 417}
434 418
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;
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 37f8bff97df1..e15f2886d33e 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -322,6 +322,7 @@ struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid,
322int btrfs_shrink_device(struct btrfs_device *device, u64 new_size); 322int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
323int btrfs_init_new_device(struct btrfs_root *root, char *path); 323int btrfs_init_new_device(struct btrfs_root *root, char *path);
324int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path, 324int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
325 struct btrfs_device *srcdev,
325 struct btrfs_device **device_out); 326 struct btrfs_device **device_out);
326int btrfs_balance(struct btrfs_balance_control *bctl, 327int btrfs_balance(struct btrfs_balance_control *bctl,
327 struct btrfs_ioctl_balance_args *bargs); 328 struct btrfs_ioctl_balance_args *bargs);