aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/volumes.c
diff options
context:
space:
mode:
authorXiao Guangrong <xiaoguangrong@cn.fujitsu.com>2011-04-20 06:09:16 -0400
committerChris Mason <chris.mason@oracle.com>2011-05-23 13:24:43 -0400
commit1f78160ce1b1b8e657e2248118c4d91f881763f0 (patch)
tree98c5496a9ab3e77e4cd682c0487f4c0127198396 /fs/btrfs/volumes.c
parent46224705656633466ca7dc71d81b3c0abc76cae4 (diff)
Btrfs: using rcu lock in the reader side of devices list
fs_devices->devices is only updated on remove and add device paths, so we can use rcu to protect it in the reader side Signed-off-by: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r--fs/btrfs/volumes.c85
1 files changed, 59 insertions, 26 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 0b5ca273726..e7844f8a347 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -363,7 +363,7 @@ static noinline int device_list_add(const char *path,
363 INIT_LIST_HEAD(&device->dev_alloc_list); 363 INIT_LIST_HEAD(&device->dev_alloc_list);
364 364
365 mutex_lock(&fs_devices->device_list_mutex); 365 mutex_lock(&fs_devices->device_list_mutex);
366 list_add(&device->dev_list, &fs_devices->devices); 366 list_add_rcu(&device->dev_list, &fs_devices->devices);
367 mutex_unlock(&fs_devices->device_list_mutex); 367 mutex_unlock(&fs_devices->device_list_mutex);
368 368
369 device->fs_devices = fs_devices; 369 device->fs_devices = fs_devices;
@@ -471,6 +471,29 @@ again:
471 return 0; 471 return 0;
472} 472}
473 473
474static void __free_device(struct work_struct *work)
475{
476 struct btrfs_device *device;
477
478 device = container_of(work, struct btrfs_device, rcu_work);
479
480 if (device->bdev)
481 blkdev_put(device->bdev, device->mode);
482
483 kfree(device->name);
484 kfree(device);
485}
486
487static void free_device(struct rcu_head *head)
488{
489 struct btrfs_device *device;
490
491 device = container_of(head, struct btrfs_device, rcu);
492
493 INIT_WORK(&device->rcu_work, __free_device);
494 schedule_work(&device->rcu_work);
495}
496
474static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices) 497static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
475{ 498{
476 struct btrfs_device *device; 499 struct btrfs_device *device;
@@ -480,18 +503,27 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
480 503
481 mutex_lock(&fs_devices->device_list_mutex); 504 mutex_lock(&fs_devices->device_list_mutex);
482 list_for_each_entry(device, &fs_devices->devices, dev_list) { 505 list_for_each_entry(device, &fs_devices->devices, dev_list) {
483 if (device->bdev) { 506 struct btrfs_device *new_device;
484 blkdev_put(device->bdev, device->mode); 507
508 if (device->bdev)
485 fs_devices->open_devices--; 509 fs_devices->open_devices--;
486 } 510
487 if (device->writeable) { 511 if (device->writeable) {
488 list_del_init(&device->dev_alloc_list); 512 list_del_init(&device->dev_alloc_list);
489 fs_devices->rw_devices--; 513 fs_devices->rw_devices--;
490 } 514 }
491 515
492 device->bdev = NULL; 516 new_device = kmalloc(sizeof(*new_device), GFP_NOFS);
493 device->writeable = 0; 517 BUG_ON(!new_device);
494 device->in_fs_metadata = 0; 518 memcpy(new_device, device, sizeof(*new_device));
519 new_device->name = kstrdup(device->name, GFP_NOFS);
520 BUG_ON(!new_device->name);
521 new_device->bdev = NULL;
522 new_device->writeable = 0;
523 new_device->in_fs_metadata = 0;
524 list_replace_rcu(&device->dev_list, &new_device->dev_list);
525
526 call_rcu(&device->rcu, free_device);
495 } 527 }
496 mutex_unlock(&fs_devices->device_list_mutex); 528 mutex_unlock(&fs_devices->device_list_mutex);
497 529
@@ -1204,11 +1236,13 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
1204 struct block_device *bdev; 1236 struct block_device *bdev;
1205 struct buffer_head *bh = NULL; 1237 struct buffer_head *bh = NULL;
1206 struct btrfs_super_block *disk_super; 1238 struct btrfs_super_block *disk_super;
1239 struct btrfs_fs_devices *cur_devices;
1207 u64 all_avail; 1240 u64 all_avail;
1208 u64 devid; 1241 u64 devid;
1209 u64 num_devices; 1242 u64 num_devices;
1210 u8 *dev_uuid; 1243 u8 *dev_uuid;
1211 int ret = 0; 1244 int ret = 0;
1245 bool clear_super = false;
1212 1246
1213 mutex_lock(&uuid_mutex); 1247 mutex_lock(&uuid_mutex);
1214 mutex_lock(&root->fs_info->volume_mutex); 1248 mutex_lock(&root->fs_info->volume_mutex);
@@ -1294,6 +1328,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
1294 list_del_init(&device->dev_alloc_list); 1328 list_del_init(&device->dev_alloc_list);
1295 unlock_chunks(root); 1329 unlock_chunks(root);
1296 root->fs_info->fs_devices->rw_devices--; 1330 root->fs_info->fs_devices->rw_devices--;
1331 clear_super = true;
1297 } 1332 }
1298 1333
1299 ret = btrfs_shrink_device(device, 0); 1334 ret = btrfs_shrink_device(device, 0);
@@ -1304,16 +1339,15 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
1304 if (ret) 1339 if (ret)
1305 goto error_undo; 1340 goto error_undo;
1306 1341
1307 device->in_fs_metadata = 0;
1308
1309 /* 1342 /*
1310 * the device list mutex makes sure that we don't change 1343 * the device list mutex makes sure that we don't change
1311 * the device list while someone else is writing out all 1344 * the device list while someone else is writing out all
1312 * the device supers. 1345 * the device supers.
1313 */ 1346 */
1347
1348 cur_devices = device->fs_devices;
1314 mutex_lock(&root->fs_info->fs_devices->device_list_mutex); 1349 mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
1315 list_del_init(&device->dev_list); 1350 list_del_rcu(&device->dev_list);
1316 mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
1317 1351
1318 device->fs_devices->num_devices--; 1352 device->fs_devices->num_devices--;
1319 1353
@@ -1327,36 +1361,36 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
1327 if (device->bdev == root->fs_info->fs_devices->latest_bdev) 1361 if (device->bdev == root->fs_info->fs_devices->latest_bdev)
1328 root->fs_info->fs_devices->latest_bdev = next_device->bdev; 1362 root->fs_info->fs_devices->latest_bdev = next_device->bdev;
1329 1363
1330 if (device->bdev) { 1364 if (device->bdev)
1331 blkdev_put(device->bdev, device->mode);
1332 device->bdev = NULL;
1333 device->fs_devices->open_devices--; 1365 device->fs_devices->open_devices--;
1334 } 1366
1367 call_rcu(&device->rcu, free_device);
1368 mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
1335 1369
1336 num_devices = btrfs_super_num_devices(&root->fs_info->super_copy) - 1; 1370 num_devices = btrfs_super_num_devices(&root->fs_info->super_copy) - 1;
1337 btrfs_set_super_num_devices(&root->fs_info->super_copy, num_devices); 1371 btrfs_set_super_num_devices(&root->fs_info->super_copy, num_devices);
1338 1372
1339 if (device->fs_devices->open_devices == 0) { 1373 if (cur_devices->open_devices == 0) {
1340 struct btrfs_fs_devices *fs_devices; 1374 struct btrfs_fs_devices *fs_devices;
1341 fs_devices = root->fs_info->fs_devices; 1375 fs_devices = root->fs_info->fs_devices;
1342 while (fs_devices) { 1376 while (fs_devices) {
1343 if (fs_devices->seed == device->fs_devices) 1377 if (fs_devices->seed == cur_devices)
1344 break; 1378 break;
1345 fs_devices = fs_devices->seed; 1379 fs_devices = fs_devices->seed;
1346 } 1380 }
1347 fs_devices->seed = device->fs_devices->seed; 1381 fs_devices->seed = cur_devices->seed;
1348 device->fs_devices->seed = NULL; 1382 cur_devices->seed = NULL;
1349 lock_chunks(root); 1383 lock_chunks(root);
1350 __btrfs_close_devices(device->fs_devices); 1384 __btrfs_close_devices(cur_devices);
1351 unlock_chunks(root); 1385 unlock_chunks(root);
1352 free_fs_devices(device->fs_devices); 1386 free_fs_devices(cur_devices);
1353 } 1387 }
1354 1388
1355 /* 1389 /*
1356 * at this point, the device is zero sized. We want to 1390 * at this point, the device is zero sized. We want to
1357 * remove it from the devices list and zero out the old super 1391 * remove it from the devices list and zero out the old super
1358 */ 1392 */
1359 if (device->writeable) { 1393 if (clear_super) {
1360 /* make sure this device isn't detected as part of 1394 /* make sure this device isn't detected as part of
1361 * the FS anymore 1395 * the FS anymore
1362 */ 1396 */
@@ -1365,8 +1399,6 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
1365 sync_dirty_buffer(bh); 1399 sync_dirty_buffer(bh);
1366 } 1400 }
1367 1401
1368 kfree(device->name);
1369 kfree(device);
1370 ret = 0; 1402 ret = 0;
1371 1403
1372error_brelse: 1404error_brelse:
@@ -1425,7 +1457,8 @@ static int btrfs_prepare_sprout(struct btrfs_trans_handle *trans,
1425 mutex_init(&seed_devices->device_list_mutex); 1457 mutex_init(&seed_devices->device_list_mutex);
1426 1458
1427 mutex_lock(&root->fs_info->fs_devices->device_list_mutex); 1459 mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
1428 list_splice_init(&fs_devices->devices, &seed_devices->devices); 1460 list_splice_init_rcu(&fs_devices->devices, &seed_devices->devices,
1461 synchronize_rcu);
1429 mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); 1462 mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
1430 1463
1431 list_splice_init(&fs_devices->alloc_list, &seed_devices->alloc_list); 1464 list_splice_init(&fs_devices->alloc_list, &seed_devices->alloc_list);
@@ -1624,7 +1657,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
1624 * half setup 1657 * half setup
1625 */ 1658 */
1626 mutex_lock(&root->fs_info->fs_devices->device_list_mutex); 1659 mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
1627 list_add(&device->dev_list, &root->fs_info->fs_devices->devices); 1660 list_add_rcu(&device->dev_list, &root->fs_info->fs_devices->devices);
1628 list_add(&device->dev_alloc_list, 1661 list_add(&device->dev_alloc_list,
1629 &root->fs_info->fs_devices->alloc_list); 1662 &root->fs_info->fs_devices->alloc_list);
1630 root->fs_info->fs_devices->num_devices++; 1663 root->fs_info->fs_devices->num_devices++;