All of lore.kernel.org
 help / color / mirror / Atom feed
* [dm-devel] [PATCH v2] dm: send just one event on resize, not two
@ 2023-02-09 15:11 Mikulas Patocka
  2023-02-10 10:04 ` Peter Rajnoha
  0 siblings, 1 reply; 2+ messages in thread
From: Mikulas Patocka @ 2023-02-09 15:11 UTC (permalink / raw)
  To: Mike Snitzer, Zdenek Kabelac, Peter Rajnoha, Steve Baker; +Cc: dm-devel

Hi

I discussed this uevent thing with Zdenek and we concluded that it is 
sufficient to send just one uevent on resize, not two.

So, I made a second patch that fixes the uevent-while-suspended bug. It 
replaces set_capacity_and_notify with set_capacity (so that no uevent is 
set at this point) and it detects capacity change in do_resume - and if 
the capacity was changed, it adds "RESIZE=1" to an uevent that is being 
sent.

Zdenek and Peter, please test it.

Mikulas




From: Mikulas Patocka <mpatocka@redhat.com>

Device mapper sends an uevent when the device is suspended, using the
function set_capacity_and_notify. However, this causes a race condition
with udev.

Udev skips scanning dm devices that are suspended. If we send an uevent
while we are suspended, udev will be racing with device mapper resume
code. If the device mapper resume code wins the race, udev will process
the uevent after the device is resumed and it will properly scan the
device.

However, if udev wins the race, it will receive the uevent, find out that
the dm device is suspended and skip scanning the device. This causes bugs
such as systemd unmounting the device - see
https://bugzilla.redhat.com/show_bug.cgi?id=2158628

This commit fixes this race.

We replace the function set_capacity_and_notify with set_capacity, so that
the uevent is not sent at this point. In do_resume, we detect if the
capacity has changed and we pass a boolean variable need_resize_uevent to
dm_kobject_uevent. dm_kobject_uevent adds "RESIZE=1" to the uevent if
need_resize_uevent is set.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Cc: stable@vger.kernel.org

---
 drivers/md/dm-ioctl.c |   13 ++++++++++---
 drivers/md/dm.c       |   27 +++++++++++++--------------
 drivers/md/dm.h       |    2 +-
 3 files changed, 24 insertions(+), 18 deletions(-)

Index: linux-2.6/drivers/md/dm-ioctl.c
===================================================================
--- linux-2.6.orig/drivers/md/dm-ioctl.c	2023-02-09 15:46:39.000000000 +0100
+++ linux-2.6/drivers/md/dm-ioctl.c	2023-02-09 15:46:39.000000000 +0100
@@ -482,7 +482,7 @@ static struct mapped_device *dm_hash_ren
 		dm_table_event(table);
 	dm_put_live_table(hc->md, srcu_idx);
 
-	if (!dm_kobject_uevent(hc->md, KOBJ_CHANGE, param->event_nr))
+	if (!dm_kobject_uevent(hc->md, KOBJ_CHANGE, param->event_nr, false))
 		param->flags |= DM_UEVENT_GENERATED_FLAG;
 
 	md = hc->md;
@@ -995,7 +995,7 @@ static int dev_remove(struct file *filp,
 
 	dm_ima_measure_on_device_remove(md, false);
 
-	if (!dm_kobject_uevent(md, KOBJ_REMOVE, param->event_nr))
+	if (!dm_kobject_uevent(md, KOBJ_REMOVE, param->event_nr, false))
 		param->flags |= DM_UEVENT_GENERATED_FLAG;
 
 	dm_put(md);
@@ -1129,6 +1129,7 @@ static int do_resume(struct dm_ioctl *pa
 	struct hash_cell *hc;
 	struct mapped_device *md;
 	struct dm_table *new_map, *old_map = NULL;
+	bool need_resize_uevent = false;
 
 	down_write(&_hash_lock);
 
@@ -1149,6 +1150,8 @@ static int do_resume(struct dm_ioctl *pa
 
 	/* Do we need to load a new map ? */
 	if (new_map) {
+		sector_t old_size, new_size;
+
 		/* Suspend if it isn't already suspended */
 		if (param->flags & DM_SKIP_LOCKFS_FLAG)
 			suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG;
@@ -1157,6 +1160,7 @@ static int do_resume(struct dm_ioctl *pa
 		if (!dm_suspended_md(md))
 			dm_suspend(md, suspend_flags);
 
+		old_size = dm_get_size(md);
 		old_map = dm_swap_table(md, new_map);
 		if (IS_ERR(old_map)) {
 			dm_sync_table(md);
@@ -1164,6 +1168,9 @@ static int do_resume(struct dm_ioctl *pa
 			dm_put(md);
 			return PTR_ERR(old_map);
 		}
+		new_size = dm_get_size(md);
+		if (old_size && new_size && old_size != new_size)
+			need_resize_uevent = true;
 
 		if (dm_table_get_mode(new_map) & FMODE_WRITE)
 			set_disk_ro(dm_disk(md), 0);
@@ -1176,7 +1183,7 @@ static int do_resume(struct dm_ioctl *pa
 		if (!r) {
 			dm_ima_measure_on_device_resume(md, new_map ? true : false);
 
-			if (!dm_kobject_uevent(md, KOBJ_CHANGE, param->event_nr))
+			if (!dm_kobject_uevent(md, KOBJ_CHANGE, param->event_nr, need_resize_uevent))
 				param->flags |= DM_UEVENT_GENERATED_FLAG;
 		}
 	}
Index: linux-2.6/drivers/md/dm.c
===================================================================
--- linux-2.6.orig/drivers/md/dm.c	2023-02-09 15:46:39.000000000 +0100
+++ linux-2.6/drivers/md/dm.c	2023-02-09 15:46:39.000000000 +0100
@@ -2172,10 +2172,7 @@ static struct dm_table *__bind(struct ma
 	if (size != dm_get_size(md))
 		memset(&md->geometry, 0, sizeof(md->geometry));
 
-	if (!get_capacity(md->disk))
-		set_capacity(md->disk, size);
-	else
-		set_capacity_and_notify(md->disk, size);
+	set_capacity(md->disk, size);
 
 	dm_table_event_callback(t, event_callback, md);
 
@@ -2968,23 +2965,25 @@ EXPORT_SYMBOL_GPL(dm_internal_resume_fas
  * Event notification.
  *---------------------------------------------------------------*/
 int dm_kobject_uevent(struct mapped_device *md, enum kobject_action action,
-		       unsigned cookie)
+		      unsigned cookie, bool need_resize_uevent)
 {
 	int r;
 	unsigned noio_flag;
 	char udev_cookie[DM_COOKIE_LENGTH];
-	char *envp[] = { udev_cookie, NULL };
-
-	noio_flag = memalloc_noio_save();
-
-	if (!cookie)
-		r = kobject_uevent(&disk_to_dev(md->disk)->kobj, action);
-	else {
+	char *envp[3] = { NULL, NULL, NULL };
+	char **envpp = envp;
+	if (cookie) {
 		snprintf(udev_cookie, DM_COOKIE_LENGTH, "%s=%u",
 			 DM_COOKIE_ENV_VAR_NAME, cookie);
-		r = kobject_uevent_env(&disk_to_dev(md->disk)->kobj,
-				       action, envp);
+		*envpp++ = udev_cookie;
 	}
+	if (need_resize_uevent) {
+		*envpp++ = "RESIZE=1";
+	}
+
+	noio_flag = memalloc_noio_save();
+
+	r = kobject_uevent_env(&disk_to_dev(md->disk)->kobj, action, envp);
 
 	memalloc_noio_restore(noio_flag);
 
Index: linux-2.6/drivers/md/dm.h
===================================================================
--- linux-2.6.orig/drivers/md/dm.h	2023-02-09 15:46:39.000000000 +0100
+++ linux-2.6/drivers/md/dm.h	2023-02-09 15:46:39.000000000 +0100
@@ -203,7 +203,7 @@ int dm_get_table_device(struct mapped_de
 void dm_put_table_device(struct mapped_device *md, struct dm_dev *d);
 
 int dm_kobject_uevent(struct mapped_device *md, enum kobject_action action,
-		      unsigned cookie);
+		      unsigned cookie, bool need_resize_uevent);
 
 void dm_internal_suspend(struct mapped_device *md);
 void dm_internal_resume(struct mapped_device *md);
--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [dm-devel] [PATCH v2] dm: send just one event on resize, not two
  2023-02-09 15:11 [dm-devel] [PATCH v2] dm: send just one event on resize, not two Mikulas Patocka
@ 2023-02-10 10:04 ` Peter Rajnoha
  0 siblings, 0 replies; 2+ messages in thread
