btrfs_free_extra_devids() reorgs fs_devices::latest_bdev
to point to the bdev with greatest device::generation number.
For a typical-missing device the generation number is zero so
fs_devices::latest_bdev will never point to it.
But if the missing device is due to alienation [1], then
device::generation is not-zero and if it is >= to rest of
device::generation in the list, then fs_devices::latest_bdev
ends up pointing to the missing device and reports the error
like this [2]
[1] We maintain devices of a fsid (as in fs_device::fsid) in the
fs_devices::devices list, a device is considered as an alien device
if its fsid does not match with the fs_device::fsid
Consider a working raid1.
$ mkfs.btrfs -fq -draid1 -mraid1 /dev/sdb /dev/sdc
$ mount /dev/sdb /btrfs
$ umount /btrfs
While raid1 was unmounted the user decides to force add one its
device to another btrfs fs.
$ mkfs.btrfs -fq /dev/sdd
$ mount /dev/sdd /btrfs1
$ btrfs dev add -f /dev/sdb /btrfs1
Now the original raid1 fails to mount in degraded, because
fs_devices::latest_bdev is pointing to the alien device.
$ mount -o degraded /dev/sdc /btrfs
[2]
mount: wrong fs type, bad option, bad superblock on /dev/sdc,
missing codepage or helper program, or other error
In some cases useful info is found in syslog - try
dmesg | tail or so.
kernel: BTRFS warning (device sdc): devid 1 uuid 072a0192-675b-4d5a-8640-a5cf2b2c704d is missing
kernel: BTRFS error (device sdc): failed to read devices
kernel: BTRFS error (device sdc): open_ctree failed
Fix the root of the issue, by checking if the the device is not
missing before it can be a contender for the fs_devices::latest_bdev
title.
Signed-off-by: Anand Jain <anand.jain@xxxxxxxxxx>
Reviewed-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
---
v3-rebased: update change log.
v4: update change log.
fs/btrfs/volumes.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index bf953c4895f3..f93739afe681 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -1042,6 +1042,8 @@ void btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices, int step)
&device->dev_state)) {
if (!test_bit(BTRFS_DEV_STATE_REPLACE_TGT,
&device->dev_state) &&
+ !test_bit(BTRFS_DEV_STATE_MISSING,
+ &device->dev_state) &&
(!latest_dev ||
device->generation > latest_dev->generation)) {
latest_dev = device;
--
2.25.1