Btrfs: Add locking around volume management (device add/remove/balance)

Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
Chris Mason
2008-07-08 14:19:17 -04:00
parent a7a16fd772
commit 7d9eb12c87
6 changed files with 104 additions and 41 deletions

View File

@@ -56,6 +56,18 @@ void btrfs_unlock_volumes(void)
mutex_unlock(&uuid_mutex);
}
static void lock_chunks(struct btrfs_root *root)
{
mutex_lock(&root->fs_info->alloc_mutex);
mutex_lock(&root->fs_info->chunk_mutex);
}
static void unlock_chunks(struct btrfs_root *root)
{
mutex_unlock(&root->fs_info->alloc_mutex);
mutex_unlock(&root->fs_info->chunk_mutex);
}
int btrfs_cleanup_fs_uuids(void)
{
struct btrfs_fs_devices *fs_devices;
@@ -822,6 +834,7 @@ static int btrfs_rm_dev_item(struct btrfs_root *root,
key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
key.type = BTRFS_DEV_ITEM_KEY;
key.offset = device->devid;
lock_chunks(root);
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
if (ret < 0)
@@ -856,6 +869,7 @@ static int btrfs_rm_dev_item(struct btrfs_root *root,
total_bytes - 1);
out:
btrfs_free_path(path);
unlock_chunks(root);
btrfs_commit_transaction(trans, root);
return ret;
}
@@ -870,9 +884,8 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
u64 devid;
int ret = 0;
mutex_lock(&root->fs_info->alloc_mutex);
mutex_lock(&root->fs_info->chunk_mutex);
mutex_lock(&uuid_mutex);
mutex_lock(&root->fs_info->volume_mutex);
all_avail = root->fs_info->avail_data_alloc_bits |
root->fs_info->avail_system_alloc_bits |
@@ -988,9 +1001,8 @@ error_close:
if (bdev)
close_bdev_excl(bdev);
out:
mutex_unlock(&root->fs_info->volume_mutex);
mutex_unlock(&uuid_mutex);
mutex_unlock(&root->fs_info->chunk_mutex);
mutex_unlock(&root->fs_info->alloc_mutex);
return ret;
}
@@ -1010,10 +1022,10 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
return -EIO;
}
mutex_lock(&root->fs_info->alloc_mutex);
mutex_lock(&root->fs_info->chunk_mutex);
mutex_lock(&root->fs_info->volume_mutex);
trans = btrfs_start_transaction(root, 1);
lock_chunks(root);
devices = &root->fs_info->fs_devices->devices;
list_for_each(cur, devices) {
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)
root->fs_info->fs_devices->num_devices++;
root->fs_info->fs_devices->open_devices++;
out:
unlock_chunks(root);
btrfs_end_transaction(trans, root);
mutex_unlock(&root->fs_info->chunk_mutex);
mutex_unlock(&root->fs_info->alloc_mutex);
mutex_unlock(&root->fs_info->volume_mutex);
return ret;
@@ -1122,7 +1134,7 @@ out:
return ret;
}
int btrfs_grow_device(struct btrfs_trans_handle *trans,
static int __btrfs_grow_device(struct btrfs_trans_handle *trans,
struct btrfs_device *device, u64 new_size)
{
struct btrfs_super_block *super_copy =
@@ -1134,6 +1146,16 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans,
return btrfs_update_device(trans, device);
}
int btrfs_grow_device(struct btrfs_trans_handle *trans,
struct btrfs_device *device, u64 new_size)
{
int ret;
lock_chunks(device->dev_root);
ret = __btrfs_grow_device(trans, device, new_size);
unlock_chunks(device->dev_root);
return ret;
}
static int btrfs_free_chunk(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 chunk_tree, u64 chunk_objectid,
@@ -1234,6 +1256,8 @@ int btrfs_relocate_chunk(struct btrfs_root *root,
trans = btrfs_start_transaction(root, 1);
BUG_ON(!trans);
lock_chunks(root);
/*
* step two, delete the device extents and the
* chunk tree entries
@@ -1278,6 +1302,7 @@ int btrfs_relocate_chunk(struct btrfs_root *root,
/* once for us */
free_extent_map(em);
unlock_chunks(root);
btrfs_end_transaction(trans, root);
return 0;
}
@@ -1308,8 +1333,7 @@ int btrfs_balance(struct btrfs_root *dev_root)
struct btrfs_key found_key;
BUG(); /* FIXME, needs locking */
mutex_lock(&dev_root->fs_info->volume_mutex);
dev_root = dev_root->fs_info->dev_root;
/* step one make some room on all the devices */
@@ -1355,13 +1379,14 @@ int btrfs_balance(struct btrfs_root *dev_root)
ret = btrfs_previous_item(chunk_root, path, 0,
BTRFS_CHUNK_ITEM_KEY);
if (ret) {
if (ret)
break;
}
btrfs_item_key_to_cpu(path->nodes[0], &found_key,
path->slots[0]);
if (found_key.objectid != key.objectid)
break;
chunk = btrfs_item_ptr(path->nodes[0],
path->slots[0],
struct btrfs_chunk);
@@ -1370,16 +1395,17 @@ int btrfs_balance(struct btrfs_root *dev_root)
if (key.offset == 0)
break;
btrfs_release_path(chunk_root, path);
ret = btrfs_relocate_chunk(chunk_root,
chunk_root->root_key.objectid,
found_key.objectid,
found_key.offset);
BUG_ON(ret);
btrfs_release_path(chunk_root, path);
}
ret = 0;
error:
btrfs_free_path(path);
mutex_unlock(&dev_root->fs_info->volume_mutex);
return ret;
}
@@ -1419,14 +1445,18 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
path->reada = 2;
lock_chunks(root);
device->total_bytes = new_size;
ret = btrfs_update_device(trans, device);
if (ret) {
unlock_chunks(root);
btrfs_end_transaction(trans, root);
goto done;
}
WARN_ON(diff > old_total);
btrfs_set_super_total_bytes(super_copy, old_total - diff);
unlock_chunks(root);
btrfs_end_transaction(trans, root);
key.objectid = device->devid;