[2.4] VFS locking problem during concurrent link/unlink

From: Oleg Drokin (green@namesys.com)
Date: Thu Jan 16 2003 - 06:00:15 EST


   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");
     decreases i_nlink of a/b to zero
     and removes name "b" from "a"
                                        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 (*)

   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?

PS: Here's the script:

# 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
read av1 av5 av15 rest < /proc/loadavg
echo -n "Load Average: $av1 ... "
if [ $av1 -lt 10 ]; then
        echo OK
        exit 0
        echo "Whoa, Nellie!"
        exit 1
# 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 &
# 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/

This archive was generated by hypermail 2b29 : Thu Jan 23 2003 - 22:00:12 EST