2016-04-12 12:48:00 +03:00
|
|
|
#!/bin/bash
|
|
|
|
#
|
|
|
|
# This script can be used as a workaround for systemd autofs mount migration.
|
|
|
|
# The problem is that systemd is a clever guy: before mounting of actual file
|
|
|
|
# system on top of autofs mount, it first checks that device number of autofs
|
|
|
|
# mount is equal to the one, stored in sytemd internals. If they do not match,
|
|
|
|
# systemd ignores kernel request.
|
|
|
|
# The problem happens each time autofs is restored (new device number for
|
|
|
|
# autofs superblock) and can't be properly solved without some kind of "device
|
|
|
|
# namespaces", where device number can be preseved.
|
|
|
|
# But some of systemd services can be painlessly restarted. Like
|
|
|
|
# proc-sys-fs-binfmt_misc.
|
|
|
|
#
|
|
|
|
# Usage:
|
|
|
|
# criu restore <options> --action-script $(pwd)/scripts/systemd-autofs-restart.sh
|
|
|
|
#
|
|
|
|
[ "$CRTOOLS_SCRIPT_ACTION" == "post-resume" ] || exit 0
|
|
|
|
|
2020-09-17 17:05:33 +00:00
|
|
|
if [ -z "$CRTOOLS_INIT_PID" ]; then
|
2016-04-12 12:48:00 +03:00
|
|
|
echo "CRTOOLS_INIT_PID environment variable is not set"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ ! -d "/proc/$CRTOOLS_INIT_PID" ]; then
|
|
|
|
echo "Process with CRTOOLS_INIT_PID=$CRTOOLS_INIT_PID doesn't exist"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
2016-04-15 19:32:00 +03:00
|
|
|
NS_ENTER=/bin/nsenter
|
2018-06-06 08:05:05 +00:00
|
|
|
[ ! -x $NS_ENTER ] || NS_ENTER=/usr/bin/nsenter
|
2016-04-12 12:48:00 +03:00
|
|
|
|
|
|
|
if [ ! -x $NS_ENTER ]; then
|
|
|
|
echo "$NS_ENTER binary not found"
|
|
|
|
exit 2
|
|
|
|
fi
|
|
|
|
|
2016-04-21 19:54:00 +03:00
|
|
|
JOIN_CT="$NS_ENTER -t $CRTOOLS_INIT_PID -m -u -p"
|
2016-04-12 12:48:00 +03:00
|
|
|
|
|
|
|
# Skip container, if it's not systemd based
|
2020-09-17 17:05:33 +00:00
|
|
|
[ "$($JOIN_CT basename -- "$($JOIN_CT readlink /proc/1/exe)")" == "systemd" ] || exit 0
|
2016-04-12 12:48:00 +03:00
|
|
|
|
|
|
|
AUTOFS_SERVICES="proc-sys-fs-binfmt_misc.automount"
|
|
|
|
|
2016-04-29 13:38:00 +03:00
|
|
|
bindmount=""
|
|
|
|
|
|
|
|
function remove_bindmount {
|
|
|
|
if [ -n "$bindmount" ]; then
|
2021-04-22 15:30:47 -07:00
|
|
|
$JOIN_CT umount "$bindmount"
|
|
|
|
$JOIN_CT rm -rf "$bindmount"
|
2016-04-29 13:38:00 +03:00
|
|
|
bindmount=""
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
trap remove_bindmount EXIT
|
|
|
|
|
2016-08-29 14:07:00 +03:00
|
|
|
function get_fs_type {
|
2016-04-29 13:38:00 +03:00
|
|
|
local mountpoint=$1
|
|
|
|
|
2016-05-02 19:43:00 +03:00
|
|
|
local top_mount_id=""
|
|
|
|
local top_mount_fs_type=""
|
|
|
|
|
2016-06-07 18:06:04 +03:00
|
|
|
while IFS='' read -r line; do
|
2016-05-02 19:43:00 +03:00
|
|
|
# Skip those entries which do not match the mountpoint
|
2020-09-17 17:05:33 +00:00
|
|
|
[ "$(echo "$line" | awk '{print $5;}')" = "$mountpoint" ] || continue
|
2016-05-02 19:43:00 +03:00
|
|
|
|
2020-09-17 17:05:33 +00:00
|
|
|
local mnt_id
|
|
|
|
mnt_id=$(echo "$line" | awk '{print $1;}')
|
|
|
|
local mnt_parent_id
|
|
|
|
mnt_parent_id=$(echo "$line" | awk '{print $2;}')
|
|
|
|
local mnt_fs_type
|
|
|
|
mnt_fs_type=$(echo "$line" | sed 's/.* - //g' | awk '{print $1;}')
|
2016-05-02 19:43:00 +03:00
|
|
|
|
|
|
|
# Skip mount entry, if not the first one and not a child
|
|
|
|
[ -n "$top_mount_id" ] && [ "$mnt_parent_id" != "$top_mount_id" ] && continue
|
|
|
|
|
|
|
|
top_mount_id=$mnt_id
|
|
|
|
top_mount_fs_type=$mnt_fs_type
|
|
|
|
done < "/proc/$CRTOOLS_INIT_PID/mountinfo"
|
|
|
|
|
systemd-autofs-restart.sh: explicitly return result from get_fs_type
This helper uses other binaries (like awk), which can fail or be killed.
It this case might be, that no mountpoint is found.
Or, on other hand, the whole mount point path is wrong, and is absend in
mountinfo.
Return explicit error in this case.
Without this patch, script will proceed further, and, since returned value is
empty, it doesn't equal to "autofs", so script will try to bind-mount autofs
mount, resulting in hung.
travis-ci: success for systemd-autofs-restart.sh: explicitly return result from get_fs_type
Signed-off-by: Stanislav Kinsburskiy <skinsbursky@virtuozzo.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
2016-10-06 16:21:00 +03:00
|
|
|
if [ -z "$top_mount_fs_type" ]; then
|
|
|
|
echo "Failed to find $mountpoint mountpoint"
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
|
2020-09-17 17:05:33 +00:00
|
|
|
echo "$top_mount_fs_type"
|
systemd-autofs-restart.sh: explicitly return result from get_fs_type
This helper uses other binaries (like awk), which can fail or be killed.
It this case might be, that no mountpoint is found.
Or, on other hand, the whole mount point path is wrong, and is absend in
mountinfo.
Return explicit error in this case.
Without this patch, script will proceed further, and, since returned value is
empty, it doesn't equal to "autofs", so script will try to bind-mount autofs
mount, resulting in hung.
travis-ci: success for systemd-autofs-restart.sh: explicitly return result from get_fs_type
Signed-off-by: Stanislav Kinsburskiy <skinsbursky@virtuozzo.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
2016-10-06 16:21:00 +03:00
|
|
|
return 0
|
2016-04-29 13:38:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function bind_mount {
|
|
|
|
local from=$1
|
|
|
|
local to=$2
|
|
|
|
|
2020-09-17 17:05:33 +00:00
|
|
|
$JOIN_CT mount --bind "$from" "$to" && return 0
|
2016-04-29 13:38:00 +03:00
|
|
|
|
|
|
|
echo "Failed to bind mount $from to $to"
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
function save_mountpoint {
|
|
|
|
local mountpoint=$1
|
2016-08-29 14:07:00 +03:00
|
|
|
local top_mount_fs_type=""
|
|
|
|
|
2020-09-17 17:05:33 +00:00
|
|
|
if ! top_mount_fs_type=$(get_fs_type "$mountpoint"); then
|
systemd-autofs-restart.sh: explicitly return result from get_fs_type
This helper uses other binaries (like awk), which can fail or be killed.
It this case might be, that no mountpoint is found.
Or, on other hand, the whole mount point path is wrong, and is absend in
mountinfo.
Return explicit error in this case.
Without this patch, script will proceed further, and, since returned value is
empty, it doesn't equal to "autofs", so script will try to bind-mount autofs
mount, resulting in hung.
travis-ci: success for systemd-autofs-restart.sh: explicitly return result from get_fs_type
Signed-off-by: Stanislav Kinsburskiy <skinsbursky@virtuozzo.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
2016-10-06 16:21:00 +03:00
|
|
|
echo "$top_mount_fs_type"
|
2016-08-29 14:07:00 +03:00
|
|
|
return
|
|
|
|
fi
|
2016-04-29 13:38:00 +03:00
|
|
|
|
|
|
|
# Nothing to do, if no file system is on top of autofs
|
2016-08-29 14:07:00 +03:00
|
|
|
[ "$top_mount_fs_type" = "autofs" ] && return
|
2016-04-29 13:38:00 +03:00
|
|
|
|
2021-04-22 15:30:47 -07:00
|
|
|
bindmount="$($JOIN_CT mktemp -d)"
|
2016-04-29 13:38:00 +03:00
|
|
|
if [ -z "$bindmount" ]; then
|
|
|
|
echo "Failed to create temporary directory"
|
2016-06-07 18:42:45 +03:00
|
|
|
return 1
|
2016-04-29 13:38:00 +03:00
|
|
|
fi
|
|
|
|
|
|
|
|
# No need to unmount fs on top of autofs:
|
|
|
|
# systemd will does it for us on service restart
|
2020-09-17 17:05:33 +00:00
|
|
|
bind_mount "$mountpoint" "$bindmount" || $JOIN_CT rm -rf "$bindmount"
|
2016-04-29 13:38:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function restore_mountpoint {
|
|
|
|
local mountpoint=$1
|
|
|
|
|
2016-08-05 17:31:00 +03:00
|
|
|
[ -n "$bindmount" ] || return
|
2016-04-29 13:38:00 +03:00
|
|
|
|
|
|
|
# Umount file system, remounted by systemd, if any
|
2020-09-17 17:05:33 +00:00
|
|
|
if ! top_mount_fs_type=$(get_fs_type "$mountpoint"); then
|
2017-02-22 19:52:16 +03:00
|
|
|
echo "$top_mount_fs_type"
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Nothing to do, if no file system is on top of autofs
|
|
|
|
if [ "$top_mount_fs_type" != "autofs" ]; then
|
2020-09-17 17:05:33 +00:00
|
|
|
$JOIN_CT umount "$mountpoint" || echo "Failed to umount $mountpoint"
|
2016-04-29 13:38:00 +03:00
|
|
|
fi
|
|
|
|
|
|
|
|
# Restore origin file system even if we failed to unmount the new one
|
2020-09-17 17:05:33 +00:00
|
|
|
bind_mount "$bindmount" "$mountpoint"
|
2016-04-29 13:38:00 +03:00
|
|
|
remove_bindmount
|
|
|
|
}
|
|
|
|
|
|
|
|
function restart_service {
|
|
|
|
local service=$1
|
2020-09-17 17:05:33 +00:00
|
|
|
local mountpoint
|
|
|
|
mountpoint=$($JOIN_CT systemctl show "$service" -p Where | sed 's/.*=//g')
|
2016-04-29 13:38:00 +03:00
|
|
|
|
|
|
|
if [ -z "$mountpoint" ]; then
|
|
|
|
echo "Failed to discover $service mountpoint"
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Try to move restored bind-mount aside and exit if Failed
|
|
|
|
# Nothing to do, if we Failed
|
2020-09-17 17:05:33 +00:00
|
|
|
save_mountpoint "$mountpoint" || return
|
2016-04-29 13:38:00 +03:00
|
|
|
|
2020-09-17 17:05:33 +00:00
|
|
|
if ! $JOIN_CT systemctl restart "$service"; then
|
2016-04-29 13:38:00 +03:00
|
|
|
echo "Failed to restart $service service"
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
echo "$service restarted"
|
|
|
|
|
|
|
|
# Try to move saved monutpoint back on top of autofs
|
2020-09-17 17:05:33 +00:00
|
|
|
restore_mountpoint "$mountpoint"
|
2016-04-29 13:38:00 +03:00
|
|
|
}
|
|
|
|
|
2016-04-12 12:48:00 +03:00
|
|
|
for service in $AUTOFS_SERVICES; do
|
2020-09-17 17:05:33 +00:00
|
|
|
status=$($JOIN_CT systemctl is-active "$service")
|
2016-04-29 13:38:00 +03:00
|
|
|
|
2020-09-17 17:05:33 +00:00
|
|
|
if [ "$status" == "active" ]; then
|
|
|
|
restart_service "$service"
|
2016-04-12 12:48:00 +03:00
|
|
|
else
|
|
|
|
echo "$service skipped ($status)"
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
|
|
|
exit 0
|