]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
Btrfs: make sure we update latest_bdev
authorChris Mason <chris.mason@oracle.com>
Tue, 21 Feb 2012 01:53:43 +0000 (20:53 -0500)
committerChris Mason <chris.mason@oracle.com>
Tue, 21 Feb 2012 01:56:15 +0000 (20:56 -0500)
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>
fs/btrfs/disk-io.c
fs/btrfs/volumes.c

index 858ab347413e3bd920bbbfbd858da100f135d4dc..0044360a857d8e1a46296a2f1da1ad08be403bb7 100644 (file)
@@ -2279,6 +2279,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));
index a031201930ac1d14230a4ab5f9988229ebea93bc..fca14cd85c1093075a0451c39045078a59b39b40 100644 (file)
@@ -457,12 +457,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);
@@ -485,6 +496,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;
 }