public inbox for linux-block@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 1/3] loop: fix partition scan race between udev and loop_reread_partitions()
@ 2026-03-31 10:51 Daan De Meyer
  2026-03-31 11:45 ` Christian Brauner
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Daan De Meyer @ 2026-03-31 10:51 UTC (permalink / raw)
  To: linux-block; +Cc: axboe, brauner, hch, Daan De Meyer

When LOOP_CONFIGURE is called with LO_FLAGS_PARTSCAN, the following
sequence occurs:

  1. disk_force_media_change() sets GD_NEED_PART_SCAN
  2. Uevent suppression is lifted and a KOBJ_CHANGE uevent is sent
  3. loop_global_unlock() releases the lock
  4. loop_reread_partitions() calls bdev_disk_changed() to scan

There is a race between steps 2 and 4: when udev receives the uevent
and opens the device before loop_reread_partitions() runs,
blkdev_get_whole() in bdev.c sees GD_NEED_PART_SCAN set and calls
bdev_disk_changed() for a first scan. Then loop_reread_partitions()
does a second scan. The open_mutex serializes these two scans, but
does not prevent both from running.

The second scan in bdev_disk_changed() drops all partition devices
from the first scan (via blk_drop_partitions()) before re-adding
them, causing partition block devices to briefly disappear. This
breaks any systemd unit with BindsTo= on the partition device: systemd
observes the device going dead, fails the dependent units, and does
not retry them when the device reappears.

Fix this by removing the GD_NEED_PART_SCAN set from
disk_force_media_change() entirely. None of the current callers need
the lazy on-open partition scan triggered by this flag:

  - floppy: sets GENHD_FL_NO_PART, so disk_has_partscan() is always
    false and GD_NEED_PART_SCAN has no effect.
  - loop (loop_configure, loop_change_fd): when LO_FLAGS_PARTSCAN is
    set, loop_reread_partitions() performs an explicit scan. When not
    set, GD_SUPPRESS_PART_SCAN prevents the lazy scan path.
  - loop (__loop_clr_fd): calls bdev_disk_changed() explicitly if
    LO_FLAGS_PARTSCAN is set.
  - nbd (nbd_clear_sock_ioctl): capacity is set to zero immediately
    after; nbd manages GD_NEED_PART_SCAN explicitly elsewhere.

With GD_NEED_PART_SCAN no longer set by disk_force_media_change(),
udev opening the loop device after the uevent no longer triggers a
redundant scan in blkdev_get_whole(), and only the single explicit
scan from loop_reread_partitions() runs.

A regression test for this bug has been submitted to blktests:
https://github.com/linux-blktests/blktests/pull/240.

Fixes: 9f65c489b68d ("loop: raise media_change event")
Signed-off-by: Daan De Meyer <daan@amutable.com>
---
 block/disk-events.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/block/disk-events.c b/block/disk-events.c
index 9f9f9f8a2d6b..074731ecc3d2 100644
--- a/block/disk-events.c
+++ b/block/disk-events.c
@@ -290,13 +290,14 @@ EXPORT_SYMBOL(disk_check_media_change);
  * Should be called when the media changes for @disk.  Generates a uevent
  * and attempts to free all dentries and inodes and invalidates all block
  * device page cache entries in that case.
+ *
+ * Callers that need a partition re-scan should arrange for one explicitly.
  */
 void disk_force_media_change(struct gendisk *disk)
 {
 	disk_event_uevent(disk, DISK_EVENT_MEDIA_CHANGE);
 	inc_diskseq(disk);
 	bdev_mark_dead(disk->part0, true);
-	set_bit(GD_NEED_PART_SCAN, &disk->state);
 }
 EXPORT_SYMBOL_GPL(disk_force_media_change);
 
-- 
2.53.0


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

* Re: [PATCH v3 1/3] loop: fix partition scan race between udev and loop_reread_partitions()
  2026-03-31 10:51 [PATCH v3 1/3] loop: fix partition scan race between udev and loop_reread_partitions() Daan De Meyer
@ 2026-03-31 11:45 ` Christian Brauner
  2026-03-31 13:07 ` Jens Axboe
  2026-03-31 14:59 ` Christoph Hellwig
  2 siblings, 0 replies; 4+ messages in thread
From: Christian Brauner @ 2026-03-31 11:45 UTC (permalink / raw)
  To: Daan De Meyer; +Cc: linux-block, axboe, hch, Daan De Meyer

