diff options
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 119 |
1 files changed, 83 insertions, 36 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index b8fc2fa91fdf..c48214ef5c09 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -350,7 +350,7 @@ static noinline int device_list_add(const char *path, | |||
350 | INIT_LIST_HEAD(&device->dev_alloc_list); | 350 | INIT_LIST_HEAD(&device->dev_alloc_list); |
351 | 351 | ||
352 | mutex_lock(&fs_devices->device_list_mutex); | 352 | mutex_lock(&fs_devices->device_list_mutex); |
353 | list_add(&device->dev_list, &fs_devices->devices); | 353 | list_add_rcu(&device->dev_list, &fs_devices->devices); |
354 | mutex_unlock(&fs_devices->device_list_mutex); | 354 | mutex_unlock(&fs_devices->device_list_mutex); |
355 | 355 | ||
356 | device->fs_devices = fs_devices; | 356 | device->fs_devices = fs_devices; |
@@ -393,7 +393,7 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig) | |||
393 | fs_devices->latest_trans = orig->latest_trans; | 393 | fs_devices->latest_trans = orig->latest_trans; |
394 | memcpy(fs_devices->fsid, orig->fsid, sizeof(fs_devices->fsid)); | 394 | memcpy(fs_devices->fsid, orig->fsid, sizeof(fs_devices->fsid)); |
395 | 395 | ||
396 | mutex_lock(&orig->device_list_mutex); | 396 | /* We have held the volume lock, it is safe to get the devices. */ |
397 | list_for_each_entry(orig_dev, &orig->devices, dev_list) { | 397 | list_for_each_entry(orig_dev, &orig->devices, dev_list) { |
398 | device = kzalloc(sizeof(*device), GFP_NOFS); | 398 | device = kzalloc(sizeof(*device), GFP_NOFS); |
399 | if (!device) | 399 | if (!device) |
@@ -416,10 +416,8 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig) | |||
416 | device->fs_devices = fs_devices; | 416 | device->fs_devices = fs_devices; |
417 | fs_devices->num_devices++; | 417 | fs_devices->num_devices++; |
418 | } | 418 | } |
419 | mutex_unlock(&orig->device_list_mutex); | ||
420 | return fs_devices; | 419 | return fs_devices; |
421 | error: | 420 | error: |
422 | mutex_unlock(&orig->device_list_mutex); | ||
423 | free_fs_devices(fs_devices); | 421 | free_fs_devices(fs_devices); |
424 | return ERR_PTR(-ENOMEM); | 422 | return ERR_PTR(-ENOMEM); |
425 | } | 423 | } |
@@ -430,7 +428,7 @@ int btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices) | |||
430 | 428 | ||
431 | mutex_lock(&uuid_mutex); | 429 | mutex_lock(&uuid_mutex); |
432 | again: | 430 | again: |
433 | mutex_lock(&fs_devices->device_list_mutex); | 431 | /* This is the initialized path, it is safe to release the devices. */ |
434 | list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) { | 432 | list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) { |
435 | if (device->in_fs_metadata) | 433 | if (device->in_fs_metadata) |
436 | continue; | 434 | continue; |
@@ -450,7 +448,6 @@ again: | |||
450 | kfree(device->name); | 448 | kfree(device->name); |
451 | kfree(device); | 449 | kfree(device); |
452 | } | 450 | } |
453 | mutex_unlock(&fs_devices->device_list_mutex); | ||
454 | 451 | ||
455 | if (fs_devices->seed) { | 452 | if (fs_devices->seed) { |
456 | fs_devices = fs_devices->seed; | 453 | fs_devices = fs_devices->seed; |
@@ -461,6 +458,29 @@ again: | |||
461 | return 0; | 458 | return 0; |
462 | } | 459 | } |
463 | 460 | ||
461 | static void __free_device(struct work_struct *work) | ||
462 | { | ||
463 | struct btrfs_device *device; | ||
464 | |||
465 | device = container_of(work, struct btrfs_device, rcu_work); | ||
466 | |||
467 | if (device->bdev) | ||
468 | blkdev_put(device->bdev, device->mode); | ||
469 | |||
470 | kfree(device->name); | ||
471 | kfree(device); | ||
472 | } | ||
473 | |||
474 | static void free_device(struct rcu_head *head) | ||
475 | { | ||
476 | struct btrfs_device *device; | ||
477 | |||
478 | device = container_of(head, struct btrfs_device, rcu); | ||
479 | |||
480 | INIT_WORK(&device->rcu_work, __free_device); | ||
481 | schedule_work(&device->rcu_work); | ||
482 | } | ||
483 | |||
464 | static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices) | 484 | static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices) |
465 | { | 485 | { |
466 | struct btrfs_device *device; | 486 | struct btrfs_device *device; |
@@ -468,20 +488,32 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices) | |||
468 | if (--fs_devices->opened > 0) | 488 | if (--fs_devices->opened > 0) |
469 | return 0; | 489 | return 0; |
470 | 490 | ||
491 | mutex_lock(&fs_devices->device_list_mutex); | ||
471 | list_for_each_entry(device, &fs_devices->devices, dev_list) { | 492 | list_for_each_entry(device, &fs_devices->devices, dev_list) { |
472 | if (device->bdev) { | 493 | struct btrfs_device *new_device; |
473 | blkdev_put(device->bdev, device->mode); | 494 | |
495 | if (device->bdev) | ||
474 | fs_devices->open_devices--; | 496 | fs_devices->open_devices--; |
475 | } | 497 | |
476 | if (device->writeable) { | 498 | if (device->writeable) { |
477 | list_del_init(&device->dev_alloc_list); | 499 | list_del_init(&device->dev_alloc_list); |
478 | fs_devices->rw_devices--; | 500 | fs_devices->rw_devices--; |
479 | } | 501 | } |
480 | 502 | ||
481 | device->bdev = NULL; | 503 | new_device = kmalloc(sizeof(*new_device), GFP_NOFS); |
482 | device->writeable = 0; | 504 | BUG_ON(!new_device); |
483 | device->in_fs_metadata = 0; | 505 | memcpy(new_device, device, sizeof(*new_device)); |
506 | new_device->name = kstrdup(device->name, GFP_NOFS); | ||
507 | BUG_ON(!new_device->name); | ||
508 | new_device->bdev = NULL; | ||
509 | new_device->writeable = 0; | ||
510 | new_device->in_fs_metadata = 0; | ||
511 | list_replace_rcu(&device->dev_list, &new_device->dev_list); | ||
512 | |||
513 | call_rcu(&device->rcu, free_device); | ||
484 | } | 514 | } |
515 | mutex_unlock(&fs_devices->device_list_mutex); | ||
516 | |||
485 | WARN_ON(fs_devices->open_devices); | 517 | WARN_ON(fs_devices->open_devices); |
486 | WARN_ON(fs_devices->rw_devices); | 518 | WARN_ON(fs_devices->rw_devices); |
487 | fs_devices->opened = 0; | 519 | fs_devices->opened = 0; |
@@ -584,6 +616,7 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices, | |||
584 | list_add(&device->dev_alloc_list, | 616 | list_add(&device->dev_alloc_list, |
585 | &fs_devices->alloc_list); | 617 | &fs_devices->alloc_list); |
586 | } | 618 | } |
619 | brelse(bh); | ||
587 | continue; | 620 | continue; |
588 | 621 | ||
589 | error_brelse: | 622 | error_brelse: |
@@ -933,14 +966,14 @@ static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans, | |||
933 | if (ret > 0) { | 966 | if (ret > 0) { |
934 | ret = btrfs_previous_item(root, path, key.objectid, | 967 | ret = btrfs_previous_item(root, path, key.objectid, |
935 | BTRFS_DEV_EXTENT_KEY); | 968 | BTRFS_DEV_EXTENT_KEY); |
936 | BUG_ON(ret); | 969 | if (ret) |
970 | goto out; | ||
937 | leaf = path->nodes[0]; | 971 | leaf = path->nodes[0]; |
938 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | 972 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); |
939 | extent = btrfs_item_ptr(leaf, path->slots[0], | 973 | extent = btrfs_item_ptr(leaf, path->slots[0], |
940 | struct btrfs_dev_extent); | 974 | struct btrfs_dev_extent); |
941 | BUG_ON(found_key.offset > start || found_key.offset + | 975 | BUG_ON(found_key.offset > start || found_key.offset + |
942 | btrfs_dev_extent_length(leaf, extent) < start); | 976 | btrfs_dev_extent_length(leaf, extent) < start); |
943 | ret = 0; | ||
944 | } else if (ret == 0) { | 977 | } else if (ret == 0) { |
945 | leaf = path->nodes[0]; | 978 | leaf = path->nodes[0]; |
946 | extent = btrfs_item_ptr(leaf, path->slots[0], | 979 | extent = btrfs_item_ptr(leaf, path->slots[0], |
@@ -951,8 +984,8 @@ static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans, | |||
951 | if (device->bytes_used > 0) | 984 | if (device->bytes_used > 0) |
952 | device->bytes_used -= btrfs_dev_extent_length(leaf, extent); | 985 | device->bytes_used -= btrfs_dev_extent_length(leaf, extent); |
953 | ret = btrfs_del_item(trans, root, path); | 986 | ret = btrfs_del_item(trans, root, path); |
954 | BUG_ON(ret); | ||
955 | 987 | ||
988 | out: | ||
956 | btrfs_free_path(path); | 989 | btrfs_free_path(path); |
957 | return ret; | 990 | return ret; |
958 | } | 991 | } |
@@ -1187,11 +1220,13 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) | |||
1187 | struct block_device *bdev; | 1220 | struct block_device *bdev; |
1188 | struct buffer_head *bh = NULL; | 1221 | struct buffer_head *bh = NULL; |
1189 | struct btrfs_super_block *disk_super; | 1222 | struct btrfs_super_block *disk_super; |
1223 | struct btrfs_fs_devices *cur_devices; | ||
1190 | u64 all_avail; | 1224 | u64 all_avail; |
1191 | u64 devid; | 1225 | u64 devid; |
1192 | u64 num_devices; | 1226 | u64 num_devices; |
1193 | u8 *dev_uuid; | 1227 | u8 *dev_uuid; |
1194 | int ret = 0; | 1228 | int ret = 0; |
1229 | bool clear_super = false; | ||
1195 | 1230 | ||
1196 | mutex_lock(&uuid_mutex); | 1231 | mutex_lock(&uuid_mutex); |
1197 | mutex_lock(&root->fs_info->volume_mutex); | 1232 | mutex_lock(&root->fs_info->volume_mutex); |
@@ -1222,14 +1257,16 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) | |||
1222 | 1257 | ||
1223 | device = NULL; | 1258 | device = NULL; |
1224 | devices = &root->fs_info->fs_devices->devices; | 1259 | devices = &root->fs_info->fs_devices->devices; |
1225 | mutex_lock(&root->fs_info->fs_devices->device_list_mutex); | 1260 | /* |
1261 | * It is safe to read the devices since the volume_mutex | ||
1262 | * is held. | ||
1263 | */ | ||
1226 | list_for_each_entry(tmp, devices, dev_list) { | 1264 | list_for_each_entry(tmp, devices, dev_list) { |
1227 | if (tmp->in_fs_metadata && !tmp->bdev) { | 1265 | if (tmp->in_fs_metadata && !tmp->bdev) { |
1228 | device = tmp; | 1266 | device = tmp; |
1229 | break; | 1267 | break; |
1230 | } | 1268 | } |
1231 | } | 1269 | } |
1232 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); | ||
1233 | bdev = NULL; | 1270 | bdev = NULL; |
1234 | bh = NULL; | 1271 | bh = NULL; |
1235 | disk_super = NULL; | 1272 | disk_super = NULL; |
@@ -1271,8 +1308,11 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) | |||
1271 | } | 1308 | } |
1272 | 1309 | ||
1273 | if (device->writeable) { | 1310 | if (device->writeable) { |
1311 | lock_chunks(root); | ||
1274 | list_del_init(&device->dev_alloc_list); | 1312 | list_del_init(&device->dev_alloc_list); |
1313 | unlock_chunks(root); | ||
1275 | root->fs_info->fs_devices->rw_devices--; | 1314 | root->fs_info->fs_devices->rw_devices--; |
1315 | clear_super = true; | ||
1276 | } | 1316 | } |
1277 | 1317 | ||
1278 | ret = btrfs_shrink_device(device, 0); | 1318 | ret = btrfs_shrink_device(device, 0); |
@@ -1291,9 +1331,10 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) | |||
1291 | * the device list while someone else is writing out all | 1331 | * the device list while someone else is writing out all |
1292 | * the device supers. | 1332 | * the device supers. |
1293 | */ | 1333 | */ |
1334 | |||
1335 | cur_devices = device->fs_devices; | ||
1294 | mutex_lock(&root->fs_info->fs_devices->device_list_mutex); | 1336 | mutex_lock(&root->fs_info->fs_devices->device_list_mutex); |
1295 | list_del_init(&device->dev_list); | 1337 | list_del_rcu(&device->dev_list); |
1296 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); | ||
1297 | 1338 | ||
1298 | device->fs_devices->num_devices--; | 1339 | device->fs_devices->num_devices--; |
1299 | 1340 | ||
@@ -1307,34 +1348,36 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) | |||
1307 | if (device->bdev == root->fs_info->fs_devices->latest_bdev) | 1348 | if (device->bdev == root->fs_info->fs_devices->latest_bdev) |
1308 | root->fs_info->fs_devices->latest_bdev = next_device->bdev; | 1349 | root->fs_info->fs_devices->latest_bdev = next_device->bdev; |
1309 | 1350 | ||
1310 | if (device->bdev) { | 1351 | if (device->bdev) |
1311 | blkdev_put(device->bdev, device->mode); | ||
1312 | device->bdev = NULL; | ||
1313 | device->fs_devices->open_devices--; | 1352 | device->fs_devices->open_devices--; |
1314 | } | 1353 | |
1354 | call_rcu(&device->rcu, free_device); | ||
1355 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); | ||
1315 | 1356 | ||
1316 | num_devices = btrfs_super_num_devices(&root->fs_info->super_copy) - 1; | 1357 | num_devices = btrfs_super_num_devices(&root->fs_info->super_copy) - 1; |
1317 | btrfs_set_super_num_devices(&root->fs_info->super_copy, num_devices); | 1358 | btrfs_set_super_num_devices(&root->fs_info->super_copy, num_devices); |
1318 | 1359 | ||
1319 | if (device->fs_devices->open_devices == 0) { | 1360 | if (cur_devices->open_devices == 0) { |
1320 | struct btrfs_fs_devices *fs_devices; | 1361 | struct btrfs_fs_devices *fs_devices; |
1321 | fs_devices = root->fs_info->fs_devices; | 1362 | fs_devices = root->fs_info->fs_devices; |
1322 | while (fs_devices) { | 1363 | while (fs_devices) { |
1323 | if (fs_devices->seed == device->fs_devices) | 1364 | if (fs_devices->seed == cur_devices) |
1324 | break; | 1365 | break; |
1325 | fs_devices = fs_devices->seed; | 1366 | fs_devices = fs_devices->seed; |
1326 | } | 1367 | } |
1327 | fs_devices->seed = device->fs_devices->seed; | 1368 | fs_devices->seed = cur_devices->seed; |
1328 | device->fs_devices->seed = NULL; | 1369 | cur_devices->seed = NULL; |
1329 | __btrfs_close_devices(device->fs_devices); | 1370 | lock_chunks(root); |
1330 | free_fs_devices(device->fs_devices); | 1371 | __btrfs_close_devices(cur_devices); |
1372 | unlock_chunks(root); | ||
1373 | free_fs_devices(cur_devices); | ||
1331 | } | 1374 | } |
1332 | 1375 | ||
1333 | /* | 1376 | /* |
1334 | * at this point, the device is zero sized. We want to | 1377 | * at this point, the device is zero sized. We want to |
1335 | * remove it from the devices list and zero out the old super | 1378 | * remove it from the devices list and zero out the old super |
1336 | */ | 1379 | */ |
1337 | if (device->writeable) { | 1380 | if (clear_super) { |
1338 | /* make sure this device isn't detected as part of | 1381 | /* make sure this device isn't detected as part of |
1339 | * the FS anymore | 1382 | * the FS anymore |
1340 | */ | 1383 | */ |
@@ -1343,8 +1386,6 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) | |||
1343 | sync_dirty_buffer(bh); | 1386 | sync_dirty_buffer(bh); |
1344 | } | 1387 | } |
1345 | 1388 | ||
1346 | kfree(device->name); | ||
1347 | kfree(device); | ||
1348 | ret = 0; | 1389 | ret = 0; |
1349 | 1390 | ||
1350 | error_brelse: | 1391 | error_brelse: |
@@ -1358,8 +1399,10 @@ out: | |||
1358 | return ret; | 1399 | return ret; |
1359 | error_undo: | 1400 | error_undo: |
1360 | if (device->writeable) { | 1401 | if (device->writeable) { |
1402 | lock_chunks(root); | ||
1361 | list_add(&device->dev_alloc_list, | 1403 | list_add(&device->dev_alloc_list, |
1362 | &root->fs_info->fs_devices->alloc_list); | 1404 | &root->fs_info->fs_devices->alloc_list); |
1405 | unlock_chunks(root); | ||
1363 | root->fs_info->fs_devices->rw_devices++; | 1406 | root->fs_info->fs_devices->rw_devices++; |
1364 | } | 1407 | } |
1365 | goto error_brelse; | 1408 | goto error_brelse; |
@@ -1399,7 +1442,12 @@ static int btrfs_prepare_sprout(struct btrfs_trans_handle *trans, | |||
1399 | INIT_LIST_HEAD(&seed_devices->devices); | 1442 | INIT_LIST_HEAD(&seed_devices->devices); |
1400 | INIT_LIST_HEAD(&seed_devices->alloc_list); | 1443 | INIT_LIST_HEAD(&seed_devices->alloc_list); |
1401 | mutex_init(&seed_devices->device_list_mutex); | 1444 | mutex_init(&seed_devices->device_list_mutex); |
1402 | list_splice_init(&fs_devices->devices, &seed_devices->devices); | 1445 | |
1446 | mutex_lock(&root->fs_info->fs_devices->device_list_mutex); | ||
1447 | list_splice_init_rcu(&fs_devices->devices, &seed_devices->devices, | ||
1448 | synchronize_rcu); | ||
1449 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); | ||
1450 | |||
1403 | list_splice_init(&fs_devices->alloc_list, &seed_devices->alloc_list); | 1451 | list_splice_init(&fs_devices->alloc_list, &seed_devices->alloc_list); |
1404 | list_for_each_entry(device, &seed_devices->devices, dev_list) { | 1452 | list_for_each_entry(device, &seed_devices->devices, dev_list) { |
1405 | device->fs_devices = seed_devices; | 1453 | device->fs_devices = seed_devices; |
@@ -1596,7 +1644,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) | |||
1596 | * half setup | 1644 | * half setup |
1597 | */ | 1645 | */ |
1598 | mutex_lock(&root->fs_info->fs_devices->device_list_mutex); | 1646 | mutex_lock(&root->fs_info->fs_devices->device_list_mutex); |
1599 | list_add(&device->dev_list, &root->fs_info->fs_devices->devices); | 1647 | list_add_rcu(&device->dev_list, &root->fs_info->fs_devices->devices); |
1600 | list_add(&device->dev_alloc_list, | 1648 | list_add(&device->dev_alloc_list, |
1601 | &root->fs_info->fs_devices->alloc_list); | 1649 | &root->fs_info->fs_devices->alloc_list); |
1602 | root->fs_info->fs_devices->num_devices++; | 1650 | root->fs_info->fs_devices->num_devices++; |
@@ -1754,10 +1802,9 @@ static int btrfs_free_chunk(struct btrfs_trans_handle *trans, | |||
1754 | BUG_ON(ret); | 1802 | BUG_ON(ret); |
1755 | 1803 | ||
1756 | ret = btrfs_del_item(trans, root, path); | 1804 | ret = btrfs_del_item(trans, root, path); |
1757 | BUG_ON(ret); | ||
1758 | 1805 | ||
1759 | btrfs_free_path(path); | 1806 | btrfs_free_path(path); |
1760 | return 0; | 1807 | return ret; |
1761 | } | 1808 | } |
1762 | 1809 | ||
1763 | static int btrfs_del_sys_chunk(struct btrfs_root *root, u64 chunk_objectid, u64 | 1810 | static int btrfs_del_sys_chunk(struct btrfs_root *root, u64 chunk_objectid, u64 |