@@ -541,6 +541,48 @@ int btrfs_scan_argv_devices(int dev_optind, int dev_argc, char **dev_argv)
return 0;
}
+int scan_reunite_fs_devices(char *path)
+{
+ int ret;
+ int fd;
+ u64 total_devs;
+ struct btrfs_fs_devices *fs_devices;
+
+ ret = check_arg_type(path);
+ if (ret != BTRFS_ARG_BLKDEV && ret != BTRFS_ARG_REG) {
+ if (ret < 0) {
+ errno = -ret;
+ error("invalid argument %s: %m", path);
+ } else {
+ error("not a block device or regular file: %s", path);
+ }
+ }
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ error("cannot open %s: %m", path);
+ return -errno;
+ }
+ ret = btrfs_scan_one_device(fd, path, &fs_devices, &total_devs,
+ BTRFS_SUPER_INFO_OFFSET, SBREAD_DEFAULT);
+ close(fd);
+ if (ret < 0) {
+ errno = -ret;
+ error("device scan of %s failed: %m", path);
+ return ret;
+ }
+
+ ret = 0;
+ /* Check for missing device */
+ if (fs_devices->num_devices != total_devs)
+ ret = reunite_fs_devices(fs_devices);
+
+ if (!ret)
+ fs_devices->sanitized = true;
+
+ return ret;
+}
+
bool array_append(char **dest, char *src, int *cnt)
{
char *this_tok = strtok(src, ",");
@@ -61,5 +61,6 @@ void free_seen_fsid(struct seen_fsid *seen_fsid_hash[]);
int test_uuid_unique(const char *uuid_str);
bool array_append(char **dest, char *src, int *cnt);
void free_array(char **prt, int cnt);
+int scan_reunite_fs_devices(char *path);
#endif
@@ -2958,3 +2958,76 @@ int btrfs_fix_device_and_super_size(struct btrfs_fs_info *fs_info)
}
return ret;
}
+
+static int find_unifiable(struct btrfs_fs_devices *fsinfo_fs_devices,
+ struct btrfs_fs_devices **ret_fs_devices)
+{
+ u8 *orig_uuid = fsinfo_fs_devices->metadata_uuid;
+ u8 *orig_fsid = fsinfo_fs_devices->fsid;
+ struct btrfs_fs_devices *fs_devices = NULL;
+ int ret = 0;
+
+ list_for_each_entry(fs_devices, &fs_uuids, list) {
+ /* skip the same fs_info fsid */
+ if (!memcmp(fs_devices->fsid, orig_fsid, BTRFS_FSID_SIZE))
+ continue;
+
+ /* skip the metadata_uuid which isn't fs_info metadata_uuid */
+ if (memcmp(fs_devices->metadata_uuid, orig_uuid, BTRFS_FSID_SIZE))
+ continue;
+
+ ret++;
+ *ret_fs_devices = fs_devices;
+ }
+
+ return ret;
+}
+
+int reunite_fs_devices(struct btrfs_fs_devices *fs_devices)
+{
+ struct btrfs_fs_devices *other_fs_devices = NULL;
+ struct btrfs_device *tmp_device;
+ struct btrfs_device *device;
+ int other_fsid_cnt = 0;
+ int missing_devs;
+
+ missing_devs = fs_devices->total_devices - fs_devices->num_devices;
+ other_fsid_cnt = find_unifiable(fs_devices, &other_fs_devices);
+
+ if (other_fsid_cnt == 0) {
+ error("No missing device(s) found");
+ return -EINVAL;
+ } else if (other_fsid_cnt > 1) {
+ error("Found more than one fsid with the same metadata_uuid");
+ error("Try use --device and --noscan options");
+ return -EINVAL;
+ }
+
+ /* Missing count in the fs_info should match with the scanned devices */
+ if (missing_devs != other_fs_devices->num_devices) {
+ error("Missing device(s) found %d expected %d",
+ other_fs_devices->num_devices, missing_devs);
+ return -EINVAL;
+ }
+
+ list_for_each_entry_safe(device, tmp_device, &other_fs_devices->devices,
+ dev_list) {
+ /* We have found the missing device, bring it in */
+ list_move(&device->dev_list, &fs_devices->devices);
+ fs_devices->num_devices++;
+ missing_devs--;
+ }
+
+ if (!list_empty(&other_fs_devices->devices) || missing_devs != 0 ||
+ fs_devices->total_devices != fs_devices->num_devices) {
+ error("Found more or fewer missing devices");
+ return -EINVAL;
+ }
+
+ if (other_fs_devices->changing_fsid)
+ fs_devices->changing_fsid = true;
+ if (other_fs_devices->active_metadata_uuid)
+ fs_devices->active_metadata_uuid = true;
+
+ return 0;
+}
@@ -104,6 +104,7 @@ struct btrfs_fs_devices {
bool changing_fsid;
bool active_metadata_uuid;
+ bool sanitized;
};
struct btrfs_bio_stripe {
@@ -318,5 +319,6 @@ int btrfs_bg_type_to_nparity(u64 flags);
int btrfs_bg_type_to_sub_stripes(u64 flags);
u64 btrfs_bg_flags_for_device_num(int number);
bool btrfs_bg_type_is_stripey(u64 flags);
+int reunite_fs_devices(struct btrfs_fs_devices *fs_devices);
#endif
The btrfstune -m|M option allows the user to change the fsid of the filesystem. However, in a multi-device filesystem, if the fsid is not successfully changed simultaneously on all devices, problems may arise. In such cases, the user cannot use btrfstune again to resolve the incomplete fsid change. This patch provides helper function to find other devices having the the same metadata_uuid and have them reunited with the given scanned device so that btrfstune can fix the fsid. Signed-off-by: Anand Jain <anand.jain@oracle.com> --- common/device-scan.c | 42 ++++++++++++++++++++++++ common/device-scan.h | 1 + kernel-shared/volumes.c | 73 +++++++++++++++++++++++++++++++++++++++++ kernel-shared/volumes.h | 2 ++ 4 files changed, 118 insertions(+)