[Fai-commit] r5907 - in trunk: bin debian lib/setup-storage man

Michael Tautschnig mt at alioth.debian.org
Thu Jul 29 16:24:16 UTC 2010


Author: mt
Date: 2010-07-29 16:24:12 +0000 (Thu, 29 Jul 2010)
New Revision: 5907

Modified:
   trunk/bin/device2grub
   trunk/bin/setup-storage
   trunk/debian/changelog
   trunk/lib/setup-storage/Commands.pm
   trunk/lib/setup-storage/Exec.pm
   trunk/lib/setup-storage/Fstab.pm
   trunk/lib/setup-storage/Init.pm
   trunk/lib/setup-storage/Parser.pm
   trunk/lib/setup-storage/Sizes.pm
   trunk/lib/setup-storage/Volumes.pm
   trunk/man/setup-storage.8
Log:
Merged a larger number of patches from experimental into trunk:

- setup-storage_used-devs-only
- setup-storage_preserve-lazy
- setup-storage_lvm-preserve2
- setup-storage_resize2fs
- setup-storage_always-format
- setup-storage_parted2.2
- setup-storage_empty-vg
- setup-storage_ramsize
- setup-storage_tmpfs
- setup-storage_external-journal
- setup-storage_cciss-bugfix
- setup-storage_better-parser-errors
- setup-storage_exit-codes
- device2grub_stable_names


Modified: trunk/bin/device2grub
===================================================================
--- trunk/bin/device2grub	2010-07-29 15:42:56 UTC (rev 5906)
+++ trunk/bin/device2grub	2010-07-29 16:24:12 UTC (rev 5907)
@@ -5,11 +5,15 @@
 # TODO: read from stdin if no parameter given
 
 use strict;
+
+use Cwd 'abs_path';
+
 my $grubdevice;
 my %map;
 
 my $device=shift;
 my $devicemap="$ENV{target}/boot/grub/device.map";
