diff mbox series

[STABLE,5.4] btrfs: harden identification of a stale device

Message ID 73979e98c7edc6690959f1d5e9e8d2bb678a8101.1661473186.git.anand.jain@oracle.com (mailing list archive)
State New, archived
Headers show
Series [STABLE,5.4] btrfs: harden identification of a stale device | expand

Commit Message

Anand Jain Sept. 2, 2022, 9:09 a.m. UTC
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.

CC: stable@vger.kernel.org #5.4
Reported-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Anand Jain <anand.jain@oracle.com>
Signed-off-by: David Sterba <dsterba@suse.com>
---
 fs/btrfs/volumes.c | 44 +++++++++++++++++++++++++++++++++++++-------
 1 file changed, 37 insertions(+), 7 deletions(-)

Comments

Greg Kroah-Hartman Sept. 2, 2022, 9:23 a.m. UTC | #1
On Fri, Sep 02, 2022 at 05:09:38PM +0800, Anand Jain wrote:
> 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.
> 
> CC: stable@vger.kernel.org #5.4
> Reported-by: Josef Bacik <josef@toxicpanda.com>
> Signed-off-by: Anand Jain <anand.jain@oracle.com>
> Signed-off-by: David Sterba <dsterba@suse.com>
> ---
>  fs/btrfs/volumes.c | 44 +++++++++++++++++++++++++++++++++++++-------
>  1 file changed, 37 insertions(+), 7 deletions(-)

What about the same change for 5.10.y?

thanks,

greg k-h
Anand Jain Sept. 3, 2022, 12:25 p.m. UTC | #2
On 9/2/22 17:23, Greg KH wrote:
> On Fri, Sep 02, 2022 at 05:09:38PM +0800, Anand Jain wrote:
>> 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.
>>
>> CC: stable@vger.kernel.org #5.4
>> Reported-by: Josef Bacik <josef@toxicpanda.com>
>> Signed-off-by: Anand Jain <anand.jain@oracle.com>
>> Signed-off-by: David Sterba <dsterba@suse.com>
>> ---
>>   fs/btrfs/volumes.c | 44 +++++++++++++++++++++++++++++++++++++-------
>>   1 file changed, 37 insertions(+), 7 deletions(-)
> 
> What about the same change for 5.10.y?
> 

Thanks for reminding me.
I have sent a separate patch for 5.10 as this patch won't apply to 5.10.

- Anand

> thanks,
> 
> greg k-h
Greg Kroah-Hartman Sept. 6, 2022, 12:01 p.m. UTC | #3
On Sat, Sep 03, 2022 at 08:25:12PM +0800, Anand Jain wrote:
> On 9/2/22 17:23, Greg KH wrote:
> > On Fri, Sep 02, 2022 at 05:09:38PM +0800, Anand Jain wrote:
> > > 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.
> > > 
> > > CC: stable@vger.kernel.org #5.4
> > > Reported-by: Josef Bacik <josef@toxicpanda.com>
> > > Signed-off-by: Anand Jain <anand.jain@oracle.com>
> > > Signed-off-by: David Sterba <dsterba@suse.com>
> > > ---
> > >   fs/btrfs/volumes.c | 44 +++++++++++++++++++++++++++++++++++++-------
> > >   1 file changed, 37 insertions(+), 7 deletions(-)
> > 
> > What about the same change for 5.10.y?
> > 
> 
> Thanks for reminding me.
> I have sent a separate patch for 5.10 as this patch won't apply to 5.10.

Both now queued up, thanks.

greg k-h
diff mbox series

Patch

diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index c7706a769de1..548de841cee5 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -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 */