[elbe-devel] [PATCH] Introduce generic filesystem tuning

Daniel Braunwarth daniel at braunwarth.dev
Sun Jan 1 21:40:13 CET 2023


This patch introduces a generic way for filesystem tuning with the new
XML node "fs-finetuning".

This new node can contain two different command variants:

1. "device-command", which is being executed directly after the
   filesystem has been created but before it is going to be mounted.
   This command variant provides a "{device}" placeholder which is
   replaced with the device containing the filesystem.

2. "path-command", which is being executed after the filesystem has been
   mounted  but before it is going to be filled with its content.
   This command variant provides a "{path}" placeholder which is
   replaced with the path of the mounted filesystem.

Those filesystem tuning commands shall replace the currently existing
"tune2fs" node. For example:

<fs>
    <type>ext4</type>
    <fs-finetuning>
        <device-command>tune2fs -i 0 {device}</device-command>
    </fs-finetuning>
</fs>

To be backward compatible the currently existing "tune2fs" nodes are
automatically converted during the XML preprocessing.

Another use case for those commands could be to create Btrfs subvolumes.
For example:

<fs>
    <type>btrfs</type>
    <fs-finetuning>
        <path-command>btrfs subvolume create {path}/home</path-command>
        <path-command>btrfs subvolume create {path}/var/log</path-command>
    </fs-finetuning>
</fs>

Signed-off-by: Daniel Braunwarth <daniel at braunwarth.dev>
---
 elbepack/fstab.py                             | 13 +++---
 elbepack/hdimg.py                             | 32 +++++++++----
 elbepack/xmlpreprocess.py                     | 22 ++++++++-
 examples/arm64-qemu-virt.xml                  |  4 +-
 examples/armhf-ti-beaglebone-black.xml        |  4 +-
 examples/powerpc.xml                          |  4 +-
 .../x86_32-pc-hdimg-minimal-grub-buster.xml   |  4 +-
 ...6_32-pc-hdimg-with-include-development.xml |  4 +-
 ...86_32-pc-hdimg-with-include-production.xml |  4 +-
 examples/x86_64-pc-hdimg-gnome3.xml           |  8 +++-
 .../x86_64-pc-hdimg-grub-hybrid-buster.xml    |  4 +-
 examples/x86_64-pc-hdimg-grub-uefi-buster.xml |  4 +-
 schema/dbsfed.xsd                             | 45 ++++++++++++++++++-
 tests/simple-amd64-with-grub-uefi.xml         |  4 +-
 14 files changed, 129 insertions(+), 27 deletions(-)

diff --git a/elbepack/fstab.py b/elbepack/fstab.py
index aeff493e8..8102f3c88 100644
--- a/elbepack/fstab.py
+++ b/elbepack/fstab.py
@@ -129,7 +129,14 @@ class fstabentry(hdpart):
             self.fstype = entry.text("fs/type")
             self.mkfsopt = entry.text("fs/mkfs", default="")
             self.passno = entry.text("fs/passno", default="0")
-            self.tune = entry.text("fs/tune2fs", default=None)
+
+            self.fs_device_commands = []
+            self.fs_path_commands = []
+            for command in entry.node("fs/fs-finetuning") or []:
+                if command.tag == "device-command":
+                    self.fs_device_commands.append(command.text("."))
+                elif command.tag == "path-command":
+                    self.fs_path_commands.append(command.text("."))
 
         self.id = str(fsid)
 
@@ -153,7 +160,3 @@ class fstabentry(hdpart):
         if self.fstype == "vfat":
             return "-n " + self.label
         return ""
-
-    def tuning(self, loopdev):
-        if self.tune:
-            do(f'tune2fs {self.tune} {loopdev}')
diff --git a/elbepack/hdimg.py b/elbepack/hdimg.py
index deeedce2e..a10ef7804 100644
--- a/elbepack/hdimg.py
+++ b/elbepack/hdimg.py
@@ -10,6 +10,8 @@
 import logging
 import os
 
+from pathlib import Path
+
 import parted
 import _ped
 
