[Fai-commit] r6334 - in trunk: bin lib/setup-storage

Michael Tautschnig mt at alioth.debian.org
Thu Apr 14 11:31:44 UTC 2011


Author: mt
Date: 2011-04-14 11:31:40 +0000 (Thu, 14 Apr 2011)
New Revision: 6334

Modified:
   trunk/bin/setup-storage
   trunk/lib/setup-storage/Commands.pm
   trunk/lib/setup-storage/Exec.pm
   trunk/lib/setup-storage/Init.pm
   trunk/lib/setup-storage/Parser.pm
   trunk/lib/setup-storage/Volumes.pm
Log:
setup-storage, setup-storage/{Volumes,Commands,Exec,Init,Parser}.pm: Software RAID bugfixes

* setup-storage/Volumes.pm: Properly handle preserved partitions when marked
  missing in RAID volume.
* setup-storage/Commands.pm: Don't add "missing" when doing mdadm --assemble.
* setup-storage/{Init,Parser,Volumes}.pm: Build device nesting tree.
* setup-storage/Commands.pm: Honor dependencies and nesting of LVM/RAID
  devices when stopping and removing volumes and partitions.
* setup-storage/Commands.pm: Add mdadm --assemble call if arrays were detected
  by mdadm --examine (these might exist but haven't necessarily been started).
* setup-storage/Exec.pm: Ignore error exit code 2 in this mdadm --assemble
  call.
* setup-storage: Force start of arrays using mdadm-startall. Added debug
  output of device nesting tree.


Modified: trunk/bin/setup-storage
===================================================================
--- trunk/bin/setup-storage	2011-04-14 11:11:31 UTC (rev 6333)
+++ trunk/bin/setup-storage	2011-04-14 11:31:40 UTC (rev 6334)
@@ -130,6 +130,15 @@
 # make sure there are no empty disk_config stanzas
 &FAI::check_config;
 
+# first find the proper way to tell udev to settle
+$FAI::udev_settle = "udevadm settle --timeout=10" if (&FAI::in_path("udevadm"));
+$FAI::udev_settle = "udevsettle --timeout=10" if (&FAI::in_path("udevsettle"));
+defined($FAI::udev_settle) or die "Failed to find determine a proper way to tell udev to settle; is udev installed?";
+
+# start all RAID arrays in case some of the aren't running yet
+`mdadm-startall`;
+`$FAI::udev_settle`;
+
 # read the sizes and partition tables of all disks listed in $FAI::disks
 &FAI::get_current_disks;
 
@@ -163,6 +172,11 @@
 
   our %current_raid_config;
   print Dumper \%current_raid_config;
+
+  print "Current device tree\n";
+
+  our %current_dev_children;
+  print Dumper \%current_dev_children;
 }
 
 # compute the new LVM and partition sizes; do the partition sizes first to have
@@ -173,6 +187,8 @@
 # print the current contents of $FAI::configs
 $FAI::debug and print "Desired disk layout\n";
 $FAI::debug and print Dumper \%FAI::configs;
+$FAI::debug and print "Desired device tree\n";
+$FAI::debug and print Dumper \%FAI::dev_children;
 
 # generate the command script
 &FAI::build_disk_commands;
@@ -193,10 +209,6 @@
 }
 
 # run the commands (if $FAI::no_dry_run is set)
