summaryrefslogtreecommitdiffstats
path: root/perl-install/partition_table.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perl-install/partition_table.pm')
-rw-r--r--perl-install/partition_table.pm107
1 files changed, 78 insertions, 29 deletions
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 {