+my $devbyid = "/dev/disk/by-id";
 
 open (DEVICEMAP,"<$devicemap") || die "Can't open $devicemap\n";
 while (<DEVICEMAP>) {
@@ -23,7 +27,22 @@
 if ($map{$disk}) {
   $grubdevice=$map{$disk};
 } else {
-  die "No match in $devicemap for $disk\n";
+    opendir (my $dh, $devbyid) || die "Can't open /dev/disk/by-id\n";
+    while (my $diskid = readdir $dh) {
+	next if ($diskid =~ /[.].*/);
+
+	$diskid = $devbyid . "/" . $diskid;
+
+	my $shortdev = abs_path($diskid);
+
+	if (($shortdev eq $disk) && $map{$diskid}) {
+	    $grubdevice = $map{$diskid};
+	    last;
+	}
+    }
+    closedir $dh;
+
+    die "No match in $devicemap for $disk\n" unless $grubdevice;
 }
 
 if ($partition) {

Modified: trunk/bin/setup-storage
===================================================================
--- trunk/bin/setup-storage	2010-07-29 15:42:56 UTC (rev 5906)
+++ trunk/bin/setup-storage	2010-07-29 16:24:12 UTC (rev 5907)
@@ -53,7 +53,7 @@
 
 package FAI;
 
-my $version = "1.2.1";
+my $version = "1.3";
 
 # command line parameter handling
 use Getopt::Std;
@@ -127,10 +127,6 @@
 print "Using config file: $opt_f\n";
 &FAI::run_parser($config_file);
 
-# mark devices as preserve, where not all already done so and check that only
-# defined devices are marked preserve
-&FAI::propagate_and_check_preserve;
-
 # read the sizes and partition tables of all disks listed in $FAI::disks
 &FAI::get_current_disks;
 
@@ -140,6 +136,10 @@
 # see whether there are any existing RAID devices
 &FAI::get_current_raid;
 
+# mark devices as preserve, where not all already done so and check that only
+# defined devices are marked preserve
+&FAI::propagate_and_check_preserve;
+
 # debugging only: print the current configuration
 if ($FAI::debug) {
   # for debugging purposes to print the hash structures

Modified: trunk/debian/changelog
===================================================================
--- trunk/debian/changelog	2010-07-29 15:42:56 UTC (rev 5906)
+++ trunk/debian/changelog	2010-07-29 16:24:12 UTC (rev 5907)
@@ -91,8 +91,40 @@
     (closes: #557544)
     
   [ Michael Tautschnig ]
+  * setup-storage: Bumped version number to 1.3
   * control: Move setup-storage to its own package (fai-setup-storage). Thanks
     Michael Prokop <mika at debian.org> for the patch (closes: #575812)
+  * setup-storage/Volumes.pm: Only read sizes and partitioning of disks
+    referenced in the configuration (thanks Henning Sprang).
+  * setup-storage, setup-storage/{Parser.pm,Volumes.pm}: Added support for new
+    preserve_lazy option that will preserve volumes that exist, but newly
+    create them if not found.
+  * setup-storage.8: Document new preserve_lazy option.
+  * setup-storage/{Commands.pm,Volumes.pm}: Completed support for preserve in
+    LVM/RAID contexts; extended checking for volume groups that remain alive,
+    fixed bug in LV resize code, disable existing volume groups, remove
+    non-preserved volume groups (thanks Mathieu Alorent <malorent at echo.fr> for
+    extensive testing).
+  * setup-storage/{Volumes.pm,Sizes.pm}: eff_size is bytes. Always.
+  * setup-storage/Commands.pm: Prefer resize2fs over parted to resize logical
+    volumes. Future versions of parted will allow even more use of resize2fs.
+    Fix use of eff_size as bytes.
+  * setup-storage/{Parser.pm,Commands.pm}: Added support for new always_format
+    option.
+  * setup-storage.8: Documented new always_format option.
+  * setup-storage/Volumes.pm: Fixed uninitialized variable warnings in parsing
+    output of parted 2.2.
+  * setup-storage/Volumes.pm: Use VG size for volume group size, not space in
+    use. Thanks Mathieu Alorent for reporting this.
+  * setup-storage/Init.pm: Properly handle /dev/cciss disk devices, even
+    without partitions (thanks Steffen Grunewald
+    <steffen.grunewald at aei.mpg.de> and Mathieu Alorent <malorent at echo.fr>).
+  * setup-storage/Parser.pm: Handle parse errors earlier for more informative
+    error messages.
+  * setup-storage/Volumes.pm: Proper error message in case an extended
+    partition is marked as preserve
+  * setup-storage/Exec.pm: All unexpected non-zero exit codes of subcommands
+    lead to immediate failure of setup-storage.
 
   [ Michael Prokop ]
   * subroutines, fai: make sure fai exits with the according return
@@ -106,6 +138,23 @@
     inside $FAI_ROOT but are still registered in /etc/mtab outside of
     $FAI_ROOT, so let's get rid of them outside the chroot as well iff
     they are present
+
+  [ Julien BLACHE ]
+  * setup-storage/Parser.pm: add support for RAM:XX% (closes: #493237)
+  * setup-storage.8: document RAM:XX%.
+  * setup-storage/Commands.pm: support the TMPFS key where necessary.
+  * setup-storage/Fstab.pm: add support for tmpfs mounts.
+  * setup-storage/Parser.pm: add a new tmpfs stanza, a new tmpfs volume type
+    and tmpfs_size (slightly differing from the regular size, no range
+    support).
+  * setup-storage.8: document the tmpfs stanza.
+  * setup-storage/Commands.pm: support the creation of journal devices
+    (ext3/4) and filesystems with external journal (ext3/4, xfs).
+  * setup-storage/Parser.pm: add support for FS_journal and FS:journal=.
+  * setup-storage.8: document external journal support.
+  * bin/device2grub: try to find and use a stable name (by-id) for the device
+    if the shortname has no match in device.map. Needed now that grub2 in
+    unstable has switched to using stable names in device.map.
   
  -- Thomas Lange <lange at debian.org>  Wed, 28 Jul 2010 16:28:51 -0400
 

Modified: trunk/lib/setup-storage/Commands.pm
===================================================================
--- trunk/lib/setup-storage/Commands.pm	2010-07-29 15:42:56 UTC (rev 5906)
+++ trunk/lib/setup-storage/Commands.pm	2010-07-29 16:24:12 UTC (rev 5907)
@@ -55,6 +55,7 @@
   defined ($partition->{filesystem})
     or &FAI::internal_error("filesystem is undefined");
   my $fs = $partition->{filesystem};
+  my $journal = $partition->{journal_dev};
 
   return if ($fs eq "-");
 
@@ -67,14 +68,46 @@
   print "$partition->{mountpoint} FS create_options: $create_options\n" if ($FAI::debug && $create_options);
   print "$partition->{mountpoint} FS tune_options: $tune_options\n" if ($FAI::debug && $tune_options);
 
-  # create the file system with options
-  my $create_tool = "mkfs.$fs";
-  ($fs eq "swap") and $create_tool = "mkswap";
-  ($fs eq "xfs") and $create_options = "$create_options -f" unless ($create_options =~ m/-f/);
-  ($fs eq "reiserfs") and $create_options = "$create_options -q" unless ($create_options =~ m/-(f|q|y)/);
-  &FAI::push_command( "$create_tool $create_options $device", "exist_$device",
-    "has_fs_$device" );
+  my $prereqs = "exist_$device";
+  my $provides;
+  my $create_tool;
 
+  # create filesystem journal
+  if ($fs =~ m/.*_journal$/) {
+      $provides = "journal_preped_$device";
+      undef($tune_options);
+
+      if ($fs =~ /ext[34]_journal/) {
+	  $create_tool = "mke2fs";
+	  $create_options = "-O journal_dev";
+      } elsif ($fs eq "xfs_journal") {
+	  $create_tool = "/bin/true";
+	  $create_options = "";
+      } else {
+	  &FAI::internal_error("unsupported journal type $fs");
+      }
+  } else {
+      # create regular filesystem
+      $provides = "has_fs_$device";
+      $create_tool = "mkfs.$fs";
+
+      ($fs eq "swap") and $create_tool = "mkswap";
+      ($fs eq "xfs") and $create_options = "$create_options -f" unless ($create_options =~ m/-f/);
+      ($fs eq "reiserfs") and $create_options = "$create_options -q" unless ($create_options =~ m/-(f|q|y)/);
+
+      # adjust options for filesystem with external journal
+      if (defined($journal)) {
+	  $journal =~ s/^journal=//;
+	  $prereqs = "$prereqs,journal_preped_$journal";
+
+	  ($fs eq "xfs") and $create_options = "$create_options -l logdev=$journal";
+	  ($fs eq "ext3") and $create_options = "$create_options -J device=$journal";
+	  ($fs eq "ext4") and $create_options = "$create_options -J device=$journal";
+      }
+  }
+
+  &FAI::push_command( "$create_tool $create_options $device", $prereqs, $provides);
+
   # possibly tune the file system - this depends on whether the file system
   # supports tuning at all
   return unless $tune_options;
@@ -143,14 +176,15 @@
 
   my ($d, $t) = @_;
   my ($i_p_d, $disk, $part_no) = &FAI::phys_dev($d);
-  return unless $i_p_d;
+  return 0 unless $i_p_d;
   # make sure this device really exists (we can't check for the partition
   # as that may be created later on
   (-b $disk) or die "Specified disk $disk does not exist in this system!\n";
   # set the raid/lvm unless this is an entire disk flag
   my $cmd = "parted -s $disk set $part_no $t on";
   $cmd = "true" if ($part_no == -1);
-  &FAI::push_command( $cmd, "exist_$d", "type_${t}_$d" );
+  &FAI::push_command( $cmd, "cleared2_$disk,exist_$d", "type_${t}_$d" );
+  return 1;
 }
 
 ################################################################################
@@ -236,8 +270,8 @@
 sub build_raid_commands {
 
   foreach my $config (keys %FAI::configs) { # loop through all configs
-    # no LVM or physical devices here
-    next if ($config eq "CRYPT" || $config =~ /^VG_./ || $config =~ /^PHY_./);
+    # no encrypted, tmpfs, LVM or physical devices here
+    next if ($config eq "CRYPT" || $config eq "TMPFS" || $config =~ /^VG_./ || $config =~ /^PHY_./);
     ($config eq "RAID") or &FAI::internal_error("Invalid config $config");
 
     # create all raid devices
@@ -245,12 +279,21 @@
 
       # keep a reference to the current volume
       my $vol = (\%FAI::configs)->{$config}->{volumes}->{$id};
+
+      # if it is a volume that has to be preserved, there is not much to be
+      # done; its existance has been checked in propagate_and_check_preserve
+      if ($vol->{preserve}) {
+        &FAI::push_command("true", "", "exist_/dev/md$id");
+        # create the filesystem on the volume, if requested
+        &FAI::build_mkfs_commands("/dev/md$id",
+          \%{ $FAI::configs{$config}{volumes}{$id} })
+          if (1 == $vol->{always_format});
+        next;
+      }
+
       # the desired RAID level
       my $level = $vol->{mode};
 
-      warn "RAID implementation is incomplete - preserve is not supported\n" if
-        ($vol->{preserve});
-
       # prepend "raid", if the mode is numeric-only
       $level = "raid$level" if ($level =~ /^\d+$/);
 
@@ -308,29 +351,6 @@
 
 ################################################################################
 #
-# @brief Erase the LVM signature from a list of devices that should be prestine
-# in order to avoid confusion of the lvm tools
-#
-################################################################################
-sub erase_lvm_signature {
-
-  my ($devices_aref) = @_;
-  # first remove the dm_mod module to prevent ghost lvm volumes 
-  # from existing
-  # push @FAI::commands, "modprobe -r dm_mod";
-  # zero out (broken?) lvm signatures
-  # push @FAI::commands, "dd if=/dev/zero of=$_ bs=1 count=1"
-  #   foreach ( @{$devices_aref} );
-  my $device_list = join (" ", @{$devices_aref});
-  $FAI::debug and print "Erased devices: $device_list\n"; 
-  &FAI::push_command( "pvremove -ff -y $device_list", "", "pv_sigs_removed" );
-
-  # reload module
-  # push @FAI::commands, "modprobe dm_mod";
-}
-
-################################################################################
-#
 # @brief Create the volume group $config, unless it exists already; if the
 # latter is the case, only add/remove the physical devices
 #
@@ -343,24 +363,6 @@
   ($config =~ /^VG_(.+)$/) and ($1 ne "--ANY--") or &FAI::internal_error("Invalid config $config");
   my $vg = $1; # the actual volume group
 
-  my $vg_exists = 0;
-  if (defined ($FAI::current_lvm_config{$vg})) {
-    $vg_exists = 1;
-    foreach my $dev (@{ $FAI::current_lvm_config{$vg}{"physical_volumes"} }) {
-      my ($i_p_d, $disk, $part_no) = &FAI::phys_dev($dev);
-      # if this is not a physical disk, just assume that the volume group will
-      # not exist anymore
-      if ($i_p_d) {
-        defined ($FAI::configs{"PHY_$disk"}) or next;
-        defined ($FAI::configs{"PHY_$disk"}{partitions}{$part_no}) and
-          ($FAI::configs{"PHY_$disk"}{partitions}{$part_no}{size}{preserve}) and
-          next;
-      }
-      $vg_exists = 0;
-      last;
-    }
-  }
-
   my ($pv_create_options) = $FAI::configs{$config}{pvcreateopts};
   my ($vg_create_options) = $FAI::configs{$config}{vgcreateopts};
   # prevent warnings of uninitialized variables
@@ -368,59 +370,82 @@
   $vg_create_options = '' unless $vg_create_options;
   print "/dev/$vg PV create_options: $pv_create_options\n" if ($FAI::debug && $pv_create_options);
   print "/dev/$vg VG create_options: $vg_create_options\n" if ($FAI::debug && $vg_create_options);
+
   # create the volume group, if it doesn't exist already
-  if (!$vg_exists) {
+  if (!defined($FAI::configs{"VG_$vg"}{exists})) {
+    my $pre_dev = "";
+    my $devs = "";
     # create all the devices
-    my @devices = ();
-    push @devices, &FAI::enc_name($_) foreach (keys %{ $FAI::configs{$config}{devices} });
-    &FAI::erase_lvm_signature(\@devices);
-    &FAI::push_command( "pvcreate $pv_create_options $_",
-      "pv_sigs_removed,exist_$_", "pv_done_$_") foreach (@devices);
+    foreach my $d (keys %{ $FAI::configs{$config}{devices} }) {
+      my $dev = &FAI::enc_name($d);
+
+      # set proper partition types for LVM
+      my $type_pre = "";
+      $type_pre .= ",type_lvm_$dev" if (&FAI::set_partition_type_on_phys_dev($dev, "lvm"));
+
+      &FAI::push_command( "pvcreate $pv_create_options $dev",
+        "all_pv_sigs_removed,exist_$dev$type_pre", "pv_done_$dev");
+      $devs .= " $dev";
+      $pre_dev .= ",pv_done_$dev";
+    }
+    $pre_dev =~ s/^,//;
+
     # create the volume group
-    my $pre_dev = "";
-    $pre_dev .= ",exist_$_,pv_done_$_" foreach (@devices);
-    $pre_dev =~ s/^,//;
-    &FAI::push_command( "vgcreate $vg_create_options $vg " . join (" ",
-        @devices), "$pre_dev", "vg_created_$vg" );
+    &FAI::push_command( "vgcreate $vg_create_options $vg $devs",
+      "$pre_dev", "vg_created_$vg" );
+
     # we are done
     return;
   }
 
   # otherwise add or remove the devices for the volume group, run pvcreate
   # where needed
-  # the list of devices to be created
-  my %new_devs = ();
+  # the devices to be removed later on
+  my %rm_devs = ();
+  @rm_devs{ @{ $FAI::current_lvm_config{$vg}{"physical_volumes"} } } = ();
 
-  # create an undefined entry for each new device
-  @new_devs{ keys %{ $FAI::configs{$config}{devices} } } = ();
+  # all devices of this VG
+  my @all_devices = ();
 
+  # the list of devices to be created
   my @new_devices = ();
-  push @new_devices, &FAI::enc_name($_) foreach (keys %new_devs);
 
-  # &FAI::erase_lvm_signature( \@new_devices );
+  # create an undefined entry for each device
+  foreach my $d (keys %{ $FAI::configs{$config}{devices} }) {
+    my $denc = &FAI::enc_name($d);
+    push @all_devices, $denc;
+    push @new_devices, $denc unless (exists($rm_devs{$denc}));
+  }
 
+  # remove remaining devices from the list
+  delete $rm_devs{$_} foreach (@all_devices);
+
   # create all the devices
-  &FAI::push_command( "pvcreate $pv_create_options $_", "exist_$_", "pv_done_$_"
-    ) foreach (@new_devices);
+  my $pre_dev = "vg_exists_$vg";
+  foreach my $dev (@new_devices) {
+    # set proper partition types for LVM
+    my $type_pre = "";
+    $type_pre .= ",type_lvm_$dev" if (&FAI::set_partition_type_on_phys_dev($dev, "lvm"));
 
-  # extend the volume group by the new devices (includes the current ones)
-  my $pre_dev = "";
-  $pre_dev .= ",pv_done_$_" foreach (@new_devices);
+    &FAI::push_command( "pvcreate $pv_create_options $dev",
+      "all_pv_sigs_removed,exist_$dev$type_pre", "pv_done_$dev");
+    $pre_dev .= ",pv_done_$dev";
+  }
   $pre_dev =~ s/^,//;
-  &FAI::push_command( "vgextend $vg " . join (" ", @new_devices), "$pre_dev",
-    "vg_extended_$vg" );
 
-  # the devices to be removed
-  my %rm_devs = ();
-  @rm_devs{ @{ $FAI::current_lvm_config{$vg}{"physical_volumes"} } } = ();
 
-  # remove remaining devices from the list
-  delete $rm_devs{$_} foreach (@new_devices);
+  # extend the volume group by the new devices
+  if (scalar (@new_devices)) {
+    &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" );
+  }
 
   # run vgreduce to get them removed
   if (scalar (keys %rm_devs)) {
     $pre_dev = "";
-    $pre_dev .= ",pv_done_$_" foreach (keys %rm_devs);
+    $pre_dev .= ",exist_$_" foreach (keys %rm_devs);
     &FAI::push_command( "vgreduce $vg " . join (" ", keys %rm_devs),
       "vg_extended_$vg$pre_dev", "vg_created_$vg" );
   } else {
@@ -442,25 +467,6 @@
   ($config =~ /^VG_(.+)$/) and ($1 ne "--ANY--") or &FAI::internal_error("Invalid config $config");
   my $vg = $1; # the actual volume group
 
-  my $lv_rm_pre = "";
-  my $lv_resize_pre = "";
-  # remove, resize, create the logical volumes
-  # remove all volumes that do not exist anymore or need not be preserved
-  foreach my $lv (keys %{ $FAI::current_lvm_config{$vg}{volumes} }) {
-    # skip preserved/resized volumes
-    if (defined ( $FAI::configs{$config}{volumes}{$lv})
-      && ($FAI::configs{$config}{volumes}{$lv}{size}{preserve} == 1)) {
-      $lv_resize_pre .= ",lv_resize_$vg/$lv" if
-        $FAI::configs{$config}{volumes}{$lv}{size}{resize};
-      next;
-    }
-
-    &FAI::push_command( "lvremove -f $vg/$lv", "vg_enabled_$vg", "lv_rm_$vg/$lv");
-    $lv_rm_pre .= ",lv_rm_$vg/$lv";
-  }
-  $lv_rm_pre =~ s/^,//;
-  $lv_resize_pre =~ s/^,//;
-
   # now create or resize the configured logical volumes
   foreach my $lv (keys %{ $FAI::configs{$config}{volumes} }) {
     # reference to the size of the current logical volume
@@ -470,6 +476,10 @@
       defined ($FAI::current_lvm_config{$vg}{volumes}{$lv})
         or die "Preserved volume $vg/$lv does not exist\n";
       warn "$vg/$lv will be preserved\n";
+      # create the filesystem on the volume, if requested
+      &FAI::build_mkfs_commands("/dev/$vg/$lv",
+        \%{ $FAI::configs{$config}{volumes}{$lv} })
+        if (1 == $lv_size->{always_format});
       next;
     }
 
@@ -479,30 +489,54 @@
         or die "Resized volume $vg/$lv does not exist\n";
       warn "$vg/$lv will be resized\n";
 
-      if ($lv_size->{eff_size} <
-        $FAI::current_lvm_config{$vg}{volumes}{$lv}{size})
+      use POSIX qw(floor);
+
+      my $lvsize_mib = &FAI::convert_unit($lv_size->{eff_size} . "B");
+      if ($lvsize_mib < $FAI::current_lvm_config{$vg}{volumes}{$lv}{size})
       {
-        &FAI::push_command( "parted -s /dev/$vg/$lv resize 1 0 " . $lv_size->{eff_size} .  "B",
-          "vg_enabled_$vg,$lv_rm_pre", "lv_shrink_$vg/$lv" );
-        &FAI::push_command( "lvresize -L " . $lv_size->{eff_size} . " $vg/$lv",
-          "vg_enabled_$vg,$lv_rm_pre,lv_shrink_$vg/$lv", "lv_created_$vg/$lv" );
+        if (($FAI::configs{$config}{volumes}{$lv}{filesystem} =~
+            /^ext[23]$/) && &FAI::in_path("resize2fs")) {
+          my $block_count = POSIX::floor($lv_size->{eff_size} / 512);
+          &FAI::push_command( "e2fsck -p -f /dev/$vg/$lv",
+            "vg_enabled_$vg,exist_/dev/$vg/$lv", "e2fsck_f_resize_$vg/$lv" );
+          &FAI::push_command( "resize2fs /dev/$vg/$lv ${block_count}s",
+            "e2fsck_f_resize_$vg/$lv", "lv_shrink_$vg/$lv" );
+        } else {
+          &FAI::push_command( "parted -s /dev/$vg/$lv resize 1 0 " . $lv_size->{eff_size} .  "B",
+            "vg_enabled_$vg", "lv_shrink_$vg/$lv" );
+        }
+        &FAI::push_command( "lvresize -L $lvsize_mib $vg/$lv",
+          "vg_enabled_$vg,lv_shrink_$vg/$lv", "lv_created_$vg/$lv" );
       } else {
-        &FAI::push_command( "lvresize -L " . $lv_size->{eff_size} . " $vg/$lv",
-          "vg_enabled_$vg,$lv_rm_pre", "lv_grow_$vg/$lv" );
-        &FAI::push_command( "parted -s /dev/$vg/$lv resize 1 0 " . $lv_size->{eff_size} .  "B",
-          "vg_enabled_$vg,$lv_rm_pre,lv_grow_$vg/$lv", "exist_/dev/$vg/$lv" );
+        &FAI::push_command( "lvresize -L $lvsize_mib $vg/$lv",
+          "vg_enabled_$vg,exist_/dev/$vg/$lv", "lv_grow_$vg/$lv" );
+        if (($FAI::configs{$config}{volumes}{$lv}{filesystem} =~
+            /^ext[23]$/) && &FAI::in_path("resize2fs")) {
+          my $block_count = POSIX::floor($lv_size->{eff_size} / 512);
+          &FAI::push_command( "e2fsck -p -f /dev/$vg/$lv",
+            "vg_enabled_$vg,lv_grow_$vg/$lv", "e2fsck_f_resize_$vg/$lv" );
+          &FAI::push_command( "resize2fs /dev/$vg/$lv ${block_count}s",
+            "e2fsck_f_resize_$vg/$lv", "exist_/dev/$vg/$lv" );
+        } else {
+          &FAI::push_command( "parted -s /dev/$vg/$lv resize 1 0 " . $lv_size->{eff_size} .  "B",
+            "vg_enabled_$vg,lv_grow_$vg/$lv", "exist_/dev/$vg/$lv" );
+        }
       }
 
+      # create the filesystem on the volume, if requested
+      &FAI::build_mkfs_commands("/dev/$vg/$lv",
+        \%{ $FAI::configs{$config}{volumes}{$lv} })
+        if (1 == $lv_size->{always_format});
       next;
     }
 
     my ($create_options) = $FAI::configs{$config}{volumes}{$lv}{lvcreateopts};
     # prevent warnings of uninitialized variables
     $create_options = '' unless $create_options;
-  print "/dev/$vg/$lv LV create_options: $create_options\n" if ($FAI::debug && $create_options);
+    print "/dev/$vg/$lv LV create_options: $create_options\n" if ($FAI::debug && $create_options);
     # create a new volume
     &FAI::push_command( "lvcreate $create_options -n $lv -L " .
-      $lv_size->{eff_size} . " $vg", "vg_enabled_$vg,$lv_rm_pre",
+      &FAI::convert_unit($lv_size->{eff_size} . "B") . " $vg", "vg_enabled_$vg",
       "exist_/dev/$vg/$lv" );
 
     # create the filesystem on the volume
@@ -513,6 +547,85 @@
 
 ################################################################################
 #
+# @brief Remove existing volume group if underlying devices will be modified,
+# otherwise add proper exist_ preconditions
+#
+################################################################################
+sub cleanup_vg {
+
+  my ($vg) = @_;
+  my $clear_vg = 0;
+
+  foreach my $dev (@{ $FAI::current_lvm_config{$vg}{"physical_volumes"} }) {
+    my ($i_p_d, $disk, $part_no) = &FAI::phys_dev($dev);
+    if ($i_p_d) {
+      defined ($FAI::configs{"PHY_$disk"}) or next;
+      defined ($FAI::configs{"PHY_$disk"}{partitions}{$part_no}) and
+        ($FAI::configs{"PHY_$disk"}{partitions}{$part_no}{size}{preserve}) and
+        next;
+    } elsif ($dev =~ m{^/dev/md[\/]?(\d+)$}) {
+      my $vol = $1;
+      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"}{volumes}{$lv}) or next;
+      next if (1 == $FAI::configs{"VG_$ivg"}{volumes}{$lv}{size}{preserve});
+    } else {
+      warn "Don't know how to check preservation of $dev\n";
+      next;
+    }
+    $clear_vg = 1;
+    last;
+  }
+
+  if (0 == $clear_vg) {
+    my $vg_setup_pre = "vgchange_a_n";
+    if (defined($FAI::configs{"VG_$vg"}{volumes})) {
+      $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} }) {
+        # 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");
+            next;
+          }
+        }
+
+        &FAI::push_command( "lvremove -f $vg/$lv", "vgchange_a_n", "lv_rm_$vg/$lv");
+        $vg_setup_pre .= ",lv_rm_$vg/$lv";
+      }
+    } else {
+      &FAI::push_command("true", "vgchange_a_n", "exist_/dev/$vg/$_") foreach
+        (keys %{ $FAI::current_lvm_config{$vg}{volumes} });
+    }
+    &FAI::push_command("true", $vg_setup_pre, "vg_exists_$vg");
+
+    return 0;
+  }
+
+  my $vg_destroy_pre = "vgchange_a_n";
+  foreach my $lv (keys %{ $FAI::current_lvm_config{$vg}{volumes} }) {
+    &FAI::push_command( "lvremove -f $vg/$lv", "vgchange_a_n", "lv_rm_$vg/$lv");
+    $vg_destroy_pre .= ",lv_rm_$vg/$lv";
+  }
+  &FAI::push_command( "vgremove $vg", "$vg_destroy_pre", "vg_removed_$vg");
+
+  # clear all the devices
+  my $devices = "";
+  $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" );
+  return 1;
+}
+
+################################################################################
+#
 # @brief Using the configurations from %FAI::configs, a list of commands is
 # built to setup the LVM
 # creates the volume groups, the logical volumes and the filesystems
@@ -520,33 +633,31 @@
 ################################################################################
 sub build_lvm_commands {
 
+  # disable volumes if there are pre-existing ones
+  my $all_vg_pre = "";
+  if (scalar(keys %FAI::current_lvm_config)) {
+    &FAI::push_command("vgchange -a n", "", "vgchange_a_n");
+    foreach my $vg (keys %FAI::current_lvm_config) {
+      $all_vg_pre .= ",pv_sigs_removed_$vg" if (&FAI::cleanup_vg($vg));
+    }
+    $all_vg_pre =~ s/^,//;
+  }
+  &FAI::push_command("true", "$all_vg_pre", "all_pv_sigs_removed");
+
   # loop through all configs
   foreach my $config (keys %FAI::configs) {
 
-    # no physical devices, RAID or encrypted here
-    next if ($config =~ /^PHY_./ || $config eq "RAID" || $config eq "CRYPT");
+    # no physical devices, RAID, encrypted or tmpfs here
+    next if ($config =~ /^PHY_./ || $config eq "RAID" || $config eq "CRYPT" || $config eq "TMPFS");
     ($config =~ /^VG_(.+)$/) or &FAI::internal_error("Invalid config $config");
     next if ($1 eq "--ANY--");
     my $vg = $1; # the volume group
 
-    # set proper partition types for LVM
-    &FAI::set_partition_type_on_phys_dev($_, "lvm")
-      foreach (keys %{ $FAI::configs{$config}{devices} });
-    my $type_pre = "";
-    foreach my $d (keys %{ $FAI::configs{$config}{devices} }) {
-      $d = &FAI::enc_name($d);
-      if ((&FAI::phys_dev($d))[0]) {
-        $type_pre .= ",type_lvm_$d"
-      } else {
-        $type_pre .= ",exist_$d"
-      }
-    }
-
     # create the volume group or add/remove devices
     &FAI::create_volume_group($config);
     # enable the volume group
     &FAI::push_command( "vgchange -a y $vg",
-      "vg_created_$vg$type_pre", "vg_enabled_$vg" );
+      "vg_created_$vg", "vg_enabled_$vg" );
 
     # perform all necessary operations on the underlying logical volumes
     &FAI::setup_logical_volumes($config);
@@ -755,8 +866,8 @@
     or die "Can't change disklabel, partitions are to be preserved\n";
 
   # write the disklabel to drop the previous partition table
-  &FAI::push_command( "parted -s $disk mklabel $label", "exist_$disk",
-    "cleared1_$disk" );
+  &FAI::push_command( "parted -s $disk mklabel $label",
+    "exist_$disk,all_pv_sigs_removed", "cleared1_$disk" );
 
   &FAI::rebuild_preserved_partitions($config, \@to_preserve);
 
@@ -830,25 +941,42 @@
     my $start = $part->{start_byte};
     my $end = $part->{end_byte};
 
+    # ntfs/ext2,3 partition can't be moved
+    ($start == $FAI::current_config{$disk}{partitions}{$mapped_id}{begin_byte})
+      or &FAI::internal_error(
+        $FAI::current_config{$disk}{partitions}{$mapped_id}{filesystem}
+          . " partition start supposed to move, which is not allowed") if
+      ($FAI::current_config{$disk}{partitions}{$mapped_id}{filesystem} =~
+        /^(ntfs|ext[23])$/);
+
     # build an appropriate command
     # ntfs requires specific care
     if ($FAI::current_config{$disk}{partitions}{$mapped_id}{filesystem} eq
       "ntfs") {
       # check, whether ntfsresize is available
       &FAI::in_path("ntfsresize") or die "ntfsresize not found in PATH\n";
-      # ntfs partition can't be moved
-      ($start == $FAI::current_config{$disk}{partitions}{$mapped_id}{begin_byte}) 
-        or &FAI::internal_error("ntfs partition supposed to move");
-      # ntfsresize requires device names
-      my $eff_size = $part->{size}->{eff_size};
 
-      &FAI::push_command( "yes | ntfsresize -s $eff_size " .
+      &FAI::push_command( "yes | ntfsresize -s " . $part->{size}->{eff_size} .
         &FAI::make_device_name($disk, $p), "rebuilt_" .
         &FAI::make_device_name($disk, $p) . $deps, "ntfs_ready_for_rm_" .
         &FAI::make_device_name($disk, $p) );
+      # TODO this is just a hack, we would really need support for resize
+      # without data resize in parted, which will be added in some parted
+      # version > 2.1
       &FAI::push_command( "parted -s $disk rm $p", "ntfs_ready_for_rm_" .
         &FAI::make_device_name($disk, $p), "resized_" .
         &FAI::make_device_name($disk, $p) );
+    ## } elsif (($FAI::current_config{$disk}{partitions}{$mapped_id}{filesystem} =~
+    ##     /^ext[23]$/) && &FAI::in_path("resize2fs")) {
+    ##   TODO: BROKEN needs more checks, enlarge partition table before resize, just as
+    ##   NTFS case
+    ##   my $block_count = $part->{size}->{eff_size} / 512;
+    ##   &FAI::push_command( "e2fsck -p -f " . &FAI::make_device_name($disk, $p),
+    ##     "rebuilt_" . &FAI::make_device_name($disk, $p) . $deps,
+    ##     "e2fsck_f_resize_" .  &FAI::make_device_name($disk, $p) );
+    ##   &FAI::push_command( "resize2fs " . &FAI::make_device_name($disk, $p) .
+    ##     " ${block_count}s", "e2fsck_f_resize_" . &FAI::make_device_name($disk, $p),
+    ##     "resized_" .  &FAI::make_device_name($disk, $p) );
     } else {
       &FAI::push_command( "parted -s $disk resize $p ${start}B ${end}B",
         "rebuilt_" . &FAI::make_device_name($disk, $p) . $deps, "resized_" .
@@ -886,12 +1014,14 @@
       }
     }
 
-    my $fs = $part->{filesystem};
-    $fs = "" unless defined($fs);
+    my $fs = (defined($part->{filesystem}) && $part->{filesystem} =~ /\S+/) ?
+      $part->{filesystem} : "-";
+    ($fs) = split(/:/, $fs);
     $fs = "linux-swap" if ($fs eq "swap");
     $fs = "fat32" if ($fs eq "vfat");
     $fs = "fat16" if ($fs eq "msdos");
     $fs = "ext3" if ($fs eq "ext4");
+    $fs = "" if ($fs =~ m/.*_journal$/);
     $fs = $FAI::current_config{$disk}{partitions}{$mapped_id}{filesystem}
       if ($part->{size}->{preserve} || $part->{size}->{resize});
     $fs = "" if ($fs eq "-");
@@ -932,8 +1062,8 @@
 
   # loop through all configs
   foreach my $config ( keys %FAI::configs ) {
-    # no RAID, encrypted or LVM devices here
-    next if ($config eq "RAID" || $config eq "CRYPT" || $config =~ /^VG_./);
+    # no RAID, encrypted, tmpfs or LVM devices here
+    next if ($config eq "RAID" || $config eq "CRYPT" || $config eq "TMPFS" || $config =~ /^VG_./);
     ($config =~ /^PHY_(.+)$/) or &FAI::internal_error("Invalid config $config");
     my $disk = $1; # the device to be configured
 
@@ -956,8 +1086,9 @@
       my $part = (\%FAI::configs)->{$config}->{partitions}->{$part_id};
 
       # skip preserved/resized/extended partitions
-      next if ($part->{size}->{preserve} == 1
-        || $part->{size}->{resize} == 1 || $part->{size}->{extended} == 1);
+      next if (($part->{size}->{always_format} == 0 &&
+          ($part->{size}->{preserve} == 1 || $part->{size}->{resize} == 1))
+        || $part->{size}->{extended} == 1);
 
       # create the filesystem on the device
       &FAI::build_mkfs_commands( &FAI::make_device_name($disk, $part_id), $part );

Modified: trunk/lib/setup-storage/Exec.pm
===================================================================
--- trunk/lib/setup-storage/Exec.pm	2010-07-29 15:42:56 UTC (rev 5906)
+++ trunk/lib/setup-storage/Exec.pm	2010-07-29 16:24:12 UTC (rev 5907)
@@ -58,6 +58,7 @@
     stdout_regex => "",
     program      => "parted",
     response     => "die",
+    exit_codes   => [0..255],
   },
   {
     error   => "parted_1_new",
@@ -66,22 +67,25 @@
     stdout_regex => "Error: Could not stat device .* - No such file or directory",
     program      => "parted",
     response     => "die",
+    exit_codes   => [0..255],
   },
   {
     error        => "parted_2",
-    message      => "Parted could not read a disk label\n",
+    message      => "Parted could not read a disk label (new disk?)\n",
     stderr_regex => "Error: Unable to open .* - unrecognised disk label",
     stdout_regex => "",
-    program      => "parted",
+    program      => "parted -s \\S+ unit TiB print",
     response     => "warn",
+    exit_codes   => [1],
   },
   {
     error        => "parted_2_new",
-    message      => "Parted could not read a disk label\n",
+    message      => "Parted could not read a disk label (new disk?)\n",
     stderr_regex => "",
     stdout_regex => "Error: .* unrecognised disk label",
-    program      => "parted",
+    program      => "parted -s \\S+ unit TiB print",
     response     => "warn",
+    exit_codes   => [1],
   },
   ## {
   ##   error        => "parted_3",
@@ -90,6 +94,7 @@
   ##   stdout_regex => "",
   ##   program      => "parted",
   ##   response     => \&FAI::restore_partition_table,
+  ##   exit_codes   => [0..255],
   ## },
   {
     error        => "parted_4",
@@ -98,6 +103,7 @@
     stdout_regex => "",
     program      => "parted",
     response     => "die",
+    exit_codes   => [0..255],
   },
   {
     error        => "parted_4_new",
@@ -106,6 +112,7 @@
     stdout_regex => "No Implementation: Partition \\d+ isn't aligned to cylinder boundaries",
     program      => "parted",
     response     => "die",
+    exit_codes   => [0..255],
   },
   {
     error        => "parted_5",
@@ -114,6 +121,7 @@
     stdout_regex => "",
     program      => "parted",
     response     => "die",
+    exit_codes   => [0..255],
   },
   {
     error        => "parted_5_new",
@@ -122,6 +130,7 @@
     stdout_regex => "Error: Can't have overlapping partitions",
     program      => "parted",
     response     => "die",
+    exit_codes   => [0..255],
   },
   {
     error        => "parted_6",
@@ -130,6 +139,7 @@
     stdout_regex => "",
     program      => "parted",
     response     => "die",
+    exit_codes   => [0..255],
   },
   {
     error        => "parted_6_new",
@@ -138,6 +148,7 @@
     stdout_regex => "Error: Unable to satisfy all constraints on the partition",
     program      => "parted",
     response     => "die",
+    exit_codes   => [0..255],
   },
   {
     error   => "cmd_parted_1",
@@ -145,7 +156,8 @@
     stderr_regex => "(parted: command not found|/sbin/parted: No such file or directory)",
     stdout_regex => "",
     program      => "parted",
-    response     => "die"
+    response     => "die",
+    exit_codes   => [0..255],
   },
   {
     error => "mkfs.xfs_1",
@@ -154,6 +166,7 @@
     stdout_regex => "",
     program      => "mkfs.xfs",
     response     => "die",
+    exit_codes   => [0..255],
   },
   {
     error        => "ntfsresize_1",
@@ -162,7 +175,17 @@
     stdout_regex => "",
     program      => "ntfsresize",
     response     => "die",
+    exit_codes   => [0..255],
   },
+  {
+    error        => "catch_all_nonzero_exit_code",
+    message      => "Command had non-zero exit code\n",
+    stderr_regex => "",
+    stdout_regex => "",
+    program      => ".*",
+    response     => "die",
+    exit_codes   => [1..255],
+  },
 ];
 
 ################################################################################
@@ -301,6 +324,7 @@
   my @stdout      = ();
   my $stderr_line = "";
   my $stdout_line = "";
+  my $exit_code   = 0;
 
   #make tempfile, get perl filehandle and filename of the file
   my ($stderr_fh, $stderr_filename) = File::Temp::tempfile(UNLINK => 1);
@@ -315,9 +339,10 @@
     # execute the bash command, write stderr and stdout into the testfiles
     print "Executing: $command\n";
     `$command 1> $stdout_filename 2> $stderr_filename`;
-    ( ($?>>8) ne 0 ) and warn "Command $command had exit code " . ($?>>8) . "\n";
+    $exit_code = ($?>>8);
   } else {
-    print "would run command $command; to have them executed, use -X \n";
+    print "would run command $command; to have it executed, use -X \n";
+    return "";
   }
 
   # read the tempfile into lists, each element of the list one line
@@ -345,11 +370,11 @@
 
   #get the error, if there was any
   foreach my $err (@$FAI::error_codes) {
-    if (($err->{stdout_regex} eq "" || $stdout_line =~ /$err->{stdout_regex}/)
-      && ($err->{stderr_regex} eq "" || $stderr_line =~ /$err->{stderr_regex}/)
-      && ($err->{program} eq "" || $command =~ /$err->{program}/)) {
-      return $err->{error};
-    }
+    return $err->{error} if
+      (($err->{stdout_regex} eq "" || $stdout_line =~ /$err->{stdout_regex}/)
+        && ($err->{stderr_regex} eq "" || $stderr_line =~ /$err->{stderr_regex}/)
+        && ($err->{program} eq "" || $command =~ /$err->{program}/)
+        && (grep {$_ == $exit_code} @{ $err->{exit_codes} }));
   }
 
 }

Modified: trunk/lib/setup-storage/Fstab.pm
===================================================================
--- trunk/lib/setup-storage/Fstab.pm	2010-07-29 15:42:56 UTC (rev 5906)
+++ trunk/lib/setup-storage/Fstab.pm	2010-07-29 16:24:12 UTC (rev 5907)
@@ -59,9 +59,10 @@
   push @fstab_line, ($d_ref->{mountpoint}, $d_ref->{filesystem},
     $d_ref->{mount_options}, 0, 2);
   # order of filesystem checks: the root filesystem gets a 1, the others
-  # get 2, swap gets 0
+  # get 2, swap and tmpfs get 0
   $fstab_line[-1] = 1 if ($d_ref->{mountpoint} eq "/");
   $fstab_line[-1] = 0 if ($d_ref->{filesystem} eq "swap");
+  $fstab_line[-1] = 0 if ($d_ref->{filesystem} eq "tmpfs");
 
   # set the ROOT_PARTITION variable, if this is the mountpoint for /
   $FAI::disk_var{ROOT_PARTITION} = $name
@@ -271,6 +272,29 @@
 
         push @fstab, &FAI::create_fstab_line($c_ref, $device_name, $device_name);
       }
+    } elsif ($c eq "TMPFS") {
+      # not usable for /boot
+      next;
+    } elsif ($c eq "TMPFS") {
+      foreach my $v (keys %{ $config->{$c}->{volumes} }) {
+        my $c_ref = $config->{$c}->{volumes}->{$v};
+
+        next if ($c_ref->{mountpoint} eq "-");
+
+        ($c_ref->{mountpoint} eq "/boot" || ($c_ref->{mountpoint} eq "/" &&
+            !defined ($FAI::disk_var{BOOT_PARTITION}))) and
+          die "Boot partition cannot be a tmpfs\n";
+
+	if (($c_ref->{mount_options} =~ m/size=/) || ($c_ref->{mount_options} =~ m/nr_blocks=/)) {
+          warn "Specified tmpfs size for $c_ref->{mountpoint} ignored as mount options contain size= or nr_blocks=\n";
+        } else {
+	  $c_ref->{mount_options} .= "," if ($c_ref->{mount_options} ne "");
+          # Size will be in % or MiB
+	  $c_ref->{mount_options} .= "size=" . $c_ref->{size};
+	}
+
+        push @fstab, &FAI::create_fstab_line($c_ref, "tmpfs", "tmpfs");
+      }
     } else {
       &FAI::internal_error("Unexpected key $c");
     }