-# first find the proper way to tell udev to settle
-$FAI::udev_settle = "udevadm settle --timeout=10" if (&FAI::in_path("udevadm"));
-$FAI::udev_settle = "udevsettle --timeout=10" if (&FAI::in_path("udevsettle"));
-defined($FAI::udev_settle) or die "Failed to find determine a proper way to tell udev to settle; is udev installed?";
 foreach (&numsort(keys %FAI::commands)) {
   `$FAI::udev_settle`;
   next if ($FAI::commands{$_}{cmd} eq "true");

Modified: trunk/lib/setup-storage/Commands.pm
===================================================================
--- trunk/lib/setup-storage/Commands.pm	2011-04-14 11:11:31 UTC (rev 6333)
+++ trunk/lib/setup-storage/Commands.pm	2011-04-14 11:31:40 UTC (rev 6334)
@@ -276,6 +276,19 @@
 ################################################################################
 sub build_raid_commands {
 
+  # check RAID arrays if there are pre-existing ones
+  &FAI::push_command("mdadm --assemble --scan --config=$FAI::DATADIR/mdadm-from-examine.conf",
+    "", "mdadm_startall_examined") if (scalar(keys %FAI::current_raid_config));
+  foreach my $id (keys %FAI::current_raid_config) {
+    my $md = "/dev/md$id";
+    my $pre_deps_cl = "mdadm_startall_examined";
+    $pre_deps_cl .= ",self_cleared_" .
+      join(",self_cleared_", @{ $FAI::current_dev_children{$md} })
+      if (defined($FAI::current_dev_children{$md}) &&
+        scalar(@{ $FAI::current_dev_children{$md} }));
+    &FAI::push_command( "mdadm -W --stop $md", "$pre_deps_cl", "self_cleared_$md");
+  }
+
   foreach my $config (keys %FAI::configs) { # loop through all configs
     # no encrypted, tmpfs, LVM or physical devices here
     next if ($config eq "CRYPT" || $config eq "TMPFS" || $config =~ /^VG_./ || $config =~ /^PHY_./);
@@ -332,7 +345,7 @@
 	$pre_req =~ s/^,//;
         # Assemble the array
         &FAI::push_command(
-	    "mdadm --assemble /dev/md$id " . join(" ", @eff_devs),
+	    "mdadm --assemble /dev/md$id " . join(" ", grep(!/^missing$/, @eff_devs)),
 	    "$pre_req", "exist_/dev/md$id");
 
         # create the filesystem on the volume, if requested
@@ -397,14 +410,14 @@
     # create all the devices
     foreach my $d (keys %{ $FAI::configs{$config}{devices} }) {
       $d = &FAI::enc_name($d);
-      my $pre = ",exist_$d";
+      my $pre = "exist_$d";
       my ($i_p_d, $disk, $part_no) = &FAI::phys_dev($d);
-      $pre = ",pt_complete_$disk"
+      $pre .= ",pt_complete_$disk"
         if (&FAI::set_partition_type_on_phys_dev($d, "lvm") &&
           defined($FAI::configs{"PHY_$disk"}));
 
       &FAI::push_command( "pvcreate -ff -y $pv_create_options $d",
-        "all_pv_sigs_removed$pre", "pv_done_$d");
+        "$pre", "pv_done_$d");
       $devs .= " $d";
       $pre_dev .= ",pv_done_$d";
     }
@@ -449,14 +462,14 @@
 
   # create all the devices
   foreach my $dev (@new_devices) {
-    my $pre = ",exist_$dev";
+    my $pre = "exist_$dev";
     my ($i_p_d, $disk, $part_no) = &FAI::phys_dev($dev);
-    $pre = ",pt_complete_$disk"
+    $pre .= ",pt_complete_$disk"
       if (&FAI::set_partition_type_on_phys_dev($dev, "lvm") &&
         defined($FAI::configs{"PHY_$disk"}));
 
     &FAI::push_command( "pvcreate -ff -y $pv_create_options $dev",
-      "all_pv_sigs_removed$pre", "pv_done_$dev");
+      "$pre", "pv_done_$dev");
     $pre_dev .= ",pv_done_$dev";
   }
   $pre_dev =~ s/^,//;
@@ -467,7 +480,7 @@
     &FAI::push_command( "vgextend $vg " . join (" ", @new_devices), "$pre_dev",
       "vg_extended_$vg" );
   } else {
-    &FAI::push_command( "true", "all_pv_sigs_removed,$pre_dev", "vg_extended_$vg" );
+    &FAI::push_command( "true", "self_cleared_VG_$vg,$pre_dev", "vg_extended_$vg" );
   }
 
   # run vgreduce to get them removed
