Whamcloud - gitweb
Branch: HEAD
[fs/lustre-release.git] / lustre / tests / sanity-gns.sh
index 8c0318a..6c529f1 100644 (file)
@@ -7,7 +7,7 @@
 set -e
 
 ONLY=${ONLY:-"$*"}
-ALWAYS_EXCEPT=${ALWAYS_EXCEPT:-""}
+ALWAYS_EXCEPT=${ALWAYS_EXCEPT:-"1b 1c"}
 [ "$ALWAYS_EXCEPT$EXCEPT" ] && echo "Skipping tests: $ALWAYS_EXCEPT $EXCEPT"
 
 SRCDIR=`dirname $0`
@@ -38,21 +38,6 @@ PTLDEBUG=${PTLDEBUG:-0}
 
 . krb5_env.sh
 
-if [ $UID -ne 0 ]; then
-       RUNAS_ID="$UID"
-       RUNAS=""
-else
-       RUNAS_ID=${RUNAS_ID:-500}
-       RUNAS=${RUNAS:-"runas -u $RUNAS_ID"}
-fi
-
-if [ `using_krb5_sec $SECURITY` == 'y' ] ; then
-    start_krb5_kdc || exit 1
-    if [ $RUNAS_ID -ne $UID ]; then
-        $RUNAS ./krb5_refresh_cache.sh || exit 2
-    fi
-fi
-
 export NAME=${NAME:-local}
 
 SAVE_PWD=$PWD
@@ -97,7 +82,7 @@ check_kernel_version() {
 }
 
 run_one() {
-       if ! mount | grep -q $DIR; then
+       if ! cat /proc/mounts | grep -q $DIR; then
                $START
        fi
        echo $PTLDEBUG >/proc/sys/portals/debug 
@@ -189,12 +174,11 @@ rm -rf $DIR/[Rdfs][1-9]*
 build_test_filter
 
 echo preparing for tests involving mounts
-EXT2_DEV=${EXT2_DEV:-/tmp/SANITY.LOOP}
+EXT2_DEV=${EXT2_DEV:-$TMP/SANITY.LOOP}
 touch $EXT2_DEV
 mke2fs -j -F $EXT2_DEV 8000 >/dev/null 2>&1
 
-find_free_loop() {
-    local LOOP_DEV=""
+find_loop() {
     test -b /dev/loop0 && 
        base="/dev/loop" || base="/dev/loop/"
 
@@ -202,18 +186,26 @@ find_free_loop() {
        test -b $base$i || continue
        
        losetup $base$i >/dev/null 2>&1 || {
-           LOOP_DEV="$base$i"
+           echo "$base$i"
            break
        }
     done
-    echo $LOOP_DEV
 }
 
-setup_loop() {
+cleanup_loop() {
     local LOOP_DEV=$1
     local LOOP_FILE=$2
     
-    dd if=/dev/zero of=$LOOP_FILE bs=1M count=10 2>/dev/null || return $?
+    losetup -d $LOOP_DEV >/dev/null 2>&1
+    rm -fr $LOOP_FILE >/dev/null 2>&1
+}
+
+setup_loop() {
+    local LOOP_DEV=$(find_loop)
+    local LOOP_FILE=$1
+    
+    dd if=/dev/zero of=$LOOP_FILE bs=1M count=10 2>/dev/null ||
+       return $?
 
     losetup $LOOP_DEV $LOOP_FILE || {
        rc=$?
@@ -224,18 +216,11 @@ setup_loop() {
     mke2fs -F $LOOP_DEV >/dev/null 2>&1 || {
        rc=$?
        cleanup_loop $LOOP_DEV $LOOP_FILE
-       echo "cannot create test ext2 fs on $LOOP_DEV"
-       return $?
+       return rc
     }
-    return 0
-}
-
-cleanup_loop() {
-    local LOOP_DEV=$1
-    local LOOP_FILE=$2
     
-    losetup -d $LOOP_DEV >/dev/null 2>&1
-    rm -fr $LOOP_FILE >/dev/null 2>&1
+    echo $LOOP_DEV
+    return 0
 }
 
 setup_upcall() {
@@ -245,7 +230,9 @@ setup_upcall() {
     local LOG=$3
     local BG=$4
     
-    test "x$BG" = "xBACKGROUND" && 
+    echo "generating upcall $UPCALL" >&2
+
+    test "x$BG" = "xBG" && 
        BG="&" || BG=""
     
     test "x$MODE" = "xDEADLOCK" &&
@@ -268,7 +255,15 @@ $INJECTION
 exit \$?
 EOF
     chmod +x $UPCALL
-    return $?
+
+    echo "$UPCALL" > /proc/fs/lustre/llite/fs0/gns_upcall || return $?
+    echo "upcall:  $(cat /proc/fs/lustre/llite/fs0/gns_upcall)"
+
+    echo "======================== upcall script ===========================" >&2
+    cat $UPCALL >&2
+    echo "==================================================================" >&2
+   
+    return 0
 }
 
 cleanup_upcall() {
@@ -280,49 +275,116 @@ show_log() {
     local LOG=$1
     
     test -f $LOG && {
-       echo "======================== upcall log ==========================="
-       cat $LOG
-       echo "==============================================================="
+       echo "======================== upcall log ===========================" >&2
+       cat $LOG >&2
+       echo "===============================================================" >&2
     }
 }
 
-check_gns() {
-    local LOG="/tmp/gns-log"
-    local UPCALL_PATH=""
+sleep_on()
+{
+    local TIMOUT=$1
+    local TICK=$2
     
-    local UPCALL=$1
-    local OBJECT1=$2
-    local OBJECT2=$3
-    local TIMOUT=$4
-    local TICK=$5
-    local MODE=$6
-    local BG=$7
-    
-    rm -fr $LOG >/dev/null 2>&1
-    UPCALL_PATH="/tmp/gns-upcall-$UPCALL.sh"
-    
-    echo "generating upcall $UPCALL_PATH"
-    setup_upcall $UPCALL_PATH $UPCALL $LOG $BG || return $rc
-
-    echo "======================== upcall script ==========================="
-    cat $UPCALL_PATH 2>/dev/null || return $?
-    echo "=================================================================="
-   
-    echo "$UPCALL_PATH" > /proc/fs/lustre/llite/fs0/gns_upcall || return $?
-    echo "upcall:  $(cat /proc/fs/lustre/llite/fs0/gns_upcall)"
+    local sleep_time=$TIMOUT
+    let sleep_time+=$TICK*2
+    sleep $sleep_time
+}
+
+check_mnt()
+{
+    local OBJECT=$1
+    local MODE=$2
+    local TIMOUT=$3
+    local TICK=$4
+    
+    local res=0
+    local mnt=""
+    local p=""
+    local op
+    
+    test $MODE -eq 1 && op="mount" || op="umount"
+    echo -n "checking for $op $OBJECT: " >&2
+
+    test $MODE -eq 0 && sleep_on $TIMOUT $TICK
+
+    OBJECT="`echo $OBJECT | sed 's/\/*$//'`"
+    mnt="`cat /proc/mounts | grep $OBJECT | awk '{print \$2}'`"
+    test -z "$mnt" && {
+       res=0
+    } || {
+       for p in $mnt; do
+           test "x$p" = "x$OBJECT" && {
+               res=1
+               break
+           }
+       done
+    }
+    
+    if test $MODE -eq 0; then
+       test $res -eq 1 && {
+           echo "failed" >&2
+           return 1
+       }
+    else
+       test $res -eq 0 && {
+           echo "failed" >&2
+           return 1
+       }
+    fi
+
+    echo "success" >&2
+    return 0
+}
 
+check_gns() {
+    local OBJECT1=$1
+    local OBJECT2=$2
+    local TIMOUT=$3
+    local TICK=$4
+    local MODE=$5
+    local OP=$6
+    local CHECK=$7
+    
+    local OLD_PWD=$(pwd)
+    echo "testing mount on $OP against $OBJECT1 in $MODE mode" >&2
+    
     case "$MODE" in
        GENERIC)
-           echo -n "mount on open $OBJECT1/test_file1 (generic): "
-           echo -n "test data" > $OBJECT1/test_file1 >/dev/null 2>&1 || return $?
+           case "$OP" in
+               OPEN)
+                   echo -n "test data" > $OBJECT1/test_file1 >/dev/null 2>&1
+                   ;;
+               LIST)
+                   ls -la $OBJECT1/
+                   ;;
+               CHDIR)
+                   cd $OBJECT1 || return $?
+                   ;;
+               *)
+                   echo "invalid testing operation $OP" >&2
+                   return 1
+           esac
            ;;
        CONCUR1)
            local i=1
            local nr=20
        
-           echo -n "mount on open $OBJECT1/test_file1 ($nr threads): "
            for ((;i<=$nr;i++)); do 
-               echo -n "test data" > $OBJECT1/test_file$i >/dev/null 2>&1 &
+               case "$OP" in
+                   OPEN)
+                       echo -n "test data" > $OBJECT1/test_file$i >/dev/null 2>&1 &
+                       ;;
+                   LIST)
+                       ls -la $OBJECT1/
+                       ;;
+                   CHDIR)
+                       cd $OBJECT1 >/dev/null 2>&1 &
+                       ;;
+                   *)
+                       echo "invalid testing operation $OP" >&2
+                       return 1
+               esac
            done
        
            wait
