From a0092a3d667863341339645f5d0bc9bc4b4b5108 Mon Sep 17 00:00:00 2001 From: Pascal Rigaux Date: Thu, 15 Jan 2004 11:27:12 +0000 Subject: - remove the use of BLKRRPART (telling the kernel to re-read the partition table) in most cases - replace with tell_kernel() and will_tell_kernel() - correctly handle in standalone the need to reboot, with no way to forget it (telling the WM to quit nicely then call reboot when it's done) --- perl-install/c/stuff.xs.pl | 17 +++++- perl-install/diskdrake/interactive.pm | 52 ++++++++++++++--- perl-install/fsedit.pm | 4 +- perl-install/install_interactive.pm | 2 +- perl-install/partition_table.pm | 107 +++++++++++++++++++++++++--------- perl-install/partition_table/raw.pm | 18 +----- 6 files changed, 143 insertions(+), 57 deletions(-) diff --git a/perl-install/c/stuff.xs.pl b/perl-install/c/stuff.xs.pl index dc162af36..ec4047b0c 100644 --- a/perl-install/c/stuff.xs.pl +++ b/perl-install/c/stuff.xs.pl @@ -229,11 +229,24 @@ dgettext(domainname, msgid) char * msgid int -add_partition(hd, start_sector, size_sector, part_number) +del_partition(hd, part_number) int hd + int part_number + CODE: + { + struct blkpg_partition p = { 0, 0, part_number, "", "" }; + struct blkpg_ioctl_arg s = { BLKPG_DEL_PARTITION, 0, sizeof(struct blkpg_partition), (void *) &p }; + RETVAL = ioctl(hd, BLKPG, &s) == 0; + } + OUTPUT: + RETVAL + +int +add_partition(hd, part_number, start_sector, size_sector) + int hd + int part_number unsigned long start_sector unsigned long size_sector - int part_number CODE: { long long start = start_sector * 512; diff --git a/perl-install/diskdrake/interactive.pm b/perl-install/diskdrake/interactive.pm index 67c9cb721..e9acaf4e6 100644 --- a/perl-install/diskdrake/interactive.pm +++ b/perl-install/diskdrake/interactive.pm @@ -110,7 +110,7 @@ struct hd { bool readonly # is it allowed to modify the partition table bool getting_rid_of_readonly_allowed # is it forbidden to write because the partition table is badly handled, or is it because we MUST not change the partition table bool isDirty # does it need to be written to the disk - bool needKernelReread # must we tell the kernel to reread the partition table + list will_tell_kernel # list of actions to tell to the kernel so that it knows the new partition table bool hasBeenDirty # for undo bool rebootNeeded # happens when a kernel reread failed bool partitionsRenumbered # happens when you @@ -142,7 +142,7 @@ struct raw_hd inherits hd { string mntpoint # '/', '/usr' ... string options # 'defaults', 'noauto' - # invalid: isDirty, needKernelReread, hasBeenDirty, rebootNeeded, primary, extended + # invalid: isDirty, will_tell_kernel, hasBeenDirty, rebootNeeded, primary, extended } struct all_hds { @@ -259,7 +259,7 @@ sub Done { $in->ask_okcancel('', [ formatError($err), N("Continue anyway?") ]) or return; } foreach (@{$all_hds->{hds}}) { - if (!write_partitions($in, $_)) { + if (!write_partitions($in, $_, 'skip_check_rebootNeeded')) { return if !$::isStandalone; $in->ask_yesorno(N("Quit without saving"), N("Quit without writing the partition table?"), 1) or return; } @@ -270,6 +270,10 @@ sub Done { $all_hds->{current_fstab} = $new; fs::write_fstab($all_hds); } + if (any { $_->{rebootNeeded} } @{$all_hds->{hds}}) { + $in->ask_warn('', N("You need to reboot for the partition table modifications to take place")); + tell_wm_and_reboot(); + } } 1; } @@ -705,7 +709,6 @@ sub Resize { $part->{size} == $size and return; my $oldsize = $part->{size}; - $hd->{isDirty} = $hd->{needKernelReread} = 1; $part->{size} = $size; $hd->adjustEnd($part); @@ -715,6 +718,8 @@ sub Resize { my $adjust = sub { my ($write_partitions) = @_; + partition_table::will_tell_kernel($hd, resize => $part); + if (isLVM($hd)) { lvm::lv_resize($part, $oldsize); } else { @@ -1043,16 +1048,20 @@ sub check { check_mntpoint($in, $part->{mntpoint}, $hd, $part, $all_hds); } +sub check_rebootNeeded { + my ($_in, $hd) = @_; + $hd->{rebootNeeded} and die \N("You'll need to reboot before the modification can take place"); +} + sub write_partitions { - my ($in, $hd) = @_; + my ($in, $hd, $b_skip_check_rebootNeeded) = @_; + check_rebootNeeded($in, $hd) if !$b_skip_check_rebootNeeded; $hd->{isDirty} or return 1; isLVM($hd) and return 1; $in->ask_okcancel(N("Read carefully!"), N("Partition table of drive %s is going to be written to disk!", $hd->{device}), 1) or return; - if (!$::testing) { - partition_table::write($hd); - } - $hd->{rebootNeeded} and die \N("You'll need to reboot before the modification can take place"); + partition_table::write($hd) if !$::testing; + check_rebootNeeded($in, $hd) if !$b_skip_check_rebootNeeded; 1; } @@ -1244,3 +1253,28 @@ sub choose_encrypt_key { { label => N("Encryption key (again)"), val => \$encrypt_key2, hidden => 1 }, ]) && $encrypt_key; } + + +sub tell_wm_and_reboot() { + my ($wm, $pid) = any::running_window_manager(); + + if (!$wm) { + system('reboot'); + } else { + if (fork()) { + any::ask_window_manager_to_logout($wm); + return; + } + + open STDIN, "/dev/null"; + open STDERR, ">&STDERR"; + c::setsid(); + exec 'perl', '-e', q( + my ($wm, $pid) = @ARGV; + my $nb; + for ($nb = 20; $nb && -e "/proc/$pid"; $nb--) { sleep 1 } + exec 'reboot'; + ), $wm, $pid; + } +} diff --git a/perl-install/fsedit.pm b/perl-install/fsedit.pm index dcba0d267..58143023a 100644 --- a/perl-install/fsedit.pm +++ b/perl-install/fsedit.pm @@ -682,7 +682,9 @@ sub undo { my $h; eval $code; @$_{@partition_table::fields2save} = @$h; - $_->{isDirty} = $_->{needKernelReread} = 1 if $_->{hasBeenDirty}; + if ($_->{hasBeenDirty}) { + partition_table::will_tell_kernel($_, 'force_reboot'); #- next action needing write_partitions will force it. We can't do it now since more undo may occur, and we must not needReboot now + } } } diff --git a/perl-install/install_interactive.pm b/perl-install/install_interactive.pm index 3b8e350e4..154f1bde1 100644 --- a/perl-install/install_interactive.pm +++ b/perl-install/install_interactive.pm @@ -195,7 +195,7 @@ When sure, press Ok."))) or return; filesystem checks will be run on your next boot into Windows(TM)")) if !isFat($part); $part->{isFormatted} = 1; - $hd->{isDirty} = $hd->{needKernelReread} = 1; + partition_table::will_tell_kernel($hd, resize => $part); #- down-sizing, write_partitions is not needed partition_table::adjust_local_extended($hd, $part); partition_table::adjust_main_extended($hd); diff --git a/perl-install/partition_table.pm b/perl-install/partition_table.pm index 2d3fe168d..fd911f7b0 100644 --- a/perl-install/partition_table.pm +++ b/perl-install/partition_table.pm @@ -23,7 +23,7 @@ use log; if_(arch() =~ /ppc/, 'Journalised FS: ext3', 'Journalised FS: ReiserFS', 'Journalised FS: JFS', 'Journalised FS: XFS', 'Apple HFS Partition', 'Apple Bootstrap')); @important_types2 = ('Linux RAID', 'Linux Logical Volume Manager partition'); -@fields2save = qw(primary extended totalsectors isDirty needKernelReread); +@fields2save = qw(primary extended totalsectors isDirty will_tell_kernel); @bad_types = ('Empty', 'DOS 3.3+ Extended Partition', 'Win95: Extended partition, LBA-mapped', 'Linux extended partition'); @@ -374,9 +374,18 @@ sub assign_device_numbers { } foreach (map { $_->{normal} } @{$hd->{extended} || []}) { my $dev = $hd->{prefix} . $i; - push @{$hd->{partitionsRenumbered}}, [ $_->{device}, $dev ] if $_->{device} && $dev ne $_->{device}; + my $renumbered = $_->{device} && $dev ne $_->{device}; + if ($renumbered) { + require fs; + eval { fs::umount_part($_) }; #- at least try to umount it + will_tell_kernel($hd, del => $_, 'delay_del'); + push @{$hd->{partitionsRenumbered}}, [ $_->{device}, $dev ]; + } $_->{device} = $dev; $_->{devfs_device} = $hd->{devfs_prefix} . '/part' . $i; + if ($renumbered) { + will_tell_kernel($hd, add => $_, 'delay_add'); + } $i++; } } @@ -576,6 +585,64 @@ sub read_extended { } } +sub will_tell_kernel { + my ($hd, $action, $o_part, $o_delay) = @_; + + if ($action eq 'resize') { + will_tell_kernel($hd, del => $o_part); + will_tell_kernel($hd, add => $o_part); + } else { + my $part_number = sub { $o_part->{device} =~ /(\d+)$/ ? $1 : internal_error("bad device " . description($o_part)) }; + push @{$hd->{'will_tell_kernel' . ($o_delay || '')} ||= []}, + [ + $action, + $action eq 'force_reboot' ? () : + $action eq 'add' ? ($part_number->(), $o_part->{start}, $o_part->{size}) : + $action eq 'del' ? $part_number->() : + internal_error("unknown action $action") + ]; + } + if (!$o_delay) { + foreach my $delay ('delay_del', 'delay_add') { + my $l = delete $hd->{"will_tell_kernel$delay"} or next; + push @{$hd->{will_tell_kernel} ||= []}, @$l; + } + } + $hd->{isDirty} = 1; +} + +sub tell_kernel { + my ($hd, $tell_kernel) = @_; + + my $F = partition_table::raw::openit($hd); + + my $force_reboot = any { $_->[0] eq 'force_reboot' } @$tell_kernel; + if (!$force_reboot) { + foreach (@$tell_kernel) { + my ($action, $part_number, $o_start, $o_size) = @$_; + + if ($action eq 'add') { + $force_reboot ||= !c::add_partition(fileno $F, $part_number, $o_start, $o_size); + } elsif ($action eq 'del') { + $force_reboot ||= !c::del_partition(fileno $F, $part_number); + } + log::l("tell kernel $action ($part_number $o_start $o_size), rebootNeeded is now $hd->{rebootNeeded}."); + } + } + if ($force_reboot) { + my @magic_parts = grep { $_->{isMounted} && $_->{real_mntpoint} } get_normal_parts($hd); + foreach (@magic_parts) { + syscall_('umount', $_->{real_mntpoint}) or log::l(N("error unmounting %s: %s", $_->{real_mntpoint}, $!)); + } + $hd->{rebootNeeded} = !ioctl($F, c::BLKRRPART(), 0); + log::l("tell kernel force_reboot, rebootNeeded is now $hd->{rebootNeeded}."); + + foreach (@magic_parts) { + syscall_('mount', $_->{real_mntpoint}, type2fs($_), c::MS_MGC_VAL()) or log::l(N("mount failed: ") . $!); + } + } +} + # write the partition table sub write { my ($hd) = @_; @@ -610,29 +677,9 @@ sub write { $hd->{isDirty} = 0; $hd->{hasBeenDirty} = 1; #- used in undo (to know if undo should believe isDirty or not) - if ($hd->{needKernelReread} && ref($hd->{needKernelReread}) eq 'ARRAY' && $::isStandalone) { - #- we've only been adding partitions. Try special add_partition (using BLKPG_ADD_PARTITION) - my $F = partition_table::raw::openit($hd) or goto force_reread; - - foreach (@{$hd->{needKernelReread}}) { - c::add_partition(fileno $F, $_->{start}, $_->{size}, $_->{device} =~ /(\d+)$/) - or goto force_reread; - } - } elsif ($hd->{needKernelReread}) { - force_reread: - #- now sync disk and re-read the partition table - common::sync(); - - my @magic_parts = grep { $_->{isMounted} && $_->{real_mntpoint} } get_normal_parts($hd); - foreach (@magic_parts) { - syscall_('umount', $_->{real_mntpoint}) or log::l(N("error unmounting %s: %s", $_->{real_mntpoint}, $!)); - } - $hd->kernel_read; - foreach (@magic_parts) { - syscall_('mount', $_->{real_mntpoint}, type2fs($_), c::MS_MGC_VAL()) or log::l(N("mount failed: ") . $!); - } + if (my $tell_kernel = delete $hd->{will_tell_kernel}) { + tell_kernel($hd, $tell_kernel); } - $hd->{needKernelReread} = 0; } sub active { @@ -652,11 +699,13 @@ sub remove { #- first search it in the primary partitions $i = 0; foreach (@{$hd->{primary}{normal}}) { if ($_ eq $part) { + will_tell_kernel($hd, del => $_); + splice(@{$hd->{primary}{normal}}, $i, 1); %$_ = (); #- blank it $hd->raw_removed($hd->{primary}{raw}); - return $hd->{isDirty} = $hd->{needKernelReread} = 1; + return 1; } $i++; } @@ -674,7 +723,8 @@ sub remove { remove_empty_extended($hd); assign_device_numbers($hd); - return $hd->{isDirty} = $hd->{needKernelReread} = 1; + will_tell_kernel($hd, del => $part); + return 1; } 0; } @@ -769,8 +819,7 @@ sub add { } success: assign_device_numbers($hd); - $hd->{isDirty} = 1; - push @{$hd->{needKernelReread} ||= []}, $part if !$hd->{needKernelReread} || ref($hd->{needKernelReread}) eq 'ARRAY' + will_tell_kernel($hd, add => $part); } # search for the next partition @@ -813,7 +862,7 @@ sub load { @$hd{@fields2save} = @$h; delete @$_{qw(isMounted isFormatted notFormatted toFormat toFormatUnsure)} foreach get_normal_parts($hd); - $hd->{isDirty} = $hd->{needKernelReread} = 1; + will_tell_kernel($hd, 'force_reboot'); #- just like undo, do not force write_partitions so that user can see the new partition table but can still discard it } sub save { diff --git a/perl-install/partition_table/raw.pm b/perl-install/partition_table/raw.pm index 5713e69d6..d8bcf8954 100644 --- a/perl-install/partition_table/raw.pm +++ b/perl-install/partition_table/raw.pm @@ -113,18 +113,6 @@ sub openit { my $F; sysopen($F, $hd->{file}, $o_mode || 0) && $F; } -# cause kernel to re-read partition table -sub kernel_read($) { - my ($hd) = @_; - common::sync(); - my $F = openit($hd) or return 0; - common::sync(); sleep(1); - $hd->{rebootNeeded} = !ioctl($F, c::BLKRRPART(), 0); - common::sync(); - close $F; - common::sync(); sleep(1); -} - sub raw_removed { my ($_hd, $_raw) = @_; } @@ -157,10 +145,10 @@ sub zero_MBR { } sub zero_MBR_and_dirty { - my ($hd) = @_; + my ($hd) = @_; + my @parts = (partition_table::get_normal_parts($hd), if_($hd->{primary}{extended}, $hd->{primary}{extended})); + partition_table::will_tell_kernel($hd, del => $_) foreach @parts; zero_MBR($hd); - $hd->{isDirty} = $hd->{needKernelReread} = 1; - } #- ugly stuff needed mainly for Western Digital IDE drives -- cgit v1.2.1