summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2015-09-24 18:13:14 +0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2015-09-24 19:59:44 +0200
commit9d92bd7845a0fcf895a1e7c4ae95c908be673060 (patch)
treea5c0990def36969e3bc19d4aa9fc97f7dadcc846
parentf40c7ed1435d9507868337ae7509fe6d0392498b (diff)
downloadnixlib-9d92bd7845a0fcf895a1e7c4ae95c908be673060.tar
nixlib-9d92bd7845a0fcf895a1e7c4ae95c908be673060.tar.gz
nixlib-9d92bd7845a0fcf895a1e7c4ae95c908be673060.tar.bz2
nixlib-9d92bd7845a0fcf895a1e7c4ae95c908be673060.tar.lz
nixlib-9d92bd7845a0fcf895a1e7c4ae95c908be673060.tar.xz
nixlib-9d92bd7845a0fcf895a1e7c4ae95c908be673060.tar.zst
nixlib-9d92bd7845a0fcf895a1e7c4ae95c908be673060.zip
Add filesystem option to automatically grow to the maximum size
This is primarily for EC2 and other cloud environments, where the disk
may be bigger than the original image.
-rw-r--r--nixos/modules/system/boot/stage-1-init.sh15
-rw-r--r--nixos/modules/system/boot/stage-1.nix7
-rw-r--r--nixos/modules/tasks/filesystems.nix16
-rw-r--r--nixos/tests/make-test.nix2
-rw-r--r--nixos/tests/resize-root.nix36
5 files changed, 71 insertions, 5 deletions
diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh
index 480bbfa2b07b..516cbb295fa4 100644
--- a/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixos/modules/system/boot/stage-1-init.sh
@@ -290,10 +290,23 @@ mountFS() {
         if [ -z "$fsType" ]; then fsType=auto; fi
     fi
 
-    echo "$device /mnt-root$mountPoint $fsType $options" >> /etc/fstab
+    # Filter out x- options, which busybox doesn't do yet.
+    local optionsFiltered="$(IFS=,; for i in $options; do if [ "${i:0:2}" != "x-" ]; then echo -n $i,; fi; done)"
+
+    echo "$device /mnt-root$mountPoint $fsType $optionsFiltered" >> /etc/fstab
 
     checkFS "$device" "$fsType"
 
+    # Optionally resize the filesystem.
+    case $options in
+        *x-nixos.autoresize*)
+            if [ "$fsType" = ext2 -o "$fsType" = ext3 -o "$fsType" = ext4 ]; then
+                echo "resizing $device..."
+                resize2fs "$device"
+            fi
+            ;;
+    esac
+
     # Create backing directories for unionfs-fuse.
     if [ "$fsType" = unionfs-fuse ]; then
         for i in $(IFS=:; echo ${options##*,dirs=}); do
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index f782eca3f647..ace2d10ec9c1 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -70,6 +70,12 @@ let
       copy_bin_and_libs ${pkgs.kmod}/bin/kmod
       ln -sf kmod $out/bin/modprobe
 
+      # Copy resize2fs if needed.
+      ${optionalString (any (fs: fs.autoResize) (attrValues config.fileSystems)) ''
+        # We need mke2fs in the initrd.
+        copy_bin_and_libs ${pkgs.e2fsprogs}/sbin/resize2fs
+      ''}
+
       ${config.boot.initrd.extraUtilsCommands}
 
       # Copy ld manually since it isn't detected correctly
@@ -393,7 +399,6 @@ in
       }
     ];
 
-
     system.build.bootStage1 = bootStage1;
     system.build.initialRamdisk = initialRamdisk;
     system.build.extraUtils = extraUtils;
diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix
index ab64106f3533..9dd250f140ce 100644
--- a/nixos/modules/tasks/filesystems.nix
+++ b/nixos/modules/tasks/filesystems.nix
@@ -7,7 +7,7 @@ let
 
   fileSystems = attrValues config.fileSystems;
 
-  prioOption = prio: optionalString (prio !=null) " pri=${toString prio}";
+  prioOption = prio: optionalString (prio != null) " pri=${toString prio}";
 
   fileSystemOpts = { name, config, ... }: {
 
@@ -43,7 +43,7 @@ let
       options = mkOption {
         default = "defaults";
         example = "data=journal";
-        type = types.commas;
+        type = types.commas; # FIXME: should be a list
         description = "Options used to mount the file system.";
       };
 
@@ -58,6 +58,17 @@ let
         '';
       };
 
+      autoResize = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          If set, the filesystem is grown to its maximum size before
+          being mounted. (This is typically the size of the containing
+          partition.) This is currently only supported for ext2/3/4
+          filesystems that are mounted during early boot.
+        '';
+      };
+
       noCheck = mkOption {
         default = false;
         type = types.bool;
@@ -69,6 +80,7 @@ let
     config = {
       mountPoint = mkDefault name;
       device = mkIf (config.fsType == "tmpfs") (mkDefault config.fsType);
+      options = mkIf config.autoResize "x-nixos.autoresize";
     };
 
   };
diff --git a/nixos/tests/make-test.nix b/nixos/tests/make-test.nix
index 285ca5b71d6e..f3e26aa7e74d 100644
--- a/nixos/tests/make-test.nix
+++ b/nixos/tests/make-test.nix
@@ -2,4 +2,4 @@ f: { system ? builtins.currentSystem, ... } @ args:
 
 with import ../lib/testing.nix { inherit system; };
 
-makeTest (if builtins.isFunction f then f (args // { inherit pkgs; }) else f)
+makeTest (if builtins.isFunction f then f (args // { inherit pkgs; inherit (pkgs) lib; }) else f)
diff --git a/nixos/tests/resize-root.nix b/nixos/tests/resize-root.nix
new file mode 100644
index 000000000000..c8ccab38ab6f
--- /dev/null
+++ b/nixos/tests/resize-root.nix
@@ -0,0 +1,36 @@
+import ./make-test.nix ({ pkgs, lib, ...} : {
+
+  meta.maintainers = [ lib.maintainers.eelco ];
+
+  machine = { config, pkgs, ... }: {
+    virtualisation.diskSize = 512;
+    fileSystems = lib.mkVMOverride {
+      "/".autoResize = true;
+    };
+  };
+
+  testScript =
+    ''
+      # Create a VM with a 512 MiB disk.
+      $machine->start;
+      $machine->waitForUnit("multi-user.target");
+      my $blocks = $machine->succeed("stat -c %b -f /");
+      my $bsize = $machine->succeed("stat -c %S -f /");
+      my $size = $blocks * $bsize;
+      die "wrong free space $size" if $size < 480 * 1024 * 1024 || $size > 512 * 1024 * 1024;
+      $machine->succeed("touch /marker");
+      $machine->shutdown;
+
+      # Grow the disk to 1024 MiB.
+      system("qemu-img resize vm-state-machine/machine.qcow2 1024M") == 0 or die;
+
+      # Start the VM again and check whether the initrd has correctly
+      # grown the root filesystem.
+      $machine->start;
+      $machine->waitForUnit("multi-user.target");
+      $machine->succeed("[ -e /marker ]");
+      my $blocks = $machine->succeed("stat -c %b -f /");
+      my $size = $blocks * $bsize;
+      die "wrong free space $size" if $size < 980 * 1024 * 1024 || $size > 1024 * 1024 * 1024;
+    '';
+})