Skip to content

Commit

Permalink
Fix btrfs_open_devices to deal with changes since the scan ioctls
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
chrismason-xx committed Sep 25, 2008
1 parent dfe2502 commit a0af469
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 15 deletions.
4 changes: 2 additions & 2 deletions fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -1266,10 +1266,10 @@ struct btrfs_root *open_ctree(struct super_block *sb,

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",
(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))
printk("continuing in degraded mode\n");
else {
Expand Down
70 changes: 59 additions & 11 deletions fs/btrfs/volumes.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ int btrfs_cleanup_fs_uuids(void)
dev_list);
if (dev->bdev) {
close_bdev_excl(dev->bdev);
fs_devices->open_devices--;
}
list_del(&dev->dev_list);
kfree(dev->name);
Expand Down Expand Up @@ -174,9 +175,10 @@ int btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices)
list_for_each(cur, head) {
device = list_entry(cur, struct btrfs_device, dev_list);
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);
fs_devices->open_devices--;
}
list_del(&device->dev_list);
list_del(&device->dev_alloc_list);
fs_devices->num_devices--;
Expand All @@ -188,6 +190,7 @@ printk("getting rid of extra dev %s\n", device->name);
mutex_unlock(&uuid_mutex);
return 0;
}

int btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
{
struct list_head *head = &fs_devices->devices;
Expand All @@ -199,10 +202,12 @@ int btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
device = list_entry(cur, struct btrfs_device, dev_list);
if (device->bdev) {
close_bdev_excl(device->bdev);
fs_devices->open_devices--;
}
device->bdev = NULL;
device->in_fs_metadata = 0;
}
fs_devices->mounted = 0;
mutex_unlock(&uuid_mutex);
return 0;
}
Expand All @@ -214,9 +219,19 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
struct list_head *head = &fs_devices->devices;
struct list_head *cur;
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);
if (fs_devices->mounted)
goto out;

list_for_each(cur, head) {
device = list_entry(cur, struct btrfs_device, dev_list);
if (device->bdev)
Expand All @@ -229,21 +244,52 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,

if (IS_ERR(bdev)) {
printk("open %s failed\n", device->name);
ret = PTR_ERR(bdev);
goto fail;
goto error;
}
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->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);
return 0;
fail:
mutex_unlock(&uuid_mutex);
btrfs_close_devices(fs_devices);
return ret;
}

Expand Down Expand Up @@ -828,6 +874,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
if (device->bdev) {
/* one close for the device struct or super_block */
close_bdev_excl(device->bdev);
root->fs_info->fs_devices->open_devices--;
}
if (bdev) {
/* one close for us */
Expand Down Expand Up @@ -914,6 +961,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
list_add(&device->dev_alloc_list,
&root->fs_info->fs_devices->alloc_list);
root->fs_info->fs_devices->num_devices++;
root->fs_info->fs_devices->open_devices++;
out:
btrfs_end_transaction(trans, root);
mutex_unlock(&root->fs_info->fs_mutex);
Expand Down
4 changes: 2 additions & 2 deletions fs/btrfs/volumes.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,16 @@ struct btrfs_fs_devices {
/* the device with this id has the most recent coyp of the super */
u64 latest_devid;
u64 latest_trans;
u64 lowest_devid;
u64 num_devices;
u64 open_devices;
struct block_device *latest_bdev;
struct block_device *lowest_bdev;
/* all of the devices in the FS */
struct list_head devices;

/* devices not currently being allocated */
struct list_head alloc_list;
struct list_head list;
int mounted;
};

struct btrfs_bio_stripe {
Expand Down

0 comments on commit a0af469

Please sign in to comment.