Wait for udev change on /dev/DISK when erasing signatures (#83)

A user reported that formatting a whole disk device with a file system
failed like this:

    Format /dev/sdd as ext4                                    (ERROR)
    + calibrate /dev/sdd                                       (SUCCESS)
        path: /dev/sdd (device)
        start: 0
        end: 15633407
        size: 15633408 (7.45 GiB)
    + clear old file system signatures in /dev/sdd             (SUCCESS)
      + write 512.00 KiB of zeros at byte offset 0             (SUCCESS)
      + write 4.00 KiB of zeros at byte offset 67108864        (SUCCESS)
      + write 512.00 KiB of zeros at byte offset 8003780608    (SUCCESS)
      + write 4.00 KiB of zeros at byte offset 8004239360      (SUCCESS)
      + write 8.00 KiB of zeros at byte offset 8004296704      (SUCCESS)
      + flush operating system cache of /dev/sdd               (SUCCESS)
    + create new ext4 file system                              (ERROR)
      + mkfs.ext4 -F -O ^64bit -L '' '/dev/sdd'                (ERROR)
        mke2fs 1.44.1 (24-Mar-2018)
        /dev/sdd is apparently in use by the system; will not make a filesystem here!

Opening the whole disk block device exclusively causes mkfs.ext4 to
report that error like this:

    # python
    >>> import os
    >>> f = os.open('/dev/sdb',os.O_RDONLY|os.O_EXCL)
    >>> ^Z
    [1]+  Stopped                 python
    # mkfs.ext4 -F -O ^64bit -L '' '/dev/sdb'
    mke2fs 1.42.9 (28-Dec-2013)
    /dev/sdb is apparently in use by the system; will not make a filesystem here!
    # echo $?
    1

I have not been able to reproduce this error, but with debugging and
sleeping in GParted, stracing GParted and using 'udevadm monitor' to
watch udev events the following sequence of events is seen:

  gparted    |format(partition, operationdetail)
  gparted    |  erase_filesystem_signatures(partition, operationdetail)
  gparted    |    get_device(device_path="/dev/sdb", lp_device, flush=false)
  gparted    |      ped_device_get("/dev/sdb")
  libparted  |        open("/dev/sdb", O_RDONLY) = 11
  libparted  |        close(11)
  gparted    |    ped_device_open(lp_device)
  libparted  |      open("/dev/sdb", O_RDWR) = 11
  gparted    |    ped_device_sync(lp_device)
  libparted  |      ioctl(11, BLKFLSBUF)
  gparted    |    ped_device_close()
  libparted  |      close(11)
  udev(async)|        KERNEL change /devices/.../sdb (block)
  udev(async)|        UDEV   change /devices/.../sdb (block)
  gparted    |  set_partition_type(partition, operationdetail)
  gparted    |  create_filesystem(partition, operationdetail)
  gparted    |    ext2::create(partition, operationdetail)
  gparted    |      FileSystem::execute_command("mkfs.ext4 -F -O ^64bit -L '' '/dev/sdb')

So it is assumed that the processing of the udev change rule after
closing the block device in erase_filesystem_signatures() overlaps with
the execution mkfs.ext4 and causes the seen error.  Fix by waiting for
those udev events to complete as was previously done by commits [1][2]
[3].

Also note that this is specific to creating file systems on and
formatting unpartitioned whole disk devices because set_partition_type()
is a no-operation.  Where as on a partitioned device
set_partition_type() calls commit() which already waits for udev rules
to complete [3].

[1] 50c8924a8e4d9cc96a2ea45f13291114402affee
    Wait for udev to recreate /dev/PTN entries when querying partition
    FSs (!46)
[2] 4f6c312e3bc68cafb5e6035fd4a5b5bbbfcea992
    Wait for udev change on /dev/DISK when querying whole device FS
    (!46)
[3] 2f53876c0f
    Wait for the kernel and udev to settle partitions for a second time
    (#790418)

Closes #83 - /dev/sdd is apparently in use by the system; will not make
             a filesystem here!
This commit is contained in:
Mike Fleetwood 2020-02-03 08:12:08 +00:00 committed by Curtis Gedak
parent 24c0b81bfc
commit 8ae9abada4
1 changed files with 7 additions and 0 deletions

View File

@ -3872,6 +3872,13 @@ bool GParted_Core::erase_filesystem_signatures( const Partition & partition, Ope
{
flush_success = ped_device_sync( lp_device ) ;
ped_device_close( lp_device ) ;
// (#83) Wait for udev rules to complete after this
// ped_device_close() to avoid busy /dev/DISK entry when running
// following file system specific manipulation commands on the
// whole disk device in format(), after this
// erase_filesystem_signatures().
settle_device(SETTLE_DEVICE_APPLY_MAX_WAIT_SECONDS);
}
od.get_last_child().set_success_and_capture_errors( flush_success );
overall_success &= flush_success ;