@@ -357,23 +359,37 @@ def create_label(disk, part, ppart, fslabel, target, grub):
 
     try:
         do(
-            f'mkfs.{entry.fstype} {entry.mkfsopt} {entry.get_label_opt()} '
-            f'{loopdev}')
-        do(f'mount {loopdev} {os.path.join(target, "imagemnt")}')
+            f"mkfs.{entry.fstype} {entry.mkfsopt} {entry.get_label_opt()} "
+            f"{loopdev}")
+
+        _execute_fs_commands(entry.fs_device_commands, dict(device=loopdev))
+
+        mount_path = Path(target, "imagemnt")
+        do(f"mount {loopdev} {mount_path}")
+
+        _execute_fs_commands(entry.fs_path_commands, dict(path=mount_path))
 
         try:
             do(
                 f'cp -a "{os.path.join(target, "filesystems", entry.id)}/." '
-                f'"{os.path.join(target, "imagemnt")}/"',
-               allow_fail=True)
+                f'"{mount_path}/"',
+                allow_fail=True)
         finally:
-            do(f'umount {loopdev}')
-        entry.tuning(loopdev)
+            do(f"umount {loopdev}")
     finally:
-        do(f'losetup -d {loopdev}')
+        do(f"losetup -d {loopdev}")
 
     return ppart
 
+def _execute_fs_commands(commands, replacements):
+    for command in commands:
+        try:
+            do(command.format(**replacements))
+        except KeyError as E:
+            logging.error('Filesystem finetuning command failed: invalid key "%s"', E)
+        except Exception as E:
+            logging.error('Filesystem finetuning command failed: %s', E)
+
 def create_binary(disk, part, ppart, target):
 
     entry = hdpart()
diff --git a/elbepack/xmlpreprocess.py b/elbepack/xmlpreprocess.py
index 680e7a361..34d7d1468 100644
--- a/elbepack/xmlpreprocess.py
+++ b/elbepack/xmlpreprocess.py
@@ -17,7 +17,7 @@ from urllib.request import urlopen
 from passlib.hash import sha512_crypt
 
 from lxml import etree
-from lxml.etree import XMLParser, parse, Element
+from lxml.etree import XMLParser, parse, Element, SubElement
 
 from elbepack.archivedir import ArchivedirError, combinearchivedir
 from elbepack.config import cfg
@@ -77,6 +77,23 @@ def preprocess_bootstrap(xml):
 
     old_node.getparent().replace(old_node, bootstrap)
 
+def preprocess_tune2fs(xml):
+    "Replaces all maybe existing tune2fs elements with fs-finetuning command"
+
+    old_nodes = xml.findall(".//tune2fs")
+    for old_node in old_nodes:
+        print("[WARN] <tune2fs> is deprecated. Use <fs-finetuning> instead.")
+
+        fs_node = old_node.getparent()
+        finetuning_node = fs_node.find("fs-finetuning")
+        if finetuning_node is None:
+            finetuning_node = SubElement(fs_node, "fs-finetuning")
+
+        command = SubElement(finetuning_node, "device-command")
+        command.text = f"tune2fs {old_node.text} {{device}}"
+
+        fs_node.remove(old_node)
+
 def preprocess_iso_option(xml):
 
     src_opts = xml.find(".//src-cdrom/src-opts")
@@ -349,6 +366,9 @@ def xmlpreprocess(fname, output, variants=None, proxy=None):
         # Replace old debootstrapvariant with debootstrap
         preprocess_bootstrap(xml)
 
+        # Replace old tune2fs with fs-finetuning command
+        preprocess_tune2fs(xml)
+
         preprocess_iso_option(xml)
 
         preprocess_initvm_ports(xml)
diff --git a/examples/arm64-qemu-virt.xml b/examples/arm64-qemu-virt.xml
index efbfa21b0..ddccbfa2d 100644
--- a/examples/arm64-qemu-virt.xml
+++ b/examples/arm64-qemu-virt.xml
@@ -63,7 +63,9 @@ SPDX-FileCopyrightText: Linutronix GmbH
 				<mountpoint>/</mountpoint>
 				<fs>
 					<type>ext2</type>
-					<tune2fs>-i 0</tune2fs>
+					<fs-finetuning>
+						<device-command>tune2fs -i 0 {device}</device-command>
+					</fs-finetuning>
 				</fs>
 			</bylabel>
 		</fstab>
diff --git a/examples/armhf-ti-beaglebone-black.xml b/examples/armhf-ti-beaglebone-black.xml
index 8e59cb79d..5a10c2aad 100644
--- a/examples/armhf-ti-beaglebone-black.xml
+++ b/examples/armhf-ti-beaglebone-black.xml
@@ -81,7 +81,9 @@ SPDX-FileCopyrightText: Linutronix GmbH
 				<fs>
 					<!-- fs type and options -->
 					<type>ext2</type>
-					<tune2fs>-i 0</tune2fs>
+					<fs-finetuning>
+						<device-command>tune2fs -i 0 {device}</device-command>
+					</fs-finetuning>
 				</fs>
 			</bylabel>
 			<bylabel>