@@ -334,13 +396,26 @@ check_gns() {
            ;;
        CONCUR2)
            test "x$OBJECT2" = "x" && {
-               echo "not defined object2 for concurrent2 testing"
+               echo "not defined object2 for concurrent2 testing" >&2
                return 1
            }
-           echo -n "mount on open $OBJECT1/test_file1: "
-           echo -n "mount on open $OBJECT2/test_file1: "
-           echo -n "test data" > $OBJECT1/test_file1 >/dev/null 2>&1 &
-           echo -n "test data" > $OBJECT2/test_file1 >/dev/null 2>&1 &
+           case "$OP" in
+               OPEN)
+                   echo -n "test data" > $OBJECT1/test_file1 >/dev/null 2>&1 &
+                   echo -n "test data" > $OBJECT2/test_file1 >/dev/null 2>&1 &
+                   ;;
+               LIST)
+                   ls -la $OBJECT1/
+                   ls -la $OBJECT2/
+                   ;;
+               CHDIR)
+                   cd $OBJECT1 >/dev/null 2>&1 &
+                   cd $OBJECT2 >/dev/null 2>&1 &
+                   ;;
+               *)
+                   echo "invalid testing operation $OP" >&2
+                   return 1
+           esac
            
            wait
            
@@ -350,15 +425,30 @@ check_gns() {
                return $RETVAL
            ;;
        CONCUR3)
-           echo -n "mount on open $OBJECT1/test_file1: "
-           
            local i=1
            local nr=20
            
            for ((;i<$nr;i++)); do
-               touch $OBJECT1/file$i &
-               echo -n "test data" > $OBJECT1/test_file$i >/dev/null 2>&1 &
-               mkdir $OBJECT1/dir$i &
+               case "$OP" in
+                   OPEN)
+                       touch $OBJECT1/file$i &
+                       echo -n "test data" > $OBJECT1/test_file$i >/dev/null 2>&1 &
+                       mkdir $OBJECT1/dir$i &
+                       ;;
+                   LIST)
+                       touch $OBJECT1/file &
+                       ls -la $OBJECT1/ &
+                       mkdir $OBJECT1/dir$i &
+                       ;;
+                   CHDIR)
+                       touch $OBJECT1/file$i &
+                       cd $OBJECT1 >/dev/null 2>&1 &
+                       mkdir $OBJECT1/dir$i &
+                       ;;
+                   *)
+                       echo "invalid testing operation $OP" >&2
+                       return 1
+               esac
            done
 
            wait
@@ -369,48 +459,26 @@ check_gns() {
                return $RETVAL
            ;;
        *)
-           echo "invalid testing mode $MODE"
+           echo "invalid testing mode $MODE" >&2
            return 1
     esac
-    
-    local ENTRY1="`basename $OBJECT1`"
-    local ENTRY2="`basename $OBJECT2`"
-    
-    cat /proc/mounts | grep -q "$ENTRY1" || {
-       echo "fail"
-       show_log $LOG
-       return 1
-    }
-    
-    if test "x$MODE" = "xCONCUR2"; then
-       cat /proc/mounts | grep -q "$ENTRY2" || {
-           echo "fail"
-           show_log $LOG
-           return 1
-       }
-    fi
-    
-    echo "success"
 