Modified: trunk/lib/setup-storage/Init.pm
===================================================================
--- trunk/lib/setup-storage/Init.pm	2010-07-29 15:42:56 UTC (rev 5906)
+++ trunk/lib/setup-storage/Init.pm	2010-07-29 16:24:12 UTC (rev 5907)
@@ -183,10 +183,10 @@
     return (1, "/dev/$1", $2);
   }
   elsif ($dev =~
-    m{^/dev/(cciss/c\dd\d|ida/c\dd\d|rd/c\dd\d|ataraid/d\d|etherd/e\d+\.\d+)p(\d+)?$})
+    m{^/dev/(cciss/c\dd\d|ida/c\dd\d|rd/c\dd\d|ataraid/d\d|etherd/e\d+\.\d+)(p(\d+))?$})
   {
     defined($2) or return (1, "/dev/$1", -1);
-    return (1, "/dev/$1", $2);
+    return (1, "/dev/$1", $3);
   }
   return (0, "", -2);
 }

Modified: trunk/lib/setup-storage/Parser.pm
===================================================================
--- trunk/lib/setup-storage/Parser.pm	2010-07-29 15:42:56 UTC (rev 5906)
+++ trunk/lib/setup-storage/Parser.pm	2010-07-29 16:24:12 UTC (rev 5907)
@@ -239,7 +239,7 @@
 
       # msdos disk labels don't allow for more than 4 primary partitions
       ($extended < 5)
