1
0
mirror of git://git.sv.gnu.org/coreutils.git synced 2026-03-06 13:05:04 +02:00
Files
coreutils/tests/du/move-dir-while-traversing.sh
Pádraig Brady f9c6c730eb tests: du: avoid false failure in racy test
* tests/du/move-dir-while-traversing.sh: Expand the work to avoid
a false failure where du completes before the directory is moved.
Also expand the timeout to our more standard 10s to avoid the
"directory mover" being killed before du processes the directory.
This doesn't perceptibly impact the run time of the test.
Reported by Bruno Haible on a CentOS 7 system.
2025-09-22 00:09:03 +01:00

99 lines
3.2 KiB
Bash
Executable File

#!/bin/sh
# Trigger a failed assertion in coreutils-8.9 and earlier.
# Copyright (C) 2011-2025 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ du
require_trap_signame_
# We use a python-inotify script, so...
python -m pyinotify -h > /dev/null \
|| skip_ 'python inotify package not installed'
# Move a directory "up" while du is processing its sub-directories.
# While du is processing a hierarchy .../B/C/D/... this script
# detects when du opens D/, and then moves C/ "up" one level
# so that it is a sibling of B/.
# Given the inherent race condition, we have to add enough "weight"
# under D/ so that in most cases, the monitor performs the single
# rename syscall before du finishes processing the subtree under D/.
cat <<'EOF' > inotify-watch-for-dir-access.py
#!/usr/bin/env python
import pyinotify as pn
import os,sys
dir = sys.argv[1]
dest_parent = os.path.dirname(os.path.dirname(dir))
dest = os.path.join(dest_parent, os.path.basename(dir))
class ProcessDir(pn.ProcessEvent):
def process_IN_OPEN(self, event):
os.rename(dir, dest)
sys.exit(0)
def process_default(self, event):
pass
wm = pn.WatchManager()
notifier = pn.Notifier(wm)
wm.watch_transient_file(dir, pn.IN_OPEN, ProcessDir)
sys.stdout.write('started\n')
sys.stdout.flush()
notifier.loop()
EOF
chmod a+x inotify-watch-for-dir-access.py
t=T/U
mkdir d2 || framework_failure_
long=d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z
# One iteration of this loop creates a tree with which
# du sometimes completes its traversal before the above rename.
# Five iterations was not enough in 2 of 7 "make -j20 check" runs on a
# 6/12-core system. However, using "10", I saw no failure in 20 trials.
# 2011 this was set at 50, 2025 this was set at 99
for i in $(seq 99); do
mkdir -p $t/3/a/b/c/$i/$long || framework_failure_
done
# Terminate any background cp process
cleanup_() { kill $pid 2>/dev/null && wait $pid; }
# Prohibit suspension, which could otherwise cause a timeout-induced FP failure.
trap '' TSTP
timeout 10 ./inotify-watch-for-dir-access.py $t/3/a/b > start-msg & pid=$!
# Wait for the watcher to start...
nonempty() { sleep $1; test -s start-msg; }
retry_delay_ nonempty .1 5 || fail=1
# The above watches for an IN_OPEN event on $t/3/a/b,
# and when it triggers, moves the parent, $t/3/a, up one level
# so it's directly under $t.
# Before coreutils-8.10, du would abort.
returns_ 1 du -a $t d2 2> err || fail=1
# check for the new diagnostic
printf "du: fts_read failed: $t/3/a/b: No such file or directory\n" > exp \
|| fail=1
compare exp err || fail=1
Exit $fail