diff --git a/examples/powerpc.xml b/examples/powerpc.xml
index f2b1d346f..8880e05de 100644
--- a/examples/powerpc.xml
+++ b/examples/powerpc.xml
@@ -38,7 +38,9 @@ SPDX-FileCopyrightText: Linutronix GmbH
 				<mountpoint>/</mountpoint>
 				<fs>
 					<type>ext4</type>
-					<tune2fs>-i 0</tune2fs>
+					<fs-finetuning>
+						<device-command>tune2fs -i 0 {device}</device-command>
+					</fs-finetuning>
 				</fs>
 			</bylabel>
 			<bydev>
diff --git a/examples/x86_32-pc-hdimg-minimal-grub-buster.xml b/examples/x86_32-pc-hdimg-minimal-grub-buster.xml
index 2ff012ab1..aa8f6bd5e 100644
--- a/examples/x86_32-pc-hdimg-minimal-grub-buster.xml
+++ b/examples/x86_32-pc-hdimg-minimal-grub-buster.xml
@@ -37,7 +37,9 @@ SPDX-FileCopyrightText: Linutronix GmbH
 				<mountpoint>/</mountpoint>
 				<fs>
 					<type>ext4</type>
-					<tune2fs>-i 0</tune2fs>
+					<fs-finetuning>
+						<device-command>tune2fs -i 0 {device}</device-command>
+					</fs-finetuning>
 				</fs>
 			</bylabel>
 		</fstab>
diff --git a/examples/x86_32-pc-hdimg-with-include-development.xml b/examples/x86_32-pc-hdimg-with-include-development.xml
index aa698c4bf..6a5371575 100644
--- a/examples/x86_32-pc-hdimg-with-include-development.xml
+++ b/examples/x86_32-pc-hdimg-with-include-development.xml
@@ -33,7 +33,9 @@ SPDX-FileCopyrightText: Linutronix GmbH
 				<mountpoint>/</mountpoint>
 				<fs>
 					<type>ext4</type>
-					<tune2fs>-i 0</tune2fs>
+					<fs-finetuning>
+						<device-command>tune2fs -i 0 {device}</device-command>
+					</fs-finetuning>
 				</fs>
 			</bylabel>
 		</fstab>
diff --git a/examples/x86_32-pc-hdimg-with-include-production.xml b/examples/x86_32-pc-hdimg-with-include-production.xml
index ab631ce81..c0a32f359 100644
--- a/examples/x86_32-pc-hdimg-with-include-production.xml
+++ b/examples/x86_32-pc-hdimg-with-include-production.xml
@@ -33,7 +33,9 @@ SPDX-FileCopyrightText: Linutronix GmbH
 				<mountpoint>/</mountpoint>
 				<fs>
 					<type>ext4</type>
-					<tune2fs>-i 0</tune2fs>
+					<fs-finetuning>
+						<device-command>tune2fs -i 0 {device}</device-command>
+					</fs-finetuning>
 				</fs>
 			</bylabel>
 		</fstab>
diff --git a/examples/x86_64-pc-hdimg-gnome3.xml b/examples/x86_64-pc-hdimg-gnome3.xml
index 6e035cea4..05782771c 100644
--- a/examples/x86_64-pc-hdimg-gnome3.xml
+++ b/examples/x86_64-pc-hdimg-gnome3.xml
@@ -47,7 +47,9 @@ SPDX-FileCopyrightText: Linutronix GmbH
 				<mountpoint>/</mountpoint>
 				<fs>
 					<type>ext4</type>
-					<tune2fs>-i 0</tune2fs>
+					<fs-finetuning>
+						<device-command>tune2fs -i 0 {device}</device-command>
+					</fs-finetuning>
 				</fs>
 			</bylabel>
 			<bylabel>
@@ -55,7 +57,9 @@ SPDX-FileCopyrightText: Linutronix GmbH
 				<mountpoint>/home</mountpoint>
 				<fs>
 					<type>ext4</type>
-					<tune2fs>-i 0</tune2fs>
+					<fs-finetuning>
+						<device-command>tune2fs -i 0 {device}</device-command>
+					</fs-finetuning>
 				</fs>
 			</bylabel>
 			<bydev>
