Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9ab0c653 authored by Anand Jain's avatar Anand Jain Committed by Greg Kroah-Hartman
Browse files

btrfs: harden identification of a stale device



commit 770c79fb65506fc7c16459855c3839429f46cb32 upstream.

Identifying and removing the stale device from the fs_uuids list is done
by btrfs_free_stale_devices().  btrfs_free_stale_devices() in turn
depends on device_path_matched() to check if the device appears in more
than one btrfs_device structure.

The matching of the device happens by its path, the device path. However,
when device mapper is in use, the dm device paths are nothing but a link
to the actual block device, which leads to the device_path_matched()
failing to match.

Fix this by matching the dev_t as provided by lookup_bdev() instead of
plain string compare of the device paths.

Reported-by: default avatarJosef Bacik <josef@toxicpanda.com>
Signed-off-by: default avatarAnand Jain <anand.jain@oracle.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 4e5ba186
Loading
Loading
Loading
Loading
+37 −7
Original line number Diff line number Diff line
@@ -713,15 +713,47 @@ static void pending_bios_fn(struct btrfs_work *work)
	run_scheduled_bios(device);
}

static bool device_path_matched(const char *path, struct btrfs_device *device)
/*
 * Check if the device in the path matches the device in the given struct device.
 *
 * Returns:
 *   true  If it is the same device.
 *   false If it is not the same device or on error.
 */
static bool device_matched(const struct btrfs_device *device, const char *path)
{
	int found;
	char *device_name;
	struct block_device *bdev_old;
	struct block_device *bdev_new;

	/*
	 * If we are looking for a device with the matching dev_t, then skip
	 * device without a name (a missing device).
	 */
	if (!device->name)
		return false;

	device_name = kzalloc(BTRFS_PATH_NAME_MAX, GFP_KERNEL);
	if (!device_name)
		return false;

	rcu_read_lock();
	found = strcmp(rcu_str_deref(device->name), path);
	scnprintf(device_name, BTRFS_PATH_NAME_MAX, "%s", rcu_str_deref(device->name));
	rcu_read_unlock();

	return found == 0;
	bdev_old = lookup_bdev(device_name);
	kfree(device_name);
	if (IS_ERR(bdev_old))
		return false;

	bdev_new = lookup_bdev(path);
	if (IS_ERR(bdev_new))
		return false;

	if (bdev_old == bdev_new)
		return true;

	return false;
}

/*
@@ -754,9 +786,7 @@ static int btrfs_free_stale_devices(const char *path,
					 &fs_devices->devices, dev_list) {
			if (skip_device && skip_device == device)
				continue;
			if (path && !device->name)
				continue;
			if (path && !device_path_matched(path, device))
			if (path && !device_matched(device, path))
				continue;
			if (fs_devices->opened) {
				/* for an already deleted device return 0 */