From: Peter Rajnoha @ 2023-02-10 10:04 UTC (permalink / raw)
  To: Mikulas Patocka, Mike Snitzer, Zdenek Kabelac, Steve Baker; +Cc: dm-devel

On 2/9/23 16:11, Mikulas Patocka wrote:
> Hi
> 
> I discussed this uevent thing with Zdenek and we concluded that it is 
> sufficient to send just one uevent on resize, not two.
> 
> So, I made a second patch that fixes the uevent-while-suspended bug. It 
> replaces set_capacity_and_notify with set_capacity (so that no uevent is 
> set at this point) and it detects capacity change in do_resume - and if 
> the capacity was changed, it adds "RESIZE=1" to an uevent that is being 
> sent.
> 
> Zdenek and Peter, please test it.
> 

OK, I've tested this and this works correctly as expected. If we could
go with this patch, that would much better than having 2 independent
uevents. With just one uevent we don't need any special treatment in
udev rules for the extra "RESIZE=1" uevent and also we don't need to
process all the udev rules twice uselessly when those 2 uevents
(RESIZE="1" and "DM RESUME") always go together anyway.

Thanks!

-- 
Peter

--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2023-02-10 10:04 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-09 15:11 [dm-devel] [PATCH v2] dm: send just one event on resize, not two Mikulas Patocka
2023-02-10 10:04 ` Peter Rajnoha

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.