-        or die "Too many primary partitions while creating extended\n";
+        or die "Too many primary partitions; cannot add extended partition\n";
 
       # initialize the entry, unless it already exists
       defined ($FAI::configs{$FAI::device}{partitions}{$extended})
@@ -247,6 +247,10 @@
           size => {}
         };
 
+      # as we can't compute the index from the reference, we need to store the
+      # $part_number explicitly
+      (\%FAI::configs)->{$FAI::device}->{partitions}->{$extended}->{number} = $extended;
+
       my $part_size =
         (\%FAI::configs)->{$FAI::device}->{partitions}->{$extended}->{size};
 
@@ -257,6 +261,10 @@
       defined ($part_size->{preserve})
         or $part_size->{preserve} = 0;
 
+      # add the always_format = 0 flag, if it doesn't exist already
+      defined ($part_size->{always_format})
+        or $part_size->{always_format} = 0;
+
       # add the resize = 0 flag, if it doesn't exist already
       defined ($part_size->{resize}) or $part_size->{resize} = 0;
     }
@@ -284,6 +292,10 @@
   defined ($FAI::partition_pointer->{size}->{preserve})
     or $FAI::partition_pointer->{size}->{preserve} = 0;
 
+  # add the always_format = 0 flag, if it doesn't exist already
+  defined ($FAI::partition_pointer->{size}->{always_format})
+    or $FAI::partition_pointer->{size}->{always_format} = 0;
+
   # add the resize = 0 flag, if it doesn't exist already
   defined ($FAI::partition_pointer->{size}->{resize})
     or $FAI::partition_pointer->{size}->{resize} = 0;
