Whamcloud - gitweb
- fixes and improvements in GNS:
authoryury <yury>
Mon, 16 May 2005 06:48:21 +0000 (06:48 +0000)
committeryury <yury>
Mon, 16 May 2005 06:48:21 +0000 (06:48 +0000)
  - making it work in some stat cases (stat target is behind mount object)
  - making it work in sys_mount() control path (is mount point is behind mount object)

  - to avoid deadlock is mount case is_subdir() is used for detecting is current dentry is
    parent of dentry being in progress of mounting.

  - do not mount on revalidate if there is not valid @nd applied.
  - using nd->flags if possible for both lookup and revalidate cases.
  - added debug info printing in mounting cases.
  - totaly removed -ERESTARTSYS approach stuff.

  - fixed bug with many waiters on ->ll_gns_mount_finished - only first of them will find GNS
    in IDLE state and will start mounting and the rest will assert on wrong GNS state (MOUNTING)

  - reinit ->ll_gns_mount_finished after all waiters are awakaned, this fixes the bug when
    after first using this completion it does not functions, because complete_all() has
    slighly diff. semanthics then complete() and namely does not just decrease ->done but
    sets it to MAX_INT/2.

  - fully rewritten sanity-gns.sh to make it more flexible and easy to add new sanity tests.

lustre/llite/dcache.c
lustre/llite/llite_gns.c
lustre/llite/llite_internal.h
lustre/llite/llite_lib.c
lustre/llite/namei.c
lustre/tests/sanity-gns.sh