-    local sleep_time=$TIMOUT
-    let sleep_time+=$TICK*2
-    echo -n "waiting for umount ${sleep_time}s (timeout + tick*2): "
-    sleep $sleep_time
+    test "x$OP" = "xCHDIR" && cd $OLD_PWD
 
-    cat /proc/mounts | grep -q "$ENTRY1" && {
-       echo "failed"
-       return 2
-    }
+    test $CHECK -eq 1 && {
+       # check if mount is here
+       check_mnt $OBJECT1 1 0 0 || return 1
+       if test "x$MODE" = "xCONCUR2"; then
+           check_mnt $OBJECT2 1 0 0 || return 1
+       fi
     
-    if test "x$MODE" = "xCONCUR2"; then
-       cat /proc/mounts | grep -q "$ENTRY2" && {
-           echo "failed"
-           return 2
-       }
-    fi
+       # wait for $TIMEOUT and check for mount, it should go
+       check_mnt $OBJECT1 0 $TIMOUT $TICK || return 2
+       if test "x$MODE" = "xCONCUR2"; then
+           check_mnt $OBJECT2 0 $TIMOUT $TICK || return 2
+       fi
+    }
     
-    echo "success"
-    cleanup_upcall $UPCALL_PATH
     return 0
 }
 
@@ -418,25 +486,25 @@ setup_object() {
     local OBJPATH=$1
     local OBJECT=$2
     local CONTENT=$3
-    local EXTRA_OPT=$4
+    
+    echo "preparing mount object at $OBJPATH..." >&2
     
     mkdir -p $OBJPATH || return $?
     echo -n $CONTENT > $OBJPATH/$OBJECT || return $?
     
-    echo "======================== mount object ==========================="
-    cat $OBJPATH/$OBJECT
-    echo ""
-    echo "================================================================="
+    echo "======================== mount object ===========================" >&2
+    cat $OBJPATH/$OBJECT >&2
+    echo "" >&2
+    echo "=================================================================" >&2
     
-    chmod u+s $OBJPATH $EXTRA_OPT
+    chmod u+s $OBJPATH
     return $?
 }
 
 cleanup_object() {
     local OBJPATH=$1
-    local EXTRA_OPT=$2
 
-    chmod u-s $OBJPATH $EXTRA_OPT
+    chmod u-s $OBJPATH
     umount $OBJPATH >/dev/null 2>&1
     rm -fr $OBJPATH >/dev/null 2>&1
 }