@@ -593,11 +606,13 @@
         next;
     } elsif ($dev =~ m{^/dev/md[\/]?(\d+)$}) {
       my $vol = $1;
+      defined ($FAI::configs{RAID}) or next;
       defined ($FAI::configs{RAID}{volumes}{$vol}) or next;
       next if (1 == $FAI::configs{RAID}{volumes}{$vol}{preserve});
     } elsif ($dev =~ m{^/dev/([^/\s]+)/([^/\s]+)$}) {
       my $ivg = $1;
       my $lv = $2;
+      defined($FAI::configs{"VG_$ivg"}) or next;
       defined($FAI::configs{"VG_$ivg"}{volumes}{$lv}) or next;
       next if (1 == $FAI::configs{"VG_$ivg"}{volumes}{$lv}{size}{preserve});
     } else {
@@ -609,26 +624,35 @@
   }
 
   if (0 == $clear_vg) {
-    my $vg_setup_pre = "vgchange_a_n";
-    if (defined($FAI::configs{"VG_$vg"}{volumes})) {
+    my $vg_setup_pre = "vgchange_a_n_VG_$vg";
+    if (defined($FAI::configs{"VG_$vg"})) {
       $FAI::configs{"VG_$vg"}{exists} = 1;
 
       # remove all volumes that do not exist anymore or need not be preserved
       foreach my $lv (keys %{ $FAI::current_lvm_config{$vg}{volumes} }) {
+        my $pre_deps_cl = "";
+        $pre_deps_cl = ",self_cleared_" .
+          join(",self_cleared_", @{ $FAI::current_dev_children{"/dev/$vg/$lv"} })
+            if (defined($FAI::current_dev_children{"/dev/$vg/$lv"}) &&
+              scalar(@{ $FAI::current_dev_children{"/dev/$vg/$lv"} }));
         # skip preserved/resized volumes
         if (defined ( $FAI::configs{"VG_$vg"}{volumes}{$lv})) {
           if ($FAI::configs{"VG_$vg"}{volumes}{$lv}{size}{preserve} == 1 ||
             $FAI::configs{"VG_$vg"}{volumes}{$lv}{size}{resize} == 1) {
-            &FAI::push_command("true", "vgchange_a_n", "exist_/dev/$vg/$lv");
+            &FAI::push_command("true", "vgchange_a_n_VG_$vg$pre_deps_cl",
+              "exist_/dev/$vg/$lv,self_cleared_/dev/$vg/$lv");
             next;
           }
         }
 
-        &FAI::push_command( "lvremove -f $vg/$lv", "vgchange_a_n", "lv_rm_$vg/$lv");
+        &FAI::push_command( "lvremove -f $vg/$lv",
+          "vgchange_a_n_VG_$vg$pre_deps_cl",
+          "lv_rm_$vg/$lv,self_cleared_/dev/$vg/$lv");
         $vg_setup_pre .= ",lv_rm_$vg/$lv";
       }
     } else {
-      &FAI::push_command("true", "vgchange_a_n", "exist_/dev/$vg/$_") foreach
+      &FAI::push_command("true", "vgchange_a_n_VG_$vg",
+        "exist_/dev/$vg/$_,self_cleared_/dev/$vg/$_") foreach
         (keys %{ $FAI::current_lvm_config{$vg}{volumes} });
     }
     &FAI::push_command("true", $vg_setup_pre, "vg_exists_$vg");
@@ -636,9 +660,16 @@
     return 0;
   }
 
-  my $vg_destroy_pre = "vgchange_a_n";
+  my $vg_destroy_pre = "vgchange_a_n_VG_$vg";
   foreach my $lv (keys %{ $FAI::current_lvm_config{$vg}{volumes} }) {
-    &FAI::push_command( "lvremove -f $vg/$lv", "vgchange_a_n", "lv_rm_$vg/$lv");
+    my $pre_deps_cl = "";
+    $pre_deps_cl = ",self_cleared_" .
+      join(",self_cleared_", @{ $FAI::current_dev_children{"/dev/$vg/$lv"} })
+        if (defined($FAI::current_dev_children{"/dev/$vg/$lv"}) &&
+          scalar(@{ $FAI::current_dev_children{"/dev/$vg/$lv"} }));
+    &FAI::push_command( "lvremove -f $vg/$lv",
+      "vgchange_a_n_VG_$vg$pre_deps_cl",
+      "lv_rm_$vg/$lv,self_cleared_/dev/$vg/$lv");
     $vg_destroy_pre .= ",lv_rm_$vg/$lv";
   }
   &FAI::push_command( "vgremove $vg", "$vg_destroy_pre", "vg_removed_$vg");
@@ -648,7 +679,7 @@
   $devices .= " " . &FAI::enc_name($_) foreach
     (@{ $FAI::current_lvm_config{$vg}{physical_volumes} });
   $FAI::debug and print "Erased devices:$devices\n";
-  &FAI::push_command( "pvremove $devices", "", "pv_sigs_removed_$vg" );
+  &FAI::push_command( "pvremove $devices", "vg_removed_$vg", "pv_sigs_removed_$vg" );
   return 1;
 }
 