@@ -300,6 +312,21 @@
 {
   my ($val) = @_;
 
+  if ($val =~ /^RAM:(\d+)%/) {
+      $val = $1 / 100.0;
+
+      ## get total RAM
+      open(F, "/proc/meminfo");
+      my @meminfo = <F>;
+      close F;
+
+      my ($totalmem) = grep /^MemTotal:/, @meminfo;
+      $totalmem =~ s/[^0-9]//g;
+      $totalmem = $totalmem / 1024.0;
+
+      return $val * $totalmem;
+  }
+
   ## don't warn for now, G/GiB/GB are all treated the same way
   ## ($val =~ /([kKMGTP])\s*$/) and
   ##   warn "Using $1 as size modifier is deprecated, please use $1iB or $1B
@@ -332,7 +359,6 @@
         {
           $return = 1;
         }
-        | <error>
 
     line: <skip: qr/[ \t]*/> "\\n"
         | <skip: qr/[ \t]*/> comment "\\n"
@@ -376,6 +402,12 @@
           # exit config mode
           $FAI::device = "";
         }
+        | /^tmpfs/
+        {
+          $FAI::device = "TMPFS";
+          $FAI::configs{$FAI::device}{fstabkey} = "device";
+          $FAI::configs{$FAI::device}{volumes} = {};
+        }
         | /^disk(\d+)/
         {
           # check, whether parted is available
@@ -392,6 +424,7 @@
           &FAI::init_disk_config($item[ 1 ]);
         }
         option(s?)
+        | <error>
 
     raid_option: /^preserve_always:(\d+(,\d+)*)/
         {
@@ -405,11 +438,19 @@
             $FAI::configs{RAID}{volumes}{$_}{preserve} = 1 foreach (split(",", $1));
           }
         }
+        | /^preserve_lazy:(\d+(,\d+)*)/
+        {
+          $FAI::configs{RAID}{volumes}{$_}{preserve} = 2 foreach (split(",", $1));
+        }
         | /^fstabkey:(device|label|uuid)/
         {
           # the information preferred for fstab device identifieres
           $FAI::configs{$FAI::device}{fstabkey} = $1;
         }
