fix(btrfs): allocate the swapfile with fallocate instead of dd

On a btrfs root the swapfile was written with dd from /dev/zero, so a
swapfile the size of the RAM cost tens of GiB of writes and stalled
every other writer on the filesystem. A caller that bounds the run, such
as an async Ansible task, killed dd halfway, and the next run found the
wrong size and started over. btrfs accepts a preallocated NOCOW
swapfile and the swap directory already carries +C, so every filesystem
now allocates with fallocate.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kevinveenbirkenbachandClaude Opus 5.5 committed 2026-10-23 10:36:04 +02:00
1 parent 43cdce5fba
commit 91e1eff8a6
4 files changed
+19 -34

No files matched your search

+4 -17
View File
@@ -10,9 +10,8 @@ DEFAULT_SWAP_PATH = Path("/swapfile")
SIZE_PATTERN = re.compile(r"^(\d+)([gGmM]?[bB]?)?$")
MIB_PER_GIB = 1024
REQUIRED_BINARIES = ("findmnt", "swapoff", "chmod", "mkswap", "swapon")
BTRFS_BINARIES = ("chattr", "btrfs", "dd")
NON_BTRFS_BINARIES = ("fallocate",)
REQUIRED_BINARIES = ("findmnt", "swapoff", "fallocate", "chmod", "mkswap", "swapon")
BTRFS_BINARIES = ("chattr", "btrfs")
EXIT_MISSING_BINARY = 127
EXIT_COMMAND_FAILED = 1
@@ -117,8 +116,8 @@ def create_swap(path, size_mib, fs, fstab=FSTAB_FILE):
fs: Filesystem type of the root mount.
fstab: Path of the fstab file to append to.
"""
print(f"Creating {size_mib} MiB swapfile on {fs} at {path}")
if fs == "btrfs":
print(f"Creating {size_mib} MiB swapfile on btrfs at {path}")
path.parent.mkdir(parents=True, exist_ok=True)
run(["chattr", "+C", str(path.parent)], check=False)
run(
@@ -133,20 +132,8 @@ def create_swap(path, size_mib, fs, fstab=FSTAB_FILE):
],
check=False,
)
run(
[
"dd",
"if=/dev/zero",
f"of={path}",
"bs=1M",
f"count={size_mib}",
"status=progress",
]
)
else:
print(f"Creating {size_mib} MiB swapfile on {fs} at {path}")
run(["fallocate", "-l", f"{size_mib}M", str(path)])
run(["fallocate", "-l", f"{size_mib}M", str(path)])
run(["chmod", "600", str(path)])
run(["mkswap", str(path)])
run(["swapon", str(path)])