@@ -662,14 +693,26 @@
 sub build_lvm_commands {
 
   # disable volumes if there are pre-existing ones
-  &FAI::push_command("vgchange -a n", "", "vgchange_a_n");
-  my $all_vg_pre = "vgchange_a_n";
-  if (scalar(keys %FAI::current_lvm_config)) {
-    foreach my $vg (keys %FAI::current_lvm_config) {
-      $all_vg_pre .= ",pv_sigs_removed_$vg" if (&FAI::cleanup_vg($vg));
+  foreach my $d (keys %FAI::current_dev_children) {
+    next unless ($d =~ /^VG_(.+)$/);
+    my $vg = $1;
+    my $vg_pre = "vgchange_a_n_VG_$vg";
+    my $pre_deps_vgc = "";
+    foreach my $c (@{ $FAI::current_dev_children{$d} }) {
+      $pre_deps_vgc = ",self_cleared_" .
+        join(",self_cleared_", @{ $FAI::current_dev_children{$c} })
+        if (defined($FAI::current_dev_children{$c}) &&
+          scalar(@{ $FAI::current_dev_children{$c} }));
     }
+    $pre_deps_vgc =~ s/^,//;
+    &FAI::push_command("vgchange -a n $1", "$pre_deps_vgc", $vg_pre);
+    $vg_pre .= ",pv_sigs_removed_$vg" if (&FAI::cleanup_vg($vg));
+    my $pre_deps_cl = "";
+    $pre_deps_cl = ",self_cleared_" .
+      join(",self_cleared_", @{ $FAI::current_dev_children{$d} })
+      if (scalar(@{ $FAI::current_dev_children{$d} }));
+    &FAI::push_command("true", "$vg_pre$pre_deps_cl", "self_cleared_VG_$vg");
   }
-  &FAI::push_command("true", "$all_vg_pre", "all_pv_sigs_removed");
 
   # loop through all configs
   foreach my $config (keys %FAI::configs) {
@@ -899,8 +942,15 @@
     or die "Can't change disklabel, partitions are to be preserved\n";
 
   # write the disklabel to drop the previous partition table
+  my $pre_deps = "";
+  foreach my $c (@{ $FAI::current_dev_children{$disk} }) {
+    $pre_deps .= ",self_cleared_" .
+    join(",self_cleared_", @{ $FAI::current_dev_children{$c} })
+    if (defined($FAI::current_dev_children{$c}) &&
+      scalar(@{ $FAI::current_dev_children{$c} }));
+  }
   &FAI::push_command( ($needs_resize ? "parted -s $disk mklabel $label" : "true"),
-    "exist_$disk,all_pv_sigs_removed", "cleared1_$disk" );
+    "exist_$disk$pre_deps", "cleared1_$disk" );
 
   &FAI::rebuild_preserved_partitions($config, \@to_preserve) if ($needs_resize);
 

Modified: trunk/lib/setup-storage/Exec.pm
===================================================================
--- trunk/lib/setup-storage/Exec.pm	2011-04-14 11:11:31 UTC (rev 6333)
+++ trunk/lib/setup-storage/Exec.pm	2011-04-14 11:31:40 UTC (rev 6334)
@@ -178,6 +178,15 @@
     exit_codes   => [0..255],
   },
   {
+    error        => "mdadm_assemble",
+    message      => "mdadm tried to assemble arrays but failed, ignoring as arrays might be running already\n",
+    stderr_regex => '^$',
+    stdout_regex => '^$',
+    program      => "mdadm --assemble --scan --config=$FAI::DATADIR/mdadm-from-examine.conf",
+    response     => "warn",
+    exit_codes   => [2],
+  },
+  {
     error        => "catch_all_nonzero_exit_code",
     message      => "Command had non-zero exit code\n",
     stderr_regex => "",

Modified: trunk/lib/setup-storage/Init.pm
===================================================================
--- trunk/lib/setup-storage/Init.pm	2011-04-14 11:11:31 UTC (rev 6333)
+++ trunk/lib/setup-storage/Init.pm	2011-04-14 11:31:40 UTC (rev 6334)
@@ -145,6 +145,14 @@
 
 ################################################################################
 #
+# @brief Map from devices to volumes stacked on top of them
+#
+################################################################################
+%FAI::dev_children = ();
+%FAI::current_dev_children = ();
+
+################################################################################
+#
 # @brief Add command to hash
 #
 # @param cmd Command

Modified: trunk/lib/setup-storage/Parser.pm
===================================================================
--- trunk/lib/setup-storage/Parser.pm	2011-04-14 11:11:31 UTC (rev 6333)
+++ trunk/lib/setup-storage/Parser.pm	2011-04-14 11:31:40 UTC (rev 6334)
@@ -139,6 +139,11 @@
     preserveparts => 0,
     partitions => {}
   };
+
+  # Init device tree object
+  $FAI::dev_children{$disk} = ();
+
+  return 1;
 }
 
 ################################################################################
@@ -161,10 +166,13 @@
 
   # check that a physical device is being configured; logical partitions are
   # only supported on msdos disk labels.
-  ($FAI::device =~ /^PHY_/ && ($type ne "logical"
+  ($FAI::device =~ /^PHY_(.+)$/ && ($type ne "logical"
       || $FAI::configs{$FAI::device}{disklabel} eq "msdos")) or 
     die "Syntax error: invalid partition type";
 
+  # the disk
+  my $disk = $1;
+
   # the index of the new partition
   my $part_number = 0;
 
@@ -277,6 +285,9 @@
 
       # add the resize = 0 flag, if it doesn't exist already
       defined ($part_size->{resize}) or $part_size->{resize} = 0;
+
+      # add entry to device tree
+      push @{ $FAI::dev_children{$disk} }, &FAI::make_device_name($disk, $extended);
     }
   }
 
@@ -290,6 +301,7 @@
   # the reference is used by all further processing of this config line
   $FAI::partition_pointer =
     (\%FAI::configs)->{$FAI::device}->{partitions}->{$part_number};
+  $FAI::partition_pointer_dev_name = &FAI::make_device_name($disk, $part_number);
 
   # as we can't compute the index from the reference, we need to store the
   # $part_number explicitly
@@ -309,6 +321,9 @@
   # add the resize = 0 flag, if it doesn't exist already
   defined ($FAI::partition_pointer->{size}->{resize})
     or $FAI::partition_pointer->{size}->{resize} = 0;
+
+  # add entry to device tree
+  push @{ $FAI::dev_children{$disk} }, $FAI::partition_pointer_dev_name;
 }
 
 ################################################################################