+        | /^always_format:(\d+(,\d+)*)/
+        {
+          $FAI::configs{RAID}{volumes}{$_}{always_format} = 1 foreach (split (",", $1));
+        }
 
     cryptsetup_option: /^randinit/
         {
@@ -422,7 +463,7 @@
           foreach (split (",", $1)) {
             (m{^([^/,\s\-]+)-([^/,\s\-]+)}) or 
               die &FAI::internal_error("VG re-parse failed");
-            $FAI::configs{"VG_$1"}{volumes}{$2}{size}{preserve} = 1 
+            $FAI::configs{"VG_$1"}{volumes}{$2}{size}{preserve} = 1;
           }
         }
         | m{^preserve_reinstall:([^/,\s\-]+-[^/,\s\-]+(,[^/,\s\-]+-[^/,\s\-]+)*)}
@@ -432,17 +473,25 @@
             foreach (split (",", $1)) {
               (m{^([^/,\s\-]+)-([^/,\s\-]+)}) or 
                 die &FAI::internal_error("VG re-parse failed");
-              $FAI::configs{"VG_$1"}{volumes}{$2}{size}{preserve} = 1 
+              $FAI::configs{"VG_$1"}{volumes}{$2}{size}{preserve} = 1;
             }
           }
         }
+        | m{^preserve_lazy:([^/,\s\-]+-[^/,\s\-]+(,[^/,\s\-]+-[^/,\s\-]+)*)}
+        {
+          foreach (split (",", $1)) {
+            (m{^([^/,\s\-]+)-([^/,\s\-]+)}) or
+              die &FAI::internal_error("VG re-parse failed");
+            $FAI::configs{"VG_$1"}{volumes}{$2}{size}{preserve} = 2;
+          }
+        }
         | m{^resize:([^/,\s\-]+-[^/,\s\-]+(,[^/,\s\-]+-[^/,\s\-]+)*)}
         {
           # set the resize flag for all ids
           foreach (split (",", $1)) {
             (m{^([^/,\s\-]+)-([^/,\s\-]+)}) or 
               die &FAI::internal_error("VG re-parse failed");
-            $FAI::configs{"VG_$1"}{volumes}{$2}{size}{resize} = 1 
+            $FAI::configs{"VG_$1"}{volumes}{$2}{size}{resize} = 1;
           }
         }
         | /^fstabkey:(device|label|uuid)/
@@ -450,6 +499,14 @@
           # the information preferred for fstab device identifieres
           $FAI::configs{"VG_--ANY--"}{fstabkey} = $1;
         }
+        | m{^always_format:([^/,\s\-]+-[^/,\s\-]+(,[^/,\s\-]+-[^/,\s\-]+)*)}
+        {
+          foreach (split (",", $1)) {
+            (m{^([^/,\s\-]+)-([^/,\s\-]+)}) or
+              die &FAI::internal_error("VG re-parse failed");
+            $FAI::configs{"VG_$1"}{volumes}{$2}{size}{always_format} = 1;
+          }
+        }
 
 
     option: /^preserve_always:(\d+(,\d+)*)/
@@ -466,6 +523,11 @@
             $FAI::configs{$FAI::device}{preserveparts} = 1;
           }
         }
+        | /^preserve_lazy:(\d+(,\d+)*)/
+        {
+          $FAI::configs{$FAI::device}{partitions}{$_}{size}{preserve} = 2 foreach (split(",", $1));
+          $FAI::configs{$FAI::device}{preserveparts} = 2;
+        }
         | /^resize:(\d+(,\d+)*)/
         {
           # set the resize flag for all ids
@@ -515,6 +577,10 @@
 
 	  $FAI::configs{$FAI::device} = dclone($FAI::configs{"PHY_" . $ref_dev});
 	}
+        | /^always_format:(\d+(,\d+)*)/
+        {
+          $FAI::configs{$FAI::device}{partitions}{$_}{size}{always_format} = 1 foreach (split(",", $1));
+        }
 
     volume: /^vg\s+/ name devices vgcreateopt(s?)
         | /^raid([0156]|10)\s+/
@@ -561,7 +627,28 @@
           $FAI::partition_pointer = (\%FAI::configs)->{CRYPT}->{volumes}->{$vol_id};
         }
         mountpoint devices filesystem mount_options lv_or_fsopts
+        | /^tmpfs\s+/
+        {
+          ($FAI::device eq "TMPFS") or die "tmpfs entry invalid in this context\n";
+          defined ($FAI::configs{TMPFS}) or &FAI::internal_error("TMPFS entry missing");
+
+          my $vol_id = 0;
+          foreach my $ex_vol_id (&FAI::numsort(keys %{ $FAI::configs{TMPFS}{volumes} })) {
+            defined ($FAI::configs{TMPFS}{volumes}{$ex_vol_id}{device}) or last;
+            $vol_id++;
+          }
+
+          $FAI::configs{TMPFS}{volumes}{$vol_id}{device} = "tmpfs";
+          $FAI::configs{TMPFS}{volumes}{$vol_id}{filesystem} = "tmpfs";
+
+          # We don't do preserve for tmpfs
+          $FAI::configs{TMPFS}{volumes}{$vol_id}{preserve} = 0;
+
+          $FAI::partition_pointer = (\%FAI::configs)->{TMPFS}->{volumes}->{$vol_id};
+        }
+        mountpoint tmpfs_size mount_options
         | type mountpoint size filesystem mount_options lv_or_fsopts
+        | <error>
 
     type: 'primary'
         {
@@ -589,6 +676,8 @@
           # initialise the preserve and resize flags
           defined($FAI::configs{$FAI::device}{volumes}{$2}{size}{preserve}) or
             $FAI::configs{$FAI::device}{volumes}{$2}{size}{preserve} = 0;
+          defined($FAI::configs{$FAI::device}{volumes}{$2}{size}{always_format}) or
+            $FAI::configs{$FAI::device}{volumes}{$2}{size}{always_format} = 0;
           defined($FAI::configs{$FAI::device}{volumes}{$2}{size}{resize}) or
             $FAI::configs{$FAI::device}{volumes}{$2}{size}{resize} = 0;
           # set the reference to the current volume
@@ -631,17 +720,17 @@
           1;
         }
 
