From 6da5efd29a46dc05489f03d64e9992134d6676ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:24:08 -0300 Subject: [PATCH] fix(mknb): build the genesis image atomically to survive concurrent runs mknb writes the compressed genesis filesystem by streaming cpio output straight onto the final path in $tftpdir/xcat (genesis.fs.$arch.lzma or .gz). When two mknb/nodeset runs target a shared $tftpdir at once, one run reads or overwrites the other's half-written image, producing a corrupt genesis.fs and failed netboots. Write each image to a uniquely-suffixed temporary file (xCAT::Utils::genpassword(24)) and File::Copy::move() it into place. move() within the same directory is a rename, so the final path only ever appears complete. Both modules are already imported by mknb.pm. Recovered from the unmerged lenovobuild branch (originals c651e7b8 and its fix da0723f2, which switched the suffix to genpassword after the first attempt only produced a single character). master lacks the branch's xz path, so only the lzma and gzip paths are adjusted here. Co-authored-by: Jarrod Johnson <10814490+jjohnson42@users.noreply.github.com> --- xCAT-server/lib/xcat/plugins/mknb.pm | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/xCAT-server/lib/xcat/plugins/mknb.pm b/xCAT-server/lib/xcat/plugins/mknb.pm index 50ba96e30..54c613574 100644 --- a/xCAT-server/lib/xcat/plugins/mknb.pm +++ b/xCAT-server/lib/xcat/plugins/mknb.pm @@ -248,14 +248,19 @@ sub process_request { my $lzma_exit_value = 1; if ($invisibletouch) { my $done = 0; + # Build each image under a unique suffix and atomically rename it into + # place, so concurrent mknb runs sharing $tftpdir cannot read or clobber + # a half-written genesis.fs. + my $suffix = xCAT::Utils::genpassword(24); if (-x "/usr/bin/lzma") { #let's reclaim some of that size... $callback->({ data => ["Creating genesis.fs.$arch.lzma in $tftpdir/xcat"] }); - system("cd $tempdir; find . | cpio -o -H newc | lzma -C crc32 -9 > $tftpdir/xcat/genesis.fs.$arch.lzma"); + system("cd $tempdir; find . | cpio -o -H newc | lzma -C crc32 -9 > $tftpdir/xcat/genesis.fs.$arch.lzma.$suffix"); $lzma_exit_value = $? >> 8; if ($lzma_exit_value) { $callback->({ data => ["Creating genesis.fs.$arch.lzma in $tftpdir/xcat failed, falling back to gzip"] }); - unlink("$tftpdir/xcat/genesis.fs.$arch.lzma"); + unlink("$tftpdir/xcat/genesis.fs.$arch.lzma.$suffix"); } else { + move("$tftpdir/xcat/genesis.fs.$arch.lzma.$suffix", "$tftpdir/xcat/genesis.fs.$arch.lzma"); $done = 1; $initrd_file = "$tftpdir/xcat/genesis.fs.$arch.lzma"; } @@ -263,7 +268,8 @@ sub process_request { if (not $done) { $callback->({ data => ["Creating genesis.fs.$arch.gz in $tftpdir/xcat"] }); - system("cd $tempdir; find . | cpio -o -H newc | gzip -9 > $tftpdir/xcat/genesis.fs.$arch.gz"); + system("cd $tempdir; find . | cpio -o -H newc | gzip -9 > $tftpdir/xcat/genesis.fs.$arch.gz.$suffix"); + move("$tftpdir/xcat/genesis.fs.$arch.gz.$suffix", "$tftpdir/xcat/genesis.fs.$arch.gz"); $initrd_file = "$tftpdir/xcat/genesis.fs.$arch.gz"; } } else {