@@ -577,6 +592,18 @@
 	  use Storable qw(dclone);
 
 	  $FAI::configs{$FAI::device} = dclone($FAI::configs{"PHY_" . $ref_dev});
+    # add entries to device tree
+    defined($FAI::dev_children{$ref_dev}) or
+      &FAI::internal_error("dev_children missing reference entry");
+    ($FAI::device =~ /^PHY_(.+)$/) or
+      &FAI::internal_error("unexpected device name");
+    my $disk = $1;
+    foreach my $p (@{ $FAI::dev_children{$ref_dev} }) {
+      my ($i_p_d, $rd, $pd) = &FAI::phys_dev($p);
+      (1 == $i_p_d) or next;
+      ($rd eq $ref_dev) or &FAI::internal_error("dev_children is inconsistent");
+      push @{ $FAI::dev_children{$disk} }, &FAI::make_device_name($disk, $pd);
+    }
 	}
 	| /^sameas:(\S+)/
 	{
@@ -586,6 +613,18 @@
 	  use Storable qw(dclone);
 
 	  $FAI::configs{$FAI::device} = dclone($FAI::configs{"PHY_" . $ref_dev});
+    # add entries to device tree
+    defined($FAI::dev_children{$ref_dev}) or
+      &FAI::internal_error("dev_children missing reference entry");
+    ($FAI::device =~ /^PHY_(.+)$/) or
+      &FAI::internal_error("unexpected device name");
+    my $disk = $1;
+    foreach my $p (@{ $FAI::dev_children{$ref_dev} }) {
+      my ($i_p_d, $rd, $pd) = &FAI::phys_dev($p);
+      (1 == $i_p_d) or next;
+      ($rd eq $ref_dev) or &FAI::internal_error("dev_children is inconsistent");
+      push @{ $FAI::dev_children{$disk} }, &FAI::make_device_name($disk, $pd);
+    }
 	}
         | /^always_format:(\d+(,\d+)*)/
         {
@@ -619,6 +658,7 @@
           # set the reference to the current volume
           # the reference is used by all further processing of this config line
           $FAI::partition_pointer = (\%FAI::configs)->{RAID}->{volumes}->{$vol_id};
+          $FAI::partition_pointer_dev_name = "/dev/md$vol_id";
         }
         mountpoint devices filesystem mount_options mdcreateopts
         | /^(luks|tmp|swap)\s+/
@@ -639,6 +679,7 @@
           $FAI::configs{CRYPT}{volumes}{$vol_id}{preserve} = 0;
 
           $FAI::partition_pointer = (\%FAI::configs)->{CRYPT}->{volumes}->{$vol_id};
+          $FAI::partition_pointer_dev_name = "CRYPT$vol_id";
         }
         mountpoint devices filesystem mount_options lv_or_fsopts
         | /^tmpfs\s+/