-    size: /^(\d+[kMGTP%iB]*(-(\d+[kMGTP%iB]*)?)?)(:resize)?\s+/
+    size: /^((RAM:\d+%|\d+[kMGTP%iB]*)(-(RAM:\d+%|\d+[kMGTP%iB]*)?)?)(:resize)?/
         {
           # complete the size specification to be a range in all cases
           my $range = $1;
           # the size is fixed
-          if (!defined ($2))
+          if (!defined ($3))
           {
             # make it a range of the form x-x
-            $range = "$range-$1";
+            $range = "$range-$2";
           }
-          elsif (!defined ($3))
+          elsif (!defined ($4))
           {
             # range has no upper limit, assume the whole disk
             $range = "${range}100%";
@@ -657,12 +746,12 @@
           # enter the range into the hash
           $FAI::partition_pointer->{size}->{range} = $range;
           # set the resize flag, if required
-          if (defined ($4)) {
+          if (defined ($5)) {
             $FAI::partition_pointer->{size}->{resize} = 1;
             $FAI::configs{$FAI::device}{preserveparts} = 1;
           }
         }
-        | /^(-\d+[kMGTP%iB]*)(:resize)?\s+/
+        | /^(-(RAM:\d+%|\d+[kMGTP%iB]*))(:resize)?\s+/
         {
           # complete the range by assuming 0 as the lower limit 
           my $range = "0$1";
@@ -676,13 +765,34 @@
           # enter the range into the hash
           $FAI::partition_pointer->{size}->{range} = $range;
           # set the resize flag, if required
-          if (defined ($2)) {
+          if (defined ($3)) {
             $FAI::partition_pointer->{size}->{resize} = 1;
             $FAI::configs{$FAI::device}{preserveparts} = 1;
           }
         }
         | <error: invalid partition size near "$text">
 
+    tmpfs_size: /^(RAM:(\d+%)|\d+[kMGTPiB]*)\s+/
+        {
+          my $size;
+
+          # convert the units, if necessary
+          # A percentage is kept as is as tmpfs handles it
+          if (defined($2)) {
+            $size = $2;
+          } else {
+            $size = $1;
+            $size .= "MiB" if ($size =~ /\d\s*$/);
+            $size  = &FAI::convert_unit($size);
+            # Size in MiB for tmpfs
+            $size .= "m";
+          }
+
+          # enter the size into the hash
+          $FAI::partition_pointer->{size} = $size;
+        }
+        | <error: invalid tmpfs size near "$text">
+
     devices: /^([^\d,:\s\-][^,:\s]*(:(spare|missing))*(,[^,:\s]+(:(spare|missing))*)*)/
         {
           # split the device list by ,
@@ -765,16 +875,24 @@
         }
         | /^\S+/
         {
-          $FAI::partition_pointer->{filesystem} = $item[ 1 ];
+          my ($fs, $journal) = split(/:/, $item[1]);
           my $to_be_preserved = 0;
+
+          $FAI::partition_pointer->{filesystem} = $fs;
+
+          defined($journal) and $journal =~ s/journal=//;
+          $FAI::partition_pointer->{journal_dev} = $journal;
+
           if ($FAI::device eq "RAID" or $FAI::device eq "CRYPT") {
             $to_be_preserved = $FAI::partition_pointer->{preserve};
           } else {
             $to_be_preserved = $FAI::partition_pointer->{size}->{preserve};
           }
           if (0 == $to_be_preserved) {
-            &FAI::in_path("mkfs.$item[1]") or
-              die "unknown/invalid filesystem type $item[1] (mkfs.$item[1] not found in PATH)\n";
+            $fs =~ s/_journal$//;
+
+            &FAI::in_path("mkfs.$fs") or
+              die "unknown/invalid filesystem type $fs (mkfs.$fs not found in PATH)\n";
           }
         }
 

Modified: trunk/lib/setup-storage/Sizes.pm
===================================================================
--- trunk/lib/setup-storage/Sizes.pm	2010-07-29 15:42:56 UTC (rev 5906)
+++ trunk/lib/setup-storage/Sizes.pm	2010-07-29 16:24:12 UTC (rev 5907)
@@ -202,8 +202,8 @@
   # loop through all device configurations
   foreach my $config (keys %FAI::configs) {
 
-    # for RAID, encrypted or physical disks there is nothing to be done here
-    next if ($config eq "RAID" || $config eq "CRYPT" || $config =~ /^PHY_./);
+    # for RAID, encrypted, tmpfs or physical disks there is nothing to be done here
+    next if ($config eq "RAID" || $config eq "CRYPT" || $config eq "TMPFS" || $config =~ /^PHY_./);
     ($config =~ /^VG_(.+)$/) or &FAI::internal_error("invalid config entry $config");
     next if ($1 eq "--ANY--");
     my $vg = $1; # the volume group name
@@ -252,7 +252,7 @@
       # the size is fixed
       if ($start == $end) { 
         # write the size back to the configuration
-        $lv_size->{eff_size} = $start;
+        $lv_size->{eff_size} = $start * 1024.0 * 1024.0;
       } else {
 
         # add this volume to the redistribution list
@@ -282,7 +282,7 @@
 
       # write the final size
       $FAI::configs{$config}{volumes}{$lv}{size}{eff_size} =
-        $start + (($end - $start) * $redist_factor);
+        ($start + (($end - $start) * $redist_factor)) * 1024.0 * 1024.0;
     }
   }
 }
@@ -612,8 +612,8 @@
   # loop through all device configurations
   foreach my $config (keys %FAI::configs) {
 
-    # for RAID, encrypted or LVM, there is nothing to be done here
-    next if ($config eq "RAID" || $config eq "CRYPT" || $config =~ /^VG_./);
+    # for RAID, encrypted, tmpfs or LVM, there is nothing to be done here
+    next if ($config eq "RAID" || $config eq "CRYPT" || $config eq "TMPFS" || $config =~ /^VG_./);
     ($config =~ /^PHY_(.+)$/) or &FAI::internal_error("invalid config entry $config");
     # nothing to be done, if this is a configuration for a virtual disk
     next if $FAI::configs{$config}{virtual};

Modified: trunk/lib/setup-storage/Volumes.pm
===================================================================
--- trunk/lib/setup-storage/Volumes.pm	2010-07-29 15:42:56 UTC (rev 5906)
+++ trunk/lib/setup-storage/Volumes.pm	2010-07-29 16:24:12 UTC (rev 5907)
@@ -38,18 +38,63 @@
 
 ################################################################################
 #
+# @brief Collect all physical devices reference in the desired configuration
+#
+################################################################################
+sub find_all_phys_devs {
+
+  my @phys_devs = ();
+
+  # loop through all configs
+  foreach my $config (keys %FAI::configs) {
+
+    if ($config =~ /^PHY_(.+)$/) {
+      push @phys_devs, $1;
+    } elsif ($config =~ /^VG_(.+)$/) {
+      next if ($1 eq "--ANY--");
+      foreach my $d (keys %{ $FAI::configs{$config}{devices} }) {
+        my ($i_p_d, $disk, $part_no) = &FAI::phys_dev($d);
+        push @phys_devs, $disk if (1 == $i_p_d);
+      }
+    } elsif ($config eq "RAID") {
+      foreach my $r (keys %{ $FAI::configs{$config}{volumes} }) {
+        foreach my $d (keys %{ $FAI::configs{$config}{volumes}{$r}{devices} }) {
+          my ($i_p_d, $disk, $part_no) = &FAI::phys_dev($d);
+          push @phys_devs, $disk if (1 == $i_p_d);
+        }
+      }
+    } elsif ($config eq "CRYPT") {
+      # devices must be one of the above already
+      next;
+    } elsif ($config eq "TMPFS") {
+      # no devices
+      next;
+    } else {
+      &FAI::internal_error("Unexpected key $config");
+    }
+  }
+
+  return \@phys_devs;
+}
+
+################################################################################
+#
 # @brief Collect the current partition information from all disks listed both
 # in $FAI::disks and $FAI::configs{PHY_<disk>}
 #
 ################################################################################
 sub get_current_disks {
 
+  my %referenced_devs = ();
+  @referenced_devs{ @{ &FAI::find_all_phys_devs() } } = ();
+
   # obtain the current state of all disks
   foreach my $disk (@FAI::disks) {
-
     # create full paths
     ($disk =~ m{^/}) or $disk = "/dev/$disk";
 
+    exists ($referenced_devs{$disk}) or next;
+
     # make sure, $disk is a proper block device
     (-b $disk) or die "$disk is not a block special device!\n";
 
@@ -136,6 +181,23 @@
 #  7      30450018816B  32547432959B  2097414144B   logical   ext3
 #  8      32547465216B  82343278079B  49795812864B  logical   ext3
 #
+# parted 2.2:
+# $ parted -s /dev/sda unit TiB print
+# Model: ATA VBOX HARDDISK (scsi)
+# Disk /dev/sda: 0.06TiB
+# Sector size (logical/physical): 512B/512B
+# Partition Table: msdos
+#
+# Number  Start    End      Size     Type      File system     Flags
+#  1      0.00TiB  0.00TiB  0.00TiB  primary   ext3            boot
+#  2      0.00TiB  0.00TiB  0.00TiB  primary   linux-swap(v1)
+#  3      0.00TiB  0.00TiB  0.00TiB  primary   ext3
+#  4      0.00TiB  0.06TiB  0.06TiB  extended                  lba
+#  5      0.00TiB  0.00TiB  0.00TiB  logical   ext3
+#  6      0.00TiB  0.00TiB  0.00TiB  logical   ext3
+#  7      0.00TiB  0.00TiB  0.00TiB  logical   ext3
+#  8      0.00TiB  0.01TiB  0.00TiB  logical   ext3
+#  9      0.01TiB  0.06TiB  0.05TiB  logical                   lvm
 
     # As shown above, some entries may be blank. Thus the exact column starts
     # and lengths must be parsed from the header line. This is stored in the
@@ -208,9 +270,17 @@
         # file system either
         next if ($id eq "");
 
-        # extract the set of characters
-        $line =~ /^.{$fs_cols_before}(.{$fs_col_width})/;
-        my $fs = $1;
+        # extract the file system information
+        my $fs = "";
+        if (length ($line) > $fs_cols_before) {
+          if (length ($line) >= ($fs_cols_before + $fs_col_width)) {
+            $line =~ /^.{$fs_cols_before}(.{$fs_col_width})/;
+            $fs = $1;
+          } else {
+            $line =~ /^.{$fs_cols_before}(.+)$/;
+            $fs = $1;
+          }
+        }
 
         # remove any trailing space
         $fs =~ s/\s*$//g;
@@ -301,20 +371,20 @@
 sub get_current_lvm {
 
   use Linux::LVM;
+  use Cwd qw(abs_path);
 
   # get the existing volume groups
   foreach my $vg (get_volume_group_list()) {
     # initialise the hash entry
     $FAI::current_lvm_config{$vg}{physical_volumes} = ();
-    &FAI::push_command("true", "", "vg_created_$vg");
 
     # store the vg size in MB
     my %vg_info = get_volume_group_information($vg);
     if (%vg_info) {
-      $FAI::current_lvm_config{$vg}{size} = $vg_info{alloc_pe_size} .
-        $vg_info{alloc_pe_size_unit};
+      $FAI::current_lvm_config{$vg}{size} = &FAI::convert_unit(
+        $vg_info{vg_size} . $vg_info{vg_size_unit});
     } else {
-      $FAI::current_lvm_config{$vg}{size} = "0M";
+      $FAI::current_lvm_config{$vg}{size} = "0";
     }
 
     # store the logical volumes and their sizes
@@ -325,13 +395,12 @@
       $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});
-      &FAI::push_command("true", "", "exist_/dev/$vg/$short_name");
     }
 
     # store the physical volumes
     my %pv_info = get_physical_volume_information($vg);
-    @{ $FAI::current_lvm_config{$vg}{physical_volumes} } =
-      sort keys %pv_info;
+    push @{ $FAI::current_lvm_config{$vg}{physical_volumes} },
+      abs_path($_) foreach (sort keys %pv_info);
   }
 
 }
@@ -344,6 +413,8 @@
 ################################################################################
 sub get_current_raid {
 
+  use Cwd qw(abs_path);
+
   # the list to hold the output of mdadm commands as parsed below
   my @mdadm_print = ();
 
@@ -376,10 +447,10 @@
     if ($line =~ /^ARRAY \/dev\/md[\/]?(\d+) level=(\S+) num-devices=\d+(\s+|$)/) {
       $id = $1;
       $FAI::current_raid_config{$id}{mode} = $2;
-      &FAI::push_command( "true", "", "exist_/dev/md$id" );
     } elsif ($line =~ /^\s*devices=(\S+)$/) {
       defined($id) or &FAI::internal_error("mdadm ARRAY line not yet seen");
-      @{ $FAI::current_raid_config{$id}{devices} } = split (",", $1);
+      push @{ $FAI::current_raid_config{$id}{devices} }, abs_path($_)
+        foreach (split (",", $1));
     }
   }
 }
@@ -396,11 +467,17 @@
   my ($device_name) = @_;
   my ($i_p_d, $disk, $part_no) = &FAI::phys_dev($device_name);
 
-  if (1 == $i_p_d && defined($FAI::configs{"PHY_$disk"}{partitions}{$part_no})) {
-    $FAI::configs{"PHY_$disk"}{partitions}{$part_no}{size}{preserve} = 1;
-    $FAI::configs{"PHY_$disk"}{preserveparts} = 1;
-  } elsif ($device_name =~ m{^/dev/md(\d+)$}) {
+  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})) {
+      $FAI::configs{"PHY_$disk"}{partitions}{$part_no}{size}{preserve} = 1;
+      $FAI::configs{"PHY_$disk"}{preserveparts} = 1;
+    }
+  } 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;
@@ -409,6 +486,8 @@
   } 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;
