From 23db13194282cfff24d4bc88a7790ebd272953a0 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 2 Apr 2017 19:45:27 +0100 Subject: Add safety net for informing the kernel after writing a DOS partition table. There is an unidentified condition that prevents udevd calling the BLKRRPART ioctl after a partition table is written. It looks like either the kernel or udevd drops device change events if they are too closely spaced in time. So, in the case where we expect udevd to call BLKRRPART, check /proc/partitions to make sure it has done so. Arbitrarily try 5 times, 100ms apart, before giving up and informing the kernel ourselves. --- perl-install/partition_table/dos.pm | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'perl-install/partition_table') diff --git a/perl-install/partition_table/dos.pm b/perl-install/partition_table/dos.pm index a97fcf89d..92b28beee 100644 --- a/perl-install/partition_table/dos.pm +++ b/perl-install/partition_table/dos.pm @@ -6,9 +6,11 @@ use vars qw(@ISA); @ISA = qw(partition_table::raw); +use Time::HiRes qw(usleep); use common; use partition_table::raw; use partition_table; +use fs::proc_partitions; use fs::type; use c; @@ -291,7 +293,24 @@ sub need_to_tell_kernel { # diskdrake will not let the user delete an individual partition that is mounted, but will let the # user clear all partitions. So initialize() records if any partitions were mounted and we take note # of that here. - return ! -e '/usr/lib/udev/rules.d/60-block.rules' || delete $hd->{hadMountedPartitions} || any { $_->{isMounted} } partition_table::get_normal_parts($hd); + return 1 if ! -e '/usr/lib/udev/rules.d/60-block.rules' || delete $hd->{hadMountedPartitions} || any { $_->{isMounted} } partition_table::get_normal_parts($hd); + + # No further actions must be performed until the kernel has been informed of the changes. There is + # no easy way to check that udevd has received the uevent and called the BLKRRPART ioctl, so do it + # the hard way. + my $tries = 0; + do { + usleep(100000); + log::l("checking that udevd has informed the kernel of partition table changes"); + eval { fs::proc_partitions::compare($hd) }; + return 0 if !$@; + $tries++; + } while $tries < 5; + + # We don't expect to get here, but fail safe if so. + log::l("udevd failed to inform kernel of partition table changes"); + $hd->{rebootNeeded} = 1; + 1; } sub empty_raw { { raw => [ ({}) x $nb_primary ] } } -- cgit v1.2.1