diff --git a/examples/x86_64-pc-hdimg-grub-hybrid-buster.xml b/examples/x86_64-pc-hdimg-grub-hybrid-buster.xml
index 6682d4696..486b78bb5 100644
--- a/examples/x86_64-pc-hdimg-grub-hybrid-buster.xml
+++ b/examples/x86_64-pc-hdimg-grub-hybrid-buster.xml
@@ -74,7 +74,9 @@ SPDX-FileCopyrightText: Linutronix GmbH
 				<mountpoint>/</mountpoint>
 				<fs>
 					<type>ext4</type>
-					<tune2fs>-i 0</tune2fs>
+					<fs-finetuning>
+						<device-command>tune2fs -i 0 {device}</device-command>
+					</fs-finetuning>
 				</fs>
 			</bylabel>
 			<!-- the EFI system partition needs to be mounted at /boot/efi -->
diff --git a/examples/x86_64-pc-hdimg-grub-uefi-buster.xml b/examples/x86_64-pc-hdimg-grub-uefi-buster.xml
index a1595a491..3dd73457f 100644
--- a/examples/x86_64-pc-hdimg-grub-uefi-buster.xml
+++ b/examples/x86_64-pc-hdimg-grub-uefi-buster.xml
@@ -63,7 +63,9 @@ SPDX-FileCopyrightText: Linutronix GmbH
 				<mountpoint>/</mountpoint>
 				<fs>
 					<type>ext4</type>
-					<tune2fs>-i 0</tune2fs>
+					<fs-finetuning>
+						<device-command>tune2fs -i 0 {device}</device-command>
+					</fs-finetuning>
 				</fs>
 			</bylabel>
 			<!-- the EFI system partition needs to be mounted at /boot/efi -->
diff --git a/schema/dbsfed.xsd b/schema/dbsfed.xsd
index 72bca5a3d..786ade1bb 100644
--- a/schema/dbsfed.xsd
+++ b/schema/dbsfed.xsd
@@ -1587,10 +1587,10 @@ SPDX-FileCopyrightText: Linutronix GmbH
           </documentation>
         </annotation>
       </element>
-      <element name="tune2fs" type="rfs:string" minOccurs="0" maxOccurs="1">
+      <element name="fs-finetuning" type="rfs:fs-finetuning" minOccurs="0" maxOccurs="1">
         <annotation>
           <documentation>
-            options passed to the tune2fs command
+            apply the given commands to the filesystem
           </documentation>
         </annotation>
       </element>
@@ -1719,6 +1719,47 @@ SPDX-FileCopyrightText: Linutronix GmbH
     <attribute ref="xml:base"/>
   </complexType>
 
+  <complexType name="fs-finetuning">
+    <annotation>
+      <documentation>
+         container for filesystem finetuning commands; these commands are executed directly after
+         the filesystem was created.
+      </documentation>
+    </annotation>
+    <sequence>
+      <group ref="rfs:fs-action" minOccurs="0" maxOccurs="unbounded" />
+    </sequence>
+    <attribute ref="xml:base"/>
+  </complexType>
+
+  <group name="fs-action">
+    <annotation>
+      <documentation>
+        definition of filesystem finetuning commands
+      </documentation>
+    </annotation>
+    <choice>
+      <element name="device-command" type="rfs:string" minOccurs="0">
+        <annotation>
+          <documentation>
+            execute the defined command in /bin/sh. The command is being executed before the
+            filesystem is mounted. The placeholder {device} is pointing to the device containing the
+            filesystem.
+          </documentation>
+        </annotation>
+      </element>
+      <element name="path-command" type="rfs:string" minOccurs="0">
+        <annotation>
+          <documentation>
+            execute the defined command in /bin/sh. The command is being executed after the
+            filesystem is mounted. The placeholder {path} is pointing to the path where the
+            filesystem is mounted to.
+          </documentation>
+        </annotation>
+      </element>
+    </choice>
+  </group>
+
   <complexType name="package">
     <annotation>
       <documentation>
diff --git a/tests/simple-amd64-with-grub-uefi.xml b/tests/simple-amd64-with-grub-uefi.xml
index cbe9b99d4..1464cec88 100644
--- a/tests/simple-amd64-with-grub-uefi.xml
+++ b/tests/simple-amd64-with-grub-uefi.xml
@@ -52,7 +52,9 @@
 				<mountpoint>/</mountpoint>
 				<fs>
 					<type>ext4</type>
-					<tune2fs>-i 0</tune2fs>
+					<fs-finetuning>
+						<device-command>tune2fs -i 0 {device}</device-command>
+					</fs-finetuning>
 				</fs>
 			</bylabel>
 			<!-- the EFI system partition needs to be mounted at /boot/efi -->
-- 
2.39.0



More information about the elbe-devel mailing list