[gparted] Wait for udev change on /dev/DISK when querying whole device FS (!46)



commit 1382e0b828f630a705cecd97c346dfc6267909bf
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date:   Tue Jul 9 19:04:08 2019 +0100

    Wait for udev change on /dev/DISK when querying whole device FS (!46)
    
    GParted nearly always shows this warning against a whole disk device
    FAT32 file system on my development VMs:
        plain floppy: device "/dev/sdb" busy (Resource temporarily
        unavailable): Cannot initialize '::'
        mlabel: Cannot initialize drive
    However GParted does get the label via blkid instead.  Occasionally
    everything works correctly and there is no warning.
    
    Never found a similar error for any other file system on a whole disk
    device.  The timing never seems to clash.
    
    Remember that when a writable file descriptor of a disk device is
    closed, udev events are triggered which update the kernel and /dev
    entries for any partition changes.  (This is in addition to coding which
    has always existed in the partitioning tools, including fdisk and
    parted, to inform the kernel, but not create /dev entries, of partition
    changes).
    
    With debugging and sleeping in GParted, stracing the GParted thread
    GParted_Core::set_devices_thread() and using 'udevadm monitor' to watch
    udev events the following sequence of events is observed:
    
      gparted    |set_devices_thread(pdevices)  pdevices->["/dev/sdb"]
      gparted    |  ped_device_get("/dev/sdb")
      libparted  |      open("/dev/sdb", O_RDONLY) = 8
      libparted  |      close(8)
      gparted    |  useable_device(lp_device)  lp_device->path="/dev/sdb"
      gparted    |    ped_device_open()
      libparted  |      open("/dev/sdb", O_RDWR) = 8
      gparted    |    ped_device_read()
      gparted    |    ped_device_close()
      libparted  |      close(8)
      udev(async)|        KERNEL change /devices/.../sdb (block)
      udev(async)|        KERNEL change /devices/.../sdb (block)
      udev(async)|        UDEV   change /devices/.../sdb (block)
      udev(async)|        UDEV   change /devices/.../sdb (block)
      gparted    |  set_device_from_disk(device, device_path="/dev/sdb")
      gparted    |    get_device(device_path="/dev/sdb", ..., flush=true)
      gparted    |      ped_device_get()
      gparted    |      flush_device(lp_device)  lp_device->path="/dev/sdb"
      gparted    |        ped_device_open()
      libparted  |          open("/dev/sdb", O_RDWR) = 8
      gparted    |        ped_device_sync()
      gparted    |        ped_device_close()
      libparted  |          close(8)
      udev(async)|            KERNEL change /devices/.../sdb (block)
      udev(async)|            KERNEL change /devices/.../sdb (block)
      udev(async)|            UDEV   change /devices/.../sdb (block)
      udev(async)|            UDEV   change /devices/.../sdb (block)
      gparted    |    set_device_one_partition()
      gparted    |      set_partition_label_and_uuid()
      gparted    |        read_label()
      gparted    |          fat16::read_label()
      gparted    |            Utils::execute_command("mlabel -s :: -i /dev/sdb")
    
    This sequence of events only shows which close()s by libparted trigger
    udev events.  It does not show that processing those events are
    asynchronous and overlap with GParted executing mlabel, causing the
    device busy error.
    
    As libparted's ped_device_open() doesn't offer a way to specify that a
    device will only be used for reading, it always opens it read-write
    [1][2].  Hence this sequence in GParted_Core::flush_device():
        ped_device_open()
        ped_device_sync()
        ped_device_close()
    always triggers udev change events on the whole disk device.  Fix by
    waiting for those udev events to complete.
    
    [1] libparted documentation, PedDevice, ped_device_open()
        https://www.gnu.org/software/parted/api/group__PedDevice.html#ga7c87bd06e76553c8ff3262b5e6ca256
    
    [2] parted/libparted/arch/linux.c:linux_open()
        http://git.savannah.gnu.org/cgit/parted.git/tree/libparted/arch/linux.c?id=v3.2#n1628
    
    Closes !46 - Whole device FAT32 file system reports device busy warning
                 from mlabel

 src/GParted_Core.cc | 6 ++++++
 1 file changed, 6 insertions(+)
---
diff --git a/src/GParted_Core.cc b/src/GParted_Core.cc
index 8069666a..83846c19 100644
--- a/src/GParted_Core.cc
+++ b/src/GParted_Core.cc
@@ -4090,6 +4090,12 @@ bool GParted_Core::flush_device( PedDevice * lp_device )
        {
                success = ped_device_sync( lp_device ) ;
                ped_device_close( lp_device ) ;
+
+               // (!46) Wait for udev rules to complete after this ped_device_open() and
+               // ped_device_close() pair to avoid busy /dev/DISK entry when running file
+               // system specific querying commands on the whole disk device in the call
+               // sequence after get_device() in set_device_from_disk().
+               settle_device(SETTLE_DEVICE_PROBE_MAX_WAIT_SECONDS);
        }
        return success ;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]