@@ -434,7 +513,16 @@
     if ($config =~ /^PHY_(.+)$/) {
       foreach my $part_id (&numsort(keys %{ $FAI::configs{$config}{partitions} })) {
         my $part = (\%FAI::configs)->{$config}->{partitions}->{$part_id};
+        $part->{size}->{preserve} =
+          ((defined($FAI::current_config{$1}) &&
+              defined($FAI::current_config{$1}{partitions}{$part_id})) ? 1 : 0)
+          if (2 == $part->{size}->{preserve});
         next unless ($part->{size}->{preserve} || $part->{size}->{resize});
+        ($part->{size}->{extended}) and die
+          "Preserving extended partitions is not supported; mark all logical partitions instead\n";
+        defined ($FAI::current_config{$1}{partitions}{$part_id}) or die
+          "Can't preserve ". &FAI::make_device_name($1, $part->{number})
+            . " because it does not exist\n";
         defined ($part->{size}->{range}) or die
           "Can't preserve ". &FAI::make_device_name($1, $part->{number})
             . " because it is not defined in the current config\n";
@@ -444,18 +532,28 @@
       # check for logical volumes that need to be preserved and preserve the
       # underlying devices recursively
       foreach my $l (keys %{ $FAI::configs{$config}{volumes} }) {
+        $FAI::configs{$config}{volumes}{$l}{size}{preserve} =
+          ((defined($FAI::current_lvm_config{$1}) &&
+              defined($FAI::current_lvm_config{$1}{volumes}{$l})) ? 1 : 0)
+          if (2 == $FAI::configs{$config}{volumes}{$l}{size}{preserve});
         next unless ($FAI::configs{$config}{volumes}{$l}{size}{preserve} == 1 ||
           $FAI::configs{$config}{volumes}{$l}{size}{resize} == 1);
+        defined ($FAI::current_lvm_config{$1}{volumes}{$l}) or die
+          "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} });
-        last;
       }
     } elsif ($config eq "RAID") {
       # check for volumes that need to be preserved and preserve the underlying
       # devices recursively
       foreach my $r (keys %{ $FAI::configs{$config}{volumes} }) {
+        $FAI::configs{$config}{volumes}{$r}{preserve} =
+          (defined($FAI::current_raid_config{$r}) ? 1 : 0)
+          if (2 == $FAI::configs{$config}{volumes}{$r}{preserve});
         next unless ($FAI::configs{$config}{volumes}{$r}{preserve} == 1);
+        defined ($FAI::current_raid_config{$r}) or die
+          "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} });
@@ -463,6 +561,9 @@
     } elsif ($config eq "CRYPT") {
       # We don't do preserve for encrypted partitions
       next;
+    } elsif ($config eq "TMPFS") {
+      # We don't do preserve for tmpfs
+      next;
     } else {
       &FAI::internal_error("Unexpected key $config");
     }

Modified: trunk/man/setup-storage.8
===================================================================
--- trunk/man/setup-storage.8	2010-07-29 15:42:56 UTC (rev 5906)
+++ trunk/man/setup-storage.8	2010-07-29 16:24:12 UTC (rev 5907)
@@ -137,6 +137,8 @@
 .br
            | disk_config cryptsetup( <cryptsetupoption>)*
 .br
+           | disk_config tmpfs
+.br
            | disk_config end 
 .br
            | disk_config disk[[:digit:]]+( <option>)*
@@ -157,14 +159,22 @@
 .br
            | preserve_always:[^/,\\s\\-]+-[^/,\\s\\-]+(,[^/,\\s\\-]+-[^/,\\s\\-]+)*
 .br
-           /* preserve partitions -- always */
+           /* preserve volumes -- always */
 .br
            | preserve_reinstall:[^/,\\s\\-]+-[^/,\\s\\-]+(,[^/,\\s\\-]+-[^/,\\s\\-]+)*
 .br
-           /* preserve partitions -- unless the system is installed for the 
+           /* preserve volumes -- unless the system is installed for the
 .br
            first time */
 .br
+           | preserve_lazy:[^/,\\s\\-]+-[^/,\\s\\-]+(,[^/,\\s\\-]+-[^/,\\s\\-]+)*
+.br
+           /* preserve volumes -- unless these don't exist yet */
+.br
+           | always_format:[^/,\\s\\-]+-[^/,\\s\\-]+(,[^/,\\s\\-]+-[^/,\\s\\-]+)*
+.br
+           /* run mkfs on the volumes, even if marked as preserve */
+.br
            | resize:[^/,\\s\\-]+-[^/,\\s\\-]+(,[^/,\\s\\-]+-[^/,\\s\\-]+)*
 .br
            /* attempt to resize partitions */
@@ -183,14 +193,22 @@
 .br
            | preserve_always:[[:digit:]]+(,[[:digit:]]+)*
 .br
-           /* preserve partitions -- always */
+           /* preserve volumes -- always */
 .br
            | preserve_reinstall:[[:digit:]]+(,[[:digit:]]+)*
 .br
-           /* preserve partitions -- unless the system is installed for the 
+           /* preserve volumes -- unless the system is installed for the
 .br
            first time */
 .br
+           | preserve_lazy:[[:digit:]]+(,[[:digit:]]+)*
+.br
+           /* preserve volumes -- unless these don't exist yet */
+.br
+           | always_format:[[:digit:]]+(,[[:digit:]]+)*
+.br
+           /* run mkfs on the volumes, even if marked as preserve */
+.br
            | fstabkey:(device|label|uuid)
 .br
            /* when creating the fstab the key used for defining the device
@@ -221,6 +239,14 @@
 .br
            first time */
 .br
+           | preserve_lazy:[[:digit:]]+(,[[:digit:]]+)*
+.br
+           /* preserve partitions -- unless these don't exist yet */
+.br
+           | always_format:[[:digit:]]+(,[[:digit:]]+)*
+.br
+           /* run mkfs on the partitions, even if marked as preserve */
+.br
            | resize:[[:digit:]]+(,[[:digit:]]+)*
 .br
            /* attempt to resize partitions */
@@ -265,6 +291,10 @@
 .br
            /* lvm vg */
 .br
+           | tmpfs <mountpoint> <tmpfs_size> <mount_options>
+.br
+           /* tmpfs volume */
+.br
 
 
 type ::= primary
@@ -317,19 +347,19 @@
 .br
 
 
-size ::= [[:digit:]]+[kKMGTP%iB]*(-([[:digit:]]+[kKMGTP%iB]*)?)?(:resize)?
+size ::= (RAM:[[:digit:]]+%|[[:digit:]]+[kKMGTP%iB]*)(-(RAM:[[:digit:]]+%|[[:digit:]]+[kKMGTP%iB]*)?)?(:resize)?
 .br
-         /* size in kilo (KiB), mega (default, MiB), giga (GiB), tera (TiB) or
+         /* size in kilo (KiB), mega (default, MiB), giga (GiB), tera (TiB),
 .br
-          * petabytes (PiB) or %, possibly given as a range; physical
+          * petabytes (PiB) or percentage of disk size or RAM size, possibly
 .br
-          * partitions or lvm logical volumes only; in future releases KB, MB,
+          * given as a range; physical partitions or lvm logical volumes only;
 .br
-          * GB, ... will be treated as 1000 instead of 1024 (KiB, MiB, GiB, ...)
+          * in future releases KB, MB, GB, ... will be treated as 1000 instead
 .br
-          * multipliers */
+          * of 1024 (KiB, MiB, GiB, ...) multipliers */
 .br
-         | -[[:digit:]]+[kKMGTP%iB]*(:resize)?
+         | -(RAM:[[:digit:]]+%|[[:digit:]]+[kKMGTP%iB]*)(:resize)?
 .br
          /* size in kilo, mega (default), giga, tera or petabytes or %,
 .br
@@ -343,6 +373,14 @@
 .br
 
 
+tmpfs_size ::= (RAM:[[:digit:]]+%|[[:digit:]]+[kKMGTPiB]*)
+.br
+         /* tmpfs size in percentage of the total RAM or fixed size in
+.br
+          kilo (KiB), mega (default, MiB), giga (GiB), tera (TiB) or petabytes (PiB).
+.br
+
+
 mount_options ::= [^[:space:]]+
 .br
 
@@ -379,11 +417,15 @@
 Any options to mkfs.xxx may be given using createopts="".
 .IP \(bu
 The "preserveX" and "boot" options are one of the options now given on the
-disk_config line, using preserve_reinstall or preserve_always and bootable.
-preserve_always is equivalent to the previous preserveX option, whereas
-preserve_reinstall preserves the partition unless "initial" is given as one of
-the FAI_FLAGS.
+disk_config line, using preserve_reinstall, preserve_always, or preserve_lazy,
+and bootable.  preserve_always is equivalent to the previous preserveX option,
+whereas preserve_reinstall preserves the partition unless "initial" is given as
+one of the FAI_FLAGS. preserve_lazy allows to preserve partitions only if these
+exist already. Otherwise they are created.
 .IP \(bu
+The "always_format" option overrides preserving filesystems (via one of the
+"preserveX" options), like the "format" option in setup_harddisks.
+.IP \(bu
 Support for LVM and RAID is completely new
 .IP \(bu
 Resizing partitions and filesystems is supported
@@ -476,6 +518,52 @@
 .sp
 .fi
 .PP
+
+.TP
+tmpfs example
+.sp
+.nf
+.ta 10n 20n 30n 40n 50n
+disk_config tmpfs
+tmpfs	/tmp	RAM:20%	defaults
+tmpfs	/scratch	3GiB	defaults
+.sp
+.fi
+.PP
+.IP \(bu
+Mount a tmpfs on /tmp with a maximum size equal to 20% of the total amount of
+RAM in the machine. This is equivalent to using size=20% in the tmpfs mount
+options.
+.IP \(bu
+Mount a tmpfs on /scratch with a maximum size of 3 GiB.
+
+.TP
+External log device example
+.sp
+.nf
+.ta 10n 20n 30n 40n 60n
+disk_config /dev/sda fstabkey:uuid bootable:2
+primary	/	20GiB	ext3		defaults
+primary	/boot	250	ext2		defaults
+primary	swap	4GiB	swap		defaults
+logical	-	256	ext3_journal	-
+logical	-	256	ext4_journal	-
+logical	-	256	xfs_journal	-
+
+disk_config /dev/sdb fstabkey:uuid
+primary	/mnt/ext3	33%	ext3:journal=/dev/sda5		defaults
+primary	/mnt/ext4	33%	ext4:journal=/dev/sda6		defaults
+primary	/mnt/xfs	33%	xfs:journal=/dev/sda7		defaults
+.sp
+.fi
+.PP
+.IP \(bu
+Mount an ext3 filesystem on /dev/sdb1 with an external journal on /dev/sda5
+.IP \(bu
+Mount an ext4 filesystem on /dev/sdb2 with an external journal on /dev/sda6
+.IP \(bu
+Mount an XFS filesystem on /dev/sdb3 using /dev/sda7 as the log device
+
 .SH CAVEATS
 .IP \(bu
 Partition UUID cannot be obtained: In case a partition was previously used as




More information about the Fai-commit mailing list