index 427c07a..bed7aeb 100644 (file)
@@ -308,11 +308,11 @@ int ll_revalidate_it(struct dentry *de, int flags, struct nameidata *nd,
 {
         struct lookup_intent lookup_it = { .it_op = IT_LOOKUP };
         struct ptlrpc_request *req = NULL;
+        int gns_it, gns_flags, rc = 0;
         struct obd_export *exp;
         struct it_cb_data icbd;
         struct lustre_id pid;
         struct lustre_id cid;
-        int gns_it, rc = 0;
         ENTRY;
 
         CDEBUG(D_VFSTRACE, "VFS Op:name=%s (%p), intent=%s\n", de->d_name.name,
@@ -322,8 +322,10 @@ int ll_revalidate_it(struct dentry *de, int flags, struct nameidata *nd,
         if (de->d_inode == NULL)
                 RETURN(0);
 
-        /* Root of the tree is always valid, attributes would be fixed in
-          ll_inode_revalidate_it */
+        /*
+         * root of the tree is always valid, attributes would be fixed in
+         * ll_inode_revalidate_it()
+         */
         if (de->d_sb->s_root == de)
                 RETURN(1);
 
@@ -351,8 +353,8 @@ int ll_revalidate_it(struct dentry *de, int flags, struct nameidata *nd,
                 nd->mnt->mnt_last_used = jiffies;
 
         OBD_FAIL_TIMEOUT(OBD_FAIL_MDC_REVALIDATE_PAUSE, 5);
-
-        gns_it = it ? it->it_op : IT_OPEN;
+        gns_it = nd ? nd->intent.open.it_op : IT_OPEN;
+        gns_flags = nd ? nd->flags : LOOKUP_CONTINUE;
 
         if (it && it->it_op == IT_GETATTR)
                 it = NULL; /* will use it_lookup */
@@ -483,14 +485,18 @@ out:
          * lookup control path, which is always made with parent's i_sem taken.
          * --umka
          */
-        if (atomic_read(&ll_i2sbi(de->d_inode)->ll_gns_enabled) &&
+        if (nd && atomic_read(&ll_i2sbi(de->d_inode)->ll_gns_enabled) &&
             (de->d_inode->i_mode & S_ISUID) && S_ISDIR(de->d_inode->i_mode) &&
-            (flags & LOOKUP_CONTINUE || (gns_it & (IT_CHDIR | IT_OPEN)))) {
+            (gns_flags & LOOKUP_CONTINUE || (gns_it & (IT_CHDIR | IT_OPEN)))) {
                 /* 
                  * special "." and ".." has to be always revalidated because
                  * they never should be passed to lookup()
                  */
                 if (!ll_special_name(de)) {
+                        CDEBUG(D_DENTRY, "possible GNS dentry %*s %p found, "
+                               "causing mounting\n", (int)de->d_name.len,
+                               de->d_name.name, de);
+                        
                         LASSERT(req == NULL);
                         if (it == &lookup_it) {
                                 ll_intent_release(it);
@@ -498,7 +504,7 @@ out:
                                 ll_intent_drop_lock(it);
                         }
                         ll_unhash_aliases(de->d_inode);
-                        RETURN (0);
+                        RETURN(0);
                 }
         }
 
index ab076db..289ac84 100644 (file)
@@ -40,8 +40,6 @@ static spinlock_t gns_lock = SPIN_LOCK_UNLOCKED;
 static struct ptlrpc_thread gns_thread;
 static struct ll_gns_ctl gns_ctl;
 
-#define CONCUR_GNS_RESTART_APPROACH 0
-
 /*
  * waits until passed dentry gets mountpoint or timeout and attempts are
  * exhausted. Returns 1 if dentry became mountpoint and 0 otherwise.
@@ -71,26 +69,6 @@ ll_gns_wait_for_mount(struct dentry *dentry,
         RETURN(-ETIME);
 }
 
-#if (CONCUR_GNS_RESTART_APPROACH == 1)
-/* 
- * sending a signal known to be ignored to cause restarting syscall if GNS mount
- * function returns -ERESTARTSYS.
- */
-static void
-ll_gns_send_signal(void)
-{
-        struct task_struct *task = current;
-        int signal = SIGCONT;
-
-        read_lock(&tasklist_lock);
-        spin_lock_irq(&task->sighand->siglock);
-        sigaddset(&task->pending.signal, signal);
-        spin_unlock_irq(&task->sighand->siglock);
-        read_unlock(&tasklist_lock);
-        set_tsk_thread_flag(task, TIF_SIGPENDING);
-}
-#endif
-
 /*
  * tries to mount the mount object under passed @dentry. In the case of success
  * @dentry will become mount point and 0 will be returned. Error code will be
@@ -123,19 +101,19 @@ ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
                 RETURN(-EINVAL);
 
         spin_lock(&sbi->ll_gns_lock);
-
+       
         /* 
          * another thead is in progress or just finished mounting the
          * dentry. Handling that.
          */
-        if (sbi->ll_gns_state == LL_GNS_MOUNTING ||
-            sbi->ll_gns_state == LL_GNS_FINISHED) {
+        if (sbi->ll_gns_state != LL_GNS_IDLE) {
                 /* 
                  * another thread is trying to mount GNS dentry. We'd like to
                  * handling that.
                  */
                 spin_unlock(&sbi->ll_gns_lock);
 
+        restart:
                 /* 
                  * check if dentry is mount point already, if so, do not restart
                  * syscal.
@@ -143,14 +121,14 @@ ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
                 if (d_mountpoint(dentry))
                         RETURN(0);
 
-#if (CONCUR_GNS_RESTART_APPROACH == 1)
-                /* 
-                 * causing syscall to restart and possibly find this dentry
-                 * already mounted.
-                 */
-                ll_gns_send_signal();
-                RETURN(-ERESTARTSYS);
-#else
+                spin_lock(&sbi->ll_gns_lock);
+               if (sbi->ll_gns_pending_dentry && 
+                   is_subdir(sbi->ll_gns_pending_dentry, dentry)) {
+                       spin_unlock(&sbi->ll_gns_lock);
+                       RETURN(-EAGAIN);
+               }
+                spin_unlock(&sbi->ll_gns_lock);
+
                 /* 
                  * waiting for GNS complete and check dentry again, it may be
                  * mounted already.
@@ -158,14 +136,25 @@ ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
                 wait_for_completion(&sbi->ll_gns_mount_finished);
                 if (d_mountpoint(dentry))
                         RETURN(0);
-#endif
+
+                /* 
+                 * check for he case when there are few waiters and all they are
+                 * awakened, but only one will find GNS state LL_GNS_IDLE, and
+                 * the rest will face with LL_GNS_MOUNTING.  --umka
+                 */
+                spin_lock(&sbi->ll_gns_lock);
+                if (sbi->ll_gns_state != LL_GNS_IDLE) {
+                        spin_unlock(&sbi->ll_gns_lock);
+                        goto restart;
+                }
+                spin_unlock(&sbi->ll_gns_lock);
         }
         LASSERT(sbi->ll_gns_state == LL_GNS_IDLE);
-
         CDEBUG(D_INODE, "mounting dentry %p\n", dentry);
 
         /* mounting started */
         sbi->ll_gns_state = LL_GNS_MOUNTING;
+       sbi->ll_gns_pending_dentry = dentry;
         spin_unlock(&sbi->ll_gns_lock);
 
         /* we need to build an absolute pathname to pass to mount */
@@ -193,8 +182,7 @@ ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
         /* 
          * recursive lookup with trying to mount SUID bit marked directories on
          * the way is not possible here, as lookup_one_len() does not pass @nd
-         * to ->lookup() and this is checked in ll_lookup_it(). So, do not
-         * handle possible -EAGAIN here.
+         * to ->lookup() and this is checked in ll_lookup_it().
          */
         dchild = ll_lookup_one_len(sbi->ll_gns_oname, dentry,
                                    strlen(sbi->ll_gns_oname));
@@ -343,8 +331,12 @@ cleanup:
         case 0:
                 spin_lock(&sbi->ll_gns_lock);
                 sbi->ll_gns_state = LL_GNS_IDLE;
+               sbi->ll_gns_pending_dentry = NULL;
                 spin_unlock(&sbi->ll_gns_lock);
+
+                /* waking up all waiters after GNS state is LL_GNS_IDLE */
                 complete_all(&sbi->ll_gns_mount_finished);
+                init_completion(&sbi->ll_gns_mount_finished);
         }
         return rc;
 }
index 1058df5..bb7ea25 100644 (file)
@@ -98,6 +98,7 @@ struct ll_sb_info {
         struct timer_list         ll_gns_timer;
         struct list_head          ll_gns_sbi_head;
         struct completion         ll_gns_mount_finished;
+       struct dentry            *ll_gns_pending_dentry;
 
         unsigned long             ll_gns_tick;
         unsigned long             ll_gns_timeout;
index fcf0c64..6801508 100644 (file)
@@ -83,6 +83,7 @@ struct ll_sb_info *lustre_init_sbi(struct super_block *sb)
 
         /* default values, may be changed via /proc/fs/... */
         sbi->ll_gns_state = LL_GNS_IDLE;
+       sbi->ll_gns_pending_dentry = NULL;
         atomic_set(&sbi->ll_gns_enabled, 1);
         sbi->ll_gns_tick = GNS_TICK_TIMEOUT;
         sbi->ll_gns_timeout = GNS_MOUNT_TIMEOUT;
index e322639..9d75bf9 100644 (file)
@@ -351,13 +351,13 @@ static int lookup_it_finish(struct ptlrpc_request *request, int offset,
 static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
                                    struct nameidata *nd, int flags)
 {
-        struct dentry *save = dentry, *retval;
         struct lookup_intent *it = flags ? &nd->intent.open : NULL;
-        struct lustre_id pid;
-        struct it_cb_data icbd;
-        struct ptlrpc_request *req = NULL;
         struct lookup_intent lookup_it = { .it_op = IT_LOOKUP };
-        int rc, gns_it;
+        struct dentry *save = dentry, *retval;
+        struct ptlrpc_request *req = NULL;
+        int rc, gns_it, gns_flags;
+        struct it_cb_data icbd;
+        struct lustre_id pid;
         ENTRY;
 
         if (dentry->d_name.len > EXT3_NAME_LEN)
@@ -374,6 +374,7 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
                 nd->mnt->mnt_last_used = jiffies;
 
         gns_it = nd ? nd->intent.open.it_op : IT_OPEN;
+        gns_flags = nd ? nd->flags : LOOKUP_CONTINUE;
         ll_frob_intent(&it, &lookup_it);
 
         icbd.icbd_childp = &dentry;
@@ -396,12 +397,13 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
 
         if (nd && dentry->d_inode != NULL &&
             dentry->d_inode->i_mode & S_ISUID && S_ISDIR(dentry->d_inode->i_mode) &&
-            ((flags & LOOKUP_CONTINUE) || (gns_it & (IT_CHDIR | IT_OPEN))))
+            ((gns_flags & LOOKUP_CONTINUE) || (gns_it & (IT_CHDIR | IT_OPEN))))
         {
+                CDEBUG(D_DENTRY, "possible GNS dentry %*s %p found, "
+                       "mounting it\n", (int)dentry->d_name.len,
+                       dentry->d_name.name, dentry);
+                
                 rc = ll_gns_mount_object(dentry, nd->mnt);
-                if (rc == -ERESTARTSYS)
-                        GOTO(out, retval = ERR_PTR(-ERESTARTSYS));
-
                 if (rc) {
                         /* 
                          * just reporting about GNS failures, lookup() is
@@ -417,7 +419,7 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
                          * where all ".mntinfo" are dirs and only last one is
                          * reg file.
                          */
-                        CDEBUG(D_INODE, "failed to mount %*s, err %d\n",
+                        CDEBUG(D_DENTRY, "failed to mount %*s, err %d\n",
                                (int)dentry->d_name.len, dentry->d_name.name, rc);
                 }
         }
index 0e07952..0890742 100644 (file)
@@ -7,7 +7,7 @@
 set -e
 
 ONLY=${ONLY:-"$*"}
-ALWAYS_EXCEPT=${ALWAYS_EXCEPT:-""}
+ALWAYS_EXCEPT=${ALWAYS_EXCEPT:-"1b 1c 3b"}
 [ "$ALWAYS_EXCEPT$EXCEPT" ] && echo "Skipping tests: $ALWAYS_EXCEPT $EXCEPT"
 
 SRCDIR=`dirname $0`
@@ -198,7 +198,11 @@ setup_loop() {
     local LOOP_DEV=$1
     local LOOP_FILE=$2
     
-    dd if=/dev/zero of=$LOOP_FILE bs=1M count=10 2>/dev/null || return $?
+    echo "preparing loop device $LOOP_DEV <-> $LOOP_FILE..."
+    cleanup_loop $LOOP_DEV $LOOP_FILE
+    
+    dd if=/dev/zero of=$LOOP_FILE bs=1M count=10 2>/dev/null || 
+       return $?
 
     losetup $LOOP_DEV $LOOP_FILE || {
        rc=$?
@@ -230,11 +234,13 @@ setup_upcall() {
     local LOG=$3
     local BG=$4
     
+    echo "generating upcall $UPCALL"
+
     test "x$BG" = "xBG" && 
        BG="&" || BG=""
     
-#    test "x$MODE" = "xDEADLOCK" &&
-#      INJECTION="touch \$MNTPATH/file"
+    test "x$MODE" = "xDEADLOCK" &&
+       INJECTION="touch \$MNTPATH/file"
     
     cat > $UPCALL <<- EOF
 #!/bin/sh
@@ -253,7 +259,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 ==========================="
+    cat $UPCALL 2>/dev/null || return $?
+    echo "=================================================================="
+   
+    return 0
 }
 
 cleanup_upcall() {
@@ -276,7 +290,8 @@ check_mnt()
     local OBJECT=$1
     local mnt=""
     local p=""
-    
+
+    OBJECT="`echo $OBJECT | sed 's/\/*$//'`"
     mnt="`cat /proc/mounts | grep $OBJECT | awk '{print \$2}'`"
     test -z "$mnt" && return 1
     
@@ -289,33 +304,15 @@ check_mnt()
 
 check_gns() {
     local LOG="$TMP/gns-log"
-    local UPCALL_PATH=""
+    local OBJECT1=$1
+    local OBJECT2=$2
+    local TIMOUT=$3
+    local TICK=$4
+    local MODE=$5
+    local OP=$6
     
-    local UPCALL=$1
-    local OBJECT1=$2
-    local OBJECT2=$3
-    local TIMOUT=$4
-    local TICK=$5
-    local MODE=$6
-    local BG=$7
-    local OP=$8
-    
-    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)"
-
-    echo -n "mount on $OP: "
-
     local OLD_PWD=$(pwd)
+    echo -n "mount on $OP: "
     
     case "$MODE" in
        GENERIC)
@@ -467,7 +464,6 @@ check_gns() {
     fi
     
     echo "success"
-    cleanup_upcall $UPCALL_PATH
     return 0
 }
 
@@ -476,6 +472,8 @@ setup_object() {
     local OBJECT=$2
     local CONTENT=$3
     
+    echo "preparing mount object at $OBJPATH..."
+    
     mkdir -p $OBJPATH || return $?
     echo -n $CONTENT > $OBJPATH/$OBJECT || return $?
     
@@ -501,6 +499,8 @@ setup_gns() {
     local TIMOUT=$2
     local TICK=$3
 
+    echo "setting up GNS timeouts and mount object..."
+
     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
@@ -515,48 +515,57 @@ 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 UPCALL="$TMP/gns-upcall-1a.sh"
     local LOOP_FILE="$TMP/gns_loop_1a"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
     local TIMOUT=5
     local TICK=1
 
+    disable_gns
+
     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
+    setup_loop $LOOP_DEV $LOOP_FILE || 
+       error
 
-    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"
     
-    echo ""
-    echo "testing OPEN operation"
-    
     for ((i=0;i<3;i++)); do
-       check_gns GENERIC $DIR/gns_test_1a $DIR/gns_test_1a $TIMOUT $TICK GENERIC FG OPEN || {
+       check_gns $DIR/gns_test_1a/ $DIR/gns_test_1a $TIMOUT $TICK GENERIC OPEN || {
            disable_gns
            cleanup_object $DIR/gns_test_1a
            cleanup_loop $LOOP_DEV $LOOP_FILE
@@ -564,11 +573,8 @@ test_1a() {
        }
     done
     
-    echo ""
-    echo "testing CHDIR operation"
-    
     for ((i=0;i<3;i++)); do
-       check_gns GENERIC $DIR/gns_test_1a $DIR/gns_test_1a $TIMOUT $TICK GENERIC FG CHDIR || {
+       check_gns $DIR/gns_test_1a $DIR/gns_test_1a $TIMOUT $TICK GENERIC CHDIR || {
            disable_gns
            cleanup_object $DIR/gns_test_1a
            cleanup_loop $LOOP_DEV $LOOP_FILE
@@ -577,9 +583,9 @@ test_1a() {
     done
     
     disable_gns
-
     cleanup_object $DIR/gns_test_1a
     cleanup_loop $LOOP_DEV $LOOP_FILE
+
     return 0
 }
 
@@ -587,25 +593,35 @@ run_test 1a " general GNS test - mount/umount (GENERIC) ================"
 
 test_1b() {
     local LOOP_DEV=$(find_free_loop 2>/dev/null)
+    local UPCALL="$TMP/gns-upcall-1b.sh"
     local LOOP_FILE="$TMP/gns_loop_1b"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
     local TIMOUT=5
     local TICK=1
 
+    disable_gns
+
     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
+    setup_loop $LOOP_DEV $LOOP_FILE || 
+       error
 
-    echo "setting up GNS timeouts and mount object..."
-    setup_gns $OBJECT $TIMOUT $TICK || error
+    setup_upcall $UPCALL DEADLOCK $LOG FG || {
+       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_gns $OBJECT $TIMOUT $TICK || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
+
+    setup_object $DIR/gns_test_1b $OBJECT "-t ext2 $LOOP_DEV" || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
     
     enable_gns
 
@@ -613,13 +629,13 @@ test_1b() {
     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 FG OPEN
+       check_gns $DIR/gns_test_1b $DIR/gns_test_1b $TIMOUT $TICK GENERIC OPEN
     done
     
     disable_gns
-
     cleanup_object $DIR/gns_test_1b
     cleanup_loop $LOOP_DEV $LOOP_FILE
+
     return 0
 }
 
@@ -627,25 +643,30 @@ run_test 1b " general GNS test - mount/umount (DEADLOCK) ==============="
 
 test_1c() {
     local LOOP_DEV=$(find_free_loop 2>/dev/null)
+    local UPCALL="$TMP/gns-upcall-1c.sh"
     local LOOP_FILE="$TMP/gns_loop_1c"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
     local TIMOUT=5
     local TICK=1
 
+    disable_gns
+
     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
-
-    echo "setting up GNS timeouts and mount object..."
-    setup_gns $OBJECT $TIMOUT $TICK || error
+    setup_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_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
 
@@ -654,23 +675,30 @@ test_1c() {
     local i=0
     
     for ((;i<4;i++)); do
-       test $(($i%2)) -eq 1 && {
-           check_gns DEADLOCK $DIR/gns_test_1c $DIR/gns_test_1c $TIMOUT $TICK GENERIC FG OPEN
-       } || {
-           check_gns GENERIC $DIR/gns_test_1c $DIR/gns_test_1c $TIMOUT $TICK GENERIC FG OPEN || {
-               disable_gns
-               cleanup_object $DIR/gns_test_1c
-               cleanup_loop $LOOP_DEV $LOOP_FILE
-               error "generic upcall does not work!"
-           }
-       }
+       local UPCALL_MODE
        
+       test $(($i%2)) -eq 1 && UPCALL_MODE="DEADLOCK" || 
+           UPCALL_MODE="GENERIC"
+           
+       setup_upcall $UPCALL $UPCALL_MODE $LOG FG || {
+           disable_gns
+           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 || {
+           disable_gns
+           cleanup_object $DIR/gns_test_1c
+           cleanup_loop $LOOP_DEV $LOOP_FILE
+           error
+       }
     done
     
     disable_gns
-
     cleanup_object $DIR/gns_test_1c
     cleanup_loop $LOOP_DEV $LOOP_FILE
+
     return 0
 }
 
@@ -678,26 +706,36 @@ run_test 1c " general GNS test - mount/umount (GENERIC/DEADLOCK) ========"
 
 test_1d() {
     local LOOP_DEV=$(find_free_loop 2>/dev/null)
+    local UPCALL="$TMP/gns-upcall-1d.sh"
     local LOOP_FILE="$TMP/gns_loop_1d"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
     local TIMOUT=5
     local TICK=1
 
+    disable_gns
+
     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
-
-    echo "setting up GNS timeouts and mount object..."
-    setup_gns $OBJECT $TIMOUT $TICK || error
+    setup_loop $LOOP_DEV $LOOP_FILE || 
+       error
 
-    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 ""
@@ -705,7 +743,7 @@ test_1d() {
     local i=0
     
     for ((;i<4;i++)); do
-       check_gns GENERIC $DIR/gns_test_1d $DIR/gns_test_1d $TIMOUT $TICK CONCUR1 FG OPEN || {
+       check_gns $DIR/gns_test_1d $DIR/gns_test_1d $TIMOUT $TICK CONCUR1 OPEN || {
            disable_gns
            cleanup_object $DIR/gns_test_1d
            cleanup_loop $LOOP_DEV $LOOP_FILE
@@ -714,9 +752,9 @@ test_1d() {
     done
     
     disable_gns
-
     cleanup_object $DIR/gns_test_1d
     cleanup_loop $LOOP_DEV $LOOP_FILE
+
     return 0
 }
 
@@ -724,35 +762,48 @@ run_test 1d " general GNS test - concurrent mount ======================="
 
 test_1e() {
     local LOOP_DEV=$(find_free_loop 2>/dev/null)
+    local UPCALL="$TMP/gns-upcall-1e.sh"
     local LOOP_FILE="$TMP/gns_loop_1e"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
     local TIMOUT=5
     local TICK=1
 
+    disable_gns
+
     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
+    setup_loop $LOOP_DEV $LOOP_FILE || 
+       error
 
-    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 FG OPEN || {
+    check_gns $DIR/gns_test_1e1 $DIR/gns_test_1e2 $TIMOUT $TICK CONCUR2 OPEN || {
        disable_gns
         cleanup_object $DIR/gns_test_1e1
         cleanup_object $DIR/gns_test_1e2
@@ -761,25 +812,30 @@ 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
 
+    setup_gns $OBJECT $TIMOUT $TICK || 
+       error
+
+    setup_upcall $UPCALL GENERIC $LOG FG ||
+       error
+
     echo "preparing mount object at $DIR/gns_test_2a/$OBJECT..."
     mkdir -p $DIR/gns_test_2a
     ln -s $DIR/gns_test_2a $DIR/gns_test_2a/$OBJECT
@@ -790,31 +846,32 @@ test_2a() {
     echo ""
     echo "testing GNS with GENERIC upcall"
     
-    check_gns GENERIC $DIR/gns_test_2a $DIR/gns_test_2a $TIMOUT $TICK GENERIC FG OPEN && {
-       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
     
     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
 
+    setup_gns $OBJECT $TIMOUT $TICK || 
+       error
+
+    setup_upcall $UPCALL GENERIC $LOG FG ||
+       error
+
     echo "preparing mount object at $DIR/gns_test_2b/$OBJECT..."
     mkdir -p $DIR/gns_test_2b/$OBJECT
     chmod u+s $DIR/gns_test_2b
@@ -824,31 +881,32 @@ test_2b() {
     echo ""
     echo "testing GNS with GENERIC upcall"
     
-    check_gns GENERIC $DIR/gns_test_2b $DIR/gns_test_2b $TIMOUT $TICK GENERIC FG OPEN && {
-       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
     
     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
 
+    setup_gns $OBJECT $TIMOUT $TICK || 
+       error
+
+    setup_upcall $UPCALL GENERIC $LOG FG ||
+       error
+
     echo "preparing mount object at $DIR/gns_test_2c/$OBJECT..."
     mkdir -p $DIR/gns_test_2c/$OBJECT/$OBJECT/$OBJECT/$OBJECT
     chmod u+s -R $DIR/gns_test_2c
@@ -858,31 +916,32 @@ test_2c() {
     echo ""
     echo "testing GNS with GENERIC upcall"
     
-    check_gns GENERIC $DIR/gns_test_2c $DIR/gns_test_2c $TIMOUT $TICK GENERIC FG OPEN && {
-       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
+
     disable_gns
     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
 
+    setup_gns $OBJECT $TIMOUT $TICK || 
+       error
+
+    setup_upcall $UPCALL GENERIC $LOG FG ||
+       error
+
     echo "preparing mount object at $DIR/gns_test_2d/$OBJECT..."
     mkdir -p $DIR/gns_test_2d
     chmod u+s $DIR/gns_test_2d
@@ -892,16 +951,12 @@ test_2d() {
     echo ""
     echo "testing GNS with GENERIC upcall"
     
-    check_gns GENERIC $DIR/gns_test_2d $DIR/gns_test_2d $TIMOUT $TICK GENERIC FG OPEN && {
-       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
     
     disable_gns
     chmod u-s $DIR/gns_test_2d
     rm -fr $DIR/gns_test_2d
+
     return 0
 }
 
@@ -912,9 +967,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"
@@ -930,6 +982,7 @@ 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
 }
 
@@ -937,42 +990,52 @@ run_test 2e " odd conditions ('.' and '..' as mount object) ============="
 
 test_2f() {
     local LOOP_DEV=$(find_free_loop 2>/dev/null)
+    local UPCALL="$TMP/gns-upcall-2f.sh"
     local LOOP_FILE="$TMP/gns_loop_2f"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
     local TIMOUT=5
     local TICK=1
 
+    disable_gns
+
     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
-
-    echo "setting up GNS timeouts and mount object..."
-    setup_gns $OBJECT $TIMOUT $TICK || error
+    setup_loop $LOOP_DEV $LOOP_FILE || 
+       error
 
-    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 GENERIC upcall in CONCUR3 mode"
     
-    check_gns GENERIC $DIR/gns_test_2f $DIR/gns_test_2f $TIMOUT $TICK CONCUR3 FG OPEN || {
+    check_gns $DIR/gns_test_2f $DIR/gns_test_2f $TIMOUT $TICK CONCUR3 OPEN || {
         disable_gns
         cleanup_object $DIR/gns_test_2f
         cleanup_loop $LOOP_DEV $LOOP_FILE
-        error "mount during modifying mount point does not work"
+        error
     }
     
     disable_gns
-
     cleanup_object $DIR/gns_test_2f
     cleanup_loop $LOOP_DEV $LOOP_FILE
+
     return 0
 }
 
@@ -980,26 +1043,35 @@ run_test 2f " odd conditions (mount point is modifying during mount) ===="
 
 test_2g() {
     local LOOP_DEV=$(find_free_loop 2>/dev/null)
+    local UPCALL="$TMP/gns-upcall-2g.sh"
     local LOOP_FILE="$TMP/gns_loop_2g"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
     local TIMOUT=5
     local TICK=1
 
+    disable_gns
+
     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
+    setup_loop $LOOP_DEV $LOOP_FILE || 
+       error
 
-    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/$OBJECT/$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
@@ -1007,8 +1079,8 @@ $OBJECT "-t ext2 $LOOP_DEV" || error
     echo ""
     echo "testing GNS with GENERIC upcall in GENERIC mode"
     
-    check_gns GENERIC $DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT \
-$DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT $TIMOUT $TICK GENERIC FG OPEN || {
+    check_gns $DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT \
+$DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT $TIMOUT $TICK GENERIC OPEN || {
         disable_gns
         cleanup_object $DIR/gns_test_2g
         cleanup_loop $LOOP_DEV $LOOP_FILE
@@ -1023,8 +1095,8 @@ $DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT $TIMOUT $TICK GENERIC FG OPEN || {
 
     enable_gns
 
-    check_gns GENERIC $DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT \
-$DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT $TIMOUT $TICK GENERIC FG OPEN && {
+    check_gns $DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT \
+$DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT $TIMOUT $TICK GENERIC OPEN && {
         disable_gns
         cleanup_object $DIR/gns_test_2g
         cleanup_loop $LOOP_DEV $LOOP_FILE
@@ -1032,9 +1104,9 @@ $DIR/gns_test_2g/$OBJECT/$OBJECT/$OBJECT $TIMOUT $TICK GENERIC FG OPEN && {
     }
 
     disable_gns
-
     cleanup_object $DIR/gns_test_2g
     cleanup_loop $LOOP_DEV $LOOP_FILE
+
     return 0
 }
 
@@ -1042,33 +1114,42 @@ run_test 2g " odd conditions (mount point is recursive marked SUID dir) ="
 
 test_2h() {
     local LOOP_DEV=$(find_free_loop 2>/dev/null)
+    local UPCALL="$TMP/gns-upcall-2h.sh"
     local LOOP_FILE="$TMP/gns_loop_2h"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
     local TIMOUT=5
     local TICK=1
 
+    disable_gns
+
     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
-
-    echo "setting up GNS timeouts and mount object..."
-    setup_gns $OBJECT $TIMOUT $TICK || error
+    setup_loop $LOOP_DEV $LOOP_FILE || 
+       error
 
-    disable_gns
+    setup_upcall $UPCALL GENERIC $LOG BG || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
 
-    echo "preparing mount object at $DIR/gns_test_2h/$OBJECT..."
-    setup_object $DIR/gns_test_2h $OBJECT "-t ext2 $LOOP_DEV" || error
+    setup_gns $OBJECT $TIMOUT $TICK || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
 
+    setup_object $DIR/gns_test_2h $OBJECT "-t ext2 $LOOP_DEV" || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
+    
     enable_gns
 
     echo ""
     echo "testing GNS with GENERIC upcall in GENERIC mode"
     
-    check_gns GENERIC $DIR/gns_test_2h $DIR/gns_test_2h \
-$TIMOUT $TICK GENERIC BG OPEN || {
+    check_gns $DIR/gns_test_2h $DIR/gns_test_2h $TIMOUT $TICK GENERIC OPEN || {
         disable_gns
         cleanup_object $DIR/gns_test_2h
         cleanup_loop $LOOP_DEV $LOOP_FILE
@@ -1076,9 +1157,9 @@ $TIMOUT $TICK GENERIC BG OPEN || {
     }
     
     disable_gns
-
     cleanup_object $DIR/gns_test_2h
     cleanup_loop $LOOP_DEV $LOOP_FILE
+
     return 0
 }
 
@@ -1086,33 +1167,42 @@ run_test 2h " odd conditions (mounting in background) ==================="
 
 test_3a() {
     local LOOP_DEV=$(find_free_loop 2>/dev/null)
+    local UPCALL="$TMP/gns-upcall-3a.sh"
     local LOOP_FILE="$TMP/gns_loop_3a"
+    local LOG="$TMP/gns-log"
     local OBJECT=".mntinfo"
     local TIMOUT=5
     local TICK=1
 
+    disable_gns
+
     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
-
-    echo "setting up GNS timeouts and mount object..."
-    setup_gns $OBJECT $TIMOUT $TICK || error
+    setup_loop $LOOP_DEV $LOOP_FILE || 
+       error
 
-    disable_gns
+    setup_upcall $UPCALL GENERIC $LOG FG || {
+       cleanup_loop $LOOP_DEV $LOOP_FILE
+       error
+    }
 
-    echo "preparing mount object at $DIR/gns_test_3a/$OBJECT..."
-    setup_object $DIR/gns_test_3a $OBJECT "-t ext2 $LOOP_DEV" || error
+    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
+    }
+    
     enable_gns
 
     echo ""
     echo "testing GNS with GENERIC upcall in GENERIC mode"
     
-    check_gns GENERIC $DIR/gns_test_3a $DIR/gns_test_3a \
-$TIMOUT $TICK GENERIC FG OPEN || {
+    check_gns $DIR/gns_test_3a $DIR/gns_test_3a $TIMOUT $TICK GENERIC OPEN || {
         disable_gns
         cleanup_object $DIR/gns_test_3a
         cleanup_loop $LOOP_DEV $LOOP_FILE
@@ -1136,6 +1226,7 @@ $TIMOUT $TICK GENERIC FG OPEN || {
     disable_gns
     cleanup_object $DIR/gns_test_3a
     cleanup_loop $LOOP_DEV $LOOP_FILE
+    
     return 0
 }
 
@@ -1162,70 +1253,36 @@ test_3b() {
     cleanup_loop $LOOP_DEV1 $LOOP_FILE1
     setup_loop $LOOP_DEV1 $LOOP_FILE1 || error
 
-    LOOP_DEV2=$(find_free_loop 2>/dev/null)
-    test "x$LOOP_DEV2" != "x" && test -b $LOOP_DEV2 || {
-        cleanup_loop $LOOP_DEV2 $LOOP_FILE2
-       error "can't find free loop device"
-    }
-
-    echo "preparing loop device $LOOP_DEV2 <-> $LOOP_FILE2..."
-    cleanup_loop $LOOP_DEV2 $LOOP_FILE2
-    setup_loop $LOOP_DEV2 $LOOP_FILE2 || {
-        cleanup_loop $LOOP_DEV2 $LOOP_FILE2
-       error
-    }
-    
-    LOOP_DEV3=$(find_free_loop 2>/dev/null)
-    test "x$LOOP_DEV3" != "x" && test -b $LOOP_DEV3 || {
-        cleanup_loop $LOOP_DEV1 $LOOP_FILE1
-        cleanup_loop $LOOP_DEV2 $LOOP_FILE2
-       error "can't find free loop device"
-    }
-
-    echo "preparing loop device $LOOP_DEV3 <-> $LOOP_FILE3..."
-    cleanup_loop $LOOP_DEV3 $LOOP_FILE3
-    setup_loop $LOOP_DEV3 $LOOP_FILE3 || {
-        cleanup_loop $LOOP_DEV1 $LOOP_FILE1
-        cleanup_loop $LOOP_DEV2 $LOOP_FILE2
-       error
-    }
-
-    # prepare object1
     echo "preparing mount object at $DIR/gns_test_3b1/$OBJECT..."
     setup_object $DIR/gns_test_3b1 $OBJECT "-t ext2 $LOOP_DEV1" || {
         cleanup_loop $LOOP_DEV1 $LOOP_FILE1
-        cleanup_loop $LOOP_DEV2 $LOOP_FILE2
-        cleanup_loop $LOOP_DEV3 $LOOP_FILE3
        error
     }
     
-    # prepare object2
     mkdir -p $TMP/mnt || error
-    mount -t ext2 $LOOP_DEV2 $TMP/mnt || {
+    mount -t ext2 $LOOP_DEV1 $TMP/mnt || {
         cleanup_object $DIR/gns_test_3b1
         cleanup_loop $LOOP_DEV1 $LOOP_FILE1
-        cleanup_loop $LOOP_DEV2 $LOOP_FILE2
-        cleanup_loop $LOOP_DEV3 $LOOP_FILE3
-       error "cannot mount $LOOP_DEV2"
+       error "cannot mount $LOOP_DEV1"
     }
 
-    echo "preparing mount object at $TMP/mnt/gns_test_3b2/$OBJECT..."
-    setup_object $TMP/mnt/gns_test_3b2 $OBJECT "-t ext2 $LOOP_DEV3" || {
-        cleanup_object $DIR/gns_test_3b1
+    mkdir $TMP/mnt/gns_test_3b2 || {
        umount $TMP/mnt
+        cleanup_object $DIR/gns_test_3b1
         cleanup_loop $LOOP_DEV1 $LOOP_FILE1
-        cleanup_loop $LOOP_DEV2 $LOOP_FILE2
-        cleanup_loop $LOOP_DEV3 $LOOP_FILE3
-       error
+       error "can't create $TMP/mnt/gns_test_3b2"
+    }
+    
+    umount $TMP/mnt || {
+        cleanup_object $DIR/gns_test_3b1
+        cleanup_loop $LOOP_DEV1 $LOOP_FILE1
+       error "can't umount $TMP/mnt"
     }
-    umount $TMP/mnt || error
 
     echo "setting up GNS timeouts and mount object..."
     setup_gns $OBJECT $TIMOUT $TICK || {
         cleanup_object $DIR/gns_test_3b1
         cleanup_loop $LOOP_DEV1 $LOOP_FILE1
-        cleanup_loop $LOOP_DEV2 $LOOP_FILE2
-        cleanup_loop $LOOP_DEV3 $LOOP_FILE3
        error
     }
 
@@ -1234,25 +1291,21 @@ test_3b() {
     echo ""
     echo "testing GNS with GENERIC upcall in CONCUR2 mode"
     
-    check_gns GENERIC $DIR/gns_test_3b1/gns_test_3b2 $DIR/gns_test_3b1/gns_test_3b2 $TIMOUT $TICK GENERIC FG LIST || {
+    check_gns $DIR/gns_test_3b1/gns_test_3b2 $DIR/gns_test_3b1/gns_test_3b2 $TIMOUT $TICK GENERIC LIST || {
        disable_gns
         cleanup_object $DIR/gns_test_3b1
         cleanup_loop $LOOP_DEV1 $LOOP_FILE1
-        cleanup_loop $LOOP_DEV2 $LOOP_FILE2
-        cleanup_loop $LOOP_DEV3 $LOOP_FILE3
         error
     }
     
     disable_gns
-
     cleanup_object $DIR/gns_test_3b1
     cleanup_loop $LOOP_DEV1 $LOOP_FILE1
-    cleanup_loop $LOOP_DEV2 $LOOP_FILE2
-    cleanup_loop $LOOP_DEV3 $LOOP_FILE3
+
     return 0
 }
 
-run_test 3b " general GNS test - concurrent mount of 2 GNS mounts ======="
+run_test 3b " readdir through mount point ==============================="
 
 TMPDIR=$OLDTMPDIR
 TMP=$OLDTMP