@@ -446,6 +514,8 @@ setup_gns() {
     local TIMOUT=$2
     local TICK=$3
 
+    echo "setting up GNS timeouts and mount object..." >&2
+
     echo "$OBJECT" > /proc/fs/lustre/llite/fs0/gns_object_name || error
     echo "$TIMOUT" > /proc/fs/lustre/llite/fs0/gns_timeout || error
     echo "$TICK" > /proc/fs/lustre/llite/fs0/gns_tick || error
@@ -460,45 +530,64 @@ setup_gns() {
 
 enable_gns()
 {
-    echo "1" > /proc/fs/lustre/llite/fs0/gns_enabled || error
-    test "x$(cat /proc/fs/lustre/llite/fs0/gns_enabled)" = "x1" || error
+    echo "1" > /proc/fs/lustre/llite/fs0/gns_enabled
+    test "x$(cat /proc/fs/lustre/llite/fs0/gns_enabled)" = "x1" || 
+       error "cannot enable GNS"
 }
 
 disable_gns()
 {
-    echo "0" > /proc/fs/lustre/llite/fs0/gns_enabled || error
-    test "x$(cat /proc/fs/lustre/llite/fs0/gns_enabled)" = "x0" || error
+    echo "0" > /proc/fs/lustre/llite/fs0/gns_enabled
+    test "x$(cat /proc/fs/lustre/llite/fs0/gns_enabled)" = "x0" || 
+       error "cannot disable GNS"
 }
 
 test_1a() {
-    local LOOP_DEV=$(find_free_loop 2>/dev/null)
-    local LOOP_FILE="/tmp/gns_loop_1a"
+    local UPCALL="$TMP/gns-upcall-1a.sh"
+    local LOOP_FILE="$TMP/gns_loop_1a"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
+    local LOOP_DEV=""
     local TIMOUT=5
     local TICK=1
 
-    test "x$LOOP_DEV" != "x" && test -b $LOOP_DEV ||
-       error "can't find free loop device"
+    disable_gns
 
-    echo "preparing loop device $LOOP_DEV <-> $LOOP_FILE..."
-    cleanup_loop $LOOP_DEV $LOOP_FILE
-    setup_loop $LOOP_DEV $LOOP_FILE || error
+    LOOP_DEV=$(setup_loop $LOOP_FILE)
+    test "x$LOOP_DEV" = "x" && 
+       error "can't find valid (free) loop device"
 
-    echo "setting up GNS timeouts and mount object..."
-    setup_gns $OBJECT $TIMOUT $TICK || error
-    
-    disable_gns
+    setup_upcall $UPCALL GENERIC $LOG FG || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
 
-    echo "preparing mount object at $DIR/gns_test_1a/$OBJECT..."
-    setup_object $DIR/gns_test_1a $OBJECT "-t ext2 $LOOP_DEV" || error
+    setup_gns $OBJECT $TIMOUT $TICK || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
+    
+    setup_object $DIR/gns_test_1a $OBJECT "-t ext2 $LOOP_DEV" || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
 
     enable_gns
 
-    echo ""
-    echo "testing GNS with GENERIC upcall 3 times on the row"
     for ((i=0;i<3;i++)); do
-       check_gns GENERIC $DIR/gns_test_1a $DIR/gns_test_1a $TIMOUT $TICK GENERIC || {
+       check_gns $DIR/gns_test_1a $DIR/gns_test_1a $TIMOUT $TICK GENERIC OPEN 1 || {
            disable_gns
+           show_log $LOG
+           cleanup_object $DIR/gns_test_1a
+           cleanup_loop $LOOP_DEV $LOOP_FILE
+           error
+       }
+    done
+    
+    for ((i=0;i<3;i++)); do
+       check_gns $DIR/gns_test_1a $DIR/gns_test_1a $TIMOUT $TICK GENERIC CHDIR 1 || {
+           disable_gns
+           show_log $LOG
            cleanup_object $DIR/gns_test_1a
            cleanup_loop $LOOP_DEV $LOOP_FILE
            error
@@ -506,91 +595,105 @@ test_1a() {
     done
     
     disable_gns
-
     cleanup_object $DIR/gns_test_1a
     cleanup_loop $LOOP_DEV $LOOP_FILE
+
+    return 0
 }
 
 run_test 1a " general GNS test - mount/umount (GENERIC) ================"
 
 test_1b() {
-    local LOOP_DEV=$(find_free_loop 2>/dev/null)
-    local LOOP_FILE="/tmp/gns_loop_1b"
+    local UPCALL="$TMP/gns-upcall-1b.sh"
+    local LOOP_FILE="$TMP/gns_loop_1b"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
+    local LOOP_DEV=""
     local TIMOUT=5
     local TICK=1
 
-    test "x$LOOP_DEV" != "x" && test -b $LOOP_DEV ||
-       error "can't find free loop device"
+    disable_gns
 
-    echo "preparing loop device $LOOP_DEV <-> $LOOP_FILE..."
-    cleanup_loop $LOOP_DEV $LOOP_FILE
-    setup_loop $LOOP_DEV $LOOP_FILE || error
+    LOOP_DEV=$(setup_loop $LOOP_FILE)
+    test "x$LOOP_DEV" = "x" && 
+       error "can't find valid (free) loop device"
+
+    setup_upcall $UPCALL DEADLOCK $LOG FG || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
 
-    echo "setting up GNS timeouts and mount object..."
-    setup_gns $OBJECT $TIMOUT $TICK || error
+    setup_gns $OBJECT $TIMOUT $TICK || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
 
-    disable_gns
-    
-    echo "preparing mount object at $DIR/gns_test_1b/$OBJECT..."
-    setup_object $DIR/gns_test_1b $OBJECT "-t ext2 $LOOP_DEV" || error
+    setup_object $DIR/gns_test_1b $OBJECT "-t ext2 $LOOP_DEV" || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
     
     enable_gns
 
-    echo ""
-    echo "testing GNS with DEADLOCK upcall 3 times on the row"
     for ((i=0;i<3;i++)); do
-       check_gns DEADLOCK $DIR/gns_test_1b $DIR/gns_test_1b $TIMOUT $TICK GENERIC || {
-           disable_gns
-           cleanup_object $DIR/gns_test_1b
-           cleanup_loop $LOOP_DEV $LOOP_FILE
-           error
-       }
+       check_gns $DIR/gns_test_1b $DIR/gns_test_1b $TIMOUT $TICK GENERIC OPEN 1
     done
     
     disable_gns
-
     cleanup_object $DIR/gns_test_1b
     cleanup_loop $LOOP_DEV $LOOP_FILE
+
+    return 0
 }
 
 run_test 1b " general GNS test - mount/umount (DEADLOCK) ==============="
 
 test_1c() {
-    local LOOP_DEV=$(find_free_loop 2>/dev/null)
-    local LOOP_FILE="/tmp/gns_loop_1c"
+    local UPCALL="$TMP/gns-upcall-1c.sh"
+    local LOOP_FILE="$TMP/gns_loop_1c"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
+    local LOOP_DEV=""
     local TIMOUT=5
     local TICK=1
 
-    test "x$LOOP_DEV" != "x" && test -b $LOOP_DEV ||
-       error "can't find free loop device"
-
-    echo "preparing loop device $LOOP_DEV <-> $LOOP_FILE..."
-    cleanup_loop $LOOP_DEV $LOOP_FILE
-    setup_loop $LOOP_DEV $LOOP_FILE || error
+    disable_gns
 
-    echo "setting up GNS timeouts and mount object..."
-    setup_gns $OBJECT $TIMOUT $TICK || error
+    LOOP_DEV=$(setup_loop $LOOP_FILE)
+    test "x$LOOP_DEV" = "x" && 
+       error "can't find valid (free) loop device"
 
-    disable_gns
+    setup_gns $OBJECT $TIMOUT $TICK || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
 
-    echo "preparing mount object at $DIR/gns_test_1c/$OBJECT..."
-    setup_object $DIR/gns_test_1c $OBJECT "-t ext2 $LOOP_DEV" || error
+    setup_object $DIR/gns_test_1c $OBJECT "-t ext2 $LOOP_DEV" || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
 
     enable_gns
 
-    echo ""
-    echo "testing GNS with DEADLOCK upcall 4 times on the row"
     local i=0
     
     for ((;i<4;i++)); do
-       local MODE="GENERIC"
-       
-       test $(($i%2)) -eq 1 && MODE="DEADLOCK"
+       local UPCALL_MODE
        
-       check_gns $MODE $DIR/gns_test_1c $DIR/gns_test_1c $TIMOUT $TICK GENERIC || {
+       test $(($i%2)) -eq 1 && UPCALL_MODE="DEADLOCK" || 
+           UPCALL_MODE="GENERIC"
+           
+       setup_upcall $UPCALL $UPCALL_MODE $LOG FG || {
+           disable_gns
+           show_log $LOG
+           cleanup_object $DIR/gns_test_1c
+           cleanup_loop $LOOP_DEV $LOOP_FILE
+           error
+       }
+
+       check_gns $DIR/gns_test_1c $DIR/gns_test_1c $TIMOUT $TICK GENERIC OPEN 1 || {
            disable_gns
+           show_log $LOG
            cleanup_object $DIR/gns_test_1c
            cleanup_loop $LOOP_DEV $LOOP_FILE
            error
@@ -598,48 +701,52 @@ test_1c() {
     done
     
     disable_gns
-
     cleanup_object $DIR/gns_test_1c
     cleanup_loop $LOOP_DEV $LOOP_FILE
+
+    return 0
 }
 
 run_test 1c " general GNS test - mount/umount (GENERIC/DEADLOCK) ========"
 
 test_1d() {
-    local LOOP_DEV=$(find_free_loop 2>/dev/null)
-    local LOOP_FILE="/tmp/gns_loop_1d"
+    local UPCALL="$TMP/gns-upcall-1d.sh"
+    local LOOP_FILE="$TMP/gns_loop_1d"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
+    local LOOP_DEV=""
     local TIMOUT=5
     local TICK=1
 
-    test "x$LOOP_DEV" != "x" && test -b $LOOP_DEV ||
-       error "can't find free loop device"
-
-    echo "preparing loop device $LOOP_DEV <-> $LOOP_FILE..."
-    cleanup_loop $LOOP_DEV $LOOP_FILE
-    setup_loop $LOOP_DEV $LOOP_FILE || error
+    disable_gns
 
-    echo "setting up GNS timeouts and mount object..."
-    setup_gns $OBJECT $TIMOUT $TICK || error
+    LOOP_DEV=$(setup_loop $LOOP_FILE)
+    test "x$LOOP_DEV" = "x" && 
+       error "can't find valid (free) loop device"
 
-    disable_gns
+    setup_upcall $UPCALL GENERIC $LOG FG || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
 
-    echo "preparing mount object at $DIR/gns_test_1d/$OBJECT..."
-    setup_object $DIR/gns_test_1d $OBJECT "-t ext2 $LOOP_DEV" || error
+    setup_gns $OBJECT $TIMOUT $TICK || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
 
+    setup_object $DIR/gns_test_1d $OBJECT "-t ext2 $LOOP_DEV" || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
+    
     enable_gns
 
-    echo ""
-    echo "testing GNS with GENERIC/DEADLOCK upcall 4 times on the row in CONCUR1 mode"
     local i=0
     
     for ((;i<4;i++)); do
-       local MODE="GENERIC"
-       
-       test $(($i%2)) -eq 1 && MODE="DEADLOCK"
-       
-       check_gns $MODE $DIR/gns_test_1d $DIR/gns_test_1d $TIMOUT $TICK CONCUR1 || {
+       check_gns $DIR/gns_test_1d $DIR/gns_test_1d $TIMOUT $TICK CONCUR1 OPEN 1 || {
            disable_gns
+           show_log $LOG
            cleanup_object $DIR/gns_test_1d
            cleanup_loop $LOOP_DEV $LOOP_FILE
            error
@@ -647,44 +754,55 @@ test_1d() {
     done
     
     disable_gns
-
     cleanup_object $DIR/gns_test_1d
     cleanup_loop $LOOP_DEV $LOOP_FILE
+
+    return 0
 }
 
 run_test 1d " general GNS test - concurrent mount ======================="
 
 test_1e() {
-    local LOOP_DEV=$(find_free_loop 2>/dev/null)
-    local LOOP_FILE="/tmp/gns_loop_1e"
+    local UPCALL="$TMP/gns-upcall-1e.sh"
+    local LOOP_FILE="$TMP/gns_loop_1e"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
+    local LOOP_DEV=""
     local TIMOUT=5
     local TICK=1
 
-    test "x$LOOP_DEV" != "x" && test -b $LOOP_DEV ||
-       error "can't find free loop device"
+    disable_gns
 
-    echo "preparing loop device $LOOP_DEV <-> $LOOP_FILE..."
-    cleanup_loop $LOOP_DEV $LOOP_FILE
-    setup_loop $LOOP_DEV $LOOP_FILE || error
+    LOOP_DEV=$(setup_loop $LOOP_FILE)
+    test "x$LOOP_DEV" = "x" && 
+       error "can't find valid (free) loop device"
 
-    echo "setting up GNS timeouts and mount object..."
-    setup_gns $OBJECT $TIMOUT $TICK || error
+    setup_upcall $UPCALL GENERIC $LOG FG || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
 
-    disable_gns
+    setup_gns $OBJECT $TIMOUT $TICK || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
 
-    echo "preparing mount object at $DIR/gns_test_1e1/$OBJECT..."
-    setup_object $DIR/gns_test_1e1 $OBJECT "-t ext2 $LOOP_DEV" || error
+    setup_object $DIR/gns_test_1e1 $OBJECT "-t ext2 $LOOP_DEV" || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
+    
+    setup_object $DIR/gns_test_1e2 $OBJECT "-t ext2 $LOOP_DEV" || {
+        cleanup_object $DIR/gns_test_1e1
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
     
-    echo "preparing mount object at $DIR/gns_test_1e2/$OBJECT..."
-    setup_object $DIR/gns_test_1e2 $OBJECT "-t ext2 $LOOP_DEV" || error
-
     enable_gns
 
-    echo ""
-    echo "testing GNS with GENERIC upcall in CONCUR2 mode"
-    check_gns GENERIC $DIR/gns_test_1e1 $DIR/gns_test_1e2 $TIMOUT $TICK CONCUR2 || {
+    check_gns $DIR/gns_test_1e1 $DIR/gns_test_1e2 $TIMOUT $TICK CONCUR2 OPEN 1 || {
        disable_gns
+       show_log $LOG
         cleanup_object $DIR/gns_test_1e1
         cleanup_object $DIR/gns_test_1e2
         cleanup_loop $LOOP_DEV $LOOP_FILE
@@ -692,58 +810,62 @@ test_1e() {
     }
     
     disable_gns
-
     cleanup_object $DIR/gns_test_1e1
     cleanup_object $DIR/gns_test_1e2
     cleanup_loop $LOOP_DEV $LOOP_FILE
+
+    return 0
 }
 
 run_test 1e " general GNS test - concurrent mount of 2 GNS mounts ======="
 
 test_2a() {
+    local UPCALL="$TMP/gns-upcall-2a.sh"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
     local TIMOUT=5
     local TICK=1
 
-    echo "setting up GNS timeouts and mount object..."
-    setup_gns $OBJECT $TIMOUT $TICK || error
-
     disable_gns
 
-    echo "preparing mount object at $DIR/gns_test_2a/$OBJECT..."
+    setup_gns $OBJECT $TIMOUT $TICK || 
+       error
+
+    setup_upcall $UPCALL GENERIC $LOG FG ||
+       error
+
     mkdir -p $DIR/gns_test_2a
     ln -s $DIR/gns_test_2a $DIR/gns_test_2a/$OBJECT
     chmod u+s $DIR/gns_test_2a
     
     enable_gns
 
-    echo ""
-    echo "testing GNS with GENERIC upcall"
-    check_gns GENERIC $DIR/gns_test_2a $DIR/gns_test_2a $TIMOUT $TICK GENERIC && {
-       disable_gns
-       chmod u-s $DIR/gns_test_2a
-       rm -fr $DIR/gns_test_2a
-        error "symlink as mount object works?"
-    }
+    check_gns $DIR/gns_test_2a $DIR/gns_test_2a $TIMOUT $TICK GENERIC OPEN 1
     
     disable_gns
     chmod u-s $DIR/gns_test_2a
     rm -fr $DIR/gns_test_2a
+
+    return 0
 }
 
 run_test 2a " odd conditions (mount object is symlink) ============="
 
 test_2b() {
+    local UPCALL="$TMP/gns-upcall-2b.sh"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
     local TIMOUT=5
     local TICK=1
 
-    echo "setting up GNS timeouts and mount object..."
-    setup_gns $OBJECT $TIMOUT $TICK || error
-
     disable_gns
 
-    echo "preparing mount object at $DIR/gns_test_2b/$OBJECT..."
+    setup_gns $OBJECT $TIMOUT $TICK || 
+       error
+
+    setup_upcall $UPCALL GENERIC $LOG FG ||
+       error
+
     mkdir -p $DIR/gns_test_2b/$OBJECT
     chmod u+s $DIR/gns_test_2b
     
@@ -751,80 +873,76 @@ test_2b() {
     
     echo ""
     echo "testing GNS with GENERIC upcall"
-    check_gns GENERIC $DIR/gns_test_2b $DIR/gns_test_2b $TIMOUT $TICK GENERIC && {
-       disable_gns
-       chmod u-s $DIR/gns_test_2b
-       rm -fr $DIR/gns_test_2b
-        error "dir as mount object works?"
-    }
+    
+    check_gns $DIR/gns_test_2b $DIR/gns_test_2b $TIMOUT $TICK GENERIC OPEN 1
     
     disable_gns
     chmod u-s $DIR/gns_test_2b
     rm -fr $DIR/gns_test_2b
+
+    return 0
 }
 
 run_test 2b " odd conditions (mount object is directory) ==========="
 
 test_2c() {
+    local UPCALL="$TMP/gns-upcall-2c.sh"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
     local TIMOUT=5
     local TICK=1
 
-    echo "setting up GNS timeouts and mount object..."
-    setup_gns $OBJECT $TIMOUT $TICK || error
-
     disable_gns
 
-    echo "preparing mount object at $DIR/gns_test_2c/$OBJECT..."
+    setup_gns $OBJECT $TIMOUT $TICK || 
+       error
+
+    setup_upcall $UPCALL GENERIC $LOG FG ||
+       error
+
     mkdir -p $DIR/gns_test_2c/$OBJECT/$OBJECT/$OBJECT/$OBJECT
     chmod u+s -R $DIR/gns_test_2c
     
     enable_gns
     
-    echo ""
-    echo "testing GNS with GENERIC upcall"
-    check_gns GENERIC $DIR/gns_test_2c $DIR/gns_test_2c $TIMOUT $TICK GENERIC && {
-       disable_gns
-       chmod u-s -R $DIR/gns_test_2c
-       rm -fr $DIR/gns_test_2c
-        error "recursive mounting of dir as mount object works?"
-    }
-    
+    check_gns $DIR/gns_test_2c $DIR/gns_test_2c $TIMOUT $TICK GENERIC OPEN 1
+
     disable_gns
-    chmod u-s $DIR/gns_test_2c
+    chmod u-s -R $DIR/gns_test_2c
     rm -fr $DIR/gns_test_2c
+
+    return 0
 }
 
 run_test 2c " odd conditions (mount object is recursive dir) ======="
 
 test_2d() {
+    local UPCALL="$TMP/gns-upcall-2d.sh"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
     local TIMOUT=5
     local TICK=1
 
-    echo "setting up GNS timeouts and mount object..."
-    setup_gns $OBJECT $TIMOUT $TICK || error
-
     disable_gns
 
-    echo "preparing mount object at $DIR/gns_test_2d/$OBJECT..."
+    setup_gns $OBJECT $TIMOUT $TICK || 
+       error
+
+    setup_upcall $UPCALL GENERIC $LOG FG ||
+       error
+
     mkdir -p $DIR/gns_test_2d
     chmod u+s $DIR/gns_test_2d
     
     enable_gns
 
-    echo ""
-    echo "testing GNS with GENERIC upcall"
-    check_gns GENERIC $DIR/gns_test_2d $DIR/gns_test_2d $TIMOUT $TICK GENERIC && {
-       disable_gns
-       chmod u-s $DIR/gns_test_2d
-       rm -fr $DIR/gns_test_2d
-        error "mount point with absent mount object works?"
-    }
+    check_gns $DIR/gns_test_2d $DIR/gns_test_2d $TIMOUT $TICK GENERIC OPEN 1
     
     disable_gns
     chmod u-s $DIR/gns_test_2d
     rm -fr $DIR/gns_test_2d
+
+    return 0
 }
 
 run_test 2d " odd conditions (mount object is absent) =============="
@@ -834,9 +952,6 @@ test_2e() {
     local TIMOUT=5
     local TICK=1
 
-    echo "setting up GNS timeouts and mount object..."
-    setup_gns $OBJECT $TIMOUT $TICK || error
-
     echo "." > /proc/fs/lustre/llite/fs0/gns_object_name
     test "x$(cat /proc/fs/lustre/llite/fs0/gns_object_name)" = "x." && 
        error "'.' is set as mount object name"
@@ -852,142 +967,327 @@ test_2e() {
     echo "..a" > /proc/fs/lustre/llite/fs0/gns_object_name
     test "x$(cat /proc/fs/lustre/llite/fs0/gns_object_name)" = "x..a" || 
        error "'..a' is not set as mount object name"
+
+    return 0
 }
 
 run_test 2e " odd conditions ('.' and '..' as mount object) ============="
 
 test_2f() {
-    local LOOP_DEV=$(find_free_loop 2>/dev/null)
-    local LOOP_FILE="/tmp/gns_loop_2f"
+    local UPCALL="$TMP/gns-upcall-2f.sh"
+    local LOOP_FILE="$TMP/gns_loop_2f"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
+    local LOOP_DEV=""
     local TIMOUT=5
     local TICK=1
 
-    test "x$LOOP_DEV" != "x" && test -b $LOOP_DEV ||
-       error "can't find free loop device"
-
-    echo "preparing loop device $LOOP_DEV <-> $LOOP_FILE..."
-    cleanup_loop $LOOP_DEV $LOOP_FILE
-    setup_loop $LOOP_DEV $LOOP_FILE || error
+    disable_gns
 
-    echo "setting up GNS timeouts and mount object..."
-    setup_gns $OBJECT $TIMOUT $TICK || error
+    LOOP_DEV=$(setup_loop $LOOP_FILE)
+    test "x$LOOP_DEV" = "x" && 
+       error "can't find valid (free) loop device"
 
-    disable_gns
+    setup_upcall $UPCALL GENERIC $LOG FG || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
 
-    echo "preparing mount object at $DIR/gns_test_2f/$OBJECT..."
-    setup_object $DIR/gns_test_2f $OBJECT "-t ext2 $LOOP_DEV" || error
+    setup_gns $OBJECT $TIMOUT $TICK || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
 
+    setup_object $DIR/gns_test_2f $OBJECT "-t ext2 $LOOP_DEV" || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
+    
     enable_gns
 
-    echo ""
-    echo "testing GNS with DEADLOCK upcall in CONCUR3 mode"
-    
-    local MODE="DEADLOCK"
-       
-    check_gns $MODE $DIR/gns_test_2f $DIR/gns_test_2f $TIMOUT $TICK CONCUR3 || {
+    check_gns $DIR/gns_test_2f $DIR/gns_test_2f $TIMOUT $TICK CONCUR3 OPEN 1 || {
         disable_gns
+       show_log $LOG
         cleanup_object $DIR/gns_test_2f
         cleanup_loop $LOOP_DEV $LOOP_FILE
         error
     }
     
     disable_gns
-
     cleanup_object $DIR/gns_test_2f
     cleanup_loop $LOOP_DEV $LOOP_FILE
+
+    return 0
 }
 
 run_test 2f " odd conditions (mount point is modifying during mount) ===="
 
 test_2g() {
-    local LOOP_DEV=$(find_free_loop 2>/dev/null)
-    local LOOP_FILE="/tmp/gns_loop_2g"
+    local UPCALL="$TMP/gns-upcall-2g.sh"
+    local LOOP_FILE="$TMP/gns_loop_2g"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
+    local LOOP_DEV=""
     local TIMOUT=5
     local TICK=1
 
-    test "x$LOOP_DEV" != "x" && test -b $LOOP_DEV ||
-       error "can't find free loop device"
+    disable_gns
 
-    echo "preparing loop device $LOOP_DEV <-> $LOOP_FILE..."
-    cleanup_loop $LOOP_DEV $LOOP_FILE
-    setup_loop $LOOP_DEV $LOOP_FILE || error
+    LOOP_DEV=$(setup_loop $LOOP_FILE)
+    test "x$LOOP_DEV" = "x" && 
+       error "can't find valid (free) loop device"
 
-    echo "setting up GNS timeouts and mount object..."
-    setup_gns $OBJECT $TIMOUT $TICK || error
+    setup_upcall $UPCALL GENERIC $LOG FG || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
 
-    disable_gns
+    setup_gns $OBJECT $TIMOUT $TICK || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
 
-    echo "preparing mount object at $DIR/gns_test_2g/$OBJECT..."
-    setup_object $DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT \
-$OBJECT "-t ext2 $LOOP_DEV" || error
+    setup_object $DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT $OBJECT "-t ext2 $LOOP_DEV" || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
+    chmod u+s $DIR/gns_test_2g -R
 
     enable_gns
 
-    echo ""
-    echo "testing GNS with DEADLOCK upcall in GENERIC mode"
-    
-    local MODE="DEADLOCK"
-       
-    check_gns $MODE $DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT \
-$DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT $TIMOUT $TICK GENERIC || {
+    check_gns $DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT \
+$DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT $TIMOUT $TICK GENERIC OPEN 1 || {
         disable_gns
+       show_log $LOG
         cleanup_object $DIR/gns_test_2g
         cleanup_loop $LOOP_DEV $LOOP_FILE
-        error
+        error "recursive mount point does not work"
     }
     
     disable_gns
 
+    echo ""
+    echo "turning SUID on $DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT off"
+    chmod u-s $DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT
+
+    enable_gns
+
+    check_gns $DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT \
+$DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT $TIMOUT $TICK GENERIC OPEN 1 && {
+        disable_gns
+       show_log $LOG
+        cleanup_object $DIR/gns_test_2g
+        cleanup_loop $LOOP_DEV $LOOP_FILE
+        error "GNS works whereas mount point is not SUID marked dir"
+    }
+
+    disable_gns
     cleanup_object $DIR/gns_test_2g
     cleanup_loop $LOOP_DEV $LOOP_FILE
+
+    return 0
 }
 
 run_test 2g " odd conditions (mount point is recursive marked SUID dir) ="
 
 test_2h() {
-    local LOOP_DEV=$(find_free_loop 2>/dev/null)
-    local LOOP_FILE="/tmp/gns_loop_2h"
+    local UPCALL="$TMP/gns-upcall-2h.sh"
+    local LOOP_FILE="$TMP/gns_loop_2h"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
+    local LOOP_DEV=""
     local TIMOUT=5
     local TICK=1
 
-    test "x$LOOP_DEV" != "x" && test -b $LOOP_DEV ||
-       error "can't find free loop device"
+    disable_gns
+
+    LOOP_DEV=$(setup_loop $LOOP_FILE)
+    test "x$LOOP_DEV" = "x" && 
+       error "can't find valid (free) loop device"
+
+    setup_upcall $UPCALL GENERIC $LOG BG || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
+
+    setup_gns $OBJECT $TIMOUT $TICK || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
 
-    echo "preparing loop device $LOOP_DEV <-> $LOOP_FILE..."
+    setup_object $DIR/gns_test_2h $OBJECT "-t ext2 $LOOP_DEV" || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
+    
+    enable_gns
+
+    check_gns $DIR/gns_test_2h $DIR/gns_test_2h $TIMOUT $TICK GENERIC OPEN 1 || {
+        disable_gns
+       show_log $LOG
+        cleanup_object $DIR/gns_test_2h
+        cleanup_loop $LOOP_DEV $LOOP_FILE
+        error
+    }
+    
+    disable_gns
+    cleanup_object $DIR/gns_test_2h
     cleanup_loop $LOOP_DEV $LOOP_FILE
-    setup_loop $LOOP_DEV $LOOP_FILE || error
 
-    echo "setting up GNS timeouts and mount object..."
-    setup_gns $OBJECT $TIMOUT $TICK || error
+    return 0
+}
+
+run_test 2h " odd conditions (mounting in background) ==================="
+
+test_3a() {
+    local UPCALL="$TMP/gns-upcall-3a.sh"
+    local LOOP_FILE="$TMP/gns_loop_3a"
+    local LOG="$TMP/gns-log"
+    local OBJECT=".mntinfo"
+    local LOOP_DEV=""
+    local TIMOUT=5
+    local TICK=1
 
     disable_gns
 
-    echo "preparing mount object at $DIR/gns_test_2h/$OBJECT..."
-    setup_object $DIR/gns_test_2h $OBJECT "-t ext2 $LOOP_DEV" || error
+    LOOP_DEV=$(setup_loop $LOOP_FILE)
+    test "x$LOOP_DEV" = "x" && 
+       error "can't find valid (free) loop device"
 
-    enable_gns
+    setup_upcall $UPCALL GENERIC $LOG FG || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
 
-    echo ""
-    echo "testing GNS with GENERIC upcall in GENERIC mode"
+    setup_gns $OBJECT $TIMOUT $TICK || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
+
+    setup_object $DIR/gns_test_3a $OBJECT "-t ext2 $LOOP_DEV" || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
     
-    check_gns GENERIC $DIR/gns_test_2h $DIR/gns_test_2h \
-$TIMOUT $TICK GENERIC BACKGROUND || {
+    enable_gns
+
+    check_gns $DIR/gns_test_3a $DIR/gns_test_3a $TIMOUT $TICK GENERIC OPEN 1 || {
         disable_gns
-        cleanup_object $DIR/gns_test_2h
+       show_log $LOG
+        cleanup_object $DIR/gns_test_3a
         cleanup_loop $LOOP_DEV $LOOP_FILE
         error
     }
     
+    chmod u-s $DIR/gns_test_3a || {
+        disable_gns
+        cleanup_object $DIR/gns_test_3a
+        cleanup_loop $LOOP_DEV $LOOP_FILE
+       error "can't chmod u-s $DIR/gns_test_3a"
+    }
+    
+    check_mnt $DIR/gns_test_3a 0 0 0 || {
+        disable_gns
+        cleanup_object $DIR/gns_test_3a
+        cleanup_loop $LOOP_DEV $LOOP_FILE
+       error "chmod u-s $DIR/gns_test_3a caused mounting?"
+    }
+    
     disable_gns
+    cleanup_object $DIR/gns_test_3a
+    cleanup_loop $LOOP_DEV $LOOP_FILE
+    
+    return 0
+}
 
-    cleanup_object $DIR/gns_test_2h
+run_test 3a " removing mnt by chmod u-s ================================="
+
+test_3b() {
+    local LOOP_FILE="$TMP/gns_loop_3b"
+    local UPCALL="$TMP/gns-upcall-3b.sh"
+    local LOG="$TMP/gns-log"
+    local OBJECT=".mntinfo"
+    local LOOP_DEV=""
+    local TIMOUT=5
+    local TICK=1
+
+    disable_gns
+
+    LOOP_DEV=$(setup_loop $LOOP_FILE)
+    test "x$LOOP_DEV" = "x" && 
+       error "can't find valid (free) loop device"
+
+    setup_upcall $UPCALL GENERIC $LOG FG || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
+
+    setup_object $DIR/gns_test_3b1 $OBJECT "-t ext2 $LOOP_DEV" || {
+        cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
+    
+    mkdir -p $TMP/mnt || error
+    mount -t ext2 $LOOP_DEV $TMP/mnt || {
+        cleanup_object $DIR/gns_test_3b1
+        cleanup_loop $LOOP_DEV $LOOP_FILE
+       error "cannot mount $LOOP_DEV"
+    }
+
+    mkdir $TMP/mnt/gns_test_3b2 || {
+       umount $TMP/mnt
+        cleanup_object $DIR/gns_test_3b1
+        cleanup_loop $LOOP_DEV $LOOP_FILE
+       error "can't create $TMP/mnt/gns_test_3b2"
+    }
+    
+    umount $TMP/mnt || {
+        cleanup_object $DIR/gns_test_3b1
+        cleanup_loop $LOOP_DEV $LOOP_FILE
+       error "can't umount $TMP/mnt"
+    }
+
+    setup_gns $OBJECT $TIMOUT $TICK || {
+        cleanup_object $DIR/gns_test_3b1
+        cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
+
+    enable_gns
+
+    check_gns $DIR/gns_test_3b1/gns_test_3b2 $DIR/gns_test_3b1/gns_test_3b2 \
+$TIMOUT $TICK GENERIC LIST 0 || {
+       disable_gns
+       show_log $LOG
+        cleanup_object $DIR/gns_test_3b1
+        cleanup_loop $LOOP_DEV $LOOP_FILE
+        error
+    }
+    
+    check_mnt $DIR/gns_test_3b1 1 0 0 || {
+       disable_gns
+       show_log $LOG
+        cleanup_object $DIR/gns_test_3b1
+        cleanup_loop $LOOP_DEV $LOOP_FILE
+        error
+    }
+    
+    check_mnt $DIR/gns_test_3b1 0 $TIMOUT $TICK || {
+       disable_gns
+       show_log $LOG
+        cleanup_object $DIR/gns_test_3b1
+        cleanup_loop $LOOP_DEV $LOOP_FILE
+        error
+    }
+
+    disable_gns
+    cleanup_object $DIR/gns_test_3b1
     cleanup_loop $LOOP_DEV $LOOP_FILE
+
+    return 0
 }
 
-run_test 2h " odd conditions (mounting in background) ==================="
+run_test 3b " readdir through mount point ==============================="
 
 TMPDIR=$OLDTMPDIR
 TMP=$OLDTMP