diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-07-08 14:19:17 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:04 -0400 |
commit | 7d9eb12c8739e7dc80c78c6b3596f912ecd8f941 (patch) | |
tree | 000608285b44920f22e0888753b36299bc762cef /fs/btrfs/volumes.c | |
parent | a7a16fd772620605c76e8ac8bdbc8ccc9e3df1a0 (diff) |
Btrfs: Add locking around volume management (device add/remove/balance)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 58 |
1 files changed, 44 insertions, 14 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 4e7cee27aab5..5e6ee7a6f738 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -56,6 +56,18 @@ void btrfs_unlock_volumes(void) | |||
56 | mutex_unlock(&uuid_mutex); | 56 | mutex_unlock(&uuid_mutex); |
57 | } | 57 | } |
58 | 58 | ||
59 | static void lock_chunks(struct btrfs_root *root) | ||
60 | { | ||
61 | mutex_lock(&root->fs_info->alloc_mutex); | ||
62 | mutex_lock(&root->fs_info->chunk_mutex); | ||
63 | } | ||
64 | |||
65 | static void unlock_chunks(struct btrfs_root *root) | ||
66 | { | ||
67 | mutex_unlock(&root->fs_info->alloc_mutex); | ||
68 | mutex_unlock(&root->fs_info->chunk_mutex); | ||
69 | } | ||
70 | |||
59 | int btrfs_cleanup_fs_uuids(void) | 71 | int btrfs_cleanup_fs_uuids(void) |
60 | { | 72 | { |
61 | struct btrfs_fs_devices *fs_devices; | 73 | struct btrfs_fs_devices *fs_devices; |
@@ -822,6 +834,7 @@ static int btrfs_rm_dev_item(struct btrfs_root *root, | |||
822 | key.objectid = BTRFS_DEV_ITEMS_OBJECTID; | 834 | key.objectid = BTRFS_DEV_ITEMS_OBJECTID; |
823 | key.type = BTRFS_DEV_ITEM_KEY; | 835 | key.type = BTRFS_DEV_ITEM_KEY; |
824 | key.offset = device->devid; | 836 | key.offset = device->devid; |
837 | lock_chunks(root); | ||
825 | 838 | ||
826 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); | 839 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); |
827 | if (ret < 0) | 840 | if (ret < 0) |
@@ -856,6 +869,7 @@ static int btrfs_rm_dev_item(struct btrfs_root *root, | |||
856 | total_bytes - 1); | 869 | total_bytes - 1); |
857 | out: | 870 | out: |
858 | btrfs_free_path(path); | 871 | btrfs_free_path(path); |
872 | unlock_chunks(root); | ||
859 | btrfs_commit_transaction(trans, root); | 873 | btrfs_commit_transaction(trans, root); |
860 | return ret; | 874 | return ret; |
861 | } | 875 | } |
@@ -870,9 +884,8 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) | |||
870 | u64 devid; | 884 | u64 devid; |
871 | int ret = 0; | 885 | int ret = 0; |
872 | 886 | ||
873 | mutex_lock(&root->fs_info->alloc_mutex); | ||
874 | mutex_lock(&root->fs_info->chunk_mutex); | ||
875 | mutex_lock(&uuid_mutex); | 887 | mutex_lock(&uuid_mutex); |
888 | mutex_lock(&root->fs_info->volume_mutex); | ||
876 | 889 | ||
877 | all_avail = root->fs_info->avail_data_alloc_bits | | 890 | all_avail = root->fs_info->avail_data_alloc_bits | |
878 | root->fs_info->avail_system_alloc_bits | | 891 | root->fs_info->avail_system_alloc_bits | |
@@ -988,9 +1001,8 @@ error_close: | |||
988 | if (bdev) | 1001 | if (bdev) |
989 | close_bdev_excl(bdev); | 1002 | close_bdev_excl(bdev); |
990 | out: | 1003 | out: |
1004 | mutex_unlock(&root->fs_info->volume_mutex); | ||
991 | mutex_unlock(&uuid_mutex); | 1005 | mutex_unlock(&uuid_mutex); |
992 | mutex_unlock(&root->fs_info->chunk_mutex); | ||
993 | mutex_unlock(&root->fs_info->alloc_mutex); | ||
994 | return ret; | 1006 | return ret; |
995 | } | 1007 | } |
996 | 1008 | ||
@@ -1010,10 +1022,10 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) | |||
1010 | return -EIO; | 1022 | return -EIO; |
1011 | } | 1023 | } |
1012 | 1024 | ||
1013 | mutex_lock(&root->fs_info->alloc_mutex); | 1025 | mutex_lock(&root->fs_info->volume_mutex); |
1014 | mutex_lock(&root->fs_info->chunk_mutex); | ||
1015 | 1026 | ||
1016 | trans = btrfs_start_transaction(root, 1); | 1027 | trans = btrfs_start_transaction(root, 1); |
1028 | lock_chunks(root); | ||
1017 | devices = &root->fs_info->fs_devices->devices; | 1029 | devices = &root->fs_info->fs_devices->devices; |
1018 | list_for_each(cur, devices) { | 1030 | list_for_each(cur, devices) { |
1019 | device = list_entry(cur, struct btrfs_device, dev_list); | 1031 | device = list_entry(cur, struct btrfs_device, dev_list); |
@@ -1065,9 +1077,9 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) | |||
1065 | root->fs_info->fs_devices->num_devices++; | 1077 | root->fs_info->fs_devices->num_devices++; |
1066 | root->fs_info->fs_devices->open_devices++; | 1078 | root->fs_info->fs_devices->open_devices++; |
1067 | out: | 1079 | out: |
1080 | unlock_chunks(root); | ||
1068 | btrfs_end_transaction(trans, root); | 1081 | btrfs_end_transaction(trans, root); |
1069 | mutex_unlock(&root->fs_info->chunk_mutex); | 1082 | mutex_unlock(&root->fs_info->volume_mutex); |
1070 | mutex_unlock(&root->fs_info->alloc_mutex); | ||
1071 | 1083 | ||
1072 | return ret; | 1084 | return ret; |
1073 | 1085 | ||
@@ -1122,7 +1134,7 @@ out: | |||
1122 | return ret; | 1134 | return ret; |
1123 | } | 1135 | } |
1124 | 1136 | ||
1125 | int btrfs_grow_device(struct btrfs_trans_handle *trans, | 1137 | static int __btrfs_grow_device(struct btrfs_trans_handle *trans, |
1126 | struct btrfs_device *device, u64 new_size) | 1138 | struct btrfs_device *device, u64 new_size) |
1127 | { | 1139 | { |
1128 | struct btrfs_super_block *super_copy = | 1140 | struct btrfs_super_block *super_copy = |
@@ -1134,6 +1146,16 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans, | |||
1134 | return btrfs_update_device(trans, device); | 1146 | return btrfs_update_device(trans, device); |
1135 | } | 1147 | } |
1136 | 1148 | ||
1149 | int btrfs_grow_device(struct btrfs_trans_handle *trans, | ||
1150 | struct btrfs_device *device, u64 new_size) | ||
1151 | { | ||
1152 | int ret; | ||
1153 | lock_chunks(device->dev_root); | ||
1154 | ret = __btrfs_grow_device(trans, device, new_size); | ||
1155 | unlock_chunks(device->dev_root); | ||
1156 | return ret; | ||
1157 | } | ||
1158 | |||
1137 | static int btrfs_free_chunk(struct btrfs_trans_handle *trans, | 1159 | static int btrfs_free_chunk(struct btrfs_trans_handle *trans, |
1138 | struct btrfs_root *root, | 1160 | struct btrfs_root *root, |
1139 | u64 chunk_tree, u64 chunk_objectid, | 1161 | u64 chunk_tree, u64 chunk_objectid, |
@@ -1234,6 +1256,8 @@ int btrfs_relocate_chunk(struct btrfs_root *root, | |||
1234 | trans = btrfs_start_transaction(root, 1); | 1256 | trans = btrfs_start_transaction(root, 1); |
1235 | BUG_ON(!trans); | 1257 | BUG_ON(!trans); |
1236 | 1258 | ||
1259 | lock_chunks(root); | ||
1260 | |||
1237 | /* | 1261 | /* |
1238 | * step two, delete the device extents and the | 1262 | * step two, delete the device extents and the |
1239 | * chunk tree entries | 1263 | * chunk tree entries |
@@ -1278,6 +1302,7 @@ int btrfs_relocate_chunk(struct btrfs_root *root, | |||
1278 | /* once for us */ | 1302 | /* once for us */ |
1279 | free_extent_map(em); | 1303 | free_extent_map(em); |
1280 | 1304 | ||
1305 | unlock_chunks(root); | ||
1281 | btrfs_end_transaction(trans, root); | 1306 | btrfs_end_transaction(trans, root); |
1282 | return 0; | 1307 | return 0; |
1283 | } | 1308 | } |
@@ -1308,8 +1333,7 @@ int btrfs_balance(struct btrfs_root *dev_root) | |||
1308 | struct btrfs_key found_key; | 1333 | struct btrfs_key found_key; |
1309 | 1334 | ||
1310 | 1335 | ||
1311 | BUG(); /* FIXME, needs locking */ | 1336 | mutex_lock(&dev_root->fs_info->volume_mutex); |
1312 | |||
1313 | dev_root = dev_root->fs_info->dev_root; | 1337 | dev_root = dev_root->fs_info->dev_root; |
1314 | 1338 | ||
1315 | /* step one make some room on all the devices */ | 1339 | /* step one make some room on all the devices */ |
@@ -1355,13 +1379,14 @@ int btrfs_balance(struct btrfs_root *dev_root) | |||
1355 | 1379 | ||
1356 | ret = btrfs_previous_item(chunk_root, path, 0, | 1380 | ret = btrfs_previous_item(chunk_root, path, 0, |
1357 | BTRFS_CHUNK_ITEM_KEY); | 1381 | BTRFS_CHUNK_ITEM_KEY); |
1358 | if (ret) { | 1382 | if (ret) |
1359 | break; | 1383 | break; |
1360 | } | 1384 | |
1361 | btrfs_item_key_to_cpu(path->nodes[0], &found_key, | 1385 | btrfs_item_key_to_cpu(path->nodes[0], &found_key, |
1362 | path->slots[0]); | 1386 | path->slots[0]); |
1363 | if (found_key.objectid != key.objectid) | 1387 | if (found_key.objectid != key.objectid) |
1364 | break; | 1388 | break; |
1389 | |||
1365 | chunk = btrfs_item_ptr(path->nodes[0], | 1390 | chunk = btrfs_item_ptr(path->nodes[0], |
1366 | path->slots[0], | 1391 | path->slots[0], |
1367 | struct btrfs_chunk); | 1392 | struct btrfs_chunk); |
@@ -1370,16 +1395,17 @@ int btrfs_balance(struct btrfs_root *dev_root) | |||
1370 | if (key.offset == 0) | 1395 | if (key.offset == 0) |
1371 | break; | 1396 | break; |
1372 | 1397 | ||
1398 | btrfs_release_path(chunk_root, path); | ||
1373 | ret = btrfs_relocate_chunk(chunk_root, | 1399 | ret = btrfs_relocate_chunk(chunk_root, |
1374 | chunk_root->root_key.objectid, | 1400 | chunk_root->root_key.objectid, |
1375 | found_key.objectid, | 1401 | found_key.objectid, |
1376 | found_key.offset); | 1402 | found_key.offset); |
1377 | BUG_ON(ret); | 1403 | BUG_ON(ret); |
1378 | btrfs_release_path(chunk_root, path); | ||
1379 | } | 1404 | } |
1380 | ret = 0; | 1405 | ret = 0; |
1381 | error: | 1406 | error: |
1382 | btrfs_free_path(path); | 1407 | btrfs_free_path(path); |
1408 | mutex_unlock(&dev_root->fs_info->volume_mutex); | ||
1383 | return ret; | 1409 | return ret; |
1384 | } | 1410 | } |
1385 | 1411 | ||
@@ -1419,14 +1445,18 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) | |||
1419 | 1445 | ||
1420 | path->reada = 2; | 1446 | path->reada = 2; |
1421 | 1447 | ||
1448 | lock_chunks(root); | ||
1449 | |||
1422 | device->total_bytes = new_size; | 1450 | device->total_bytes = new_size; |
1423 | ret = btrfs_update_device(trans, device); | 1451 | ret = btrfs_update_device(trans, device); |
1424 | if (ret) { | 1452 | if (ret) { |
1453 | unlock_chunks(root); | ||
1425 | btrfs_end_transaction(trans, root); | 1454 | btrfs_end_transaction(trans, root); |
1426 | goto done; | 1455 | goto done; |
1427 | } | 1456 | } |
1428 | WARN_ON(diff > old_total); | 1457 | WARN_ON(diff > old_total); |
1429 | btrfs_set_super_total_bytes(super_copy, old_total - diff); | 1458 | btrfs_set_super_total_bytes(super_copy, old_total - diff); |
1459 | unlock_chunks(root); | ||
1430 | btrfs_end_transaction(trans, root); | 1460 | btrfs_end_transaction(trans, root); |
1431 | 1461 | ||
1432 | key.objectid = device->devid; | 1462 | key.objectid = device->devid; |