[2.4] VFS locking problem during concurrent link/unlink

Oleg Drokin (green@namesys.com)
Thu, 16 Jan 2003 14:00:15 +0300


Hello!

Debugging reiserfs problem that can be demonstrated with script created by
Zygo Blaxell, I started to wonder if the problem presented is indeed reiserfs
fault and not VFS.
Though the Zygo claims script only produces problems on reiserfs, I am trying
it now myself on ext2 (which will take some time).

Debugging shows that reiserfs_link is sometimes called for inodes whose
i_nlink is zero (and all corresponding data is deleted already).
So my current guess of what's going on is this:

process 1 process 2
sys_unlink("a/b") sys_link("a/b", "c/d");
down(inode of ("a")); down(inode of "c");

lock_kernel()
reiserfs_unlink("a/b")
decreases i_nlink of a/b to zero
and removes name "b" from "a"
unlock_kernel()
d_delete("a/b")
(*)
lock_kernel()
reiserfs_link()
at this point we do usual stuff,
but inode's n_nlink is zero and
file data already removed which
indicates reiserfs_delete_inode()
was already called at (*)
unlock_kernel()

So my question is "Is it really ok that sys_link/vfs_link does not
take semaphore on parent dir of original path?", or should we
actually put a workaround in reiserfs code to avoid such a situation?

Bye,
Oleg
PS: Here's the script:
#!/bin/bash

# Create an empty filesystem:

mkreiserfs -f -f /dev/hdb2
mount /dev/hdb2 /data1 -t reiserfs

cd /data1

# Script used to control the load average. Note that as written the loops
# below will keep spawning new processes, so we need some way to throttle
# them. Change the '-lt 10' to another number to change the number
# of processes.

cat <<'LC' > loadcheck && chmod 755 loadcheck
#!/bin/sh
read av1 av5 av15 rest < /proc/loadavg
echo -n "Load Average: $av1 ... "
av1=${av1%.*}
if [ $av1 -lt 10 ]; then
echo OK
exit 0
else
echo "Whoa, Nellie!"
exit 1
fi
LC
# Create directories used by test
mkdir foo bar
mkdir foo/etc foo/usr foo/var

# Start up some rsyncs. I use /etc, /usr, and /var because there's a
# good mixture of files with some hardlinks between them, and on a normal
# Linux system some of them change from time to time.

while sleep 1m; do
./loadcheck || continue;
for x in usr etc var; do
rsync -avxHS --delete /$x/. foo/$x/. &
done;
done &
# Start up some cp -al's and rm -rf's. Note there are two concurrent
# sets of 'cp's and two concurrent sets of 'rm's, and each of those
# has different instances of 'cp' and 'rm' running at different times.
for x in 1 2; do
while sleep 1m; do
./loadcheck || continue;
cp -al foo bar/`date +%s` &
done &
while sleep 1m; do
./loadcheck || continue;
for x in bar/*; do
rm -rf $x;
sleep 1m;
done &
done &
done &

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/