summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2023-03-21 15:11:07 +0000
committerAlyssa Ross <hi@alyssa.is>2023-03-21 15:43:58 +0000
commit2a338f7e1abe182d1c0ec496540349d2084e9b4b (patch)
treeb8f1bb936fc1dbab7733487b96dbbaea5174b5fb
parent048fadd0a4bf8b29227dc67f39363305b84ff29a (diff)
downloadspectrum-2a338f7e1abe182d1c0ec496540349d2084e9b4b.tar
spectrum-2a338f7e1abe182d1c0ec496540349d2084e9b4b.tar.gz
spectrum-2a338f7e1abe182d1c0ec496540349d2084e9b4b.tar.bz2
spectrum-2a338f7e1abe182d1c0ec496540349d2084e9b4b.tar.lz
spectrum-2a338f7e1abe182d1c0ec496540349d2084e9b4b.tar.xz
spectrum-2a338f7e1abe182d1c0ec496540349d2084e9b4b.tar.zst
spectrum-2a338f7e1abe182d1c0ec496540349d2084e9b4b.zip
scripts/make-gpt.sh: use copy_file_range(2)
Before this change, a clean release/live "make -j4" had a median
runtime of 85 seconds.  Now, it's 37 seconds.  That much of a
reduction in iteration time is worth the extra complexity.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
-rw-r--r--host/initramfs/default.nix7
-rw-r--r--host/rootfs/default.nix15
-rw-r--r--img/app/default.nix12
-rw-r--r--release/live/default.nix15
-rwxr-xr-xscripts/make-gpt.sh10
-rw-r--r--tools/lseek/Makefile23
-rw-r--r--tools/lseek/default.nix26
-rw-r--r--tools/lseek/lseek.c59
-rw-r--r--vm/sys/net/default.nix12
9 files changed, 160 insertions, 19 deletions
diff --git a/host/initramfs/default.nix b/host/initramfs/default.nix
index b9b22ae..22dcbed 100644
--- a/host/initramfs/default.nix
+++ b/host/initramfs/default.nix
@@ -1,11 +1,14 @@
-# SPDX-FileCopyrightText: 2021-2022 Alyssa Ross <hi@alyssa.is>
+# SPDX-FileCopyrightText: 2021-2023 Alyssa Ross <hi@alyssa.is>
 # SPDX-License-Identifier: MIT
 
 import ../../lib/eval-config.nix (
+
 { config, src
+, lseek ? import ../../tools/lseek { inherit config; }
 , rootfs ? import ../rootfs { inherit config; }
 , ...
 }:
+
 config.pkgs.callPackage (
 
 { lib, stdenvNoCC, makeModulesClosure, runCommand, writeReferencesToFile
@@ -89,7 +92,7 @@ stdenvNoCC.mkDerivation {
   MICROCODE = microcode;
   PACKAGES_CPIO = packagesCpio;
 
-  nativeBuildInputs = [ cpio ];
+  nativeBuildInputs = [ cpio lseek ];
 
   makeFlags = [ "dest=$(out)" ];
 
diff --git a/host/rootfs/default.nix b/host/rootfs/default.nix
index 23e4b38..637c607 100644
--- a/host/rootfs/default.nix
+++ b/host/rootfs/default.nix
@@ -1,9 +1,18 @@
 # SPDX-License-Identifier: MIT
-# SPDX-FileCopyrightText: 2021-2022 Alyssa Ross <hi@alyssa.is>
+# SPDX-FileCopyrightText: 2021-2023 Alyssa Ross <hi@alyssa.is>
 # SPDX-FileCopyrightText: 2022 Unikie
 
 import ../../lib/eval-config.nix (
-{ config, src, ... }: let inherit (config) pkgs; in
+
+{ config, src
+, lseek ? import ../../tools/lseek { inherit config; }
+, ...
+}:
+
+let
+  inherit (config) pkgs;
+in
+
 pkgs.pkgsStatic.callPackage (
 
 { lib, stdenvNoCC, nixos, runCommand, writeReferencesToFile, s6-rc, tar2ext4
@@ -124,7 +133,7 @@ stdenvNoCC.mkDerivation {
   inherit src;
   sourceRoot = "source/host/rootfs";
 
-  nativeBuildInputs = [ s6-rc tar2ext4 ];
+  nativeBuildInputs = [ lseek s6-rc tar2ext4 ];
 
   MODULES_ALIAS = "${kernel}/lib/modules/${kernel.modDirVersion}/modules.alias";
   MODULES_ORDER = "${kernel}/lib/modules/${kernel.modDirVersion}/modules.order";
diff --git a/img/app/default.nix b/img/app/default.nix
index 70e6e33..538dfe2 100644
--- a/img/app/default.nix
+++ b/img/app/default.nix
@@ -1,8 +1,14 @@
 # SPDX-License-Identifier: MIT
-# SPDX-FileCopyrightText: 2021-2022 Alyssa Ross <hi@alyssa.is>
+# SPDX-FileCopyrightText: 2021-2023 Alyssa Ross <hi@alyssa.is>
 
 import ../../lib/eval-config.nix (
-{ config, src, terminfo ? config.pkgs.foot.terminfo, ... }:
+
+{ config, src
+, lseek ? import ../../tools/lseek { inherit config; }
+, terminfo ? config.pkgs.foot.terminfo
+, ...
+}:
+
 config.pkgs.pkgsStatic.callPackage (
 
 { lib, stdenvNoCC, runCommand, writeReferencesToFile, buildPackages
@@ -65,7 +71,7 @@ stdenvNoCC.mkDerivation {
   inherit src;
   sourceRoot = "source/img/app";
 
-  nativeBuildInputs = [ jq s6-rc tar2ext4 util-linux ];
+  nativeBuildInputs = [ jq lseek s6-rc tar2ext4 util-linux ];
 
   PACKAGES_TAR = packagesTar;
   VMLINUX = "${kernel.dev}/vmlinux";
diff --git a/release/live/default.nix b/release/live/default.nix
index 7ab7a22..b7ee036 100644
--- a/release/live/default.nix
+++ b/release/live/default.nix
@@ -1,12 +1,19 @@
 # SPDX-License-Identifier: MIT
-# SPDX-FileCopyrightText: 2021-2022 Alyssa Ross <hi@alyssa.is>
+# SPDX-FileCopyrightText: 2021-2023 Alyssa Ross <hi@alyssa.is>
 # SPDX-FileCopyrightText: 2022 Unikie
 
-import ../../lib/eval-config.nix ({ config, src, ... }:
+import ../../lib/eval-config.nix (
+
+{ config, src
+, lseek ? import ../../tools/lseek { inherit config; }
+, ...
+}:
+
 config.pkgs.callPackage (
 
 { stdenvNoCC, cryptsetup, dosfstools, jq, mtools, util-linux, stdenv
-, systemd }:
+, systemd
+}:
 
 let
   inherit (config) pkgs;
@@ -26,7 +33,7 @@ stdenvNoCC.mkDerivation {
   inherit src;
   sourceRoot = "source/release/live";
 
-  nativeBuildInputs = [ cryptsetup dosfstools jq mtools util-linux ];
+  nativeBuildInputs = [ cryptsetup dosfstools jq lseek mtools util-linux ];
 
   EXT_FS = extfs;
   INITRAMFS = initramfs;
diff --git a/scripts/make-gpt.sh b/scripts/make-gpt.sh
index 6931879..2d4cd59 100755
--- a/scripts/make-gpt.sh
+++ b/scripts/make-gpt.sh
@@ -20,10 +20,12 @@ sizeMiB() {
 
 # Copies from path $3 into partition number $2 in partition table $1.
 fillPartition() {
-	sfdisk -J "$1" | jq -r --argjson index "$2" \
-		'.partitiontable.partitions[$index] | "\(.start) \(.size)"' |
-		(read -r start size;
-		 dd if="$3" of="$1" seek="$start" count="$size" conv=notrunc)
+	start="$(sfdisk -J "$1" | jq -r --argjson index "$2" \
+		'.partitiontable.partitions[$index].start * 512')"
+
+	# GNU cat will use copy_file_range(2) if possible, whereas dd
+	# will always do a userspace copy, which is significantly slower.
+	lseek -S 1 "$start" cat "$3" 1<>"$1"
 }
 
 # Prints the partition path from a PATH:PARTTYPE[:PARTUUID[:PARTLABEL]] string.
diff --git a/tools/lseek/Makefile b/tools/lseek/Makefile
new file mode 100644
index 0000000..f62419b
--- /dev/null
+++ b/tools/lseek/Makefile
@@ -0,0 +1,23 @@
+# SPDX-FileCopyrightText: 2023 Alyssa Ross <hi@alyssa.is>
+# SPDX-License-Identifier: EUPL-1.2+
+
+.POSIX:
+
+CFLAGS = -Wall -Wextra -Wpedantic -O -g
+INSTALL = install
+INSTALL_PROGRAM = $(INSTALL)
+
+prefix = /usr/local
+bindir = $(prefix)/bin
+
+all: lseek
+.PHONY: all
+
+install: lseek
+	mkdir -p $(DESTDIR)$(bindir)
+	$(INSTALL_PROGRAM) lseek $(DESTDIR)$(bindir)
+.PHONY: install
+
+clean:
+	rm -f lseek *.o
+.PHONY: clean
diff --git a/tools/lseek/default.nix b/tools/lseek/default.nix
new file mode 100644
index 0000000..3d303cf
--- /dev/null
+++ b/tools/lseek/default.nix
@@ -0,0 +1,26 @@
+# SPDX-FileCopyrightText: 2023 Alyssa Ross <hi@alyssa.is>
+# SPDX-License-Identifier: MIT
+
+import ../../lib/eval-config.nix ({ config, src, ... }: config.pkgs.pkgsStatic.callPackage (
+
+{ lib, stdenv }:
+
+stdenv.mkDerivation {
+  name = "lseek";
+
+  inherit src;
+  sourceRoot = "source/tools/lseek";
+
+  makeFlags = [ "prefix=$(out)" ];
+
+  enableParallelBuilding = true;
+
+  meta = with lib; {
+    description = "Seek an open file descriptor, then exec.";
+    license = licenses.eupl12;
+    maintainers = with maintainers; [ qyliss ];
+    platforms = platforms.unix;
+  };
+}
+
+) { })
diff --git a/tools/lseek/lseek.c b/tools/lseek/lseek.c
new file mode 100644
index 0000000..64dd561
--- /dev/null
+++ b/tools/lseek/lseek.c
@@ -0,0 +1,59 @@
+// SPDX-FileCopyrightText: 2023 Alyssa Ross <hi@alyssa.is>
+// SPDX-License-Identifier: EUPL-1.2+
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdnoreturn.h>
+#include <string.h>
+#include <unistd.h>
+
+noreturn static void ex_usage(void)
+{
+	fprintf(stderr, "Usage: lseek [ -C | -E | -S ] fd offset prog...\n");
+	exit(EXIT_FAILURE);
+}
+
+int main(int argc, char *argv[])
+{
+	int opt, whence = SEEK_CUR;
+	long fd, offset;
+
+	while ((opt = getopt(argc, argv, "+CES")) != -1) {
+		switch (opt) {
+		case 'C':
+			whence = SEEK_CUR;
+			break;
+		case 'E':
+			whence = SEEK_END;
+			break;
+		case 'S':
+			whence = SEEK_SET;
+			break;
+		default:
+			ex_usage();
+		}
+	}
+
+	if (optind > argc - 2)
+		ex_usage();
+
+	fd = strtol(argv[optind++], NULL, 10);
+	if (fd < 0 || fd > INT_MAX)
+		errx(EXIT_FAILURE, "%s", strerror(EBADF));
+
+	errno = 0;
+	offset = strtol(argv[optind++], NULL, 10);
+	if (errno)
+		err(EXIT_FAILURE, "bad offset: %s", argv[optind - 1]);
+	if (offset != (off_t)offset)
+		errx(EXIT_FAILURE, "%s", strerror(EINVAL));
+
+	if (lseek(fd, offset, whence) == -1)
+		err(EXIT_FAILURE, NULL);
+
+	execvp(argv[optind], argv + optind);
+	err(EXIT_FAILURE, "exec");
+}
diff --git a/vm/sys/net/default.nix b/vm/sys/net/default.nix
index 2af46b2..19f749a 100644
--- a/vm/sys/net/default.nix
+++ b/vm/sys/net/default.nix
@@ -1,8 +1,14 @@
 # SPDX-License-Identifier: MIT
-# SPDX-FileCopyrightText: 2021-2022 Alyssa Ross <hi@alyssa.is>
+# SPDX-FileCopyrightText: 2021-2023 Alyssa Ross <hi@alyssa.is>
 
 import ../../../lib/eval-config.nix (
-{ config, src, terminfo ? config.pkgs.foot.terminfo, ... }:
+
+{ config, src
+, lseek ? import ../../../tools/lseek { inherit config; }
+, terminfo ? config.pkgs.foot.terminfo
+, ...
+}:
+
 config.pkgs.pkgsStatic.callPackage (
 
 { lib, stdenvNoCC, runCommand, writeReferencesToFile, buildPackages
@@ -74,7 +80,7 @@ stdenvNoCC.mkDerivation {
   inherit src;
   sourceRoot = "source/vm/sys/net";
 
-  nativeBuildInputs = [ jq s6-rc tar2ext4 util-linux ];
+  nativeBuildInputs = [ jq lseek s6-rc tar2ext4 util-linux ];
 
   PACKAGES_TAR = packagesTar;
   VMLINUX = "${kernel.dev}/vmlinux";