TEST-60-MOUNT-RATELIMIT sometimes fails as it cannot see the 'left rate limit' message in the journal. Tests relying on specific log messages are often flaky, as the journal is lossy. Change the test case to check for the desired outcome instead, as that also catches regressions, without being over reliant on the journal. Fixes https://github.com/systemd/systemd/issues/32712
183 lines
5.4 KiB
Bash
Executable File
183 lines
5.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
|
set -eux
|
|
set -o pipefail
|
|
|
|
# shellcheck source=test/units/test-control.sh
|
|
. "$(dirname "$0")"/test-control.sh
|
|
# shellcheck source=test/units/util.sh
|
|
. "$(dirname "$0")"/util.sh
|
|
|
|
testcase_issue_20329() {
|
|
# test that handling of mount start jobs is delayed when /proc/self/mouninfo monitor is rate limited
|
|
|
|
local tmpdir unit
|
|
tmpdir="$(mktemp -d)"
|
|
unit=$(systemd-escape --suffix mount --path "$tmpdir")
|
|
|
|
# Set up test mount unit
|
|
cat >/run/systemd/system/"$unit" <<EOF
|
|
[Mount]
|
|
What=tmpfs
|
|
Where=$tmpdir
|
|
Type=tmpfs
|
|
Options=defaults,nofail
|
|
EOF
|
|
|
|
# Start the unit
|
|
systemctl daemon-reload
|
|
systemctl start "$unit"
|
|
|
|
[[ "$(systemctl show --property SubState --value "$unit")" = "mounted" ]] || {
|
|
echo >&2 "Test mount \"$unit\" unit isn't mounted"
|
|
return 1
|
|
}
|
|
mountpoint -q "$tmpdir"
|
|
|
|
trap 'systemctl stop $unit' RETURN
|
|
|
|
# Trigger the mount ratelimiting
|
|
cd "$(mktemp -d)"
|
|
mkdir foo
|
|
for _ in {1..50}; do
|
|
mount --bind foo foo
|
|
umount foo
|
|
done
|
|
|
|
# Unmount the test mount and start it immediately again via systemd
|
|
umount "$tmpdir"
|
|
systemctl start "$unit"
|
|
|
|
# Make sure it is seen as mounted by systemd and it actually is mounted
|
|
[[ "$(systemctl show --property SubState --value "$unit")" = "mounted" ]] || {
|
|
echo >&2 "Test mount \"$unit\" unit isn't in \"mounted\" state"
|
|
return 1
|
|
}
|
|
|
|
mountpoint -q "$tmpdir" || {
|
|
echo >&2 "Test mount \"$unit\" is in \"mounted\" state, actually is not mounted"
|
|
return 1
|
|
}
|
|
}
|
|
|
|
testcase_issue_23796() {
|
|
# test for reexecuting with background mount job
|
|
|
|
local mount_path mount_mytmpfs since
|
|
|
|
mount_path="$(command -v mount 2>/dev/null)"
|
|
mount_mytmpfs="${mount_path/\/bin/\/sbin}.mytmpfs"
|
|
cat >"$mount_mytmpfs" <<EOF
|
|
#!/usr/bin/env bash
|
|
sleep ".\$RANDOM"
|
|
exec -- $mount_path -t tmpfs tmpfs "\$2"
|
|
EOF
|
|
chmod +x "$mount_mytmpfs"
|
|
|
|
mkdir -p /run/systemd/system
|
|
cat >/run/systemd/system/tmp-hoge.mount <<EOF
|
|
[Mount]
|
|
What=mytmpfs
|
|
Where=/tmp/hoge
|
|
Type=mytmpfs
|
|
EOF
|
|
|
|
# shellcheck disable=SC2064
|
|
trap "rm -f /run/systemd/system/tmp-hoge.mount '$mount_mytmpfs'" RETURN
|
|
|
|
journalctl --sync
|
|
since="$(date '+%H:%M:%S')"
|
|
|
|
for _ in {1..10}; do
|
|
systemctl --no-block start tmp-hoge.mount
|
|
sleep ".$RANDOM"
|
|
systemctl daemon-reexec
|
|
|
|
sleep 1
|
|
|
|
if [[ "$(systemctl is-failed tmp-hoge.mount)" == "failed" ]] ||
|
|
journalctl --since="$since" -u tmp-hoge.mount -q --grep "but there is no mount"; then
|
|
exit 1
|
|
fi
|
|
|
|
systemctl stop tmp-hoge.mount
|
|
done
|
|
}
|
|
|
|
testcase_long_path() {
|
|
local long_path long_mnt ts
|
|
|
|
# make sure we can handle mounts at very long paths such that mount unit name must be hashed to fall within our unit name limit
|
|
long_path="$(printf "/$(printf "x%0.s" {1..255})%0.s" {1..7})"
|
|
long_mnt="$(systemd-escape --suffix=mount --path "$long_path")"
|
|
|
|
journalctl --sync
|
|
ts="$(date '+%H:%M:%S')"
|
|
|
|
mkdir -p "$long_path"
|
|
mount -t tmpfs tmpfs "$long_path"
|
|
systemctl daemon-reload
|
|
|
|
# check that unit is active(mounted)
|
|
systemctl --no-pager show -p SubState --value "$long_path" | grep mounted >/dev/null
|
|
|
|
# check that relevant part of journal doesn't contain any errors related to unit
|
|
[ "$(journalctl -b --since="$ts" --priority=err | grep -c "$long_mnt")" = "0" ]
|
|
|
|
# check that we can successfully stop the mount unit
|
|
systemctl stop "$long_path"
|
|
rm -rf "$long_path"
|
|
}
|
|
|
|
testcase_mount_ratelimit() {
|
|
local num_dirs=20
|
|
local ts i
|
|
|
|
# mount/unmount enough times to trigger the /proc/self/mountinfo parsing rate limiting
|
|
|
|
for ((i = 0; i < num_dirs; i++)); do
|
|
mkdir "/tmp/meow${i}"
|
|
done
|
|
|
|
# The following loop may produce many journal entries.
|
|
# Let's process all pending entries before testing.
|
|
journalctl --sync
|
|
ts="$(date '+%H:%M:%S')"
|
|
|
|
for ((i = 0; i < num_dirs; i++)); do
|
|
mount -t tmpfs tmpfs "/tmp/meow${i}"
|
|
done
|
|
|
|
systemctl daemon-reload
|
|
systemctl list-units -t mount tmp-meow* | grep tmp-meow >/dev/null
|
|
|
|
for ((i = 0; i < num_dirs; i++)); do
|
|
umount "/tmp/meow${i}"
|
|
done
|
|
|
|
# Figure out if we have entered the rate limit state.
|
|
# If the infra is slow we might not enter the rate limit state; in that case skip the exit check.
|
|
journalctl --sync
|
|
if timeout 2m bash -c "journalctl -u init.scope --since='$ts' -n all --follow | grep -m 1 -q -F '(mount-monitor-dispatch) entered rate limit'"; then
|
|
# We entered the rate limit state. Verify that the manager leaves it again on its own and
|
|
# processes the pending mount table changes, i.e. that all the mount units we unmounted above are
|
|
# cleaned up automatically, without daemon-reload.
|
|
timeout 2m bash -c 'while systemctl list-units -t mount tmp-meow* | grep tmp-meow >/dev/null; do sleep 1; done'
|
|
else
|
|
# We never entered the rate limit state (e.g. on slow infra), so the recovery path above is not
|
|
# being exercised. Just make sure the mount units are cleaned up, nudging the manager if needed.
|
|
timeout 2m bash -c 'while systemctl list-units -t mount tmp-meow* | grep tmp-meow >/dev/null; do systemctl daemon-reload; sleep 10; done'
|
|
fi
|
|
}
|
|
|
|
mkdir -p /run/systemd/journald.conf.d
|
|
cat >/run/systemd/journald.conf.d/99-ratelimit.conf <<EOF
|
|
[Journal]
|
|
RateLimitBurst=0
|
|
EOF
|
|
systemctl reload systemd-journald.service
|
|
|
|
run_testcases
|
|
|
|
touch /testok
|