diff options
author | Ilya Dryomov <idryomov@gmail.com> | 2013-08-12 07:33:04 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2013-09-01 08:16:06 -0400 |
commit | a1e8780a89ec13217fa1c8f86faf5546110e1402 (patch) | |
tree | f39579b432809b689801a31207f76a2efd4499d2 /fs/btrfs/volumes.c | |
parent | 2208a378f35fea7a1b778bf856edb971fb7ea9e8 (diff) |
Btrfs: rollback btrfs_device fields on umount
It turns out we don't properly rollback in-core btrfs_device state on
umount. We zero out ->bdev, ->in_fs_metadata and that's about it. In
particular, we don't zero out ->generation, and this can lead to us
refusing a mount -- a non-NULL fs_devices->latest_bdev is essential, but
btrfs_close_extra_devices will happily assign NULL to ->latest_bdev if
the first device on the dev_list happens to be missing and consequently
has no bdev attached. This happens because since commit a6b0d5c8
btrfs_close_extra_devices adjusts ->latest_bdev, and in doing that,
relies on the ->generation. Fix this, and possibly other problems, by
zeroing out everything except for what device_list_add sets, so that a
mount right after insmod and 'btrfs dev scan' is no different from any
later mount in this respect.
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 15 |
1 files changed, 6 insertions, 9 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index d38065eca7c9..ed685991b2c1 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -674,22 +674,19 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices) | |||
674 | if (device->can_discard) | 674 | if (device->can_discard) |
675 | fs_devices->num_can_discard--; | 675 | fs_devices->num_can_discard--; |
676 | 676 | ||
677 | new_device = kmalloc(sizeof(*new_device), GFP_NOFS); | 677 | new_device = btrfs_alloc_device(NULL, &device->devid, |
678 | BUG_ON(!new_device); /* -ENOMEM */ | 678 | device->uuid); |
679 | memcpy(new_device, device, sizeof(*new_device)); | 679 | BUG_ON(IS_ERR(new_device)); /* -ENOMEM */ |
680 | 680 | ||
681 | /* Safe because we are under uuid_mutex */ | 681 | /* Safe because we are under uuid_mutex */ |
682 | if (device->name) { | 682 | if (device->name) { |
683 | name = rcu_string_strdup(device->name->str, GFP_NOFS); | 683 | name = rcu_string_strdup(device->name->str, GFP_NOFS); |
684 | BUG_ON(device->name && !name); /* -ENOMEM */ | 684 | BUG_ON(!name); /* -ENOMEM */ |
685 | rcu_assign_pointer(new_device->name, name); | 685 | rcu_assign_pointer(new_device->name, name); |
686 | } | 686 | } |
687 | new_device->bdev = NULL; | 687 | |
688 | new_device->writeable = 0; | ||
689 | new_device->in_fs_metadata = 0; | ||
690 | new_device->can_discard = 0; | ||
691 | spin_lock_init(&new_device->io_lock); | ||
692 | list_replace_rcu(&device->dev_list, &new_device->dev_list); | 688 | list_replace_rcu(&device->dev_list, &new_device->dev_list); |
689 | new_device->fs_devices = device->fs_devices; | ||
693 | 690 | ||
694 | call_rcu(&device->rcu, free_device); | 691 | call_rcu(&device->rcu, free_device); |
695 | } | 692 | } |