aboutsummaryrefslogtreecommitdiffstats
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)
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 58d0678dfcba..b801d29f3f10 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,
2305 2305
2306 btrfs_close_extra_devices(fs_devices); 2306 btrfs_close_extra_devices(fs_devices);
2307 2307
2308 if (!fs_devices->latest_bdev) {
2309 printk(KERN_CRIT "btrfs: failed to read devices on %s\n",
2310 sb->s_id);
2311 goto fail_tree_roots;
2312 }
2313
2308retry_root_backup: 2314retry_root_backup:
2309 blocksize = btrfs_level_size(tree_root, 2315 blocksize = btrfs_level_size(tree_root,
2310 btrfs_super_root_level(disk_super)); 2316 btrfs_super_root_level(disk_super));
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index cd040bf3fd87..7eefdef8a14c 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)
459{ 459{
460 struct btrfs_device *device, *next; 460 struct btrfs_device *device, *next;
461 461
462 struct block_device *latest_bdev = NULL;
463 u64 latest_devid = 0;
464 u64 latest_transid = 0;
465
462 mutex_lock(&uuid_mutex); 466 mutex_lock(&uuid_mutex);
463again: 467again:
464 /* This is the initialized path, it is safe to release the devices. */ 468 /* This is the initialized path, it is safe to release the devices. */
465 list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) { 469 list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) {
466 if (device->in_fs_metadata) 470 if (device->in_fs_metadata) {
471 if (!latest_transid ||
472 device->generation > latest_transid) {
473 latest_devid = device->devid;
474 latest_transid = device->generation;
475 latest_bdev = device->bdev;
476 }
467 continue; 477 continue;
478 }
468 479
469 if (device->bdev) { 480 if (device->bdev) {
470 blkdev_put(device->bdev, device->mode); 481 blkdev_put(device->bdev, device->mode);
@@ -487,6 +498,10 @@ again:
487 goto again; 498 goto again;
488 } 499 }
489 500
501 fs_devices->latest_bdev = latest_bdev;
502 fs_devices->latest_devid = latest_devid;
503 fs_devices->latest_trans = latest_transid;
504
490 mutex_unlock(&uuid_mutex); 505 mutex_unlock(&uuid_mutex);
491 return 0; 506 return 0;
492} 507}