]>
Commit | Line | Data |
---|---|---|
1 | #!/usr/bin/env bash | |
2 | # SPDX-License-Identifier: LGPL-2.1-or-later | |
3 | set -eux | |
4 | set -o pipefail | |
5 | ||
6 | # shellcheck source=test/units/util.sh | |
7 | . "$(dirname "$0")"/util.sh | |
8 | ||
9 | maybe_mount_usr_overlay | |
10 | trap 'maybe_umount_usr_overlay' EXIT | |
11 | ||
12 | teardown_test_dependencies() ( | |
13 | set +eux | |
14 | ||
15 | if mountpoint /tmp/deptest; then | |
16 | umount /tmp/deptest | |
17 | fi | |
18 | ||
19 | if [[ -n "${LOOP}" ]]; then | |
20 | losetup -d "${LOOP}" || : | |
21 | fi | |
22 | if [[ -n "${LOOP_0}" ]]; then | |
23 | losetup -d "${LOOP_0}" || : | |
24 | fi | |
25 | if [[ -n "${LOOP_1}" ]]; then | |
26 | losetup -d "${LOOP_1}" || : | |
27 | fi | |
28 | ||
29 | rm -f /tmp/testsuite-60-dependencies-0.img | |
30 | rm -f /tmp/testsuite-60-dependencies-1.img | |
31 | ||
32 | rm -f /run/systemd/system/tmp-deptest.mount | |
33 | systemctl daemon-reload | |
34 | ||
35 | return 0 | |
36 | ) | |
37 | ||
38 | setup_loop() { | |
39 | truncate -s 30m "/tmp/testsuite-60-dependencies-${1?}.img" | |
40 | sfdisk --wipe=always "/tmp/testsuite-60-dependencies-${1?}.img" <<EOF | |
41 | label:gpt | |
42 | ||
43 | name="loop${1?}-part1" | |
44 | EOF | |
45 | LOOP=$(losetup -P --show -f "/tmp/testsuite-60-dependencies-${1?}.img") | |
46 | udevadm wait --settle --timeout=10 "${LOOP}" | |
47 | udevadm lock --device="${LOOP}" mkfs.ext4 -L "partname${1?}-1" "${LOOP}p1" | |
48 | } | |
49 | ||
50 | check_dependencies() { | |
51 | local escaped_0 escaped_1 after | |
52 | ||
53 | escaped_0=$(systemd-escape -p "${LOOP_0}p1") | |
54 | escaped_1=$(systemd-escape -p "${LOOP_1}p1") | |
55 | ||
56 | if [[ -f /run/systemd/system/tmp-deptest.mount ]]; then | |
57 | after=$(systemctl show --property=After --value tmp-deptest.mount) | |
58 | assert_not_in "local-fs-pre.target" "$after" | |
59 | assert_in "remote-fs-pre.target" "$after" | |
60 | assert_in "network.target" "$after" | |
61 | fi | |
62 | ||
63 | # mount LOOP_0 | |
64 | mount -t ext4 "${LOOP_0}p1" /tmp/deptest | |
65 | sleep 1 | |
66 | after=$(systemctl show --property=After --value tmp-deptest.mount) | |
67 | assert_in "local-fs-pre.target" "$after" | |
68 | assert_not_in "remote-fs-pre.target" "$after" | |
69 | assert_not_in "network.target" "$after" | |
70 | assert_in "${escaped_0}.device" "$after" | |
71 | assert_in "blockdev@${escaped_0}.target" "$after" | |
72 | assert_not_in "${escaped_1}.device" "$after" | |
73 | assert_not_in "blockdev@${escaped_1}.target" "$after" | |
74 | umount /tmp/deptest | |
75 | ||
76 | if [[ -f /run/systemd/system/tmp-deptest.mount ]]; then | |
77 | after=$(systemctl show --property=After --value tmp-deptest.mount) | |
78 | assert_not_in "local-fs-pre.target" "$after" | |
79 | assert_in "remote-fs-pre.target" "$after" | |
80 | assert_in "network.target" "$after" | |
81 | fi | |
82 | ||
83 | # mount LOOP_1 (using fake _netdev option) | |
84 | mount -t ext4 -o _netdev "${LOOP_1}p1" /tmp/deptest | |
85 | sleep 1 | |
86 | after=$(systemctl show --property=After --value tmp-deptest.mount) | |
87 | assert_not_in "local-fs-pre.target" "$after" | |
88 | assert_in "remote-fs-pre.target" "$after" | |
89 | assert_in "network.target" "$after" | |
90 | assert_not_in "${escaped_0}.device" "$after" | |
91 | assert_not_in "blockdev@${escaped_0}.target" "$after" | |
92 | assert_in "${escaped_1}.device" "$after" | |
93 | assert_in "blockdev@${escaped_1}.target" "$after" | |
94 | umount /tmp/deptest | |
95 | ||
96 | if [[ -f /run/systemd/system/tmp-deptest.mount ]]; then | |
97 | after=$(systemctl show --property=After --value tmp-deptest.mount) | |
98 | assert_not_in "local-fs-pre.target" "$after" | |
99 | assert_in "remote-fs-pre.target" "$after" | |
100 | assert_in "network.target" "$after" | |
101 | fi | |
102 | ||
103 | # mount tmpfs | |
104 | mount -t tmpfs tmpfs /tmp/deptest | |
105 | sleep 1 | |
106 | after=$(systemctl show --property=After --value tmp-deptest.mount) | |
107 | assert_in "local-fs-pre.target" "$after" | |
108 | assert_not_in "remote-fs-pre.target" "$after" | |
109 | assert_not_in "network.target" "$after" | |
110 | assert_not_in "${escaped_0}.device" "$after" | |
111 | assert_not_in "blockdev@${escaped_0}.target" "$after" | |
112 | assert_not_in "${escaped_1}.device" "$after" | |
113 | assert_not_in "blockdev@${escaped_1}.target" "$after" | |
114 | umount /tmp/deptest | |
115 | ||
116 | if [[ -f /run/systemd/system/tmp-deptest.mount ]]; then | |
117 | after=$(systemctl show --property=After --value tmp-deptest.mount) | |
118 | assert_not_in "local-fs-pre.target" "$after" | |
119 | assert_in "remote-fs-pre.target" "$after" | |
120 | assert_in "network.target" "$after" | |
121 | fi | |
122 | } | |
123 | ||
124 | test_dependencies() { | |
125 | if systemd-detect-virt --quiet --container; then | |
126 | echo "Skipping test_dependencies in container" | |
127 | return | |
128 | fi | |
129 | ||
130 | trap teardown_test_dependencies RETURN | |
131 | ||
132 | setup_loop 0 | |
133 | LOOP_0="${LOOP}" | |
134 | LOOP= | |
135 | setup_loop 1 | |
136 | LOOP_1="${LOOP}" | |
137 | LOOP= | |
138 | ||
139 | mkdir -p /tmp/deptest | |
140 | ||
141 | # without .mount file | |
142 | check_dependencies | |
143 | ||
144 | # create .mount file | |
145 | mkdir -p /run/systemd/system | |
146 | cat >/run/systemd/system/tmp-deptest.mount <<EOF | |
147 | [Mount] | |
148 | Where=/tmp/deptest | |
149 | What=192.168.0.1:/tmp/mnt | |
150 | Type=nfs | |
151 | EOF | |
152 | systemctl daemon-reload | |
153 | ||
154 | # with .mount file | |
155 | check_dependencies | |
156 | } | |
157 | ||
158 | test_issue_20329() { | |
159 | local tmpdir unit | |
160 | tmpdir="$(mktemp -d)" | |
161 | unit=$(systemd-escape --suffix mount --path "$tmpdir") | |
162 | ||
163 | # Set up test mount unit | |
164 | cat >/run/systemd/system/"$unit" <<EOF | |
165 | [Mount] | |
166 | What=tmpfs | |
167 | Where=$tmpdir | |
168 | Type=tmpfs | |
169 | Options=defaults,nofail | |
170 | EOF | |
171 | ||
172 | # Start the unit | |
173 | systemctl daemon-reload | |
174 | systemctl start "$unit" | |
175 | ||
176 | [[ "$(systemctl show --property SubState --value "$unit")" = "mounted" ]] || { | |
177 | echo >&2 "Test mount \"$unit\" unit isn't mounted" | |
178 | return 1 | |
179 | } | |
180 | mountpoint -q "$tmpdir" | |
181 | ||
182 | trap 'systemctl stop $unit' RETURN | |
183 | ||
184 | # Trigger the mount ratelimiting | |
185 | cd "$(mktemp -d)" | |
186 | mkdir foo | |
187 | for _ in {1..50}; do | |
188 | mount --bind foo foo | |
189 | umount foo | |
190 | done | |
191 | ||
192 | # Unmount the test mount and start it immediately again via systemd | |
193 | umount "$tmpdir" | |
194 | systemctl start "$unit" | |
195 | ||
196 | # Make sure it is seen as mounted by systemd and it actually is mounted | |
197 | [[ "$(systemctl show --property SubState --value "$unit")" = "mounted" ]] || { | |
198 | echo >&2 "Test mount \"$unit\" unit isn't in \"mounted\" state" | |
199 | return 1 | |
200 | } | |
201 | ||
202 | mountpoint -q "$tmpdir" || { | |
203 | echo >&2 "Test mount \"$unit\" is in \"mounted\" state, actually is not mounted" | |
204 | return 1 | |
205 | } | |
206 | } | |
207 | ||
208 | test_issue_23796() { | |
209 | local mount_path mount_mytmpfs | |
210 | ||
211 | mount_path="$(command -v mount 2>/dev/null)" | |
212 | mount_mytmpfs="${mount_path/\/bin/\/sbin}.mytmpfs" | |
213 | cat >"$mount_mytmpfs" <<EOF | |
214 | #!/bin/bash | |
215 | sleep ".\$RANDOM" | |
216 | exec -- $mount_path -t tmpfs tmpfs "\$2" | |
217 | EOF | |
218 | chmod +x "$mount_mytmpfs" | |
219 | ||
220 | mkdir -p /run/systemd/system | |
221 | cat >/run/systemd/system/tmp-hoge.mount <<EOF | |
222 | [Mount] | |
223 | What=mytmpfs | |
224 | Where=/tmp/hoge | |
225 | Type=mytmpfs | |
226 | EOF | |
227 | ||
228 | # shellcheck disable=SC2064 | |
229 | trap "rm -f /run/systemd/system/tmp-hoge.mount '$mount_mytmpfs'" RETURN | |
230 | ||
231 | for _ in {1..10}; do | |
232 | systemctl --no-block start tmp-hoge.mount | |
233 | sleep ".$RANDOM" | |
234 | systemctl daemon-reexec | |
235 | ||
236 | sleep 1 | |
237 | ||
238 | if [[ "$(systemctl is-failed tmp-hoge.mount)" == "failed" ]] || \ | |
239 | journalctl -u tmp-hoge.mount -q --grep "but there is no mount"; then | |
240 | exit 1 | |
241 | fi | |
242 | ||
243 | systemctl stop tmp-hoge.mount | |
244 | done | |
245 | } | |
246 | ||
247 | systemd-analyze log-level debug | |
248 | systemd-analyze log-target journal | |
249 | ||
250 | NUM_DIRS=20 | |
251 | ||
252 | # 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 | |
253 | LONGPATH="$(printf "/$(printf "x%0.s" {1..255})%0.s" {1..7})" | |
254 | LONGMNT="$(systemd-escape --suffix=mount --path "$LONGPATH")" | |
255 | TS="$(date '+%H:%M:%S')" | |
256 | ||
257 | mkdir -p "$LONGPATH" | |
258 | mount -t tmpfs tmpfs "$LONGPATH" | |
259 | systemctl daemon-reload | |
260 | ||
261 | # check that unit is active(mounted) | |
262 | systemctl --no-pager show -p SubState --value "$LONGPATH" | grep -q mounted | |
263 | ||
264 | # check that relevant part of journal doesn't contain any errors related to unit | |
265 | [ "$(journalctl -b --since="$TS" --priority=err | grep -c "$LONGMNT")" = "0" ] | |
266 | ||
267 | # check that we can successfully stop the mount unit | |
268 | systemctl stop "$LONGPATH" | |
269 | rm -rf "$LONGPATH" | |
270 | ||
271 | # mount/unmount enough times to trigger the /proc/self/mountinfo parsing rate limiting | |
272 | ||
273 | for ((i = 0; i < NUM_DIRS; i++)); do | |
274 | mkdir "/tmp/meow${i}" | |
275 | done | |
276 | ||
277 | TS="$(date '+%H:%M:%S')" | |
278 | ||
279 | for ((i = 0; i < NUM_DIRS; i++)); do | |
280 | mount -t tmpfs tmpfs "/tmp/meow${i}" | |
281 | done | |
282 | ||
283 | systemctl daemon-reload | |
284 | systemctl list-units -t mount tmp-meow* | grep -q tmp-meow | |
285 | ||
286 | for ((i = 0; i < NUM_DIRS; i++)); do | |
287 | umount "/tmp/meow${i}" | |
288 | done | |
289 | ||
290 | # Figure out if we have entered the rate limit state. | |
291 | # If the infra is slow we might not enter the rate limit state; in that case skip the exit check. | |
292 | if timeout 2m bash -c "until journalctl -u init.scope --since=$TS | grep -q '(mount-monitor-dispatch) entered rate limit'; do sleep 1; done"; then | |
293 | timeout 2m bash -c "until journalctl -u init.scope --since=$TS | grep -q '(mount-monitor-dispatch) left rate limit'; do sleep 1; done" | |
294 | fi | |
295 | ||
296 | # Verify that the mount units are always cleaned up at the end. | |
297 | # Give some time for units to settle so we don't race between exiting the rate limit state and cleaning up the units. | |
298 | timeout 2m bash -c 'while systemctl list-units -t mount tmp-meow* | grep -q tmp-meow; do systemctl daemon-reload; sleep 10; done' | |
299 | ||
300 | # test for issue #19983 and #23552. | |
301 | test_dependencies | |
302 | ||
303 | # test that handling of mount start jobs is delayed when /proc/self/mouninfo monitor is rate limited | |
304 | test_issue_20329 | |
305 | ||
306 | # test for reexecuting with background mount job | |
307 | test_issue_23796 | |
308 | ||
309 | systemd-analyze log-level info | |
310 | ||
311 | touch /testok |