summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/disk-io.c4
-rw-r--r--fs/btrfs/volumes.c40
-rw-r--r--fs/btrfs/volumes.h4
3 files changed, 48 insertions, 0 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 22d706e4f341..89022e9f393b 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -3502,6 +3502,10 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
fs_info->generation == btrfs_super_uuid_tree_generation(disk_super))
set_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags);
+ if (unlikely(btrfs_verify_dev_items(fs_info))) {
+ ret = -EUCLEAN;
+ goto fail_block_groups;
+ }
ret = btrfs_verify_dev_extents(fs_info);
if (ret) {
btrfs_err(fs_info,
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index fe37ee05bf23..324852318afc 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -7262,6 +7262,7 @@ static int read_one_dev(struct extent_buffer *leaf,
return -EINVAL;
}
}
+ set_bit(BTRFS_DEV_STATE_ITEM_FOUND, &device->dev_state);
set_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state);
if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state) &&
!test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state)) {
@@ -8088,6 +8089,45 @@ int btrfs_verify_dev_extents(struct btrfs_fs_info *fs_info)
}
/*
+ * Ensure that all devices registered in the fs have their device items in the
+ * chunk tree.
+ *
+ * Return true if unexpected device is found.
+ * Return false otherwise.
+ */
+bool btrfs_verify_dev_items(const struct btrfs_fs_info *fs_info)
+{
+ struct btrfs_fs_devices *seed_devs;
+ struct btrfs_device *dev;
+ bool ret = false;
+
+ mutex_lock(&uuid_mutex);
+ list_for_each_entry(dev, &fs_info->fs_devices->devices, dev_list) {
+ if (!test_bit(BTRFS_DEV_STATE_ITEM_FOUND, &dev->dev_state)) {
+ btrfs_err(fs_info,
+ "devid %llu path %s is registered but not found in chunk tree",
+ dev->devid, btrfs_dev_name(dev));
+ ret = true;
+ }
+ }
+ list_for_each_entry(seed_devs, &fs_info->fs_devices->seed_list, seed_list) {
+ list_for_each_entry(dev, &seed_devs->devices, dev_list) {
+ if (!test_bit(BTRFS_DEV_STATE_ITEM_FOUND, &dev->dev_state)) {
+ btrfs_err(fs_info,
+ "devid %llu path %s is registered but not found in chunk tree",
+ dev->devid, btrfs_dev_name(dev));
+ ret = true;
+ }
+ }
+ }
+ mutex_unlock(&uuid_mutex);
+ if (ret)
+ btrfs_err(fs_info,
+"remove the above devices or use 'btrfs device scan --forget <dev>' to unregister them before mount");
+ return ret;
+}
+
+/*
* Check whether the given block group or device is pinned by any inode being
* used as a swapfile.
*/
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 34b854c1a303..f20abeb16bce 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -100,6 +100,9 @@ enum btrfs_raid_types {
#define BTRFS_DEV_STATE_FLUSH_SENT (4)
#define BTRFS_DEV_STATE_NO_READA (5)
+/* Set when the device item is found in chunk tree, used to catch unexpected registered device. */
+#define BTRFS_DEV_STATE_ITEM_FOUND (7)
+
/* Special value encoding failure to write primary super block. */
#define BTRFS_SUPER_PRIMARY_WRITE_ERROR (INT_MAX / 2)
@@ -893,6 +896,7 @@ enum btrfs_raid_types __attribute_const__ btrfs_bg_flags_to_raid_index(u64 flags
int btrfs_bg_type_to_factor(u64 flags);
const char *btrfs_bg_type_to_raid_name(u64 flags);
int btrfs_verify_dev_extents(struct btrfs_fs_info *fs_info);
+bool btrfs_verify_dev_items(const struct btrfs_fs_info *fs_info);
bool btrfs_repair_one_zone(struct btrfs_fs_info *fs_info, u64 logical);
bool btrfs_pinned_by_swapfile(struct btrfs_fs_info *fs_info, void *ptr);