Commit 7b65c810 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull btrfs fix from David Sterba:
 "Fix a problem found in 6.7 after adding the temp-fsid feature which
  changed device tracking in memory and broke grub-probe. This is used
  on initrd-less systems. There were several iterations of the fix and
  it took longer than expected"

* tag 'for-6.9-part2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: do not skip re-registration for the mounted device
parents 1b3e2513 d565fffa
Loading
Loading
Loading
Loading
+47 −11
Original line number Diff line number Diff line
@@ -1303,6 +1303,47 @@ int btrfs_forget_devices(dev_t devt)
	return ret;
}

static bool btrfs_skip_registration(struct btrfs_super_block *disk_super,
				    const char *path, dev_t devt,
				    bool mount_arg_dev)
{
	struct btrfs_fs_devices *fs_devices;

	/*
	 * Do not skip device registration for mounted devices with matching
	 * maj:min but different paths. Booting without initrd relies on
	 * /dev/root initially, later replaced with the actual root device.
	 * A successful scan ensures grub2-probe selects the correct device.
	 */
	list_for_each_entry(fs_devices, &fs_uuids, fs_list) {
		struct btrfs_device *device;

		mutex_lock(&fs_devices->device_list_mutex);

		if (!fs_devices->opened) {
			mutex_unlock(&fs_devices->device_list_mutex);
			continue;
		}

		list_for_each_entry(device, &fs_devices->devices, dev_list) {
			if (device->bdev && (device->bdev->bd_dev == devt) &&
			    strcmp(device->name->str, path) != 0) {
				mutex_unlock(&fs_devices->device_list_mutex);

				/* Do not skip registration. */
				return false;
			}
		}
		mutex_unlock(&fs_devices->device_list_mutex);
	}

	if (!mount_arg_dev && btrfs_super_num_devices(disk_super) == 1 &&
	    !(btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_SEEDING))
		return true;

	return false;
}

/*
 * Look for a btrfs signature on a device. This may be called out of the mount path
 * and we are not allowed to call set_blocksize during the scan. The superblock
@@ -1320,6 +1361,7 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags,
	struct btrfs_device *device = NULL;
	struct file *bdev_file;
	u64 bytenr, bytenr_orig;
	dev_t devt;
	int ret;

	lockdep_assert_held(&uuid_mutex);
@@ -1359,19 +1401,13 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags,
		goto error_bdev_put;
	}

	if (!mount_arg_dev && btrfs_super_num_devices(disk_super) == 1 &&
	    !(btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_SEEDING)) {
		dev_t devt;
	devt = file_bdev(bdev_file)->bd_dev;
	if (btrfs_skip_registration(disk_super, path, devt, mount_arg_dev)) {
		pr_debug("BTRFS: skip registering single non-seed device %s (%d:%d)\n",
			  path, MAJOR(devt), MINOR(devt));

		ret = lookup_bdev(path, &devt);
		if (ret)
			btrfs_warn(NULL, "lookup bdev failed for path %s: %d",
				   path, ret);
		else
		btrfs_free_stale_devices(devt, NULL);

	pr_debug("BTRFS: skip registering single non-seed device %s (%d:%d)\n",
			path, MAJOR(devt), MINOR(devt));
		device = NULL;
		goto free_disk_super;
	}