summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2012-02-20 20:53:43 -0500
committerChris Mason <chris.mason@oracle.com>2012-02-23 10:43:45 -0500
commita6b0d5c8dbfd428717fc4db4c36757783f391c7b (patch)
treefc3faaed8b1cf93c7dbe60af4c950be5edd9c8ad /fs
parentfe66a05a06795bd3b788404d69ea7709f46a1609 (diff)
downloadop-kernel-dev-a6b0d5c8dbfd428717fc4db4c36757783f391c7b.zip
op-kernel-dev-a6b0d5c8dbfd428717fc4db4c36757783f391c7b.tar.gz
Btrfs: make sure we update latest_bdev
When we are setting up the mount, we close all the devices that were not actually part of the metadata we found. But, we don't make sure that one of those devices wasn't fs_devices->latest_bdev, which means we can do a use after free on the one we closed. This updates latest_bdev as it goes. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/disk-io.c6
-rw-r--r--fs/btrfs/volumes.c17
2 files changed, 22 insertions, 1 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 58d0678..b801d29 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2305,6 +2305,12 @@ struct btrfs_root *open_ctree(struct super_block *sb,
btrfs_close_extra_devices(fs_devices);
+ if (!fs_devices->latest_bdev) {
+ printk(KERN_CRIT "btrfs: failed to read devices on %s\n",
+ sb->s_id);
+ goto fail_tree_roots;
+ }
+
retry_root_backup:
blocksize = btrfs_level_size(tree_root,
btrfs_super_root_level(disk_super));
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index cd040bf..7eefdef 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -459,12 +459,23 @@ int btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices)
{
struct btrfs_device *device, *next;
+ struct block_device *latest_bdev = NULL;
+ u64 latest_devid = 0;
+ u64 latest_transid = 0;
+
mutex_lock(&uuid_mutex);
again:
/* This is the initialized path, it is safe to release the devices. */
list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) {
- if (device->in_fs_metadata)
+ if (device->in_fs_metadata) {
+ if (!latest_transid ||
+ device->generation > latest_transid) {
+ latest_devid = device->devid;
+ latest_transid = device->generation;
+ latest_bdev = device->bdev;
+ }
continue;
+ }
if (device->bdev) {
blkdev_put(device->bdev, device->mode);
@@ -487,6 +498,10 @@ again:
goto again;
}
+ fs_devices->latest_bdev = latest_bdev;
+ fs_devices->latest_devid = latest_devid;
+ fs_devices->latest_trans = latest_transid;
+
mutex_unlock(&uuid_mutex);
return 0;
}
OpenPOWER on IntegriCloud