mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-20 00:11:22 +00:00
Fix btrfs_open_devices to deal with changes since the scan ioctls
Devices can change after the scan ioctls are done, and btrfs_open_devices needs to be able to verify them as they are opened and used by the FS. Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
parent
dfe2502068
commit
a0af469b58
@ -1266,10 +1266,10 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
|||||||
|
|
||||||
btrfs_parse_options(options, tree_root, NULL);
|
btrfs_parse_options(options, tree_root, NULL);
|
||||||
|
|
||||||
if (btrfs_super_num_devices(disk_super) > fs_devices->num_devices) {
|
if (btrfs_super_num_devices(disk_super) > fs_devices->open_devices) {
|
||||||
printk("Btrfs: wanted %llu devices, but found %llu\n",
|
printk("Btrfs: wanted %llu devices, but found %llu\n",
|
||||||
(unsigned long long)btrfs_super_num_devices(disk_super),
|
(unsigned long long)btrfs_super_num_devices(disk_super),
|
||||||
(unsigned long long)fs_devices->num_devices);
|
(unsigned long long)fs_devices->open_devices);
|
||||||
if (btrfs_test_opt(tree_root, DEGRADED))
|
if (btrfs_test_opt(tree_root, DEGRADED))
|
||||||
printk("continuing in degraded mode\n");
|
printk("continuing in degraded mode\n");
|
||||||
else {
|
else {
|
||||||
|
@ -71,6 +71,7 @@ int btrfs_cleanup_fs_uuids(void)
|
|||||||
dev_list);
|
dev_list);
|
||||||
if (dev->bdev) {
|
if (dev->bdev) {
|
||||||
close_bdev_excl(dev->bdev);
|
close_bdev_excl(dev->bdev);
|
||||||
|
fs_devices->open_devices--;
|
||||||
}
|
}
|
||||||
list_del(&dev->dev_list);
|
list_del(&dev->dev_list);
|
||||||
kfree(dev->name);
|
kfree(dev->name);
|
||||||
@ -174,9 +175,10 @@ again:
|
|||||||
list_for_each(cur, head) {
|
list_for_each(cur, head) {
|
||||||
device = list_entry(cur, struct btrfs_device, dev_list);
|
device = list_entry(cur, struct btrfs_device, dev_list);
|
||||||
if (!device->in_fs_metadata) {
|
if (!device->in_fs_metadata) {
|
||||||
printk("getting rid of extra dev %s\n", device->name);
|
if (device->bdev) {
|
||||||
if (device->bdev)
|
|
||||||
close_bdev_excl(device->bdev);
|
close_bdev_excl(device->bdev);
|
||||||
|
fs_devices->open_devices--;
|
||||||
|
}
|
||||||
list_del(&device->dev_list);
|
list_del(&device->dev_list);
|
||||||
list_del(&device->dev_alloc_list);
|
list_del(&device->dev_alloc_list);
|
||||||
fs_devices->num_devices--;
|
fs_devices->num_devices--;
|
||||||
@ -188,6 +190,7 @@ printk("getting rid of extra dev %s\n", device->name);
|
|||||||
mutex_unlock(&uuid_mutex);
|
mutex_unlock(&uuid_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
|
int btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
|
||||||
{
|
{
|
||||||
struct list_head *head = &fs_devices->devices;
|
struct list_head *head = &fs_devices->devices;
|
||||||
@ -199,10 +202,12 @@ int btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
|
|||||||
device = list_entry(cur, struct btrfs_device, dev_list);
|
device = list_entry(cur, struct btrfs_device, dev_list);
|
||||||
if (device->bdev) {
|
if (device->bdev) {
|
||||||
close_bdev_excl(device->bdev);
|
close_bdev_excl(device->bdev);
|
||||||
|
fs_devices->open_devices--;
|
||||||
}
|
}
|
||||||
device->bdev = NULL;
|
device->bdev = NULL;
|
||||||
device->in_fs_metadata = 0;
|
device->in_fs_metadata = 0;
|
||||||
}
|
}
|
||||||
|
fs_devices->mounted = 0;
|
||||||
mutex_unlock(&uuid_mutex);
|
mutex_unlock(&uuid_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -214,9 +219,19 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
|
|||||||
struct list_head *head = &fs_devices->devices;
|
struct list_head *head = &fs_devices->devices;
|
||||||
struct list_head *cur;
|
struct list_head *cur;
|
||||||
struct btrfs_device *device;
|
struct btrfs_device *device;
|
||||||
int ret;
|
struct block_device *latest_bdev = NULL;
|
||||||
|
struct buffer_head *bh;
|
||||||
|
struct btrfs_super_block *disk_super;
|
||||||
|
u64 latest_devid = 0;
|
||||||
|
u64 latest_transid = 0;
|
||||||
|
u64 transid;
|
||||||
|
u64 devid;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
mutex_lock(&uuid_mutex);
|
mutex_lock(&uuid_mutex);
|
||||||
|
if (fs_devices->mounted)
|
||||||
|
goto out;
|
||||||
|
|
||||||
list_for_each(cur, head) {
|
list_for_each(cur, head) {
|
||||||
device = list_entry(cur, struct btrfs_device, dev_list);
|
device = list_entry(cur, struct btrfs_device, dev_list);
|
||||||
if (device->bdev)
|
if (device->bdev)
|
||||||
@ -229,21 +244,52 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
|
|||||||
|
|
||||||
if (IS_ERR(bdev)) {
|
if (IS_ERR(bdev)) {
|
||||||
printk("open %s failed\n", device->name);
|
printk("open %s failed\n", device->name);
|
||||||
ret = PTR_ERR(bdev);
|
goto error;
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
set_blocksize(bdev, 4096);
|
set_blocksize(bdev, 4096);
|
||||||
if (device->devid == fs_devices->latest_devid)
|
|
||||||
fs_devices->latest_bdev = bdev;
|
bh = __bread(bdev, BTRFS_SUPER_INFO_OFFSET / 4096, 4096);
|
||||||
|
if (!bh)
|
||||||
|
goto error_close;
|
||||||
|
|
||||||
|
disk_super = (struct btrfs_super_block *)bh->b_data;
|
||||||
|
if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC,
|
||||||
|
sizeof(disk_super->magic)))
|
||||||
|
goto error_brelse;
|
||||||
|
|
||||||
|
devid = le64_to_cpu(disk_super->dev_item.devid);
|
||||||
|
if (devid != device->devid)
|
||||||
|
goto error_brelse;
|
||||||
|
|
||||||
|
transid = btrfs_super_generation(disk_super);
|
||||||
|
if (transid > latest_transid) {
|
||||||
|
latest_devid = devid;
|
||||||
|
latest_transid = transid;
|
||||||
|
latest_bdev = bdev;
|
||||||
|
}
|
||||||
|
|
||||||
device->bdev = bdev;
|
device->bdev = bdev;
|
||||||
device->in_fs_metadata = 0;
|
device->in_fs_metadata = 0;
|
||||||
|
fs_devices->open_devices++;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
error_brelse:
|
||||||
|
brelse(bh);
|
||||||
|
error_close:
|
||||||
|
close_bdev_excl(bdev);
|
||||||
|
error:
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
if (fs_devices->open_devices == 0) {
|
||||||
|
ret = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
fs_devices->mounted = 1;
|
||||||
|
fs_devices->latest_bdev = latest_bdev;
|
||||||
|
fs_devices->latest_devid = latest_devid;
|
||||||
|
fs_devices->latest_trans = latest_transid;
|
||||||
|
out:
|
||||||
mutex_unlock(&uuid_mutex);
|
mutex_unlock(&uuid_mutex);
|
||||||
return 0;
|
|
||||||
fail:
|
|
||||||
mutex_unlock(&uuid_mutex);
|
|
||||||
btrfs_close_devices(fs_devices);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -828,6 +874,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
|
|||||||
if (device->bdev) {
|
if (device->bdev) {
|
||||||
/* one close for the device struct or super_block */
|
/* one close for the device struct or super_block */
|
||||||
close_bdev_excl(device->bdev);
|
close_bdev_excl(device->bdev);
|
||||||
|
root->fs_info->fs_devices->open_devices--;
|
||||||
}
|
}
|
||||||
if (bdev) {
|
if (bdev) {
|
||||||
/* one close for us */
|
/* one close for us */
|
||||||
@ -914,6 +961,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
|
|||||||
list_add(&device->dev_alloc_list,
|
list_add(&device->dev_alloc_list,
|
||||||
&root->fs_info->fs_devices->alloc_list);
|
&root->fs_info->fs_devices->alloc_list);
|
||||||
root->fs_info->fs_devices->num_devices++;
|
root->fs_info->fs_devices->num_devices++;
|
||||||
|
root->fs_info->fs_devices->open_devices++;
|
||||||
out:
|
out:
|
||||||
btrfs_end_transaction(trans, root);
|
btrfs_end_transaction(trans, root);
|
||||||
mutex_unlock(&root->fs_info->fs_mutex);
|
mutex_unlock(&root->fs_info->fs_mutex);
|
||||||
|
@ -71,16 +71,16 @@ struct btrfs_fs_devices {
|
|||||||
/* the device with this id has the most recent coyp of the super */
|
/* the device with this id has the most recent coyp of the super */
|
||||||
u64 latest_devid;
|
u64 latest_devid;
|
||||||
u64 latest_trans;
|
u64 latest_trans;
|
||||||
u64 lowest_devid;
|
|
||||||
u64 num_devices;
|
u64 num_devices;
|
||||||
|
u64 open_devices;
|
||||||
struct block_device *latest_bdev;
|
struct block_device *latest_bdev;
|
||||||
struct block_device *lowest_bdev;
|
|
||||||
/* all of the devices in the FS */
|
/* all of the devices in the FS */
|
||||||
struct list_head devices;
|
struct list_head devices;
|
||||||
|
|
||||||
/* devices not currently being allocated */
|
/* devices not currently being allocated */
|
||||||
struct list_head alloc_list;
|
struct list_head alloc_list;
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
int mounted;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct btrfs_bio_stripe {
|
struct btrfs_bio_stripe {
|
||||||
|
Loading…
Reference in New Issue
Block a user