On Tue, Mar 31, 2026 at 10:51:28AM +0000, Daan De Meyer wrote:
> When LOOP_CONFIGURE is called with LO_FLAGS_PARTSCAN, the following
> sequence occurs:
> 
>   1. disk_force_media_change() sets GD_NEED_PART_SCAN
>   2. Uevent suppression is lifted and a KOBJ_CHANGE uevent is sent
>   3. loop_global_unlock() releases the lock
>   4. loop_reread_partitions() calls bdev_disk_changed() to scan
> 
> There is a race between steps 2 and 4: when udev receives the uevent
> and opens the device before loop_reread_partitions() runs,
> blkdev_get_whole() in bdev.c sees GD_NEED_PART_SCAN set and calls
> bdev_disk_changed() for a first scan. Then loop_reread_partitions()
> does a second scan. The open_mutex serializes these two scans, but
> does not prevent both from running.
> 
> The second scan in bdev_disk_changed() drops all partition devices
> from the first scan (via blk_drop_partitions()) before re-adding
> them, causing partition block devices to briefly disappear. This
> breaks any systemd unit with BindsTo= on the partition device: systemd
> observes the device going dead, fails the dependent units, and does
> not retry them when the device reappears.
> 
> Fix this by removing the GD_NEED_PART_SCAN set from
> disk_force_media_change() entirely. None of the current callers need
> the lazy on-open partition scan triggered by this flag:
> 
>   - floppy: sets GENHD_FL_NO_PART, so disk_has_partscan() is always
>     false and GD_NEED_PART_SCAN has no effect.
>   - loop (loop_configure, loop_change_fd): when LO_FLAGS_PARTSCAN is
>     set, loop_reread_partitions() performs an explicit scan. When not
>     set, GD_SUPPRESS_PART_SCAN prevents the lazy scan path.
>   - loop (__loop_clr_fd): calls bdev_disk_changed() explicitly if
>     LO_FLAGS_PARTSCAN is set.
>   - nbd (nbd_clear_sock_ioctl): capacity is set to zero immediately
>     after; nbd manages GD_NEED_PART_SCAN explicitly elsewhere.
> 
> With GD_NEED_PART_SCAN no longer set by disk_force_media_change(),
> udev opening the loop device after the uevent no longer triggers a
> redundant scan in blkdev_get_whole(), and only the single explicit
> scan from loop_reread_partitions() runs.
> 
> A regression test for this bug has been submitted to blktests:
> https://github.com/linux-blktests/blktests/pull/240.
> 
> Fixes: 9f65c489b68d ("loop: raise media_change event")
> Signed-off-by: Daan De Meyer <daan@amutable.com>
> ---

Looks good to me,
Acked-by: Christian Brauner <brauner@kernel.org>

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

* Re: [PATCH v3 1/3] loop: fix partition scan race between udev and loop_reread_partitions()
  2026-03-31 10:51 [PATCH v3 1/3] loop: fix partition scan race between udev and loop_reread_partitions() Daan De Meyer
  2026-03-31 11:45 ` Christian Brauner
@ 2026-03-31 13:07 ` Jens Axboe
  2026-03-31 14:59 ` Christoph Hellwig
  2 siblings, 0 replies; 4+ messages in thread
From: Jens Axboe @ 2026-03-31 13:07 UTC (permalink / raw)
  To: linux-block, Daan De Meyer; +Cc: brauner, hch, Daan De Meyer


On Tue, 31 Mar 2026 10:51:28 +0000, Daan De Meyer wrote:
> When LOOP_CONFIGURE is called with LO_FLAGS_PARTSCAN, the following
> sequence occurs:
> 
>   1. disk_force_media_change() sets GD_NEED_PART_SCAN
>   2. Uevent suppression is lifted and a KOBJ_CHANGE uevent is sent
>   3. loop_global_unlock() releases the lock
>   4. loop_reread_partitions() calls bdev_disk_changed() to scan
> 
> [...]

Applied, thanks!

[1/3] loop: fix partition scan race between udev and loop_reread_partitions()
      commit: 267ec4d7223a783f029a980f41b93c39b17996da

Best regards,
-- 
Jens Axboe




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

* Re: [PATCH v3 1/3] loop: fix partition scan race between udev and loop_reread_partitions()
  2026-03-31 10:51 [PATCH v3 1/3] loop: fix partition scan race between udev and loop_reread_partitions() Daan De Meyer
  2026-03-31 11:45 ` Christian Brauner
  2026-03-31 13:07 ` Jens Axboe
@ 2026-03-31 14:59 ` Christoph Hellwig
  2 siblings, 0 replies; 4+ messages in thread
From: Christoph Hellwig @ 2026-03-31 14:59 UTC (permalink / raw)
  To: Daan De Meyer; +Cc: linux-block, axboe, brauner, hch, Daan De Meyer

The subject looks odd - for one this is now a block patch and not
loop, so the prefix is wrong.  It also claims to be patch 1 of a
3 patch series, but so far I've not seen more than this or a cover
letter.

Otherwise this looks good to me.

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

end of thread, other threads:[~2026-03-31 14:59 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-31 10:51 [PATCH v3 1/3] loop: fix partition scan race between udev and loop_reread_partitions() Daan De Meyer
2026-03-31 11:45 ` Christian Brauner
2026-03-31 13:07 ` Jens Axboe
2026-03-31 14:59 ` Christoph Hellwig

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox