btrfs: check generation as replace duplicates devid+uuid
When FS in unmounted we need to check generation number as well since devid+uuid combination could match with the missing replaced disk when it reappears, and without this patch it might pair with the replaced disk again. device_list_add() function is called in the following threads, mount device option mount argument ioctl BTRFS_IOC_SCAN_DEV (btrfs dev scan) ioctl BTRFS_IOC_DEVICES_READY (btrfs dev ready <dev>) they have been unit tested to work fine with this patch. If the user knows what he is doing and really want to pair with replaced disk (which is not a standard operation), then he should first clear the kernel btrfs device list in the memory by doing the module unload/load and followed with the mount -o device option. Signed-off-by: Anand Jain <anand.jain@oracle.com> Signed-off-by: Wang Shilong <wangsl.fnst@cn.fujitsu.com> Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Chris Mason <clm@fb.com>
This commit is contained in:
parent
b96de000bc
commit
77bdae4d13
1 changed files with 21 additions and 1 deletions
|
@ -532,8 +532,19 @@ static noinline int device_list_add(const char *path,
|
|||
* As of now don't allow update to btrfs_fs_device through
|
||||
* the btrfs dev scan cli, after FS has been mounted.
|
||||
*/
|
||||
if (fs_devices->opened)
|
||||
if (fs_devices->opened) {
|
||||
return -EBUSY;
|
||||
} else {
|
||||
/*
|
||||
* That is if the FS is _not_ mounted and if you
|
||||
* are here, that means there is more than one
|
||||
* disk with same uuid and devid.We keep the one
|
||||
* with larger generation number or the last-in if
|
||||
* generation are equal.
|
||||
*/
|
||||
if (found_transid < device->generation)
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
name = rcu_string_strdup(path, GFP_NOFS);
|
||||
if (!name)
|
||||
|
@ -546,6 +557,15 @@ static noinline int device_list_add(const char *path,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Unmount does not free the btrfs_device struct but would zero
|
||||
* generation along with most of the other members. So just update
|
||||
* it back. We need it to pick the disk with largest generation
|
||||
* (as above).
|
||||
*/
|
||||
if (!fs_devices->opened)
|
||||
device->generation = found_transid;
|
||||
|
||||
if (found_transid > fs_devices->latest_trans) {
|
||||
fs_devices->latest_devid = devid;
|
||||
fs_devices->latest_trans = found_transid;
|
||||
|
|
Loading…
Reference in a new issue