@@ -659,6 +700,7 @@
           $FAI::configs{TMPFS}{volumes}{$vol_id}{preserve} = 0;
 
           $FAI::partition_pointer = (\%FAI::configs)->{TMPFS}->{volumes}->{$vol_id};
+          $FAI::partition_pointer_dev_name = "TMPFS$vol_id";
         }
         mountpoint tmpfs_size mount_options
         | type mountpoint size filesystem mount_options lv_or_fsopts
@@ -703,6 +745,9 @@
           # set the reference to the current volume
           # the reference is used by all further processing of this config line
           $FAI::partition_pointer = (\%FAI::configs)->{$FAI::device}->{volumes}->{$2};
+          $FAI::partition_pointer_dev_name = "/dev/$1/$2";
+          # add entry to device tree
+          push @{ $FAI::dev_children{$FAI::device} }, $FAI::partition_pointer_dev_name;
         }
 
     mountpoint: m{^(-|swap|/[^\s\:]*)(:encrypt(:randinit)?)?}
@@ -736,6 +781,8 @@
             $FAI::configs{$FAI::device}{volumes} = {};
           # initialise the list of physical devices
           $FAI::configs{$FAI::device}{devices} = ();
+          # init device tree
+          $FAI::dev_children{$FAI::device} = ();
           # the rule must not return undef
           1;
         }
@@ -865,15 +912,21 @@
                 "spare" => $spare,
                 "missing" => $missing
               };
+              # add entry to device tree
+              push @{ $FAI::dev_children{$dev} }, $FAI::partition_pointer_dev_name;
             } elsif ($FAI::device eq "CRYPT") {
               die "Failed to resolve $dev to a unique device name\n" if (scalar(@candidates) != 1);
               $FAI::partition_pointer->{device} = $candidates[0];
               &FAI::mark_encrypted($candidates[0]);
+              # add entry to device tree
+              push @{ $FAI::dev_children{$candidates[0]} }, $FAI::partition_pointer_dev_name;
             } else {
               die "Failed to resolve $dev to a unique device name\n" if (scalar(@candidates) != 1);
               $dev = $candidates[0];
               # create an empty hash for each device
               $FAI::configs{$FAI::device}{devices}{$dev} = {};
+              # add entry to device tree
+              push @{ $FAI::dev_children{$dev} }, $FAI::device;
             }
           }
           1;
@@ -1005,6 +1058,8 @@
         next if ($this_mp eq "-");
         defined($all_mount_pts{$this_mp}) and die
           "Mount point $this_mp used twice\n";
+        defined($FAI::dev_children{&FAI::make_device_name($1, $p)}) and die
+          "Mount point $this_mp is shadowed by stacked devices\n";
         ($this_mp eq "none") or $all_mount_pts{$this_mp} = 1;
       }
     } elsif ($config =~ /^VG_(.+)$/) {
@@ -1014,6 +1069,8 @@
         next if ($this_mp eq "-");
         defined($all_mount_pts{$this_mp}) and die
           "Mount point $this_mp used twice\n";
+        defined($FAI::dev_children{"/dev/$1/$p"}) and die
+          "Mount point $this_mp is shadowed by stacked devices\n";
         ($this_mp eq "none") or $all_mount_pts{$this_mp} = 1;
       }
       next;
@@ -1025,6 +1082,8 @@
         next if ($this_mp eq "-");
         defined($all_mount_pts{$this_mp}) and die
           "Mount point $this_mp used twice\n";
+        defined($FAI::dev_children{"/dev/md$p"}) and die
+          "Mount point $this_mp is shadowed by stacked devices\n";
         ($this_mp eq "none") or $all_mount_pts{$this_mp} = 1;
       }
     } elsif ($config eq "CRYPT") {

Modified: trunk/lib/setup-storage/Volumes.pm
===================================================================
--- trunk/lib/setup-storage/Volumes.pm	2011-04-14 11:11:31 UTC (rev 6333)
+++ trunk/lib/setup-storage/Volumes.pm	2011-04-14 11:31:40 UTC (rev 6334)
@@ -98,6 +98,9 @@
     # make sure, $disk is a proper block device
     (-b $disk) or die "$disk is not a block special device!\n";
 
+    # init device tree
+    $FAI::current_dev_children{$disk} = ();
+
     # the list to hold the output of parted commands as parsed below
     my @parted_print = ();
 
@@ -326,6 +329,9 @@
       ( ( $FAI::current_config{$disk}{disklabel} eq "msdos" )
           && ( $6 eq "extended" ) )
         and $FAI::current_config{$disk}{partitions}{$1}{is_extended} = 1;
+
+      # add entry in device tree
+      push @{ $FAI::current_dev_children{$disk} }, &FAI::make_device_name($disk, $1);
     }
 
     # reset the output list
