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
This commit is contained in:
parent
be52d8636e
commit
1382e0b828
|
@ -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 ;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue