* [make-initrd] [PATCH v2 01/11] runtime: Fix a lock leak in rootdelayd
2026-10-19 9:57 ` [make-initrd] [PATCH v2 00/11] Improve support for atomic actions Alexey Gladkov
@ 2026-10-19 9:57 ` Alexey Gladkov
2026-10-19 9:57 ` [make-initrd] [PATCH v2 02/11] runtime: Fix console lock shadowing by /dev mount Alexey Gladkov
` (10 subsequent siblings)
11 siblings, 0 replies; 47+ messages in thread
From: Alexey Gladkov @ 2026-10-19 9:57 UTC (permalink / raw)
To: make-initrd
From: Egor Shestakov <ved@altlinux.org>
Rdshell takes a write lock to /dev/console but never release it. Rdshell
can run in foreground, because the rootdelayd doesn't wait for anything
else and fails in an idle loop after rdshell has been invoked.
Signed-off-by: Egor Shestakov <ved@altlinux.org>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
features/runtime/data/sbin/rootdelayd | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/features/runtime/data/sbin/rootdelayd b/features/runtime/data/sbin/rootdelayd
index 7ea82afc..d61b2ae4 100755
--- a/features/runtime/data/sbin/rootdelayd
+++ b/features/runtime/data/sbin/rootdelayd
@@ -37,7 +37,8 @@ while :; do
mkdir -p -- "$disabled"
fd_lock 90 /dev/console
- rdshell "Emergency shell" &
+ rdshell "Emergency shell" 90<&-
+ fd_unlock 90
continue
fi
@@ -91,7 +92,9 @@ while :; do
mkdir -p -- "$disabled"
- rdshell "$msg" &
+ rdshell "$msg" 90<&-
+
+ fd_unlock 90
continue
fi
--
2.56.0
^ permalink raw reply [flat|nested] 47+ messages in thread* [make-initrd] [PATCH v2 02/11] runtime: Fix console lock shadowing by /dev mount
2026-10-19 9:57 ` [make-initrd] [PATCH v2 00/11] Improve support for atomic actions Alexey Gladkov
2026-10-19 9:57 ` [make-initrd] [PATCH v2 01/11] runtime: Fix a lock leak in rootdelayd Alexey Gladkov
@ 2026-10-19 9:57 ` Alexey Gladkov
2026-10-19 9:57 ` [make-initrd] [PATCH v2 03/11] runtime: Avoid leaking lock descriptor 90 to child processes Alexey Gladkov
` (9 subsequent siblings)
11 siblings, 0 replies; 47+ messages in thread
From: Alexey Gladkov @ 2026-10-19 9:57 UTC (permalink / raw)
To: make-initrd
/etc/rc.d/rc acquires an exclusive lock on /dev/console before starting
runlevel services. When the mountfs service mounts devtmpfs over /dev,
the original /dev/console inode on rootfs is shadowed by a new inode on
devtmpfs. Consequently, rc holds the lock on the shadowed inode while
processes started after mountfs lock the new /dev/console inode without
waiting for rc to finish starting services. In particular, with the
rdshell boot parameter, rootdelayd acquires the console lock and starts
the emergency shell in the middle of runlevel 3 instead of after all
services have started.
Once the console lock is preserved across mountfs, the network-up init
service deadlocks against its parent /etc/rc.d/rc because network-up
requests a shared lock on the console while rc already holds an
exclusive lock for the duration of the runlevel scripts.
Use a dedicated /.initrd/console.lock file in /.initrd so the lock
remains on the same inode across /dev mount operations, and drop the
redundant lock acquisition from the synchronous network-up init script.
Fixes: 598a4b241a4f ("Rewrite console locking")
Reported-by: Leonid Krivoshein <klark.devel@gmail.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
features/fsck/data/lib/uevent/handlers/040-mountdev | 2 +-
features/luks/data/lib/uevent/handlers/085-luks | 2 +-
features/network/data/etc/rc.d/init.d/network-up | 3 ---
features/runtime/data/etc/rc.d/rc | 2 +-
features/runtime/data/init | 1 +
.../runtime/data/lib/uevent/handlers/mount/900-localdev | 2 +-
features/runtime/data/sbin/rootdelayd | 6 +++---
features/sshfsroot/data/lib/uevent/handlers/040-sshfsroot | 2 +-
features/zfs/data/sbin/ueventd-zfs | 2 +-
9 files changed, 10 insertions(+), 12 deletions(-)
diff --git a/features/fsck/data/lib/uevent/handlers/040-mountdev b/features/fsck/data/lib/uevent/handlers/040-mountdev
index 53208f0d..9e9f06ea 100755
--- a/features/fsck/data/lib/uevent/handlers/040-mountdev
+++ b/features/fsck/data/lib/uevent/handlers/040-mountdev
@@ -56,7 +56,7 @@ handler()
}
exec 0</dev/console >/dev/console 2>&1
-fd_lock 90 /dev/console
+fd_lock 90 /.initrd/console.lock
for e in "$eventdir"/mountdev.*; do
[ -e "$e" ] || break
diff --git a/features/luks/data/lib/uevent/handlers/085-luks b/features/luks/data/lib/uevent/handlers/085-luks
index db5a217b..423082ad 100755
--- a/features/luks/data/lib/uevent/handlers/085-luks
+++ b/features/luks/data/lib/uevent/handlers/085-luks
@@ -366,7 +366,7 @@ handler() {
}
exec 0</dev/console >/dev/console 2>&1
-fd_lock 90 /dev/console
+fd_lock 90 /.initrd/console.lock
rc=0
for e in "$eventdir"/luks.*; do
diff --git a/features/network/data/etc/rc.d/init.d/network-up b/features/network/data/etc/rc.d/init.d/network-up
index 9ec3b978..ae1532e0 100755
--- a/features/network/data/etc/rc.d/init.d/network-up
+++ b/features/network/data/etc/rc.d/init.d/network-up
@@ -13,14 +13,11 @@
msg="Network up"
-. shell-locks
. network-sh-functions
# wait for network modules
udevadm settle --timeout=3
-fd_rlock 90 /dev/console
-
ifaces=' '
while :; do
set -- /sys/class/net/*
diff --git a/features/runtime/data/etc/rc.d/rc b/features/runtime/data/etc/rc.d/rc
index 02f85ae5..916fa390 100755
--- a/features/runtime/data/etc/rc.d/rc
+++ b/features/runtime/data/etc/rc.d/rc
@@ -22,7 +22,7 @@ rcd="/etc/rc.d/rc$runlevel.d"
exit 0
exec </dev/console 2>&1
-fd_lock 90 /dev/console
+fd_lock 90 /.initrd/console.lock
msg "INIT: Entering runlevel: $runlevel"
diff --git a/features/runtime/data/init b/features/runtime/data/init
index 6fd887a4..f4c789a1 100755
--- a/features/runtime/data/init
+++ b/features/runtime/data/init
@@ -11,6 +11,7 @@ export PATH=/sbin:/usr/sbin:/usr/local/sbin:/bin:/usr/bin:/usr/local/bin
# Create storage for init environment
:> /.initrd/initenv
+:> /.initrd/console.lock
# Check and create the necessary device files
[ -d /dev ] ||
diff --git a/features/runtime/data/lib/uevent/handlers/mount/900-localdev b/features/runtime/data/lib/uevent/handlers/mount/900-localdev
index ddd33df2..ecc37b36 100755
--- a/features/runtime/data/lib/uevent/handlers/mount/900-localdev
+++ b/features/runtime/data/lib/uevent/handlers/mount/900-localdev
@@ -78,7 +78,7 @@ while [ "$method" = localdev ]; do
all_mounted && sysinit_found ||
break
- fd_lock 90 /dev/console
+ fd_lock 90 /.initrd/console.lock
message "$QUEUE: session=$SESSION: $method ready. acting!"
diff --git a/features/runtime/data/sbin/rootdelayd b/features/runtime/data/sbin/rootdelayd
index d61b2ae4..cad6efd6 100755
--- a/features/runtime/data/sbin/rootdelayd
+++ b/features/runtime/data/sbin/rootdelayd
@@ -36,7 +36,7 @@ while :; do
if [ -n "${RDSHELL-}" ]; then
mkdir -p -- "$disabled"
- fd_lock 90 /dev/console
+ fd_lock 90 /.initrd/console.lock
rdshell "Emergency shell" 90<&-
fd_unlock 90
@@ -76,7 +76,7 @@ while :; do
msg="${msg:-The waiting time expired!}"
- fd_lock 90 /dev/console
+ fd_lock 90 /.initrd/console.lock
# Disallow console access
if [ "${PANIC-}" = "0" ]; then
@@ -101,7 +101,7 @@ while :; do
if [ -z "${QUIET-}" ] && [ -z "$first_iter" ] && [ $(( $delay % 15 )) -eq 0 ]; then
- fd_lock 90 /dev/console
+ fd_lock 90 /.initrd/console.lock
resume_checked &&
msg="Waiting for root ${ROOT:+($ROOT) }..." ||
diff --git a/features/sshfsroot/data/lib/uevent/handlers/040-sshfsroot b/features/sshfsroot/data/lib/uevent/handlers/040-sshfsroot
index 6730a203..dfd140cf 100755
--- a/features/sshfsroot/data/lib/uevent/handlers/040-sshfsroot
+++ b/features/sshfsroot/data/lib/uevent/handlers/040-sshfsroot
@@ -41,7 +41,7 @@ handler() {
}
exec 0</dev/console >/dev/console 2>&1
-fd_lock 90 /dev/console
+fd_lock 90 /.initrd/console.lock
rc=0
for e in "$eventdir"/sshfsroot.*; do
diff --git a/features/zfs/data/sbin/ueventd-zfs b/features/zfs/data/sbin/ueventd-zfs
index 8229eaee..e164d779 100755
--- a/features/zfs/data/sbin/ueventd-zfs
+++ b/features/zfs/data/sbin/ueventd-zfs
@@ -104,7 +104,7 @@ while :; do
fi
if resume_checked; then
- fd_lock 90 /dev/console
+ fd_lock 90 /.initrd/console.lock
findmnt -sno TARGET -t zfs | sort -d -k1,1 |
while read -r mnt; do
--
2.56.0
^ permalink raw reply [flat|nested] 47+ messages in thread* [make-initrd] [PATCH v2 03/11] runtime: Avoid leaking lock descriptor 90 to child processes
2026-10-19 9:57 ` [make-initrd] [PATCH v2 00/11] Improve support for atomic actions Alexey Gladkov
2026-10-19 9:57 ` [make-initrd] [PATCH v2 01/11] runtime: Fix a lock leak in rootdelayd Alexey Gladkov
2026-10-19 9:57 ` [make-initrd] [PATCH v2 02/11] runtime: Fix console lock shadowing by /dev mount Alexey Gladkov
@ 2026-10-19 9:57 ` Alexey Gladkov
2026-10-19 9:57 ` [make-initrd] [PATCH v2 04/11] runtime: Replace /.initrd/initenv locking with atomic file update Alexey Gladkov
` (8 subsequent siblings)
11 siblings, 0 replies; 47+ messages in thread
From: Alexey Gladkov @ 2026-10-19 9:57 UTC (permalink / raw)
To: make-initrd
fd_lock opens descriptor 90 in the current shell without FD_CLOEXEC, so
any command or subshell spawned while the lock is held inherits the open
file description and keeps the underlying flock active until that child
process exits.
Several callers either omitted closing fd 90 for child processes (most
notably ueventd-zfs when running findmnt and mount_zfs, as well as
helper invocations in rc, 900-localdev, cmdline, and network scripts) or
relied on process termination instead of explicitly calling fd_unlock.
Close descriptor 90 for commands executed under the lock and release
locks explicitly once the critical section finishes.
Fixes: 598a4b241a4f ("Rewrite console locking")
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
features/network/data/lib/network/hostname | 4 +-
features/network/data/lib/network/resolvconf | 82 ++++++++++---------
.../network/data/lib/network/udhcpc4.script | 7 +-
features/runtime/data/etc/rc.d/init.d/cmdline | 2 +-
features/runtime/data/etc/rc.d/rc | 2 +-
.../lib/uevent/handlers/mount/900-localdev | 2 +-
features/zfs/data/sbin/ueventd-zfs | 10 ++-
7 files changed, 58 insertions(+), 51 deletions(-)
diff --git a/features/network/data/lib/network/hostname b/features/network/data/lib/network/hostname
index 3597a495..43cfe0ae 100755
--- a/features/network/data/lib/network/hostname
+++ b/features/network/data/lib/network/hostname
@@ -20,6 +20,8 @@ name=
read -r name < "$confdir/hostname" ||:
if [ -n "$name" ]; then
- message "set hostname: $name"
+ message "set hostname: $name" 90<&-
printf '%s\n' "$name" > /proc/sys/kernel/hostname
fi
+
+fd_unlock 90
diff --git a/features/network/data/lib/network/resolvconf b/features/network/data/lib/network/resolvconf
index 67ccb8ab..6e54c0a3 100755
--- a/features/network/data/lib/network/resolvconf
+++ b/features/network/data/lib/network/resolvconf
@@ -16,42 +16,46 @@ get_iface_confdir &&
fd_lock 90 "$0"
-message "write resolv.conf"
-
-tmp="$(mktemp "/etc/resolv.conf.XXXXXX")"
-
-cat /etc/resolv.conf "$confdir/resolv.conf" |
-while :; do
- list=${list:-0}
-
- eof=
- read -r s || eof=1
-
- dup=
- if [ -n "$s" ]; then
- i=0
- while [ $i -lt $list ]; do
- eval '[ "$list'$i'" != "$s" ] || { dup=1; break; }'
- i=$(($i+1))
- done
- elif [ -z "${p-}" ]; then
- dup=1
- fi
- p="$s"
-
- if [ -z "$dup" ]; then
- eval "list$list=\"\$s\""
- list=$(($list+1))
- fi
-
- if [ -n "$eof" ]; then
- i=0
- while [ $i -lt $list ]; do
- eval "printf '%s\n' \"\$list$i\""
- i=$(($i+1))
- done
- break
- fi
-done >"$tmp"
-chmod 644 "$tmp"
-mv -f -- "$tmp" /etc/resolv.conf
+{
+ message "write resolv.conf"
+
+ tmp="$(mktemp "/etc/resolv.conf.XXXXXX")"
+
+ cat /etc/resolv.conf "$confdir/resolv.conf" |
+ while :; do
+ list=${list:-0}
+
+ eof=
+ read -r s || eof=1
+
+ dup=
+ if [ -n "$s" ]; then
+ i=0
+ while [ $i -lt $list ]; do
+ eval '[ "$list'$i'" != "$s" ] || { dup=1; break; }'
+ i=$(($i+1))
+ done
+ elif [ -z "${p-}" ]; then
+ dup=1
+ fi
+ p="$s"
+
+ if [ -z "$dup" ]; then
+ eval "list$list=\"\$s\""
+ list=$(($list+1))
+ fi
+
+ if [ -n "$eof" ]; then
+ i=0
+ while [ $i -lt $list ]; do
+ eval "printf '%s\n' \"\$list$i\""
+ i=$(($i+1))
+ done
+ break
+ fi
+ done >"$tmp"
+ chmod 644 "$tmp"
+ mv -f -- "$tmp" /etc/resolv.conf
+} 90<&-
+
+fd_unlock 90
diff --git a/features/network/data/lib/network/udhcpc4.script b/features/network/data/lib/network/udhcpc4.script
index 06ae31c4..d0019cab 100755
--- a/features/network/data/lib/network/udhcpc4.script
+++ b/features/network/data/lib/network/udhcpc4.script
@@ -20,7 +20,7 @@ logfile=$(
[ "${RDLOG-}" != 'console' ] &&
echo "/var/log/$CMDNAME.$INTERFACE.log" ||
echo "/dev/console"
-)
+) 90<&-
exec >>"$logfile" 2>&1
. network-sh-functions
@@ -151,7 +151,6 @@ case "$STATE" in
deconfig)
rm -rf -- "$statedir"
;;
- *)
- exit 0
- ;;
esac 90<&-
+
+fd_unlock 90
diff --git a/features/runtime/data/etc/rc.d/init.d/cmdline b/features/runtime/data/etc/rc.d/init.d/cmdline
index 74b4f556..11757e76 100755
--- a/features/runtime/data/etc/rc.d/init.d/cmdline
+++ b/features/runtime/data/etc/rc.d/init.d/cmdline
@@ -217,7 +217,7 @@ parse()
{
echo __initrd_initenv=1
environ -q -s -p 'export ' -u '_*,INITLOG_FILE,RUNLEVEL,runlevel,PWD,SHLVL'
- } > /.initrd/initenv
+ } > /.initrd/initenv 90<&-
fd_unlock 90
}
diff --git a/features/runtime/data/etc/rc.d/rc b/features/runtime/data/etc/rc.d/rc
index 916fa390..14a57ab7 100755
--- a/features/runtime/data/etc/rc.d/rc
+++ b/features/runtime/data/etc/rc.d/rc
@@ -24,7 +24,7 @@ rcd="/etc/rc.d/rc$runlevel.d"
exec </dev/console 2>&1
fd_lock 90 /.initrd/console.lock
-msg "INIT: Entering runlevel: $runlevel"
+msg "INIT: Entering runlevel: $runlevel" 90<&-
export INITLOG_FILE='/var/log/boot.log'
diff --git a/features/runtime/data/lib/uevent/handlers/mount/900-localdev b/features/runtime/data/lib/uevent/handlers/mount/900-localdev
index ecc37b36..13431cb8 100755
--- a/features/runtime/data/lib/uevent/handlers/mount/900-localdev
+++ b/features/runtime/data/lib/uevent/handlers/mount/900-localdev
@@ -80,7 +80,7 @@ while [ "$method" = localdev ]; do
fd_lock 90 /.initrd/console.lock
- message "$QUEUE: session=$SESSION: $method ready. acting!"
+ message "$QUEUE: session=$SESSION: $method ready. acting!" 90<&-
echo 2 > /.initrd/telinit
diff --git a/features/zfs/data/sbin/ueventd-zfs b/features/zfs/data/sbin/ueventd-zfs
index e164d779..8ddb6f2c 100755
--- a/features/zfs/data/sbin/ueventd-zfs
+++ b/features/zfs/data/sbin/ueventd-zfs
@@ -106,10 +106,12 @@ while :; do
if resume_checked; then
fd_lock 90 /.initrd/console.lock
- findmnt -sno TARGET -t zfs | sort -d -k1,1 |
- while read -r mnt; do
- mount_zfs "$mnt" </dev/null ||:
- done
+ {
+ findmnt -sno TARGET -t zfs | sort -d -k1,1 |
+ while read -r mnt; do
+ mount_zfs "$mnt" </dev/null ||:
+ done
+ } 90<&-
fd_unlock 90
fi
--
2.56.0
^ permalink raw reply [flat|nested] 47+ messages in thread* [make-initrd] [PATCH v2 04/11] runtime: Replace /.initrd/initenv locking with atomic file update
2026-10-19 9:57 ` [make-initrd] [PATCH v2 00/11] Improve support for atomic actions Alexey Gladkov
` (2 preceding siblings ...)
2026-10-19 9:57 ` [make-initrd] [PATCH v2 03/11] runtime: Avoid leaking lock descriptor 90 to child processes Alexey Gladkov
@ 2026-10-19 9:57 ` Alexey Gladkov
2026-10-19 9:57 ` [make-initrd] [PATCH v2 05/11] runtime: Centralize file and console locking helpers Alexey Gladkov
` (7 subsequent siblings)
11 siblings, 0 replies; 47+ messages in thread
From: Alexey Gladkov @ 2026-10-19 9:57 UTC (permalink / raw)
To: make-initrd
cmdline takes an exclusive lock on /.initrd/initenv while generating the
environment file, but only rootdelayd and ueventd-zfs acquire a shared
lock before sourcing it. All other init scripts, uevent filters, and
handlers source /.initrd/initenv without locking and could observe a
truncated or partially written file while cmdline is running.
Write the generated environment to a temporary file and atomically
rename it to /.initrd/initenv so any reader either sees the initial
empty file or the complete environment without needing file locks.
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
features/runtime/data/etc/rc.d/init.d/cmdline | 6 ++----
features/runtime/data/sbin/rootdelayd | 2 --
features/zfs/data/sbin/ueventd-zfs | 2 --
3 files changed, 2 insertions(+), 8 deletions(-)
diff --git a/features/runtime/data/etc/rc.d/init.d/cmdline b/features/runtime/data/etc/rc.d/init.d/cmdline
index 11757e76..6c4f7463 100755
--- a/features/runtime/data/etc/rc.d/init.d/cmdline
+++ b/features/runtime/data/etc/rc.d/init.d/cmdline
@@ -18,7 +18,6 @@
. shell-error
. shell-var
. shell-cmdline
-. shell-locks
defaults()
{
@@ -213,12 +212,11 @@ parse()
fi
fi
- fd_lock 90 /.initrd/initenv
{
echo __initrd_initenv=1
environ -q -s -p 'export ' -u '_*,INITLOG_FILE,RUNLEVEL,runlevel,PWD,SHLVL'
- } > /.initrd/initenv 90<&-
- fd_unlock 90
+ } > /.initrd/initenv.new
+ mv -f -- /.initrd/initenv.new /.initrd/initenv
}
action_shell 'Parsing cmdline arguments:' parse
diff --git a/features/runtime/data/sbin/rootdelayd b/features/runtime/data/sbin/rootdelayd
index cad6efd6..27002dfc 100755
--- a/features/runtime/data/sbin/rootdelayd
+++ b/features/runtime/data/sbin/rootdelayd
@@ -16,9 +16,7 @@ while :; do
fi
if [ -z "${__initrd_initenv-}" ] && [ -f /.initrd/initenv ]; then
- fd_rlock 90 /.initrd/initenv
. /.initrd/initenv
- fd_unlock 90
if [ -z "${__initrd_initenv-}" ]; then
# Waiting for cmdline service
diff --git a/features/zfs/data/sbin/ueventd-zfs b/features/zfs/data/sbin/ueventd-zfs
index 8ddb6f2c..81f8d746 100755
--- a/features/zfs/data/sbin/ueventd-zfs
+++ b/features/zfs/data/sbin/ueventd-zfs
@@ -86,9 +86,7 @@ period=0.5
while :; do
if [ -z "${__initrd_initenv-}" ] && [ -f /.initrd/initenv ]; then
- fd_rlock 90 /.initrd/initenv
. /.initrd/initenv
- fd_unlock 90
if [ -z "${__initrd_initenv-}" ]; then
# Waiting for cmdline service
--
2.56.0
^ permalink raw reply [flat|nested] 47+ messages in thread* [make-initrd] [PATCH v2 05/11] runtime: Centralize file and console locking helpers
2026-10-19 9:57 ` [make-initrd] [PATCH v2 00/11] Improve support for atomic actions Alexey Gladkov
` (3 preceding siblings ...)
2026-10-19 9:57 ` [make-initrd] [PATCH v2 04/11] runtime: Replace /.initrd/initenv locking with atomic file update Alexey Gladkov
@ 2026-10-19 9:57 ` Alexey Gladkov
2026-10-19 9:57 ` [make-initrd] [PATCH v2 06/11] create-rootfs: Require bash 4.1 or newer for initramfs Alexey Gladkov
` (6 subsequent siblings)
11 siblings, 0 replies; 47+ messages in thread
From: Alexey Gladkov @ 2026-10-19 9:57 UTC (permalink / raw)
To: make-initrd
Using raw fd_lock and fd_unlock calls across scripts requires every
caller to hardcode file descriptor 90, repeat the /.initrd/console.lock
path, manually close descriptor 90 for spawned commands, and remember to
release the lock on exit. If two locks are ever taken in the same shell
context, reusing descriptor 90 silently drops the earlier lock.
Provide lock_file, unlock_file, and run_locked helpers in
initrd-sh-functions using bash automatic file descriptor allocation
({lock_file_fd}<"$file") along with console-specific wrappers, and
convert all callers to use them.
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
.../data/lib/uevent/handlers/040-mountdev | 19 +--
.../luks/data/lib/uevent/handlers/085-luks | 33 ++--
.../network/data/bin/network-sh-functions | 1 +
features/network/data/lib/network/hostname | 20 +--
features/network/data/lib/network/resolvconf | 10 +-
.../network/data/lib/network/udhcpc4.script | 80 +++++-----
features/runtime/data/bin/initrd-sh-functions | 47 ++++++
features/runtime/data/etc/rc.d/rc | 148 +++++++++---------
.../lib/uevent/handlers/mount/900-localdev | 15 +-
features/runtime/data/sbin/rootdelayd | 70 +++++----
.../data/lib/uevent/handlers/040-sshfsroot | 26 ++-
features/zfs/data/sbin/ueventd-zfs | 21 ++-
12 files changed, 268 insertions(+), 222 deletions(-)
diff --git a/features/fsck/data/lib/uevent/handlers/040-mountdev b/features/fsck/data/lib/uevent/handlers/040-mountdev
index 9e9f06ea..78bfd165 100755
--- a/features/fsck/data/lib/uevent/handlers/040-mountdev
+++ b/features/fsck/data/lib/uevent/handlers/040-mountdev
@@ -2,7 +2,6 @@
. /.initrd/initenv
-. shell-locks
. shell-source
source_if_exists /etc/sysconfig/fsck
@@ -55,12 +54,14 @@ handler()
reboot
}
-exec 0</dev/console >/dev/console 2>&1
-fd_lock 90 /.initrd/console.lock
-
-for e in "$eventdir"/mountdev.*; do
- [ -e "$e" ] || break
- ( . "$e"; handler; ) ||:
-done 90<&-
+process_events()
+{
+ local e
+ for e in "$eventdir"/mountdev.*; do
+ [ -e "$e" ] || break
+ ( . "$e"; handler; ) ||:
+ done
+}
-fd_unlock 90
+exec 0</dev/console >/dev/console 2>&1
+run_console_locked process_events
diff --git a/features/luks/data/lib/uevent/handlers/085-luks b/features/luks/data/lib/uevent/handlers/085-luks
index 423082ad..0c1f2a47 100755
--- a/features/luks/data/lib/uevent/handlers/085-luks
+++ b/features/luks/data/lib/uevent/handlers/085-luks
@@ -4,7 +4,6 @@
. shell-error
. shell-var
-. shell-locks
. uevent-sh-functions
. initrd-sh-functions
@@ -365,20 +364,20 @@ handler() {
fi
}
-exec 0</dev/console >/dev/console 2>&1
-fd_lock 90 /.initrd/console.lock
-
-rc=0
-for e in "$eventdir"/luks.*; do
- [ -f "$e" ] || break
- r=0
- ( . "$e"; handler; ) || r="$?"
- case "$r" in
- 2) ;;
- 1) rc=1 ;;
- 0) done_event "$e" ;;
- esac
-done 90<&-
+process_events() {
+ local e r rc=0
+ for e in "$eventdir"/luks.*; do
+ [ -f "$e" ] || break
+ r=0
+ ( . "$e"; handler; ) || r="$?"
+ case "$r" in
+ 2) ;;
+ 1) rc=1 ;;
+ 0) done_event "$e" ;;
+ esac
+ done
+ return $rc
+}
-fd_unlock 90
-exit $rc
+exec 0</dev/console >/dev/console 2>&1
+run_console_locked process_events
diff --git a/features/network/data/bin/network-sh-functions b/features/network/data/bin/network-sh-functions
index 58f9a4b6..fbe31b54 100644
--- a/features/network/data/bin/network-sh-functions
+++ b/features/network/data/bin/network-sh-functions
@@ -18,6 +18,7 @@ ip_cmd()
}
. uevent-sh-functions
+. initrd-sh-functions
net_event()
{
diff --git a/features/network/data/lib/network/hostname b/features/network/data/lib/network/hostname
index 43cfe0ae..48d4abac 100755
--- a/features/network/data/lib/network/hostname
+++ b/features/network/data/lib/network/hostname
@@ -1,7 +1,6 @@
#!/bin/bash -efu
. shell-error
-. shell-locks
. network-sh-functions
[ "$NET_EV_ACTION" = update ] ||
@@ -14,14 +13,15 @@ get_iface_confdir &&
[ -f "$confdir/hostname" ] ||
exit 0
-fd_lock 90 "$0"
+update_hostname()
+{
+ local name=
+ read -r name < "$confdir/hostname" ||:
-name=
-read -r name < "$confdir/hostname" ||:
+ if [ -n "$name" ]; then
+ message "set hostname: $name"
+ printf '%s\n' "$name" > /proc/sys/kernel/hostname
+ fi
+}
-if [ -n "$name" ]; then
- message "set hostname: $name" 90<&-
- printf '%s\n' "$name" > /proc/sys/kernel/hostname
-fi
-
-fd_unlock 90
+run_locked "$0" update_hostname
diff --git a/features/network/data/lib/network/resolvconf b/features/network/data/lib/network/resolvconf
index 6e54c0a3..2132f390 100755
--- a/features/network/data/lib/network/resolvconf
+++ b/features/network/data/lib/network/resolvconf
@@ -1,7 +1,6 @@
#!/bin/bash -efu
. shell-error
-. shell-locks
. network-sh-functions
[ "$NET_EV_ACTION" = update ] ||
@@ -14,9 +13,10 @@ get_iface_confdir &&
[ -f "$confdir/resolv.conf" ] ||
exit 0
-fd_lock 90 "$0"
-
+update_resolvconf()
{
+ local tmp list eof s dup i p
+
message "write resolv.conf"
tmp="$(mktemp "/etc/resolv.conf.XXXXXX")"
@@ -56,6 +56,6 @@ fd_lock 90 "$0"
done >"$tmp"
chmod 644 "$tmp"
mv -f -- "$tmp" /etc/resolv.conf
-} 90<&-
+}
-fd_unlock 90
+run_locked "$0" update_resolvconf
diff --git a/features/network/data/lib/network/udhcpc4.script b/features/network/data/lib/network/udhcpc4.script
index d0019cab..98e419e0 100755
--- a/features/network/data/lib/network/udhcpc4.script
+++ b/features/network/data/lib/network/udhcpc4.script
@@ -1,6 +1,6 @@
#!/bin/bash -efu
-. shell-locks
+. network-sh-functions
STATE="$1"
@@ -13,18 +13,6 @@ INTERFACE="${interface-}"
lock="/tmp/$CMDNAME.$INTERFACE.lock"
[ -d "$lock" ] || mkdir -p -- "$lock"
-fd_lock 90 "$lock"
-
-logfile=$(
- . /.initrd/initenv
- [ "${RDLOG-}" != 'console' ] &&
- echo "/var/log/$CMDNAME.$INTERFACE.log" ||
- echo "/dev/console"
-) 90<&-
-exec >>"$logfile" 2>&1
-
-. network-sh-functions
-
cfg="$net_confdir/ifaces/$INTERFACE/ipv${V}dhcp"
[ ! -e "$cfg" ] || . "$cfg"
@@ -127,30 +115,42 @@ gen_net_event()
net_event "$2" "$INTERFACE"
}
-case "$STATE" in
- renew)
- env_to_configs
- gen_net_event "$dir/iplink" "network.link.update"
- gen_net_event "$dir/ipv${V}address" "network.addr.update"
- gen_net_event "$dir/ipv${V}route" "network.route.update"
- gen_net_event "$dir/resolv.conf" "network.resolvconf.update"
- gen_net_event "$dir/hostname" "network.hostname.update"
- mkdir -p -- "$statedir"
- echo ready > "$state"
- ;;
- bound)
- suffix=
- env_to_configs
- mkdir -p -- "$statedir"
- echo ready > "$state"
- ;;
- leasefail)
- mkdir -p -- "$statedir"
- echo failed > "$state"
- ;;
- deconfig)
- rm -rf -- "$statedir"
- ;;
-esac 90<&-
-
-fd_unlock 90
+handle_state()
+{
+ local logfile
+ logfile=$(
+ . /.initrd/initenv
+ [ "${RDLOG-}" != 'console' ] &&
+ echo "/var/log/$CMDNAME.$INTERFACE.log" ||
+ echo "/dev/console"
+ )
+ exec >>"$logfile" 2>&1
+
+ case "$STATE" in
+ renew)
+ env_to_configs
+ gen_net_event "$dir/iplink" "network.link.update"
+ gen_net_event "$dir/ipv${V}address" "network.addr.update"
+ gen_net_event "$dir/ipv${V}route" "network.route.update"
+ gen_net_event "$dir/resolv.conf" "network.resolvconf.update"
+ gen_net_event "$dir/hostname" "network.hostname.update"
+ mkdir -p -- "$statedir"
+ echo ready > "$state"
+ ;;
+ bound)
+ suffix=
+ env_to_configs
+ mkdir -p -- "$statedir"
+ echo ready > "$state"
+ ;;
+ leasefail)
+ mkdir -p -- "$statedir"
+ echo failed > "$state"
+ ;;
+ deconfig)
+ rm -rf -- "$statedir"
+ ;;
+ esac
+}
+
+run_locked "$lock" handle_state
diff --git a/features/runtime/data/bin/initrd-sh-functions b/features/runtime/data/bin/initrd-sh-functions
index 156beda1..8c9746d7 100644
--- a/features/runtime/data/bin/initrd-sh-functions
+++ b/features/runtime/data/bin/initrd-sh-functions
@@ -155,4 +155,51 @@ resume_checked()
return 1
}
+. shell-locks
+
+lock_file_fd=
+
+lock_file()
+{
+ exec {lock_file_fd}<"$1"
+ shift
+ flock "$@" "$lock_file_fd"
+}
+
+unlock_file()
+{
+ [ -n "${lock_file_fd-}" ] || return 0
+ fd_unlock "$lock_file_fd"
+ lock_file_fd=
+}
+
+run_locked()
+{
+ local lock_file_fd='' rc=0
+
+ lock_file "$1" -x
+ shift
+ "$@" {lock_file_fd}<&- || rc=$?
+ unlock_file
+
+ return $rc
+}
+
+console_lock_file=/.initrd/console.lock
+
+console_lock()
+{
+ lock_file "$console_lock_file" -x
+}
+
+console_unlock()
+{
+ unlock_file
+}
+
+run_console_locked()
+{
+ run_locked "$console_lock_file" "$@"
+}
+
fi
diff --git a/features/runtime/data/etc/rc.d/rc b/features/runtime/data/etc/rc.d/rc
index 14a57ab7..bdb26342 100755
--- a/features/runtime/data/etc/rc.d/rc
+++ b/features/runtime/data/etc/rc.d/rc
@@ -8,7 +8,7 @@
#
. /etc/init.d/functions
-. shell-locks
+. initrd-sh-functions
# Get first argument. Set new runlevel to this argument.
[ $# -eq 0 ] ||
@@ -21,13 +21,6 @@ rcd="/etc/rc.d/rc$runlevel.d"
[ -d "$rcd" ] ||
exit 0
-exec </dev/console 2>&1
-fd_lock 90 /.initrd/console.lock
-
-msg "INIT: Entering runlevel: $runlevel" 90<&-
-
-export INITLOG_FILE='/var/log/boot.log'
-
run_scripts() {
local s n="$1"
shift
@@ -36,80 +29,87 @@ run_scripts() {
done
}
-# First, run the KILL scripts.
-for i in "$rcd"/K*; do
- [ -x "$i" ] ||
- continue
-
- subsys=${i#$rcd/K*:}
-
- # Check if the subsystem is already up.
- [ -f "$locksys/$subsys" ] ||
- continue
-
- SourceIfExists /.initrd/initenv
-
- [ "${RDLOG-}" != 'console' ] ||
- export INITLOG_FILE=/dev/console
+run_runlevel() {
+ msg "INIT: Entering runlevel: $runlevel"
- run_scripts "pre/$subsys" stop "$subsys"
+ export INITLOG_FILE='/var/log/boot.log'
- "$i" stop
- rc="$?"
+ # First, run the KILL scripts.
+ for i in "$rcd"/K*; do
+ [ -x "$i" ] ||
+ continue
- run_scripts "post/$subsys" stop "$subsys" "$rc"
-done 90<&-
+ subsys=${i#$rcd/K*:}
-# Now run the START scripts.
-for i in "$rcd"/S*; do
- [ -x "$i" ] ||
- continue
+ # Check if the subsystem is already up.
+ [ -f "$locksys/$subsys" ] ||
+ continue
- subsys="${i#$rcd/S*:}"
+ SourceIfExists /.initrd/initenv
- SourceIfExists /.initrd/initenv
+ [ "${RDLOG-}" != 'console' ] ||
+ export INITLOG_FILE=/dev/console
- [ "${RDLOG-}" != 'console' ] ||
- export INITLOG_FILE=/dev/console
+ run_scripts "pre/$subsys" stop "$subsys"
- interactive=
- [ -z "${STOP-}" ] ||
- for n in all "$subsys"; do
- [ -n "${STOP##*,$n,*}" ] || interactive=1
- done
+ "$i" stop
+ rc="$?"
- if [ -n "$interactive" ]; then
- while :; do
- printf 'Start service %s (Y)es/(N)o/(C)ontinue/(S)hell? [Y] ' "$subsys"
- read -r answer < /dev/console
- case "${answer,,}" in
- c|continue)
- printf 'STOP=,,\n' >> /.initrd/initenv
- break
- ;;
- s|shell)
- rdshell 'This shell remains here for debug purposes. Press Ctrl-D to continue.'
- ;;
- n|no)
- continue 2
- ;;
- y|yes|'')
- break
- ;;
- esac
- done
- fi
-
- # Check if the subsystem is already up.
- [ ! -f "$locksys/$subsys" ] ||
- continue
-
- run_scripts "pre/$subsys" start "$subsys"
-
- "$i" start
- rc="$?"
+ run_scripts "post/$subsys" stop "$subsys" "$rc"
+ done
- run_scripts "post/$subsys" start "$subsys" "$rc"
-done 90<&-
+ # Now run the START scripts.
+ for i in "$rcd"/S*; do
+ [ -x "$i" ] ||
+ continue
+
+ subsys="${i#$rcd/S*:}"
+
+ SourceIfExists /.initrd/initenv
+
+ [ "${RDLOG-}" != 'console' ] ||
+ export INITLOG_FILE=/dev/console
+
+ interactive=
+ [ -z "${STOP-}" ] ||
+ for n in all "$subsys"; do
+ [ -n "${STOP##*,$n,*}" ] || interactive=1
+ done
+
+ if [ -n "$interactive" ]; then
+ while :; do
+ printf 'Start service %s (Y)es/(N)o/(C)ontinue/(S)hell? [Y] ' "$subsys"
+ read -r answer < /dev/console
+ case "${answer,,}" in
+ c|continue)
+ printf 'STOP=,,\n' >> /.initrd/initenv
+ break
+ ;;
+ s|shell)
+ rdshell 'This shell remains here for debug purposes. Press Ctrl-D to continue.'
+ ;;
+ n|no)
+ continue 2
+ ;;
+ y|yes|'')
+ break
+ ;;
+ esac
+ done
+ fi
+
+ # Check if the subsystem is already up.
+ [ ! -f "$locksys/$subsys" ] ||
+ continue
+
+ run_scripts "pre/$subsys" start "$subsys"
+
+ "$i" start
+ rc="$?"
+
+ run_scripts "post/$subsys" start "$subsys" "$rc"
+ done
+}
-fd_unlock 90
+exec </dev/console 2>&1
+run_console_locked run_runlevel
diff --git a/features/runtime/data/lib/uevent/handlers/mount/900-localdev b/features/runtime/data/lib/uevent/handlers/mount/900-localdev
index 13431cb8..37ee4c2b 100755
--- a/features/runtime/data/lib/uevent/handlers/mount/900-localdev
+++ b/features/runtime/data/lib/uevent/handlers/mount/900-localdev
@@ -3,7 +3,6 @@
. /.initrd/initenv
. shell-error
-. shell-locks
. uevent-sh-functions
. initrd-sh-functions
@@ -67,6 +66,12 @@ sysinit_found()
return 1
}
+activate_localdev()
+{
+ message "$QUEUE: session=$SESSION: $method ready. acting!"
+ echo 2 > /.initrd/telinit
+}
+
method=
{ read -r method < /etc/initrd/method; } >/dev/null 2>&1 ||:
@@ -78,13 +83,7 @@ while [ "$method" = localdev ]; do
all_mounted && sysinit_found ||
break
- fd_lock 90 /.initrd/console.lock
-
- message "$QUEUE: session=$SESSION: $method ready. acting!" 90<&-
-
- echo 2 > /.initrd/telinit
-
- fd_unlock 90
+ run_console_locked activate_localdev
break
done
diff --git a/features/runtime/data/sbin/rootdelayd b/features/runtime/data/sbin/rootdelayd
index 27002dfc..c285c7d8 100755
--- a/features/runtime/data/sbin/rootdelayd
+++ b/features/runtime/data/sbin/rootdelayd
@@ -1,7 +1,6 @@
#!/bin/bash -efu
. shell-error
-. shell-locks
. initrd-sh-functions
@@ -9,6 +8,39 @@ message_time=1
disabled="/.initrd/rootdelay/disabled"
period=1
+timeout_expired()
+{
+ local msg="$1"
+
+ # Disallow console access
+ if [ "${PANIC-}" = "0" ]; then
+ {
+ PROG=initramfs
+
+ message "$msg"
+ message "Disallow console access (panic=0). reboot."
+ } >/dev/console 2>&1 ||:
+
+ reboot -f
+ fi
+
+ mkdir -p -- "$disabled"
+
+ rdshell "$msg"
+}
+
+show_waiting_message()
+{
+ local msg
+
+ resume_checked &&
+ msg="Waiting for root ${ROOT:+($ROOT) }..." ||
+ msg="Waiting for resume device ${RESUME:+($RESUME) }..."
+
+ PROG=initramfs \
+ message "$msg" >/dev/console 2>&1 ||:
+}
+
while :; do
if [ -e "$disabled" ] || rootdelay_paused; then
sleep $period
@@ -34,9 +66,7 @@ while :; do
if [ -n "${RDSHELL-}" ]; then
mkdir -p -- "$disabled"
- fd_lock 90 /.initrd/console.lock
- rdshell "Emergency shell" 90<&-
- fd_unlock 90
+ run_console_locked rdshell "Emergency shell"
continue
fi
@@ -74,41 +104,13 @@ while :; do
msg="${msg:-The waiting time expired!}"
- fd_lock 90 /.initrd/console.lock
-
- # Disallow console access
- if [ "${PANIC-}" = "0" ]; then
- {
- PROG=initramfs
-
- message "$msg"
- message "Disallow console access (panic=0). reboot."
- } >/dev/console 2>&1 90<&- ||:
-
- reboot -f
- fi
-
- mkdir -p -- "$disabled"
-
- rdshell "$msg" 90<&-
-
- fd_unlock 90
+ run_console_locked timeout_expired "$msg"
continue
fi
if [ -z "${QUIET-}" ] && [ -z "$first_iter" ] && [ $(( $delay % 15 )) -eq 0 ]; then
-
- fd_lock 90 /.initrd/console.lock
-
- resume_checked &&
- msg="Waiting for root ${ROOT:+($ROOT) }..." ||
- msg="Waiting for resume device ${RESUME:+($RESUME) }..."
-
- PROG=initramfs \
- message "$msg" >/dev/console 2>&1 90<&- ||:
-
- fd_unlock 90
+ run_console_locked show_waiting_message
fi
sleep $period
diff --git a/features/sshfsroot/data/lib/uevent/handlers/040-sshfsroot b/features/sshfsroot/data/lib/uevent/handlers/040-sshfsroot
index dfd140cf..2a612380 100755
--- a/features/sshfsroot/data/lib/uevent/handlers/040-sshfsroot
+++ b/features/sshfsroot/data/lib/uevent/handlers/040-sshfsroot
@@ -2,8 +2,6 @@
. /.initrd/initenv
-. shell-locks
-
. initrd-sh-functions
. uevent-sh-functions
. network-sh-functions
@@ -40,16 +38,16 @@ handler() {
done
}
+process_events() {
+ local e rc=0
+ for e in "$eventdir"/sshfsroot.*; do
+ [ -f "$e" ] || break
+ ( . "$e"; handler; ) ||
+ rc=1
+ done_event "$e"
+ done
+ return $rc
+}
+
exec 0</dev/console >/dev/console 2>&1
-fd_lock 90 /.initrd/console.lock
-
-rc=0
-for e in "$eventdir"/sshfsroot.*; do
- [ -f "$e" ] || break
- ( . "$e"; handler; ) ||
- rc=1
- done_event "$e"
-done 90<&-
-
-fd_unlock 90
-exit $rc
+run_console_locked process_events
diff --git a/features/zfs/data/sbin/ueventd-zfs b/features/zfs/data/sbin/ueventd-zfs
index 81f8d746..54c65a98 100755
--- a/features/zfs/data/sbin/ueventd-zfs
+++ b/features/zfs/data/sbin/ueventd-zfs
@@ -1,7 +1,6 @@
#!/bin/bash -efu
. shell-error
-. shell-locks
. initrd-sh-functions
. uevent-sh-functions
@@ -82,6 +81,15 @@ mount_zfs()
release_event mountdev "$event"
}
+mount_all_zfs()
+{
+ local mnt
+ findmnt -sno TARGET -t zfs | sort -d -k1,1 |
+ while read -r mnt; do
+ mount_zfs "$mnt" </dev/null ||:
+ done
+}
+
period=0.5
while :; do
@@ -102,16 +110,7 @@ while :; do
fi
if resume_checked; then
- fd_lock 90 /.initrd/console.lock
-
- {
- findmnt -sno TARGET -t zfs | sort -d -k1,1 |
- while read -r mnt; do
- mount_zfs "$mnt" </dev/null ||:
- done
- } 90<&-
-
- fd_unlock 90
+ run_console_locked mount_all_zfs
fi
sleep $period
--
2.56.0
^ permalink raw reply [flat|nested] 47+ messages in thread* [make-initrd] [PATCH v2 06/11] create-rootfs: Require bash 4.1 or newer for initramfs
2026-10-19 9:57 ` [make-initrd] [PATCH v2 00/11] Improve support for atomic actions Alexey Gladkov
` (4 preceding siblings ...)
2026-10-19 9:57 ` [make-initrd] [PATCH v2 05/11] runtime: Centralize file and console locking helpers Alexey Gladkov
@ 2026-10-19 9:57 ` Alexey Gladkov
2026-10-19 9:57 ` [make-initrd] [PATCH v2 07/11] network: Share DHCP hook lock between IPv4 and IPv6 on the same interface Alexey Gladkov
` (5 subsequent siblings)
11 siblings, 0 replies; 47+ messages in thread
From: Alexey Gladkov @ 2026-10-19 9:57 UTC (permalink / raw)
To: make-initrd
The locking helpers in initrd-sh-functions rely on automatic file
descriptor allocation via {var}<file and {var}<&- redirections, which
were introduced in bash 4.1.
Check the version of the selected bash binary before copying it into the
initramfs root so image creation fails early instead of breaking at boot
time if an older bash is provided.
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
tools/create-rootfs | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tools/create-rootfs b/tools/create-rootfs
index d19cbf97..b2113717 100755
--- a/tools/create-rootfs
+++ b/tools/create-rootfs
@@ -348,6 +348,8 @@ ln_if_missing()
[ -n "$BASH" ] ||
fatal "bash not found"
+"$BASH" -c '(( BASH_VERSINFO[0] > 4 || (BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] >= 1) ))' >/dev/null 2>&1 ||
+ fatal "$BASH is too old (bash 4.1 or newer is required)"
put-file . "$BASH"
ln_if_missing "$BASH" ./bin/sh
--
2.56.0
^ permalink raw reply [flat|nested] 47+ messages in thread* [make-initrd] [PATCH v2 07/11] network: Share DHCP hook lock between IPv4 and IPv6 on the same interface
2026-10-19 9:57 ` [make-initrd] [PATCH v2 00/11] Improve support for atomic actions Alexey Gladkov
` (5 preceding siblings ...)
2026-10-19 9:57 ` [make-initrd] [PATCH v2 06/11] create-rootfs: Require bash 4.1 or newer for initramfs Alexey Gladkov
@ 2026-10-19 9:57 ` Alexey Gladkov
2026-10-19 9:57 ` [make-initrd] [PATCH v2 08/11] luks: Serialize /etc/luks.keys updates and avoid duplicate entries Alexey Gladkov
` (4 subsequent siblings)
11 siblings, 0 replies; 47+ messages in thread
From: Alexey Gladkov @ 2026-10-19 9:57 UTC (permalink / raw)
To: make-initrd
100-dhcp spawns udhcpc and udhcpc6 concurrently in the background for
the same network interface. Both invoke udhcpc4.script (via the
udhcpc6.script symlink for IPv6), which writes shared per-interface
configuration files under /.initrd/network/auto/ifaces/$INTERFACE/
such as iplink, hostname, and resolv.conf.
Because the lock directory name included $CMDNAME (udhcpc4 vs udhcpc6),
IPv4 and IPv6 hooks acquired different locks and could clobber each
other's configuration updates when leases arrived simultaneously.
Use a single /tmp/udhcpc.$INTERFACE.lock directory per interface to
serialize both IPv4 and IPv6 hook executions.
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
features/network/data/lib/network/udhcpc4.script | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/features/network/data/lib/network/udhcpc4.script b/features/network/data/lib/network/udhcpc4.script
index 98e419e0..8648b1f5 100755
--- a/features/network/data/lib/network/udhcpc4.script
+++ b/features/network/data/lib/network/udhcpc4.script
@@ -10,7 +10,7 @@ V="${CMDNAME##udhcpc}"
INTERFACE="${interface-}"
-lock="/tmp/$CMDNAME.$INTERFACE.lock"
+lock="/tmp/udhcpc.$INTERFACE.lock"
[ -d "$lock" ] || mkdir -p -- "$lock"
cfg="$net_confdir/ifaces/$INTERFACE/ipv${V}dhcp"
--
2.56.0
^ permalink raw reply [flat|nested] 47+ messages in thread* [make-initrd] [PATCH v2 08/11] luks: Serialize /etc/luks.keys updates and avoid duplicate entries
2026-10-19 9:57 ` [make-initrd] [PATCH v2 00/11] Improve support for atomic actions Alexey Gladkov
` (6 preceding siblings ...)
2026-10-19 9:57 ` [make-initrd] [PATCH v2 07/11] network: Share DHCP hook lock between IPv4 and IPv6 on the same interface Alexey Gladkov
@ 2026-10-19 9:57 ` Alexey Gladkov
2026-10-19 9:57 ` [make-initrd] [PATCH v2 09/11] runtime: Synchronize concurrent /etc/fstab access with shared and exclusive locks Alexey Gladkov
` (3 subsequent siblings)
11 siblings, 0 replies; 47+ messages in thread
From: Alexey Gladkov @ 2026-10-19 9:57 UTC (permalink / raw)
To: make-initrd
udevd invokes the lukskeys filter concurrently for every block device
event. Appending to /etc/luks.keys without locking allows parallel
filter invocations to interleave writes and repeatedly append identical
entries (such as pkcs11 keys or repeated block device events).
Serialize /etc/luks.keys updates with run_locked and skip entries that
are already present in the file.
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
.../luks/data/lib/uevent/filters/lukskeys | 49 ++++++++++++-------
1 file changed, 31 insertions(+), 18 deletions(-)
diff --git a/features/luks/data/lib/uevent/filters/lukskeys b/features/luks/data/lib/uevent/filters/lukskeys
index 3c1d7b66..b6e695f5 100755
--- a/features/luks/data/lib/uevent/filters/lukskeys
+++ b/features/luks/data/lib/uevent/filters/lukskeys
@@ -19,27 +19,40 @@ split() {
luksdev="${3-}"
}
+add_key() {
+ local entry
+ printf -v entry '%s\t%s\t%s' "$1" "$2" "$3"
+ grep -qsFx -- "$entry" /etc/luks.keys 2>/dev/null ||
+ printf '%s\n' "$entry" >> /etc/luks.keys
+}
+
+process_keys() {
+ local i=0 path keydev luksdev is_pkcs11 realdev
+
+ while [ "$i" -lt "$LUKS_KEY" ]; do
+ path='' keydev='' luksdev='' is_pkcs11=''
+ eval "split \"\$LUKS_KEY$i\""
+ i=$(( $i + 1 ))
+
+ if [ -n "$is_pkcs11" ]; then
+ [ -n "$path" ] || continue
+ add_key "pkcs11:$path" "" "$luksdev"
+ continue
+ fi
+
+ [ -n "$keydev" ] ||
+ continue
+ realdev=
+ get_dev realdev "$keydev" ||
+ continue
+ add_key "$path" "$realdev" "$luksdev"
+ done
+}
+
[ -z "${NO_LUKS-}" ] ||
exit 0
[ -n "$LUKS_KEY" ] && [ "$LUKS_KEY" != 0 ] ||
exit 0
-i=0
-while [ "$i" -lt "$LUKS_KEY" ]; do
- path='' keydev='' luksdev='' is_pkcs11=''
- eval "split \"\$LUKS_KEY$i\""
- i=$(( $i + 1 ))
-
- if [ -n "$is_pkcs11" ]; then
- [ -n "$path" ] || continue
- printf 'pkcs11:%s\t%s\t%s\n' "$path" "" "$luksdev"
- continue
- fi
- [ -n "$keydev" ] ||
- continue
- realdev=
- get_dev realdev "$keydev" ||
- continue
- printf '%s\t%s\t%s\n' "$path" "$realdev" "$luksdev"
-done >> /etc/luks.keys
+run_locked /etc/luks.keys process_keys
--
2.56.0
^ permalink raw reply [flat|nested] 47+ messages in thread* [make-initrd] [PATCH v2 09/11] runtime: Synchronize concurrent /etc/fstab access with shared and exclusive locks
2026-10-19 9:57 ` [make-initrd] [PATCH v2 00/11] Improve support for atomic actions Alexey Gladkov
` (7 preceding siblings ...)
2026-10-19 9:57 ` [make-initrd] [PATCH v2 08/11] luks: Serialize /etc/luks.keys updates and avoid duplicate entries Alexey Gladkov
@ 2026-10-19 9:57 ` Alexey Gladkov
2026-10-19 9:57 ` [make-initrd] [PATCH v2 10/11] runtime: Update rootdelay deadline and failure message atomically Alexey Gladkov
` (2 subsequent siblings)
11 siblings, 0 replies; 47+ messages in thread
From: Alexey Gladkov @ 2026-10-19 9:57 UTC (permalink / raw)
To: make-initrd
/etc/fstab is generated during init, rewritten by post-fstab hooks, and
modified at runtime by the btrfs-member timeout handler while udev
filters (mountdev) and other queue handlers (900-localdev, btrfs-member)
read it concurrently. Because in-place rewrites and renames replace the
/etc/fstab inode, locking /etc/fstab directly would not serialize access
across replacements.
Create a dedicated /.initrd/fstab.lock file and provide run_rlocked,
run_fstab_locked, and run_fstab_rlocked helpers in initrd-sh-functions
so writers acquire an exclusive lock while concurrent readers share a
read lock on a stable inode.
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
.../uevent/handlers/btrfs-member/100-timeout | 4 +-
features/runtime/data/bin/initrd-sh-functions | 41 ++++++-
features/runtime/data/etc/rc.d/init.d/fstab | 4 +-
features/runtime/data/init | 1 +
.../data/lib/initrd/post/fstab/mountsrc | 63 ++++++-----
.../runtime/data/lib/uevent/filters/mountdev | 71 ++++++------
.../lib/uevent/handlers/mount/900-localdev | 2 +-
features/zfs/data/lib/initrd/post/fstab/zfs | 107 ++++++++++--------
.../tests/ts0044-member-timeout-queue-api/run | 2 +
9 files changed, 182 insertions(+), 113 deletions(-)
diff --git a/features/btrfs/data/lib/uevent/handlers/btrfs-member/100-timeout b/features/btrfs/data/lib/uevent/handlers/btrfs-member/100-timeout
index 4c313ee5..fdfaeda7 100755
--- a/features/btrfs/data/lib/uevent/handlers/btrfs-member/100-timeout
+++ b/features/btrfs/data/lib/uevent/handlers/btrfs-member/100-timeout
@@ -113,7 +113,7 @@ if [ -n "$has_member_events" ]; then
exit 0
# No multi-device btrfs in fstab, or all devices already present.
- check_btrfs_arrays ||
+ run_fstab_rlocked check_btrfs_arrays ||
exit 0
queue_timeout_after btrfs-member "$delay" member REASON=degraded-check
@@ -128,4 +128,4 @@ for e in "$1"/timeout.member.*; do
done
[ -z "$has_timeout_events" ] ||
- process_timeout
+ run_fstab_locked process_timeout
diff --git a/features/runtime/data/bin/initrd-sh-functions b/features/runtime/data/bin/initrd-sh-functions
index 8c9746d7..4d1aaaed 100644
--- a/features/runtime/data/bin/initrd-sh-functions
+++ b/features/runtime/data/bin/initrd-sh-functions
@@ -185,7 +185,19 @@ run_locked()
return $rc
}
-console_lock_file=/.initrd/console.lock
+run_rlocked()
+{
+ local lock_file_fd='' rc=0
+
+ lock_file "$1" -s
+ shift
+ "$@" {lock_file_fd}<&- || rc=$?
+ unlock_file
+
+ return $rc
+}
+
+console_lock_file="${console_lock_file:-/.initrd/console.lock}"
console_lock()
{
@@ -202,4 +214,31 @@ run_console_locked()
run_locked "$console_lock_file" "$@"
}
+fstab_lock_file="${fstab_lock_file:-/.initrd/fstab.lock}"
+
+fstab_lock()
+{
+ lock_file "$fstab_lock_file" -x
+}
+
+fstab_rlock()
+{
+ lock_file "$fstab_lock_file" -s
+}
+
+fstab_unlock()
+{
+ unlock_file
+}
+
+run_fstab_locked()
+{
+ run_locked "$fstab_lock_file" "$@"
+}
+
+run_fstab_rlocked()
+{
+ run_rlocked "$fstab_lock_file" "$@"
+}
+
fi
diff --git a/features/runtime/data/etc/rc.d/init.d/fstab b/features/runtime/data/etc/rc.d/init.d/fstab
index 02041bcf..663fa957 100755
--- a/features/runtime/data/etc/rc.d/init.d/fstab
+++ b/features/runtime/data/etc/rc.d/init.d/fstab
@@ -128,4 +128,6 @@ gen_fstab()
printf '%s\n' "${fstab[@]}" > /etc/fstab
}
-action_shell 'Creating /etc/fstab:' gen_fstab
+. initrd-sh-functions
+
+action_shell 'Creating /etc/fstab:' run_fstab_locked gen_fstab
diff --git a/features/runtime/data/init b/features/runtime/data/init
index f4c789a1..75996e0f 100755
--- a/features/runtime/data/init
+++ b/features/runtime/data/init
@@ -12,6 +12,7 @@ export PATH=/sbin:/usr/sbin:/usr/local/sbin:/bin:/usr/bin:/usr/local/bin
# Create storage for init environment
:> /.initrd/initenv
:> /.initrd/console.lock
+:> /.initrd/fstab.lock
# Check and create the necessary device files
[ -d /dev ] ||
diff --git a/features/runtime/data/lib/initrd/post/fstab/mountsrc b/features/runtime/data/lib/initrd/post/fstab/mountsrc
index 3483b569..fd9b4be6 100755
--- a/features/runtime/data/lib/initrd/post/fstab/mountsrc
+++ b/features/runtime/data/lib/initrd/post/fstab/mountsrc
@@ -2,42 +2,51 @@
[ "$1" = start ] || exit 0
-mount_event_needed=
-
-eof=
-while [ -z "$eof" ]; do
- read -r fsdev fsdir fstype fsopts freq passno ||
- eof=1
+. initrd-sh-functions
- [ -n "$fsdev" ] ||
- continue
+mount_event_needed=
- fsoptions=()
- readarray -t fsoptions <<<"${fsopts//,/$'\n'}"
+update_fstab()
+{
+ local eof='' fsdev fsdir fstype fsopts freq passno i j
+ local -a fsoptions
- if [ -z "${fsdev##SOURCE=*}" ]; then
- fsdev="${fsdev#SOURCE=}"
- fsoptions+=("x-initrd-mount-virtual")
- mount_event_needed=1
- fi
+ while [ -z "$eof" ]; do
+ read -r fsdev fsdir fstype fsopts freq passno ||
+ eof=1
- fsopts=
- for (( i=0; i < ${#fsoptions[@]}; i++ )); do
- [ -n "${fsoptions[$i]}" ] ||
+ [ -n "$fsdev" ] ||
continue
- for (( j=0; j < $i; j++ )); do
- [ "${fsoptions[$i]}" != "${fsoptions[$j]}" ] ||
- continue 2
+
+ fsoptions=()
+ readarray -t fsoptions <<<"${fsopts//,/$'\n'}"
+
+ if [ -z "${fsdev##SOURCE=*}" ]; then
+ fsdev="${fsdev#SOURCE=}"
+ fsoptions+=("x-initrd-mount-virtual")
+ mount_event_needed=1
+ fi
+
+ fsopts=
+ for (( i=0; i < ${#fsoptions[@]}; i++ )); do
+ [ -n "${fsoptions[$i]}" ] ||
+ continue
+ for (( j=0; j < $i; j++ )); do
+ [ "${fsoptions[$i]}" != "${fsoptions[$j]}" ] ||
+ continue 2
+ done
+ fsopts="${fsopts:+$fsopts,}${fsoptions[$i]}"
done
- fsopts="${fsopts:+$fsopts,}${fsoptions[$i]}"
- done
- printf '%s %s %s %s %s %s\n' \
- "$fsdev" "$fsdir" "$fstype" "$fsopts" "$freq" "$passno"
+ printf '%s %s %s %s %s %s\n' \
+ "$fsdev" "$fsdir" "$fstype" "$fsopts" "$freq" "$passno"
+
+ done < /etc/fstab > /etc/fstab."$$"
-done < /etc/fstab > /etc/fstab."$$"
+ mv -f -- /etc/fstab."$$" /etc/fstab
+}
-mv /etc/fstab."$$" /etc/fstab
+run_fstab_locked update_fstab
if [ -n "$mount_event_needed" ]; then
. /etc/init.d/functions
diff --git a/features/runtime/data/lib/uevent/filters/mountdev b/features/runtime/data/lib/uevent/filters/mountdev
index a9c168a3..d24f6133 100755
--- a/features/runtime/data/lib/uevent/filters/mountdev
+++ b/features/runtime/data/lib/uevent/filters/mountdev
@@ -4,41 +4,48 @@
. uevent-sh-functions
. initrd-sh-functions
-eof=
-while [ -z "$eof" ]; do
- read -r fsdev fsdir fstype fsopts freq passno ||
- eof=1
- [ -n "$fsdev" ] ||
- continue
-
- if [ -n "${ROOTONLY-}" ]; then
- [ "$fsdir" = "$rootmnt" ] ||
+process_fstab()
+{
+ local eof='' fsdev fsdir fstype fsopts freq passno dev o
+ local -a fsoptions
+
+ while [ -z "$eof" ]; do
+ read -r fsdev fsdir fstype fsopts freq passno ||
+ eof=1
+ [ -n "$fsdev" ] ||
continue
- fi
-
- fsoptions=()
- readarray -d, -t fsoptions < <(printf '%s' "$fsopts")
-
- dev=
- for o in "${fsoptions[@]}"; do
- if [ "$o" = 'x-initrd-mount-virtual' ]; then
- # A virtual mountpoint does not have a real device and
- # fires every time a block device is found. Let's let
- # the handler decide to process this event or ignore it.
- dev="$fsdev"
- break
+
+ if [ -n "${ROOTONLY-}" ]; then
+ [ "$fsdir" = "$rootmnt" ] ||
+ continue
fi
- done
- [ -n "$dev" ] || get_dev dev "$fsdev" ||
- continue
+ fsoptions=()
+ readarray -d, -t fsoptions < <(printf '%s' "$fsopts")
+
+ dev=
+ for o in "${fsoptions[@]}"; do
+ if [ "$o" = 'x-initrd-mount-virtual' ]; then
+ # A virtual mountpoint does not have a real device and
+ # fires every time a block device is found. Let's let
+ # the handler decide to process this event or ignore it.
+ dev="$fsdev"
+ break
+ fi
+ done
+
+ [ -n "$dev" ] || get_dev dev "$fsdev" ||
+ continue
+
+ event="$(make_event)"
- event="$(make_event)"
+ cat > "$event" <<-EOF
+ MOUNTDEV="$dev"
+ MOUNTPOINT="$fsdir"
+ EOF
- cat > "$event" <<-EOF
- MOUNTDEV="$dev"
- MOUNTPOINT="$fsdir"
- EOF
+ release_event mountdev "$event"
+ done < /etc/fstab
+}
- release_event mountdev "$event"
-done < /etc/fstab
+run_fstab_rlocked process_fstab
diff --git a/features/runtime/data/lib/uevent/handlers/mount/900-localdev b/features/runtime/data/lib/uevent/handlers/mount/900-localdev
index 37ee4c2b..940635d9 100755
--- a/features/runtime/data/lib/uevent/handlers/mount/900-localdev
+++ b/features/runtime/data/lib/uevent/handlers/mount/900-localdev
@@ -80,7 +80,7 @@ while [ "$method" = localdev ]; do
resume_checked ||
exit 0
- all_mounted && sysinit_found ||
+ run_fstab_rlocked all_mounted && sysinit_found ||
break
run_console_locked activate_localdev
diff --git a/features/zfs/data/lib/initrd/post/fstab/zfs b/features/zfs/data/lib/initrd/post/fstab/zfs
index 510cc275..aba6e7a7 100755
--- a/features/zfs/data/lib/initrd/post/fstab/zfs
+++ b/features/zfs/data/lib/initrd/post/fstab/zfs
@@ -2,57 +2,66 @@
[ "$1" = start ] || exit 0
-eof=
-while [ -z "$eof" ]; do
- read -r fsdev fsdir fstype fsopts freq passno ||
- eof=1
-
- [ -n "$fsdev" ] ||
- continue
-
- fsoptions=()
- readarray -t fsoptions <<<"${fsopts//,/$'\n'}"
-
- [ "$fstype" != 'zfs' ] ||
- fsoptions+=("zfsutil")
-
- # root=<pool>/<dataset> (uses this for rpool - first part)
- # root=ZFS=<pool>/<dataset> (uses this for rpool - first part, without 'ZFS=')
- # root=zfs:<pool>/<dataset> (uses this for rpool - first part, without 'zfs:')
- # root=zfs:AUTO (tries to detect both pool and rootfs)
- case "$fsdev" in
- [Zz][Ff][Ss][:=][Aa][Uu][Tt][Oo])
- # We need an fstab record for this mountpoint. We will
- # try to detect it later when udev starts up. We don't
- # strip the prefix to distinguish autodetect from rpool.
- fspool="zfs:auto"
- fstype="zfs"
- fsoptions+=("zfsutil")
- ;;
- [Zz][Ff][Ss][:=]*)
- fspool="${fsdev#[Zz][Ff][Ss][:=]}"
- fstype="zfs"
- fsoptions+=("zfsutil")
- ;;
- *)
- fspool="$fsdev"
- ;;
- esac
-
- fsopts=
- for (( i=0; i < ${#fsoptions[@]}; i++ )); do
- [ -n "${fsoptions[$i]}" ] ||
+. initrd-sh-functions
+
+update_fstab()
+{
+ local eof='' fsdev fsdir fstype fsopts freq passno fspool i j
+ local -a fsoptions
+
+ while [ -z "$eof" ]; do
+ read -r fsdev fsdir fstype fsopts freq passno ||
+ eof=1
+
+ [ -n "$fsdev" ] ||
continue
- for (( j=0; j < $i; j++ )); do
- [ "${fsoptions[$i]}" != "${fsoptions[$j]}" ] ||
- continue 2
+
+ fsoptions=()
+ readarray -t fsoptions <<<"${fsopts//,/$'\n'}"
+
+ [ "$fstype" != 'zfs' ] ||
+ fsoptions+=("zfsutil")
+
+ # root=<pool>/<dataset> (uses this for rpool - first part)
+ # root=ZFS=<pool>/<dataset> (uses this for rpool - first part, without 'ZFS=')
+ # root=zfs:<pool>/<dataset> (uses this for rpool - first part, without 'zfs:')
+ # root=zfs:AUTO (tries to detect both pool and rootfs)
+ case "$fsdev" in
+ [Zz][Ff][Ss][:=][Aa][Uu][Tt][Oo])
+ # We need an fstab record for this mountpoint. We will
+ # try to detect it later when udev starts up. We don't
+ # strip the prefix to distinguish autodetect from rpool.
+ fspool="zfs:auto"
+ fstype="zfs"
+ fsoptions+=("zfsutil")
+ ;;
+ [Zz][Ff][Ss][:=]*)
+ fspool="${fsdev#[Zz][Ff][Ss][:=]}"
+ fstype="zfs"
+ fsoptions+=("zfsutil")
+ ;;
+ *)
+ fspool="$fsdev"
+ ;;
+ esac
+
+ fsopts=
+ for (( i=0; i < ${#fsoptions[@]}; i++ )); do
+ [ -n "${fsoptions[$i]}" ] ||
+ continue
+ for (( j=0; j < $i; j++ )); do
+ [ "${fsoptions[$i]}" != "${fsoptions[$j]}" ] ||
+ continue 2
+ done
+ fsopts="${fsopts:+$fsopts,}${fsoptions[$i]}"
done
- fsopts="${fsopts:+$fsopts,}${fsoptions[$i]}"
- done
- printf '%s %s %s %s %s %s\n' \
- "$fspool" "$fsdir" "$fstype" "$fsopts" "$freq" "$passno"
+ printf '%s %s %s %s %s %s\n' \
+ "$fspool" "$fsdir" "$fstype" "$fsopts" "$freq" "$passno"
+
+ done < /etc/fstab > /etc/fstab."$$"
-done < /etc/fstab > /etc/fstab."$$"
+ mv -f -- /etc/fstab."$$" /etc/fstab
+}
-mv /etc/fstab."$$" /etc/fstab
+run_fstab_locked update_fstab
diff --git a/testing/tests/ts0044-member-timeout-queue-api/run b/testing/tests/ts0044-member-timeout-queue-api/run
index 9427023b..50ea239e 100755
--- a/testing/tests/ts0044-member-timeout-queue-api/run
+++ b/testing/tests/ts0044-member-timeout-queue-api/run
@@ -17,6 +17,8 @@ export TEST_FILTERDIR="$root/queues"
export TEST_TIMERDIR="$root/timers"
export TEST_UEVENTDIR="$root/events"
export TEST_INITENV="$root/initenv"
+export fstab_lock_file="$root/fstab.lock"
+:> "$fstab_lock_file"
cat > "$TEST_INITENV" <<'EOF'
PROG=test
--
2.56.0
^ permalink raw reply [flat|nested] 47+ messages in thread* [make-initrd] [PATCH v2 10/11] runtime: Update rootdelay deadline and failure message atomically
2026-10-19 9:57 ` [make-initrd] [PATCH v2 00/11] Improve support for atomic actions Alexey Gladkov
` (8 preceding siblings ...)
2026-10-19 9:57 ` [make-initrd] [PATCH v2 09/11] runtime: Synchronize concurrent /etc/fstab access with shared and exclusive locks Alexey Gladkov
@ 2026-10-19 9:57 ` Alexey Gladkov
2026-10-19 9:57 ` [make-initrd] [PATCH v2 11/11] runtime: Centralize atomic file replacement in write_atomic helper Alexey Gladkov
2026-10-19 19:30 ` [make-initrd] [PATCH v2 00/11] Improve support for atomic actions Leonid Krivoshein
11 siblings, 0 replies; 47+ messages in thread
From: Alexey Gladkov @ 2026-10-19 9:57 UTC (permalink / raw)
To: make-initrd
/.initrd/rootdelay/deadline is updated in place via shell redirection by
rootdelay_reset_timer, rootdelayd, and 900-localdev while rootdelayd
periodically reads it with readline. If rootdelayd reads the file after
truncation but before the new value is written, deadline evaluates to
empty, falls back to the current timestamp, and falsely triggers an
immediate timeout.
In addition, 900-localdev sets the deadline to 0 before writing
/.initrd/rootdelay/message, allowing rootdelayd to observe the expired
deadline before the custom error message is in place.
Add rootdelay_set_deadline to update the deadline atomically via a
temporary file and rename, and write the failure message in 900-localdev
before expiring the deadline.
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
features/runtime/data/bin/initrd-sh-functions | 17 ++++++++++----
.../lib/uevent/handlers/mount/900-localdev | 23 +++++++++----------
features/runtime/data/sbin/rootdelayd | 5 ++--
3 files changed, 26 insertions(+), 19 deletions(-)
diff --git a/features/runtime/data/bin/initrd-sh-functions b/features/runtime/data/bin/initrd-sh-functions
index 4d1aaaed..b32248e3 100644
--- a/features/runtime/data/bin/initrd-sh-functions
+++ b/features/runtime/data/bin/initrd-sh-functions
@@ -123,12 +123,21 @@ rootdelay_paused()
[ -d "$_rootdelay_pause" ]
}
+rootdelay_set_deadline()
+{
+ mkdir -p -- "${_rootdelay_timestamp%/*}"
+ printf '%s\n' "$1" > "$_rootdelay_timestamp.$$.$BASHPID"
+ mv -f -- "$_rootdelay_timestamp.$$.$BASHPID" "$_rootdelay_timestamp"
+}
+
rootdelay_reset_timer()
{
- local now
- now="$(timestamp boottime raw)"
- now="${now%.*}"
- echo $(( $now + $ROOTDELAY )) > "$_rootdelay_timestamp"
+ local now="${1-}"
+ if [ -z "$now" ]; then
+ now="$(timestamp boottime raw)"
+ now="${now%.*}"
+ fi
+ rootdelay_set_deadline "$(( $now + $ROOTDELAY ))"
}
initrd_features=/.initrd/features
diff --git a/features/runtime/data/lib/uevent/handlers/mount/900-localdev b/features/runtime/data/lib/uevent/handlers/mount/900-localdev
index 940635d9..eb8d3a9f 100755
--- a/features/runtime/data/lib/uevent/handlers/mount/900-localdev
+++ b/features/runtime/data/lib/uevent/handlers/mount/900-localdev
@@ -45,23 +45,22 @@ sysinit_found()
fi
local msglock="/.initrd/polld/$PROG/message-shown"
- local deadline='/.initrd/rootdelay/deadline'
local consmsg="/.initrd/rootdelay/message"
- [ ! -f "$deadline" ] ||
- echo 0 > "$deadline" ||:
+ if [ ! -d "$msglock" ]; then
+ mkdir -p -- "$msglock" "${consmsg%/*}" ||:
- [ ! -d "$msglock" ] ||
- return 1
+ printf > "$consmsg.$$.$BASHPID" '%s\n' \
+ "The init program \`$INIT' not found in the root directory."
+ mv -f -- "$consmsg.$$.$BASHPID" "$consmsg"
- mkdir -p -- "$msglock" ||:
-
- printf > "$consmsg" '%s\n' \
- "The init program \`$INIT' not found in the root directory."
+ message "it looks like all mountpoints are ready, but \`$INIT' not found" \
+ "in the new root directory ($rootmnt)." \
+ "There is no point in waiting any longer."
+ fi
- message "it looks like all mountpoints are ready, but \`$INIT' not found" \
- "in the new root directory ($rootmnt)." \
- "There is no point in waiting any longer."
+ [ ! -f "$_rootdelay_timestamp" ] ||
+ rootdelay_set_deadline 0 ||:
return 1
}
diff --git a/features/runtime/data/sbin/rootdelayd b/features/runtime/data/sbin/rootdelayd
index c285c7d8..5fa21f07 100755
--- a/features/runtime/data/sbin/rootdelayd
+++ b/features/runtime/data/sbin/rootdelayd
@@ -80,8 +80,7 @@ while :; do
first_iter=1
deadline=$(( $now + $ROOTDELAY ))
- mkdir -p -- "${_rootdelay_timestamp%/*}"
- echo $deadline > "$_rootdelay_timestamp"
+ rootdelay_set_deadline "$deadline"
else
readline deadline "$_rootdelay_timestamp"
fi
@@ -92,7 +91,7 @@ while :; do
if [ "$delay" -le 0 ]; then
if ! resume_checked; then
set_resume_checked
- echo $(( $now + $ROOTDELAY )) > "$_rootdelay_timestamp"
+ rootdelay_reset_timer "$now"
sleep $period
continue
--
2.56.0
^ permalink raw reply [flat|nested] 47+ messages in thread* [make-initrd] [PATCH v2 11/11] runtime: Centralize atomic file replacement in write_atomic helper
2026-10-19 9:57 ` [make-initrd] [PATCH v2 00/11] Improve support for atomic actions Alexey Gladkov
` (9 preceding siblings ...)
2026-10-19 9:57 ` [make-initrd] [PATCH v2 10/11] runtime: Update rootdelay deadline and failure message atomically Alexey Gladkov
@ 2026-10-19 9:57 ` Alexey Gladkov
2026-10-19 19:30 ` [make-initrd] [PATCH v2 00/11] Improve support for atomic actions Leonid Krivoshein
11 siblings, 0 replies; 47+ messages in thread
From: Alexey Gladkov @ 2026-10-19 9:57 UTC (permalink / raw)
To: make-initrd
Multiple runtime, network, and zfs scripts open-code the same pattern
for replacing configuration and state files atomically via a temporary
sibling file followed by mv -f. Each call site uses slightly different
temporary file naming (.new, .$$, .$$.$BASHPID, or mktemp + chmod) and
typically omits cleanup if generating the new content fails partway
through.
Provide a write_atomic helper in initrd-sh-functions that writes either
command output or standard input to a process- and subshell-unique
temporary file ($dst.$$.$BASHPID), renames it into place only on
success, and removes the temporary file if the producer fails. Convert
existing atomic replacement sites to use it.
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
features/network/data/lib/network/resolvconf | 8 ++-----
.../network/data/lib/network/udhcpc4.script | 7 ++----
features/runtime/data/bin/initrd-sh-functions | 24 +++++++++++++++++--
features/runtime/data/etc/rc.d/init.d/cmdline | 4 ++--
.../data/lib/initrd/post/fstab/mountsrc | 6 ++---
.../lib/uevent/handlers/mount/900-localdev | 3 +--
features/zfs/data/lib/initrd/post/fstab/zfs | 6 ++---
7 files changed, 33 insertions(+), 25 deletions(-)
diff --git a/features/network/data/lib/network/resolvconf b/features/network/data/lib/network/resolvconf
index 2132f390..f6c0686d 100755
--- a/features/network/data/lib/network/resolvconf
+++ b/features/network/data/lib/network/resolvconf
@@ -15,12 +15,10 @@ get_iface_confdir &&
update_resolvconf()
{
- local tmp list eof s dup i p
+ local list eof s dup i p
message "write resolv.conf"
- tmp="$(mktemp "/etc/resolv.conf.XXXXXX")"
-
cat /etc/resolv.conf "$confdir/resolv.conf" |
while :; do
list=${list:-0}
@@ -53,9 +51,7 @@ update_resolvconf()
done
break
fi
- done >"$tmp"
- chmod 644 "$tmp"
- mv -f -- "$tmp" /etc/resolv.conf
+ done | write_atomic /etc/resolv.conf
}
run_locked "$0" update_resolvconf
diff --git a/features/network/data/lib/network/udhcpc4.script b/features/network/data/lib/network/udhcpc4.script
index 8648b1f5..5d952797 100755
--- a/features/network/data/lib/network/udhcpc4.script
+++ b/features/network/data/lib/network/udhcpc4.script
@@ -43,22 +43,19 @@ suffix=".new"
resolvconf_update()
{
- local hb he dst tmp
+ local hb he dst
hb="# $INTERFACE: DHCP$V start"
he="# $INTERFACE: DHCP$V end"
dst="$dir/resolv.conf$suffix"
- tmp="$(mktemp "$dst.XXXXXX")"
{
[ ! -f "$dst" ] || sed -n -e "0,/^$hb\$/{ /^$hb\$/q; p; }" "$dst"
printf '%s\n' "$hb"
cat
printf '%s\n\n' "$he"
[ ! -f "$dst" ] || sed -n -e "/^$he\$/,\${ /^$he\$/q; p; }" "$dst"
- } > "$tmp"
- chmod 644 "$tmp"
- mv -f -- "$tmp" "$dst"
+ } | write_atomic "$dst"
}
env_to_configs()
diff --git a/features/runtime/data/bin/initrd-sh-functions b/features/runtime/data/bin/initrd-sh-functions
index b32248e3..a69eabee 100644
--- a/features/runtime/data/bin/initrd-sh-functions
+++ b/features/runtime/data/bin/initrd-sh-functions
@@ -105,6 +105,27 @@ readline()
eval "$1=\"\$__v\""
}
+write_atomic()
+{
+ local __write_atomic_dst="$1"
+ local __write_atomic_tmp="$1.$$.$BASHPID"
+ local __write_atomic_rc=0
+ shift
+
+ if [ "$#" -gt 0 ]; then
+ "$@" > "$__write_atomic_tmp" || __write_atomic_rc=$?
+ else
+ cat > "$__write_atomic_tmp" || __write_atomic_rc=$?
+ fi
+
+ if [ "$__write_atomic_rc" -eq 0 ]; then
+ mv -f -- "$__write_atomic_tmp" "$__write_atomic_dst"
+ else
+ rm -f -- "$__write_atomic_tmp"
+ return "$__write_atomic_rc"
+ fi
+}
+
_rootdelay_pause=/.initrd/rootdelay/pause
_rootdelay_timestamp=/.initrd/rootdelay/deadline
@@ -126,8 +147,7 @@ rootdelay_paused()
rootdelay_set_deadline()
{
mkdir -p -- "${_rootdelay_timestamp%/*}"
- printf '%s\n' "$1" > "$_rootdelay_timestamp.$$.$BASHPID"
- mv -f -- "$_rootdelay_timestamp.$$.$BASHPID" "$_rootdelay_timestamp"
+ write_atomic "$_rootdelay_timestamp" printf '%s\n' "$1"
}
rootdelay_reset_timer()
diff --git a/features/runtime/data/etc/rc.d/init.d/cmdline b/features/runtime/data/etc/rc.d/init.d/cmdline
index 6c4f7463..925e0058 100755
--- a/features/runtime/data/etc/rc.d/init.d/cmdline
+++ b/features/runtime/data/etc/rc.d/init.d/cmdline
@@ -18,6 +18,7 @@
. shell-error
. shell-var
. shell-cmdline
+. initrd-sh-functions
defaults()
{
@@ -215,8 +216,7 @@ parse()
{
echo __initrd_initenv=1
environ -q -s -p 'export ' -u '_*,INITLOG_FILE,RUNLEVEL,runlevel,PWD,SHLVL'
- } > /.initrd/initenv.new
- mv -f -- /.initrd/initenv.new /.initrd/initenv
+ } | write_atomic /.initrd/initenv
}
action_shell 'Parsing cmdline arguments:' parse
diff --git a/features/runtime/data/lib/initrd/post/fstab/mountsrc b/features/runtime/data/lib/initrd/post/fstab/mountsrc
index fd9b4be6..01de0753 100755
--- a/features/runtime/data/lib/initrd/post/fstab/mountsrc
+++ b/features/runtime/data/lib/initrd/post/fstab/mountsrc
@@ -41,12 +41,10 @@ update_fstab()
printf '%s %s %s %s %s %s\n' \
"$fsdev" "$fsdir" "$fstype" "$fsopts" "$freq" "$passno"
- done < /etc/fstab > /etc/fstab."$$"
-
- mv -f -- /etc/fstab."$$" /etc/fstab
+ done < /etc/fstab
}
-run_fstab_locked update_fstab
+run_fstab_locked write_atomic /etc/fstab update_fstab
if [ -n "$mount_event_needed" ]; then
. /etc/init.d/functions
diff --git a/features/runtime/data/lib/uevent/handlers/mount/900-localdev b/features/runtime/data/lib/uevent/handlers/mount/900-localdev
index eb8d3a9f..385a2dd7 100755
--- a/features/runtime/data/lib/uevent/handlers/mount/900-localdev
+++ b/features/runtime/data/lib/uevent/handlers/mount/900-localdev
@@ -50,9 +50,8 @@ sysinit_found()
if [ ! -d "$msglock" ]; then
mkdir -p -- "$msglock" "${consmsg%/*}" ||:
- printf > "$consmsg.$$.$BASHPID" '%s\n' \
+ write_atomic "$consmsg" printf '%s\n' \
"The init program \`$INIT' not found in the root directory."
- mv -f -- "$consmsg.$$.$BASHPID" "$consmsg"
message "it looks like all mountpoints are ready, but \`$INIT' not found" \
"in the new root directory ($rootmnt)." \
diff --git a/features/zfs/data/lib/initrd/post/fstab/zfs b/features/zfs/data/lib/initrd/post/fstab/zfs
index aba6e7a7..b8f345d1 100755
--- a/features/zfs/data/lib/initrd/post/fstab/zfs
+++ b/features/zfs/data/lib/initrd/post/fstab/zfs
@@ -59,9 +59,7 @@ update_fstab()
printf '%s %s %s %s %s %s\n' \
"$fspool" "$fsdir" "$fstype" "$fsopts" "$freq" "$passno"
- done < /etc/fstab > /etc/fstab."$$"
-
- mv -f -- /etc/fstab."$$" /etc/fstab
+ done < /etc/fstab
}
-run_fstab_locked update_fstab
+run_fstab_locked write_atomic /etc/fstab update_fstab
--
2.56.0
^ permalink raw reply [flat|nested] 47+ messages in thread* Re: [make-initrd] [PATCH v2 00/11] Improve support for atomic actions
2026-10-19 9:57 ` [make-initrd] [PATCH v2 00/11] Improve support for atomic actions Alexey Gladkov
` (10 preceding siblings ...)
2026-10-19 9:57 ` [make-initrd] [PATCH v2 11/11] runtime: Centralize atomic file replacement in write_atomic helper Alexey Gladkov
@ 2026-10-19 19:30 ` Leonid Krivoshein
2026-10-20 14:59 ` Alexey Gladkov
11 siblings, 1 reply; 47+ messages in thread
From: Leonid Krivoshein @ 2026-10-19 19:30 UTC (permalink / raw)
To: make-initrd
Привет!
On 10/19/26 12:57 PM, Alexey Gladkov wrote:
> Нашлось ещё ряд мест, где потенциально могут возникнуть проблемы из-за
> параллельного доступа к файлам на чтение/запись.
>
> Я добавил новый API не только для flock-блокировок, но и для более атомарного
> обновления файлов.
>
> Вроде исправил всё что нашёл.
>
Грандиозно! Выходит, иногда стоит задавать тут такие вопросы.
>
> Alexey Gladkov (10):
> runtime: Fix console lock shadowing by /dev mount
> runtime: Avoid leaking lock descriptor 90 to child processes
> runtime: Replace /.initrd/initenv locking with atomic file update
> runtime: Centralize file and console locking helpers
> create-rootfs: Require bash 4.1 or newer for initramfs
> network: Share DHCP hook lock between IPv4 and IPv6 on the same
> interface
> luks: Serialize /etc/luks.keys updates and avoid duplicate entries
> runtime: Synchronize concurrent /etc/fstab access with shared and
> exclusive locks
> runtime: Update rootdelay deadline and failure message atomically
> runtime: Centralize atomic file replacement in write_atomic helper
>
> Egor Shestakov (1):
> runtime: Fix a lock leak in rootdelayd
>
> .../uevent/handlers/btrfs-member/100-timeout | 4 +-
> .../data/lib/uevent/handlers/040-mountdev | 19 +--
> .../luks/data/lib/uevent/filters/lukskeys | 49 +++---
> .../luks/data/lib/uevent/handlers/085-luks | 33 ++--
> .../network/data/bin/network-sh-functions | 1 +
> .../network/data/etc/rc.d/init.d/network-up | 3 -
> features/network/data/lib/network/hostname | 18 ++-
> features/network/data/lib/network/resolvconf | 84 +++++-----
> .../network/data/lib/network/udhcpc4.script | 90 +++++------
> features/runtime/data/bin/initrd-sh-functions | 123 ++++++++++++++-
> features/runtime/data/etc/rc.d/init.d/cmdline | 6 +-
> features/runtime/data/etc/rc.d/init.d/fstab | 4 +-
> features/runtime/data/etc/rc.d/rc | 148 +++++++++---------
> features/runtime/data/init | 2 +
> .../data/lib/initrd/post/fstab/mountsrc | 61 ++++----
> .../runtime/data/lib/uevent/filters/mountdev | 71 +++++----
> .../lib/uevent/handlers/mount/900-localdev | 39 +++--
> features/runtime/data/sbin/rootdelayd | 74 ++++-----
> .../data/lib/uevent/handlers/040-sshfsroot | 26 ++-
> features/zfs/data/lib/initrd/post/fstab/zfs | 105 +++++++------
> features/zfs/data/sbin/ueventd-zfs | 21 ++-
> .../tests/ts0044-member-timeout-queue-api/run | 2 +
> tools/create-rootfs | 2 +
> 23 files changed, 566 insertions(+), 419 deletions(-)
>
--
WBR, Leonid Krivoshein.
^ permalink raw reply [flat|nested] 47+ messages in thread* Re: [make-initrd] [PATCH v2 00/11] Improve support for atomic actions
2026-10-19 19:30 ` [make-initrd] [PATCH v2 00/11] Improve support for atomic actions Leonid Krivoshein
@ 2026-10-20 14:59 ` Alexey Gladkov
2026-10-20 19:04 ` Leonid Krivoshein
0 siblings, 1 reply; 47+ messages in thread
From: Alexey Gladkov @ 2026-10-20 14:59 UTC (permalink / raw)
To: make-initrd
On Mon, Oct 19, 2026 at 10:30:38PM +0300, Leonid Krivoshein wrote:
> Привет!
>
>
> On 10/19/26 12:57 PM, Alexey Gladkov wrote:
> > Нашлось ещё ряд мест, где потенциально могут возникнуть проблемы из-за
> > параллельного доступа к файлам на чтение/запись.
> >
> > Я добавил новый API не только для flock-блокировок, но и для более атомарного
> > обновления файлов.
> >
> > Вроде исправил всё что нашёл.
> >
>
> Грандиозно! Выходит, иногда стоит задавать тут такие вопросы.
Всегда нужно было делать.
Других вопросов нет ? Тогда я их завтра применяю.
>
> >
> > Alexey Gladkov (10):
> > runtime: Fix console lock shadowing by /dev mount
> > runtime: Avoid leaking lock descriptor 90 to child processes
> > runtime: Replace /.initrd/initenv locking with atomic file update
> > runtime: Centralize file and console locking helpers
> > create-rootfs: Require bash 4.1 or newer for initramfs
> > network: Share DHCP hook lock between IPv4 and IPv6 on the same
> > interface
> > luks: Serialize /etc/luks.keys updates and avoid duplicate entries
> > runtime: Synchronize concurrent /etc/fstab access with shared and
> > exclusive locks
> > runtime: Update rootdelay deadline and failure message atomically
> > runtime: Centralize atomic file replacement in write_atomic helper
> >
> > Egor Shestakov (1):
> > runtime: Fix a lock leak in rootdelayd
> >
> > .../uevent/handlers/btrfs-member/100-timeout | 4 +-
> > .../data/lib/uevent/handlers/040-mountdev | 19 +--
> > .../luks/data/lib/uevent/filters/lukskeys | 49 +++---
> > .../luks/data/lib/uevent/handlers/085-luks | 33 ++--
> > .../network/data/bin/network-sh-functions | 1 +
> > .../network/data/etc/rc.d/init.d/network-up | 3 -
> > features/network/data/lib/network/hostname | 18 ++-
> > features/network/data/lib/network/resolvconf | 84 +++++-----
> > .../network/data/lib/network/udhcpc4.script | 90 +++++------
> > features/runtime/data/bin/initrd-sh-functions | 123 ++++++++++++++-
> > features/runtime/data/etc/rc.d/init.d/cmdline | 6 +-
> > features/runtime/data/etc/rc.d/init.d/fstab | 4 +-
> > features/runtime/data/etc/rc.d/rc | 148 +++++++++---------
> > features/runtime/data/init | 2 +
> > .../data/lib/initrd/post/fstab/mountsrc | 61 ++++----
> > .../runtime/data/lib/uevent/filters/mountdev | 71 +++++----
> > .../lib/uevent/handlers/mount/900-localdev | 39 +++--
> > features/runtime/data/sbin/rootdelayd | 74 ++++-----
> > .../data/lib/uevent/handlers/040-sshfsroot | 26 ++-
> > features/zfs/data/lib/initrd/post/fstab/zfs | 105 +++++++------
> > features/zfs/data/sbin/ueventd-zfs | 21 ++-
> > .../tests/ts0044-member-timeout-queue-api/run | 2 +
> > tools/create-rootfs | 2 +
> > 23 files changed, 566 insertions(+), 419 deletions(-)
> >
>
> --
> WBR, Leonid Krivoshein.
>
> _______________________________________________
> Make-initrd mailing list
> Make-initrd@lists.altlinux.org
> https://lists.altlinux.org/mailman/listinfo/make-initrd
--
Rgrds, legion
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [make-initrd] [PATCH v2 00/11] Improve support for atomic actions
2026-10-20 14:59 ` Alexey Gladkov
@ 2026-10-20 19:04 ` Leonid Krivoshein
2026-10-20 19:23 ` [make-initrd] Уточнение по rootdelay_unpause() Leonid Krivoshein
2026-10-21 7:18 ` [make-initrd] [PATCH v2 00/11] Improve support for atomic actions Alexey Gladkov
0 siblings, 2 replies; 47+ messages in thread
From: Leonid Krivoshein @ 2026-10-20 19:04 UTC (permalink / raw)
To: make-initrd
On 10/20/26 5:59 PM, Alexey Gladkov wrote:
> On Mon, Oct 19, 2026 at 10:30:38PM +0300, Leonid Krivoshein wrote:
>> Привет!
>>
>>
>> On 10/19/26 12:57 PM, Alexey Gladkov wrote:
>>> Нашлось ещё ряд мест, где потенциально могут возникнуть проблемы из-за
>>> параллельного доступа к файлам на чтение/запись.
>>>
>>> Я добавил новый API не только для flock-блокировок, но и для более атомарного
>>> обновления файлов.
>>>
>>> Вроде исправил всё что нашёл.
>>>
>>
>> Грандиозно! Выходит, иногда стоит задавать тут такие вопросы.
>
> Всегда нужно было делать.
>
> Других вопросов нет ? Тогда я их завтра применяю.
>
Было бы здорово иметь одно место в документации, где будут перечислены
все файлы, доступ к которым требует блокировок. Например, из этих
коммитов я узнал, что следует блокировать доступ на запись в
/.initrd/initenv. Инклюдить его можно по-прежнему без блокировки
благодаря атомарному обновлению, если я правильно понял.
Другой момент с этими коммитами не связан, но давно напрашивался. В
v2.36.0 была добавлена rootdelay_reset_timer(), здесь проскочило её
усовершенствование. На время диалогов ввода и на время заведомо
длительных или непредсказуемых по времени выполнения операций хотелось
бы не просто приостанавливать отчёт таймера rootdelay, но и возобновлять
его отсчёт, а не просто сбрасывать. Сейчас я его просто сбрасываю, так
тоже работает, но это конечно увеличивает суммарный (фактический) rootdelay.
>>
>>>
>>> Alexey Gladkov (10):
>>> runtime: Fix console lock shadowing by /dev mount
>>> runtime: Avoid leaking lock descriptor 90 to child processes
>>> runtime: Replace /.initrd/initenv locking with atomic file update
>>> runtime: Centralize file and console locking helpers
>>> create-rootfs: Require bash 4.1 or newer for initramfs
>>> network: Share DHCP hook lock between IPv4 and IPv6 on the same
>>> interface
>>> luks: Serialize /etc/luks.keys updates and avoid duplicate entries
>>> runtime: Synchronize concurrent /etc/fstab access with shared and
>>> exclusive locks
>>> runtime: Update rootdelay deadline and failure message atomically
>>> runtime: Centralize atomic file replacement in write_atomic helper
>>>
>>> Egor Shestakov (1):
>>> runtime: Fix a lock leak in rootdelayd
>>>
>>> .../uevent/handlers/btrfs-member/100-timeout | 4 +-
>>> .../data/lib/uevent/handlers/040-mountdev | 19 +--
>>> .../luks/data/lib/uevent/filters/lukskeys | 49 +++---
>>> .../luks/data/lib/uevent/handlers/085-luks | 33 ++--
>>> .../network/data/bin/network-sh-functions | 1 +
>>> .../network/data/etc/rc.d/init.d/network-up | 3 -
>>> features/network/data/lib/network/hostname | 18 ++-
>>> features/network/data/lib/network/resolvconf | 84 +++++-----
>>> .../network/data/lib/network/udhcpc4.script | 90 +++++------
>>> features/runtime/data/bin/initrd-sh-functions | 123 ++++++++++++++-
>>> features/runtime/data/etc/rc.d/init.d/cmdline | 6 +-
>>> features/runtime/data/etc/rc.d/init.d/fstab | 4 +-
>>> features/runtime/data/etc/rc.d/rc | 148 +++++++++---------
>>> features/runtime/data/init | 2 +
>>> .../data/lib/initrd/post/fstab/mountsrc | 61 ++++----
>>> .../runtime/data/lib/uevent/filters/mountdev | 71 +++++----
>>> .../lib/uevent/handlers/mount/900-localdev | 39 +++--
>>> features/runtime/data/sbin/rootdelayd | 74 ++++-----
>>> .../data/lib/uevent/handlers/040-sshfsroot | 26 ++-
>>> features/zfs/data/lib/initrd/post/fstab/zfs | 105 +++++++------
>>> features/zfs/data/sbin/ueventd-zfs | 21 ++-
>>> .../tests/ts0044-member-timeout-queue-api/run | 2 +
>>> tools/create-rootfs | 2 +
>>> 23 files changed, 566 insertions(+), 419 deletions(-)
>>>
>>
>> --
>> WBR, Leonid Krivoshein.
>>
>> _______________________________________________
>> Make-initrd mailing list
>> Make-initrd@lists.altlinux.org
>> https://lists.altlinux.org/mailman/listinfo/make-initrd
>
--
WBR, Leonid Krivoshein.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [make-initrd] Уточнение по rootdelay_unpause()
2026-10-20 19:04 ` Leonid Krivoshein
@ 2026-10-20 19:23 ` Leonid Krivoshein
2026-10-21 10:10 ` [make-initrd] [PATCH] runtime: Freeze rootdelay countdown while paused Alexey Gladkov
2026-10-21 7:18 ` [make-initrd] [PATCH v2 00/11] Improve support for atomic actions Alexey Gladkov
1 sibling, 1 reply; 47+ messages in thread
From: Leonid Krivoshein @ 2026-10-20 19:23 UTC (permalink / raw)
To: make-initrd
Уточню данный момент...
On 10/20/26 10:04 PM, Leonid Krivoshein wrote:
> В v2.36.0 была добавлена rootdelay_reset_timer(), здесь проскочило её
> усовершенствование. На время диалогов ввода и на время заведомо
> длительных или непредсказуемых по времени выполнения операций хотелось
> бы не просто приостанавливать отчёт таймера rootdelay, но и возобновлять
> его отсчёт, а не просто сбрасывать. Сейчас я его просто сбрасываю, так
> тоже работает, но это конечно увеличивает суммарный (фактический)
> rootdelay.
Сейчас приходится делать так:
rootdelay_reset_timer
rootdelay_unpause
То есть, возобновлять отсчёт таймера с самого начала, поскольку дедлайн
сам не поменяется. Ожидаемое поведение для rootdelay_unpause (или её
аналогу): продолжить отсчёт с того же места, где он был приостановлен.
Если при остановке подсчёта до таймаута оставалось 30 секунд, а не 180,
тогда функция должна переустановить дедлайн таким образом, чтобы до него
осталось только 30 секунд, причём сама. Поскольку сейчас реализация
отталкивается от дедлайна, а не подсчёта фактически затраченного
времени. Иначе при текущей реализации придётся возложить арифметику по
пересчёту нового дедлайна на каждого пользователя
rootdelay_reset_timer(), а это вообще-то внутренний механизм рантайма.
--
WBR, Leonid Krivoshein.
^ permalink raw reply [flat|nested] 47+ messages in thread
* [make-initrd] [PATCH] runtime: Freeze rootdelay countdown while paused
2026-10-20 19:23 ` [make-initrd] Уточнение по rootdelay_unpause() Leonid Krivoshein
@ 2026-10-21 10:10 ` Alexey Gladkov
0 siblings, 0 replies; 47+ messages in thread
From: Alexey Gladkov @ 2026-10-21 10:10 UTC (permalink / raw)
To: make-initrd
The rootdelay service tracks device discovery timeouts against an
absolute deadline timestamp. When rootdelay_pause is invoked (e.g.,
during fsck filesystem checks), the deadline was left unchanged while
boottime continued to advance. When unpaused, the time spent waiting on
the blocking operation was counted against the rootdelay allowance,
often causing the timeout to expire immediately.
Fix this by recording the timestamp when pausing and shifting the
deadline forward by the elapsed pause duration upon unpause. Atomic
mkdir and directory renaming are used to eliminate time-of-check to
time-of-use races between concurrent callers. If the timer is reset
while paused, advance the recorded pause start timestamp to prevent
adding duplicate time.
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
Ты имеешь в виду что-то типа вот такого поведения ?
---
features/runtime/data/bin/initrd-sh-functions | 59 ++++++++++++++++---
features/runtime/data/sbin/rootdelayd | 4 +-
2 files changed, 54 insertions(+), 9 deletions(-)
diff --git a/features/runtime/data/bin/initrd-sh-functions b/features/runtime/data/bin/initrd-sh-functions
index a69eabee..be8d7182 100644
--- a/features/runtime/data/bin/initrd-sh-functions
+++ b/features/runtime/data/bin/initrd-sh-functions
@@ -126,17 +126,57 @@ write_atomic()
fi
}
-_rootdelay_pause=/.initrd/rootdelay/pause
-_rootdelay_timestamp=/.initrd/rootdelay/deadline
+current_seconds()
+{
+ local __v=
+ __v="$("${TIMESTAMP:-timestamp}" boottime raw 2>/dev/null)" ||:
+ __v="${__v%.*}"
+ eval "$1=\"\$__v\""
+}
+
+_rootdelay_pause="${_rootdelay_pause:-/.initrd/rootdelay/pause}"
+_rootdelay_timestamp="${_rootdelay_timestamp:-/.initrd/rootdelay/deadline}"
rootdelay_pause()
{
- mkdir -p "$_rootdelay_pause"
+ local now
+
+ mkdir -p -- "${_rootdelay_pause%/*}"
+ if ! mkdir "$_rootdelay_pause" 2>/dev/null; then
+ return 0
+ fi
+
+ current_seconds now
+ write_atomic "$_rootdelay_pause/start" printf '%s\n' "$now"
}
rootdelay_unpause()
{
- rm -rf "$_rootdelay_pause"
+ local pause_dir="$_rootdelay_pause.$$.$BASHPID"
+ local pause_start now paused_duration deadline
+
+ if ! mv "$_rootdelay_pause" "$pause_dir" 2>/dev/null; then
+ return 0
+ fi
+
+ if [ -f "$pause_dir/start" ]; then
+ readline pause_start "$pause_dir/start"
+
+ if [ -n "$pause_start" ] && [ -f "$_rootdelay_timestamp" ]; then
+ current_seconds now
+ paused_duration=$(( $now - $pause_start ))
+
+ if [ "$paused_duration" -gt 0 ]; then
+ readline deadline "$_rootdelay_timestamp"
+
+ if [ -n "$deadline" ] && [ "$deadline" -gt 0 ]; then
+ rootdelay_set_deadline "$(( $deadline + $paused_duration ))"
+ fi
+ fi
+ fi
+ fi
+
+ rm -rf "$pause_dir"
}
rootdelay_paused()
@@ -153,11 +193,16 @@ rootdelay_set_deadline()
rootdelay_reset_timer()
{
local now="${1-}"
+
if [ -z "$now" ]; then
- now="$(timestamp boottime raw)"
- now="${now%.*}"
+ current_seconds now
+ fi
+
+ rootdelay_set_deadline "$(( $now + ${ROOTDELAY:-0} ))"
+
+ if [ -f "$_rootdelay_pause/start" ]; then
+ write_atomic "$_rootdelay_pause/start" printf '%s\n' "$now"
fi
- rootdelay_set_deadline "$(( $now + $ROOTDELAY ))"
}
initrd_features=/.initrd/features
diff --git a/features/runtime/data/sbin/rootdelayd b/features/runtime/data/sbin/rootdelayd
index 5fa21f07..4b11e5a4 100755
--- a/features/runtime/data/sbin/rootdelayd
+++ b/features/runtime/data/sbin/rootdelayd
@@ -71,9 +71,9 @@ while :; do
continue
fi
+ current_seconds now
+
first_iter=
- now="$(timestamp boottime raw)"
- now="${now%.*}"
consmsg="/.initrd/rootdelay/message"
if [ ! -f "$_rootdelay_timestamp" ]; then
--
2.56.0
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [make-initrd] [PATCH v2 00/11] Improve support for atomic actions
2026-10-20 19:04 ` Leonid Krivoshein
2026-10-20 19:23 ` [make-initrd] Уточнение по rootdelay_unpause() Leonid Krivoshein
@ 2026-10-21 7:18 ` Alexey Gladkov
2026-10-21 8:50 ` Leonid Krivoshein
1 sibling, 1 reply; 47+ messages in thread
From: Alexey Gladkov @ 2026-10-21 7:18 UTC (permalink / raw)
To: make-initrd
On Tue, Oct 20, 2026 at 10:04:56PM +0300, Leonid Krivoshein wrote:
> Было бы здорово иметь одно место в документации, где будут перечислены все
> файлы, доступ к которым требует блокировок. Например, из этих коммитов я
> узнал, что следует блокировать доступ на запись в /.initrd/initenv.
> Инклюдить его можно по-прежнему без блокировки благодаря атомарному
> обновлению, если я правильно понял.
Сейчас с твоей подачи такой список стал организовываться в
features/runtime/data/bin/initrd-sh-functions вместе с API для блокировок.
Документация у нас в Documentation/ или ты про какую-то другую ?
> Другой момент с этими коммитами не связан, но давно напрашивался. В v2.36.0
> была добавлена rootdelay_reset_timer(), здесь проскочило её
> усовершенствование. На время диалогов ввода и на время заведомо длительных
> или непредсказуемых по времени выполнения операций хотелось бы не просто
> приостанавливать отчёт таймера rootdelay, но и возобновлять его отсчёт, а не
> просто сбрасывать. Сейчас я его просто сбрасываю, так тоже работает, но это
> конечно увеличивает суммарный (фактический) rootdelay.
Почему на время диалогов ты не хочешь сделать rootdelay_pause ?
Поставить rootdelay на паузу для диалогов мне кажется правильной идеей. Я
паузу как раз для этого использую в fsck и kickstart. Для последнего
rootdelay отключается по сути вообще.
>
> > >
> > > >
> > > > Alexey Gladkov (10):
> > > > runtime: Fix console lock shadowing by /dev mount
> > > > runtime: Avoid leaking lock descriptor 90 to child processes
> > > > runtime: Replace /.initrd/initenv locking with atomic file update
> > > > runtime: Centralize file and console locking helpers
> > > > create-rootfs: Require bash 4.1 or newer for initramfs
> > > > network: Share DHCP hook lock between IPv4 and IPv6 on the same
> > > > interface
> > > > luks: Serialize /etc/luks.keys updates and avoid duplicate entries
> > > > runtime: Synchronize concurrent /etc/fstab access with shared and
> > > > exclusive locks
> > > > runtime: Update rootdelay deadline and failure message atomically
> > > > runtime: Centralize atomic file replacement in write_atomic helper
> > > >
> > > > Egor Shestakov (1):
> > > > runtime: Fix a lock leak in rootdelayd
> > > >
> > > > .../uevent/handlers/btrfs-member/100-timeout | 4 +-
> > > > .../data/lib/uevent/handlers/040-mountdev | 19 +--
> > > > .../luks/data/lib/uevent/filters/lukskeys | 49 +++---
> > > > .../luks/data/lib/uevent/handlers/085-luks | 33 ++--
> > > > .../network/data/bin/network-sh-functions | 1 +
> > > > .../network/data/etc/rc.d/init.d/network-up | 3 -
> > > > features/network/data/lib/network/hostname | 18 ++-
> > > > features/network/data/lib/network/resolvconf | 84 +++++-----
> > > > .../network/data/lib/network/udhcpc4.script | 90 +++++------
> > > > features/runtime/data/bin/initrd-sh-functions | 123 ++++++++++++++-
> > > > features/runtime/data/etc/rc.d/init.d/cmdline | 6 +-
> > > > features/runtime/data/etc/rc.d/init.d/fstab | 4 +-
> > > > features/runtime/data/etc/rc.d/rc | 148 +++++++++---------
> > > > features/runtime/data/init | 2 +
> > > > .../data/lib/initrd/post/fstab/mountsrc | 61 ++++----
> > > > .../runtime/data/lib/uevent/filters/mountdev | 71 +++++----
> > > > .../lib/uevent/handlers/mount/900-localdev | 39 +++--
> > > > features/runtime/data/sbin/rootdelayd | 74 ++++-----
> > > > .../data/lib/uevent/handlers/040-sshfsroot | 26 ++-
> > > > features/zfs/data/lib/initrd/post/fstab/zfs | 105 +++++++------
> > > > features/zfs/data/sbin/ueventd-zfs | 21 ++-
> > > > .../tests/ts0044-member-timeout-queue-api/run | 2 +
> > > > tools/create-rootfs | 2 +
> > > > 23 files changed, 566 insertions(+), 419 deletions(-)
> > > >
> > >
> > > --
> > > WBR, Leonid Krivoshein.
> > >
> > > _______________________________________________
> > > Make-initrd mailing list
> > > Make-initrd@lists.altlinux.org
> > > https://lists.altlinux.org/mailman/listinfo/make-initrd
> >
>
> --
> WBR, Leonid Krivoshein.
>
> _______________________________________________
> Make-initrd mailing list
> Make-initrd@lists.altlinux.org
> https://lists.altlinux.org/mailman/listinfo/make-initrd
--
Rgrds, legion
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [make-initrd] [PATCH v2 00/11] Improve support for atomic actions
2026-10-21 7:18 ` [make-initrd] [PATCH v2 00/11] Improve support for atomic actions Alexey Gladkov
@ 2026-10-21 8:50 ` Leonid Krivoshein
2026-10-21 10:18 ` Alexey Gladkov
0 siblings, 1 reply; 47+ messages in thread
From: Leonid Krivoshein @ 2026-10-21 8:50 UTC (permalink / raw)
To: make-initrd
On 10/21/26 10:18 AM, Alexey Gladkov wrote:
> On Tue, Oct 20, 2026 at 10:04:56PM +0300, Leonid Krivoshein wrote:
>> Было бы здорово иметь одно место в документации, где будут перечислены все
>> файлы, доступ к которым требует блокировок. Например, из этих коммитов я
>> узнал, что следует блокировать доступ на запись в /.initrd/initenv.
>> Инклюдить его можно по-прежнему без блокировки благодаря атомарному
>> обновлению, если я правильно понял.
>
> Сейчас с твоей подачи такой список стал организовываться в
> features/runtime/data/bin/initrd-sh-functions вместе с API для блокировок.
>
Отлично, спасибо!
> Документация у нас в Documentation/ или ты про какую-то другую ?
>
Про неё, да. Про список вида ресурс (тип блокировки) и файл блокировки.
И раз уж заглянул... по-моему, проще так:
get_majmin()
{
mountpoint -x -- "$1" 2>/dev/null
}
результат будет аналогичным.
>> Другой момент с этими коммитами не связан, но давно напрашивался. В v2.36.0
>> была добавлена rootdelay_reset_timer(), здесь проскочило её
>> усовершенствование. На время диалогов ввода и на время заведомо длительных
>> или непредсказуемых по времени выполнения операций хотелось бы не просто
>> приостанавливать отчёт таймера rootdelay, но и возобновлять его отсчёт, а не
>> просто сбрасывать. Сейчас я его просто сбрасываю, так тоже работает, но это
>> конечно увеличивает суммарный (фактический) rootdelay.
>
> Почему на время диалогов ты не хочешь сделать rootdelay_pause ?
>
Как раз делаю.
> Поставить rootdelay на паузу для диалогов мне кажется правильной идеей. Я
> паузу как раз для этого использую в fsck и kickstart. Для последнего
> rootdelay отключается по сути вообще.
>
Раньше тоже так делал. Если что-то пошло не так, мы не увидим ни stage2,
ни отладочного rdshell. Поэтому сейчас сделаны две вещи: 1) таймаут
отключается только на время длительных операций, диалогов, а после
rootdelay перезапускается, 2) при фатальном выходе chaind устанавливает
дедлайн на now+2 секунды, чтобы поскорее попасть в rdshell.
Cпич о том, что текущая реализация отталкивается от сохранённого
дедлайна, а не учёта времени, потраченного на загрузку. В моём
понимании, rootdelay_pause() -- перестать расходовать rootdelay на
неопределённое время. Сейчас же получается, что после вызова
rootdelay_unpause() можно сразу схлопотать таймаут. Обойти можно сбросом
счётчика, но чтобы считалось правильно, необходимо добавлять арифметику
для расчёта нового дедлайна, чего бы не хотелось делать на стороне клиента.
>>
>>>>
>>>>>
>>>>> Alexey Gladkov (10):
>>>>> runtime: Fix console lock shadowing by /dev mount
>>>>> runtime: Avoid leaking lock descriptor 90 to child processes
>>>>> runtime: Replace /.initrd/initenv locking with atomic file update
>>>>> runtime: Centralize file and console locking helpers
>>>>> create-rootfs: Require bash 4.1 or newer for initramfs
>>>>> network: Share DHCP hook lock between IPv4 and IPv6 on the same
>>>>> interface
>>>>> luks: Serialize /etc/luks.keys updates and avoid duplicate entries
>>>>> runtime: Synchronize concurrent /etc/fstab access with shared and
>>>>> exclusive locks
>>>>> runtime: Update rootdelay deadline and failure message atomically
>>>>> runtime: Centralize atomic file replacement in write_atomic helper
>>>>>
>>>>> Egor Shestakov (1):
>>>>> runtime: Fix a lock leak in rootdelayd
>>>>>
>>>>> .../uevent/handlers/btrfs-member/100-timeout | 4 +-
>>>>> .../data/lib/uevent/handlers/040-mountdev | 19 +--
>>>>> .../luks/data/lib/uevent/filters/lukskeys | 49 +++---
>>>>> .../luks/data/lib/uevent/handlers/085-luks | 33 ++--
>>>>> .../network/data/bin/network-sh-functions | 1 +
>>>>> .../network/data/etc/rc.d/init.d/network-up | 3 -
>>>>> features/network/data/lib/network/hostname | 18 ++-
>>>>> features/network/data/lib/network/resolvconf | 84 +++++-----
>>>>> .../network/data/lib/network/udhcpc4.script | 90 +++++------
>>>>> features/runtime/data/bin/initrd-sh-functions | 123 ++++++++++++++-
>>>>> features/runtime/data/etc/rc.d/init.d/cmdline | 6 +-
>>>>> features/runtime/data/etc/rc.d/init.d/fstab | 4 +-
>>>>> features/runtime/data/etc/rc.d/rc | 148 +++++++++---------
>>>>> features/runtime/data/init | 2 +
>>>>> .../data/lib/initrd/post/fstab/mountsrc | 61 ++++----
>>>>> .../runtime/data/lib/uevent/filters/mountdev | 71 +++++----
>>>>> .../lib/uevent/handlers/mount/900-localdev | 39 +++--
>>>>> features/runtime/data/sbin/rootdelayd | 74 ++++-----
>>>>> .../data/lib/uevent/handlers/040-sshfsroot | 26 ++-
>>>>> features/zfs/data/lib/initrd/post/fstab/zfs | 105 +++++++------
>>>>> features/zfs/data/sbin/ueventd-zfs | 21 ++-
>>>>> .../tests/ts0044-member-timeout-queue-api/run | 2 +
>>>>> tools/create-rootfs | 2 +
>>>>> 23 files changed, 566 insertions(+), 419 deletions(-)
>>>>>
>>>>
>>>> --
>>>> WBR, Leonid Krivoshein.
>>>>
>>>> _______________________________________________
>>>> Make-initrd mailing list
>>>> Make-initrd@lists.altlinux.org
>>>> https://lists.altlinux.org/mailman/listinfo/make-initrd
>>>
>>
>> --
>> WBR, Leonid Krivoshein.
>>
>> _______________________________________________
>> Make-initrd mailing list
>> Make-initrd@lists.altlinux.org
>> https://lists.altlinux.org/mailman/listinfo/make-initrd
>
--
WBR, Leonid Krivoshein.
^ permalink raw reply [flat|nested] 47+ messages in thread* Re: [make-initrd] [PATCH v2 00/11] Improve support for atomic actions
2026-10-21 8:50 ` Leonid Krivoshein
@ 2026-10-21 10:18 ` Alexey Gladkov
2026-10-21 18:52 ` Leonid Krivoshein
0 siblings, 1 reply; 47+ messages in thread
From: Alexey Gladkov @ 2026-10-21 10:18 UTC (permalink / raw)
To: make-initrd
On Wed, Oct 21, 2026 at 11:50:15AM +0300, Leonid Krivoshein wrote:
>
> On 10/21/26 10:18 AM, Alexey Gladkov wrote:
> > On Tue, Oct 20, 2026 at 10:04:56PM +0300, Leonid Krivoshein wrote:
> > > Было бы здорово иметь одно место в документации, где будут перечислены все
> > > файлы, доступ к которым требует блокировок. Например, из этих коммитов я
> > > узнал, что следует блокировать доступ на запись в /.initrd/initenv.
> > > Инклюдить его можно по-прежнему без блокировки благодаря атомарному
> > > обновлению, если я правильно понял.
> >
> > Сейчас с твоей подачи такой список стал организовываться в
> > features/runtime/data/bin/initrd-sh-functions вместе с API для блокировок.
> >
>
> Отлично, спасибо!
>
>
> > Документация у нас в Documentation/ или ты про какую-то другую ?
> >
>
> Про неё, да. Про список вида ресурс (тип блокировки) и файл блокировки.
Кто-нибудь может сделать такую документацию ? :)
> И раз уж заглянул... по-моему, проще так:
>
> get_majmin()
> {
> mountpoint -x -- "$1" 2>/dev/null
> }
>
> результат будет аналогичным.
Этой функции очень много лет. Она появилась до того как в образе появился
mountpoint. Но да, твой код проще.
>
> > > Другой момент с этими коммитами не связан, но давно напрашивался. В v2.36.0
> > > была добавлена rootdelay_reset_timer(), здесь проскочило её
> > > усовершенствование. На время диалогов ввода и на время заведомо длительных
> > > или непредсказуемых по времени выполнения операций хотелось бы не просто
> > > приостанавливать отчёт таймера rootdelay, но и возобновлять его отсчёт, а не
> > > просто сбрасывать. Сейчас я его просто сбрасываю, так тоже работает, но это
> > > конечно увеличивает суммарный (фактический) rootdelay.
> >
> > Почему на время диалогов ты не хочешь сделать rootdelay_pause ?
> >
>
> Как раз делаю.
>
>
> > Поставить rootdelay на паузу для диалогов мне кажется правильной идеей. Я
> > паузу как раз для этого использую в fsck и kickstart. Для последнего
> > rootdelay отключается по сути вообще.
> >
>
> Раньше тоже так делал. Если что-то пошло не так, мы не увидим ни stage2, ни
> отладочного rdshell. Поэтому сейчас сделаны две вещи: 1) таймаут отключается
> только на время длительных операций, диалогов, а после rootdelay
> перезапускается, 2) при фатальном выходе chaind устанавливает дедлайн на
> now+2 секунды, чтобы поскорее попасть в rdshell.
>
> Cпич о том, что текущая реализация отталкивается от сохранённого дедлайна, а
> не учёта времени, потраченного на загрузку. В моём понимании,
> rootdelay_pause() -- перестать расходовать rootdelay на неопределённое
> время. Сейчас же получается, что после вызова rootdelay_unpause() можно
> сразу схлопотать таймаут. Обойти можно сбросом счётчика, но чтобы считалось
> правильно, необходимо добавлять арифметику для расчёта нового дедлайна, чего
> бы не хотелось делать на стороне клиента.
Предлагаемый патч в соседней ветке. Посмотри пожалуйста.
--
Rgrds, legion
^ permalink raw reply [flat|nested] 47+ messages in thread* Re: [make-initrd] [PATCH v2 00/11] Improve support for atomic actions
2026-10-21 10:18 ` Alexey Gladkov
@ 2026-10-21 18:52 ` Leonid Krivoshein
2026-10-21 19:30 ` Alexey Gladkov
2026-10-21 19:31 ` Leonid Krivoshein
0 siblings, 2 replies; 47+ messages in thread
From: Leonid Krivoshein @ 2026-10-21 18:52 UTC (permalink / raw)
To: make-initrd
On 10/21/26 1:18 PM, Alexey Gladkov wrote:
> On Wed, Oct 21, 2026 at 11:50:15AM +0300, Leonid Krivoshein wrote:
>>
>> On 10/21/26 10:18 AM, Alexey Gladkov wrote:
>>> On Tue, Oct 20, 2026 at 10:04:56PM +0300, Leonid Krivoshein wrote:
>>>> Было бы здорово иметь одно место в документации, где будут перечислены все
>>>> файлы, доступ к которым требует блокировок. Например, из этих коммитов я
>>>> узнал, что следует блокировать доступ на запись в /.initrd/initenv.
>>>> Инклюдить его можно по-прежнему без блокировки благодаря атомарному
>>>> обновлению, если я правильно понял.
>>>
>>> Сейчас с твоей подачи такой список стал организовываться в
>>> features/runtime/data/bin/initrd-sh-functions вместе с API для блокировок.
>>>
>>
>> Отлично, спасибо!
>>
>>
>>> Документация у нас в Documentation/ или ты про какую-то другую ?
>>>
>>
>> Про неё, да. Про список вида ресурс (тип блокировки) и файл блокировки.
>
> Кто-нибудь может сделать такую документацию ? :)
>
Наверное, да. Только сейчас работаю над значительным улучшением и
документированием bootchain/altboot.
>> И раз уж заглянул... по-моему, проще так:
>>
>> get_majmin()
>> {
>> mountpoint -x -- "$1" 2>/dev/null
>> }
>>
>> результат будет аналогичным.
>
> Этой функции очень много лет. Она появилась до того как в образе появился
> mountpoint. Но да, твой код проще.
>
Можно использовать, раз уж появился, я давно использую.
>>
>>>> Другой момент с этими коммитами не связан, но давно напрашивался. В v2.36.0
>>>> была добавлена rootdelay_reset_timer(), здесь проскочило её
>>>> усовершенствование. На время диалогов ввода и на время заведомо длительных
>>>> или непредсказуемых по времени выполнения операций хотелось бы не просто
>>>> приостанавливать отчёт таймера rootdelay, но и возобновлять его отсчёт, а не
>>>> просто сбрасывать. Сейчас я его просто сбрасываю, так тоже работает, но это
>>>> конечно увеличивает суммарный (фактический) rootdelay.
>>>
>>> Почему на время диалогов ты не хочешь сделать rootdelay_pause ?
>>>
>>
>> Как раз делаю.
>>
>>
>>> Поставить rootdelay на паузу для диалогов мне кажется правильной идеей. Я
>>> паузу как раз для этого использую в fsck и kickstart. Для последнего
>>> rootdelay отключается по сути вообще.
>>>
>>
>> Раньше тоже так делал. Если что-то пошло не так, мы не увидим ни stage2, ни
>> отладочного rdshell. Поэтому сейчас сделаны две вещи: 1) таймаут отключается
>> только на время длительных операций, диалогов, а после rootdelay
>> перезапускается, 2) при фатальном выходе chaind устанавливает дедлайн на
>> now+2 секунды, чтобы поскорее попасть в rdshell.
>>
>> Cпич о том, что текущая реализация отталкивается от сохранённого дедлайна, а
>> не учёта времени, потраченного на загрузку. В моём понимании,
>> rootdelay_pause() -- перестать расходовать rootdelay на неопределённое
>> время. Сейчас же получается, что после вызова rootdelay_unpause() можно
>> сразу схлопотать таймаут. Обойти можно сбросом счётчика, но чтобы считалось
>> правильно, необходимо добавлять арифметику для расчёта нового дедлайна, чего
>> бы не хотелось делать на стороне клиента.
>
> Предлагаемый патч в соседней ветке. Посмотри пожалуйста.
>
Посмотрел. Да, что-то вроде того. Потому что всегда по факту были
rootdelayd_pause() и rootdelayd_unpause(), а теперь как надо, без буквы
d на конце. :-) Приостанавливалась реакция демона, а не отсчёт таймера.
> If the timer is reset while paused, advance the recorded pause start
timestamp to prevent adding duplicate time.
А как теперь будет работать следующий код если до окончания загрузки
перед его вызовом оставалось 30 секунд?
rootdelay_reset_timer
rootdelay_unpause
По идее, пользователю должны добавить 180 секунд на загрузку, верно?
Можно ещё глянуть эти пару функций (longtermop_start и longtermop_end)
[1] и весь патч [2] на предмет взаимодействия с make-initrd rootdelay
из-вне -- здесь учитывается вложенность вызовов. Такая обёртка меня
вполне устраивает, т.е. на стороне make-initrd вложенность можно не
учитывать. Позже переделаю их с учётом атомарности.
1.
https://github.com/klark973/make-initrd-bootchain/blob/sisyphus/bootchain-core/data/bin/bootchain-sh-functions#L200
2.
https://github.com/klark973/make-initrd-bootchain/commit/8d3407240c214eee86b5421210b46ba4577da559
--
WBR, Leonid Krivoshein.
^ permalink raw reply [flat|nested] 47+ messages in thread* Re: [make-initrd] [PATCH v2 00/11] Improve support for atomic actions
2026-10-21 18:52 ` Leonid Krivoshein
@ 2026-10-21 19:30 ` Alexey Gladkov
2026-10-21 19:33 ` Leonid Krivoshein
2026-10-21 19:31 ` Leonid Krivoshein
1 sibling, 1 reply; 47+ messages in thread
From: Alexey Gladkov @ 2026-10-21 19:30 UTC (permalink / raw)
To: make-initrd
On Wed, Oct 21, 2026 at 09:52:39PM +0300, Leonid Krivoshein wrote:
> > > > Документация у нас в Documentation/ или ты про какую-то другую ?
> > > >
> > >
> > > Про неё, да. Про список вида ресурс (тип блокировки) и файл блокировки.
> >
> > Кто-нибудь может сделать такую документацию ? :)
> >
>
> Наверное, да. Только сейчас работаю над значительным улучшением и
> документированием bootchain/altboot.
>
>
> > > И раз уж заглянул... по-моему, проще так:
> > >
> > > get_majmin()
> > > {
> > > mountpoint -x -- "$1" 2>/dev/null
> > > }
> > >
> > > результат будет аналогичным.
> >
> > Этой функции очень много лет. Она появилась до того как в образе появился
> > mountpoint. Но да, твой код проще.
> >
>
> Можно использовать, раз уж появился, я давно использую.
>
>
> > >
> > > > > Другой момент с этими коммитами не связан, но давно напрашивался. В v2.36.0
> > > > > была добавлена rootdelay_reset_timer(), здесь проскочило её
> > > > > усовершенствование. На время диалогов ввода и на время заведомо длительных
> > > > > или непредсказуемых по времени выполнения операций хотелось бы не просто
> > > > > приостанавливать отчёт таймера rootdelay, но и возобновлять его отсчёт, а не
> > > > > просто сбрасывать. Сейчас я его просто сбрасываю, так тоже работает, но это
> > > > > конечно увеличивает суммарный (фактический) rootdelay.
> > > >
> > > > Почему на время диалогов ты не хочешь сделать rootdelay_pause ?
> > > >
> > >
> > > Как раз делаю.
> > >
> > >
> > > > Поставить rootdelay на паузу для диалогов мне кажется правильной идеей. Я
> > > > паузу как раз для этого использую в fsck и kickstart. Для последнего
> > > > rootdelay отключается по сути вообще.
> > > >
> > >
> > > Раньше тоже так делал. Если что-то пошло не так, мы не увидим ни stage2, ни
> > > отладочного rdshell. Поэтому сейчас сделаны две вещи: 1) таймаут отключается
> > > только на время длительных операций, диалогов, а после rootdelay
> > > перезапускается, 2) при фатальном выходе chaind устанавливает дедлайн на
> > > now+2 секунды, чтобы поскорее попасть в rdshell.
> > >
> > > Cпич о том, что текущая реализация отталкивается от сохранённого дедлайна, а
> > > не учёта времени, потраченного на загрузку. В моём понимании,
> > > rootdelay_pause() -- перестать расходовать rootdelay на неопределённое
> > > время. Сейчас же получается, что после вызова rootdelay_unpause() можно
> > > сразу схлопотать таймаут. Обойти можно сбросом счётчика, но чтобы считалось
> > > правильно, необходимо добавлять арифметику для расчёта нового дедлайна, чего
> > > бы не хотелось делать на стороне клиента.
> >
> > Предлагаемый патч в соседней ветке. Посмотри пожалуйста.
> >
>
> Посмотрел. Да, что-то вроде того. Потому что всегда по факту были
> rootdelayd_pause() и rootdelayd_unpause(), а теперь как надо, без буквы d на
> конце. :-) Приостанавливалась реакция демона, а не отсчёт таймера.
>
> > If the timer is reset while paused, advance the recorded pause start
> timestamp to prevent adding duplicate time.
>
> А как теперь будет работать следующий код если до окончания загрузки перед
> его вызовом оставалось 30 секунд?
>
> rootdelay_reset_timer
> rootdelay_unpause
>
> По идее, пользователю должны добавить 180 секунд на загрузку, верно?
Кажется моя реализация может накинуть времени пользователю в 1-2 секунды.
Нужно поправить.
> Можно ещё глянуть эти пару функций (longtermop_start и longtermop_end) [1] и
> весь патч [2] на предмет взаимодействия с make-initrd rootdelay из-вне --
> здесь учитывается вложенность вызовов. Такая обёртка меня вполне устраивает,
> т.е. на стороне make-initrd вложенность можно не учитывать. Позже переделаю
> их с учётом атомарности.
>
>
> 1. https://github.com/klark973/make-initrd-bootchain/blob/sisyphus/bootchain-core/data/bin/bootchain-sh-functions#L200
> 2. https://github.com/klark973/make-initrd-bootchain/commit/8d3407240c214eee86b5421210b46ba4577da559
>
>
> --
> WBR, Leonid Krivoshein.
>
> _______________________________________________
> Make-initrd mailing list
> Make-initrd@lists.altlinux.org
> https://lists.altlinux.org/mailman/listinfo/make-initrd
--
Rgrds, legion
^ permalink raw reply [flat|nested] 47+ messages in thread* Re: [make-initrd] [PATCH v2 00/11] Improve support for atomic actions
2026-10-21 19:30 ` Alexey Gladkov
@ 2026-10-21 19:33 ` Leonid Krivoshein
0 siblings, 0 replies; 47+ messages in thread
From: Leonid Krivoshein @ 2026-10-21 19:33 UTC (permalink / raw)
To: make-initrd
On 10/21/26 10:30 PM, Alexey Gladkov wrote:
> On Wed, Oct 21, 2026 at 09:52:39PM +0300, Leonid Krivoshein wrote:
>>>>> Документация у нас в Documentation/ или ты про какую-то другую ?
>>>>>
>>>>
>>>> Про неё, да. Про список вида ресурс (тип блокировки) и файл блокировки.
>>>
>>> Кто-нибудь может сделать такую документацию ? :)
>>>
>>
>> Наверное, да. Только сейчас работаю над значительным улучшением и
>> документированием bootchain/altboot.
>>
>>
>>>> И раз уж заглянул... по-моему, проще так:
>>>>
>>>> get_majmin()
>>>> {
>>>> mountpoint -x -- "$1" 2>/dev/null
>>>> }
>>>>
>>>> результат будет аналогичным.
>>>
>>> Этой функции очень много лет. Она появилась до того как в образе появился
>>> mountpoint. Но да, твой код проще.
>>>
>>
>> Можно использовать, раз уж появился, я давно использую.
>>
>>
>>>>
>>>>>> Другой момент с этими коммитами не связан, но давно напрашивался. В v2.36.0
>>>>>> была добавлена rootdelay_reset_timer(), здесь проскочило её
>>>>>> усовершенствование. На время диалогов ввода и на время заведомо длительных
>>>>>> или непредсказуемых по времени выполнения операций хотелось бы не просто
>>>>>> приостанавливать отчёт таймера rootdelay, но и возобновлять его отсчёт, а не
>>>>>> просто сбрасывать. Сейчас я его просто сбрасываю, так тоже работает, но это
>>>>>> конечно увеличивает суммарный (фактический) rootdelay.
>>>>>
>>>>> Почему на время диалогов ты не хочешь сделать rootdelay_pause ?
>>>>>
>>>>
>>>> Как раз делаю.
>>>>
>>>>
>>>>> Поставить rootdelay на паузу для диалогов мне кажется правильной идеей. Я
>>>>> паузу как раз для этого использую в fsck и kickstart. Для последнего
>>>>> rootdelay отключается по сути вообще.
>>>>>
>>>>
>>>> Раньше тоже так делал. Если что-то пошло не так, мы не увидим ни stage2, ни
>>>> отладочного rdshell. Поэтому сейчас сделаны две вещи: 1) таймаут отключается
>>>> только на время длительных операций, диалогов, а после rootdelay
>>>> перезапускается, 2) при фатальном выходе chaind устанавливает дедлайн на
>>>> now+2 секунды, чтобы поскорее попасть в rdshell.
>>>>
>>>> Cпич о том, что текущая реализация отталкивается от сохранённого дедлайна, а
>>>> не учёта времени, потраченного на загрузку. В моём понимании,
>>>> rootdelay_pause() -- перестать расходовать rootdelay на неопределённое
>>>> время. Сейчас же получается, что после вызова rootdelay_unpause() можно
>>>> сразу схлопотать таймаут. Обойти можно сбросом счётчика, но чтобы считалось
>>>> правильно, необходимо добавлять арифметику для расчёта нового дедлайна, чего
>>>> бы не хотелось делать на стороне клиента.
>>>
>>> Предлагаемый патч в соседней ветке. Посмотри пожалуйста.
>>>
>>
>> Посмотрел. Да, что-то вроде того. Потому что всегда по факту были
>> rootdelayd_pause() и rootdelayd_unpause(), а теперь как надо, без буквы d на
>> конце. :-) Приостанавливалась реакция демона, а не отсчёт таймера.
>>
>>> If the timer is reset while paused, advance the recorded pause start
>> timestamp to prevent adding duplicate time.
>>
>> А как теперь будет работать следующий код если до окончания загрузки перед
>> его вызовом оставалось 30 секунд?
>>
>> rootdelay_reset_timer
>> rootdelay_unpause
>>
>> По идее, пользователю должны добавить 180 секунд на загрузку, верно?
>
> Кажется моя реализация может накинуть времени пользователю в 1-2 секунды.
> Нужно поправить.
>
Я добавлял две секунды как раз с учётом того, что для расчёта
выполнялось округление до целых.
>> Можно ещё глянуть эти пару функций (longtermop_start и longtermop_end) [1] и
>> весь патч [2] на предмет взаимодействия с make-initrd rootdelay из-вне --
>> здесь учитывается вложенность вызовов. Такая обёртка меня вполне устраивает,
>> т.е. на стороне make-initrd вложенность можно не учитывать. Позже переделаю
>> их с учётом атомарности.
>>
>>
>> 1. https://github.com/klark973/make-initrd-bootchain/blob/sisyphus/bootchain-core/data/bin/bootchain-sh-functions#L200
>> 2. https://github.com/klark973/make-initrd-bootchain/commit/8d3407240c214eee86b5421210b46ba4577da559
>>
>>
>> --
>> WBR, Leonid Krivoshein.
>>
>> _______________________________________________
>> Make-initrd mailing list
>> Make-initrd@lists.altlinux.org
>> https://lists.altlinux.org/mailman/listinfo/make-initrd
>
--
WBR, Leonid Krivoshein.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [make-initrd] [PATCH v2 00/11] Improve support for atomic actions
2026-10-21 18:52 ` Leonid Krivoshein
2026-10-21 19:30 ` Alexey Gladkov
@ 2026-10-21 19:31 ` Leonid Krivoshein
2026-10-21 20:03 ` Alexey Gladkov
1 sibling, 1 reply; 47+ messages in thread
From: Leonid Krivoshein @ 2026-10-21 19:31 UTC (permalink / raw)
To: make-initrd
On 10/21/26 9:52 PM, Leonid Krivoshein wrote:
> Можно ещё глянуть эти пару функций (longtermop_start и longtermop_end)
> [1] и весь патч [2] на предмет взаимодействия с make-initrd rootdelay
> из-вне -- здесь учитывается вложенность вызовов. Такая обёртка меня
> вполне устраивает, т.е. на стороне make-initrd вложенность можно не
> учитывать. Позже переделаю их с учётом атомарности.
>
Впрочем, на мой взгляд, в самом make-initrd реализация
rootdelay_pause/rootdelay_unpause *ТОЛЬКО* с подсчётом вызовов было бы
весьма здравой идеей, поскольку предсказать, какой модуль и в какой
момент что из этого вызовет заранее невозможно. Приостанавливать таймер
нужно только при первом вызове rootdelay_pause(), а возобновлять его
работу только при последнем вызове rootdelay_unpause(). Тогда и
оборачивать не придётся. Без этого, как мне кажется, оно уже и сейчас
будет не правильно рассчитывать оставшийся таймаут с несколькими
параллельно работающими пользователями этих функций.
>
> 1. https://github.com/klark973/make-initrd-bootchain/blob/sisyphus/
> bootchain-core/data/bin/bootchain-sh-functions#L200
> 2. https://github.com/klark973/make-initrd-bootchain/
> commit/8d3407240c214eee86b5421210b46ba4577da559
--
WBR, Leonid Krivoshein.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [make-initrd] [PATCH v2 00/11] Improve support for atomic actions
2026-10-21 19:31 ` Leonid Krivoshein
@ 2026-10-21 20:03 ` Alexey Gladkov
2026-10-21 20:48 ` Leonid Krivoshein
0 siblings, 1 reply; 47+ messages in thread
From: Alexey Gladkov @ 2026-10-21 20:03 UTC (permalink / raw)
To: make-initrd
On Wed, Oct 21, 2026 at 10:31:55PM +0300, Leonid Krivoshein wrote:
>
> On 10/21/26 9:52 PM, Leonid Krivoshein wrote:
> > Можно ещё глянуть эти пару функций (longtermop_start и longtermop_end)
> > [1] и весь патч [2] на предмет взаимодействия с make-initrd rootdelay
> > из-вне -- здесь учитывается вложенность вызовов. Такая обёртка меня
> > вполне устраивает, т.е. на стороне make-initrd вложенность можно не
> > учитывать. Позже переделаю их с учётом атомарности.
> >
>
> Впрочем, на мой взгляд, в самом make-initrd реализация
> rootdelay_pause/rootdelay_unpause *ТОЛЬКО* с подсчётом вызовов было бы
> весьма здравой идеей, поскольку предсказать, какой модуль и в какой момент
> что из этого вызовет заранее невозможно. Приостанавливать таймер нужно
> только при первом вызове rootdelay_pause(), а возобновлять его работу только
> при последнем вызове rootdelay_unpause(). Тогда и оборачивать не придётся.
> Без этого, как мне кажется, оно уже и сейчас будет не правильно рассчитывать
> оставшийся таймаут с несколькими параллельно работающими пользователями этих
> функций.
Ну в целом да. rootdelay_pause / rootdelay_unpause в текущем виде это не
тот API, который избавит от коллизий и гонок. Чтобы избавиться от гонок
нужен fd_lock.
rootdelay_* функции пусть остаются как API именно для взаимодействия с
rootdelayd. Синхронизацию пользователей пусть делает API выше.
--
Rgrds, legion
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [make-initrd] [PATCH v2 00/11] Improve support for atomic actions
2026-10-21 20:03 ` Alexey Gladkov
@ 2026-10-21 20:48 ` Leonid Krivoshein
0 siblings, 0 replies; 47+ messages in thread
From: Leonid Krivoshein @ 2026-10-21 20:48 UTC (permalink / raw)
To: make-initrd
On 10/21/26 11:03 PM, Alexey Gladkov wrote:
> On Wed, Oct 21, 2026 at 10:31:55PM +0300, Leonid Krivoshein wrote:
>>
>> On 10/21/26 9:52 PM, Leonid Krivoshein wrote:
>>> Можно ещё глянуть эти пару функций (longtermop_start и longtermop_end)
>>> [1] и весь патч [2] на предмет взаимодействия с make-initrd rootdelay
>>> из-вне -- здесь учитывается вложенность вызовов. Такая обёртка меня
>>> вполне устраивает, т.е. на стороне make-initrd вложенность можно не
>>> учитывать. Позже переделаю их с учётом атомарности.
>>>
>>
>> Впрочем, на мой взгляд, в самом make-initrd реализация
>> rootdelay_pause/rootdelay_unpause *ТОЛЬКО* с подсчётом вызовов было бы
>> весьма здравой идеей, поскольку предсказать, какой модуль и в какой момент
>> что из этого вызовет заранее невозможно. Приостанавливать таймер нужно
>> только при первом вызове rootdelay_pause(), а возобновлять его работу только
>> при последнем вызове rootdelay_unpause(). Тогда и оборачивать не придётся.
>> Без этого, как мне кажется, оно уже и сейчас будет не правильно рассчитывать
>> оставшийся таймаут с несколькими параллельно работающими пользователями этих
>> функций.
>
> Ну в целом да. rootdelay_pause / rootdelay_unpause в текущем виде это не
> тот API, который избавит от коллизий и гонок. Чтобы избавиться от гонок
> нужен fd_lock.
>
> rootdelay_* функции пусть остаются как API именно для взаимодействия с
> rootdelayd. Синхронизацию пользователей пусть делает API выше.
>
Обёртка решает проблему только в пределах единой группы модулей. Но, как
я пояснил выше, оборачивать имеет смысл глобально, так как разные модули
могут не знать ничего друг о друге, не догадываться, кто и когда вызовет
эти функции. Следовательно, уже сейчас из-за гонок вычисления могут быть
ошибочными, это глобальная проблема.
--
WBR, Leonid Krivoshein.
^ permalink raw reply [flat|nested] 47+ messages in thread