@@ -378,6 +384,9 @@
     # initialise the hash entry
     $FAI::current_lvm_config{$vg}{physical_volumes} = ();
 
+    # init device tree
+    $FAI::current_dev_children{"VG_$vg"} = ();
+
     # store the vg size in MB
     my %vg_info = get_volume_group_information($vg);
     if (%vg_info) {
@@ -395,12 +404,19 @@
       $FAI::current_lvm_config{$vg}{volumes}{$short_name}{size} =
         &FAI::convert_unit($lv_info{$lv_name}->{lv_size} .
           $lv_info{$lv_name}->{lv_size_unit});
+      # add entry in device tree
+      push @{ $FAI::current_dev_children{"VG_$vg"} }, $lv_name;
     }
 
     # store the physical volumes
     my %pv_info = get_physical_volume_information($vg);
-    push @{ $FAI::current_lvm_config{$vg}{physical_volumes} },
-      abs_path($_) foreach (sort keys %pv_info);
+    foreach my $pv_name (sort keys %pv_info) {
+      push @{ $FAI::current_lvm_config{$vg}{physical_volumes} },
+        abs_path($pv_name);
+
+      # add entry in device tree
+      push @{ $FAI::current_dev_children{abs_path($pv_name)} }, "VG_$vg";
+    }
   }
 
 }
@@ -442,29 +458,37 @@
 # UUID=77a22e9f:83fd1276:135399f0:a895f15f
 #    devices=/dev/sde3,/dev/sdf3,/dev/sdd3
 
+  # create a temporary mdadm-from-examine.conf
+  open(MDADM_EX, ">$FAI::DATADIR/mdadm-from-examine.conf");
+
   # the id of the RAID
   my $id;
 
   # parse the output line by line
   foreach my $line (@mdadm_print) {
+    print MDADM_EX "$line";
     if ($line =~ /^ARRAY \/dev\/md[\/]?(\d+)\s+/) {
       $id = $1;
 
       foreach (split (" ", $line)) {
-	  if ($_ =~ /^level=(\S+)/) {
-	      $FAI::current_raid_config{$id}{mode} = $1;
-	  }
+        $FAI::current_raid_config{$id}{mode} = $1 if ($_ =~ /^level=(\S+)/);
       }
     } elsif ($line =~ /^\s*devices=(\S+)$/) {
       defined($id) or
         &FAI::internal_error("mdadm ARRAY line not yet seen -- unexpected mdadm output:\n"
-          . join("", @mdadm_print));
-      push @{ $FAI::current_raid_config{$id}{devices} }, abs_path($_)
-        foreach (split (",", $1));
- 
+        . join("", @mdadm_print));
+      foreach my $d (split (",", $1)) {
+        push @{ $FAI::current_raid_config{$id}{devices} }, abs_path($d);
+
+        # add entry in device tree
+        push @{ $FAI::current_dev_children{abs_path($d)} }, "/dev/md$id";
+      }
+
       undef($id);
     }
   }
+
+  close(MDADM_EX);
 }
 
 
@@ -476,34 +500,49 @@
 #
 ################################################################################
 sub mark_preserve {
-  my ($device_name) = @_;
+  my ($device_name, $missing) = @_;
   my ($i_p_d, $disk, $part_no) = &FAI::phys_dev($device_name);
 
   if (1 == $i_p_d) {
-    defined ($FAI::current_config{$disk}{partitions}{$part_no}) or die
-      "Can't preserve $device_name because it does not exist\n";
-    if (defined($FAI::configs{"PHY_$disk"}{partitions}{$part_no})) {
+    if (defined($FAI::configs{"PHY_$disk"}) &&
+        defined($FAI::configs{"PHY_$disk"}{partitions}{$part_no})) {
+      defined ($FAI::current_config{$disk}{partitions}{$part_no}) or die
+        "Can't preserve $device_name because it does not exist\n";
       $FAI::configs{"PHY_$disk"}{partitions}{$part_no}{size}{preserve} = 1;
       $FAI::configs{"PHY_$disk"}{preserveparts} = 1;
+    } elsif (0 == $missing) {
+      defined ($FAI::current_config{$disk}{partitions}{$part_no}) or die
+        "Can't preserve $device_name because it does not exist\n";
     }
   } elsif ($device_name =~ m{^/dev/md[\/]?(\d+)$}) {
     my $vol = $1;
-    defined ($FAI::current_raid_config{$vol}) or die
-      "Can't preserve $device_name because it does not exist\n";
-    if (defined($FAI::configs{RAID}{volumes}{$vol}) && 
-        $FAI::configs{RAID}{volumes}{$vol}{preserve} != 1) {
-      $FAI::configs{RAID}{volumes}{$vol}{preserve} = 1;
-      &FAI::mark_preserve($_) foreach (keys %{ $FAI::configs{RAID}{volumes}{$vol}{devices} });
+    if (defined($FAI::configs{RAID}) &&
+        defined($FAI::configs{RAID}{volumes}{$vol})) {
+      defined ($FAI::current_raid_config{$vol}) or die
+        "Can't preserve $device_name because it does not exist\n";
+      if ($FAI::configs{RAID}{volumes}{$vol}{preserve} != 1) {
+        $FAI::configs{RAID}{volumes}{$vol}{preserve} = 1;
+        &FAI::mark_preserve($_, $FAI::configs{RAID}{volumes}{$vol}{devices}{$_}{missing})
+          foreach (keys %{ $FAI::configs{RAID}{volumes}{$vol}{devices} });
+      }
+    } elsif (0 == $missing) {
+      defined ($FAI::current_raid_config{$vol}) or die
+        "Can't preserve $device_name because it does not exist\n";
     }
   } elsif ($device_name =~ m{^/dev/([^/\s]+)/([^/\s]+)$}) {
     my $vg = $1;
     my $lv = $2;
-    defined ($FAI::current_lvm_config{$vg}{volumes}{$lv}) or die
-      "Can't preserve $device_name because it does not exist\n";
-    if (defined($FAI::configs{"VG_$vg"}{volumes}{$lv}) &&
-        $FAI::configs{"VG_$vg"}{volumes}{$lv}{size}{preserve} != 1) {
-      $FAI::configs{"VG_$vg"}{volumes}{$lv}{size}{preserve} = 1;
-      &FAI::mark_preserve($_) foreach (keys %{ $FAI::configs{"VG_$vg"}{devices} });
+    if (defined($FAI::configs{"VG_$vg"}) &&
+        defined($FAI::configs{"VG_$vg"}{volumes}{$lv})) {
+      defined ($FAI::current_lvm_config{$vg}{volumes}{$lv}) or die
+        "Can't preserve $device_name because it does not exist\n";
+      if ($FAI::configs{"VG_$vg"}{volumes}{$lv}{size}{preserve} != 1) {
+        $FAI::configs{"VG_$vg"}{volumes}{$lv}{size}{preserve} = 1;
+        &FAI::mark_preserve($_, $missing) foreach (keys %{ $FAI::configs{"VG_$vg"}{devices} });
+      }
+    } elsif (0 == $missing) {
+      defined ($FAI::current_lvm_config{$vg}{volumes}{$lv}) or die
+        "Can't preserve $device_name because it does not exist\n";
     }
   } else {
     warn "Don't know how to mark $device_name for preserve\n";
@@ -561,7 +600,7 @@
           "Can't preserve /dev/$1/$l because it does not exist\n";
         defined ($FAI::configs{$config}{volumes}{$l}{size}{range}) or die
           "Can't preserve /dev/$1/$l because it is not defined in the current config\n";
-        &FAI::mark_preserve($_) foreach (keys %{ $FAI::configs{$config}{devices} });
+        &FAI::mark_preserve($_, 0) foreach (keys %{ $FAI::configs{$config}{devices} });
       }
     } elsif ($config eq "RAID") {
       # check for volumes that need to be preserved and preserve the underlying
@@ -575,7 +614,8 @@
           "Can't preserve /dev/md$r because it does not exist\n";
         defined ($FAI::configs{$config}{volumes}{$r}{devices}) or die
           "Can't preserve /dev/md$r because it is not defined in the current config\n";
-        &FAI::mark_preserve($_) foreach (keys %{ $FAI::configs{$config}{volumes}{$r}{devices} });
+        &FAI::mark_preserve($_, $FAI::configs{$config}{volumes}{$r}{devices}{$_}{missing})
+          foreach (keys %{ $FAI::configs{$config}{volumes}{$r}{devices} });
       }
     } elsif ($config eq "CRYPT") {
       # We don't do preserve for encrypted partitions




More information about the Fai-commit mailing list