Whamcloud - gitweb
- removed not used stuff (@lld and gns_mount_finished completion). Last is because
authoryury <yury>
Tue, 26 Apr 2005 13:15:26 +0000 (13:15 +0000)
committeryury <yury>
Tue, 26 Apr 2005 13:15:26 +0000 (13:15 +0000)
  none of thread needs to wait for mount completion in kernel space.

- small cleanups in ll_gns_mount_object(). Some checks for input invariants are
  moved after checking gns state. Fixes in comments.

- added the ability to disable GNS at all via /proc/.../gns_enabled. This is useful
  for some complex tests (like recursive suid marked .mntinfo dir) at least. May be
  useful for something else.

- added two new sanity tests to sanity-gns.sh:

  a) test 2g: mounting /mnt/lustre/gns_entry/.mntinfo/.mntinfo/.mntinfo/.mntinfo where
     only last entry is correct GNS mount object.

  b) test 2h: upcall script starts mounting in background and retuns with no waiting
     for mount command.

- in sanity tests disable GNS when preparing mount objects and mount points.

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

index 6411b4f..7b8c3b9 100644 (file)
@@ -77,7 +77,6 @@ ll_gns_wait_for_mount(struct dentry *dentry,
 int
 ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
 {
-        struct ll_dentry_data *lld = dentry->d_fsdata;
         char *path, *pathpage, *datapage, *argv[4];
         struct file *mntinfo_fd = NULL;
         int cleanup_phase = 0, rc = 0;
@@ -85,41 +84,45 @@ ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
         struct dentry *dchild;
         ENTRY;
 
-        if (mnt == NULL) {
-                CERROR("suid directory found, but no "
-                       "vfsmount available.\n");
-                RETURN(-EINVAL);
-        }
+        LASSERT(dentry->d_inode != NULL);
 
-        CDEBUG(D_INODE, "mounting dentry %p\n", dentry);
+        if (!S_ISDIR(dentry->d_inode->i_mode))
+                RETURN(-EINVAL);
 
-        LASSERT(dentry->d_inode != NULL);
-        LASSERT(S_ISDIR(dentry->d_inode->i_mode));
-        LASSERT(lld != NULL);
-        
         sbi = ll_i2sbi(dentry->d_inode);
         LASSERT(sbi != NULL);
 
+        spin_lock(&sbi->ll_gns_lock);
+
+        if (sbi->ll_gns_state == LL_GNS_DISABLED) {
+                spin_unlock(&sbi->ll_gns_lock);
+                RETURN(-EINVAL);
+        }
+        
         /* 
          * another thead is in progress or just finished mounting the
          * dentry. Handling that.
          */
-        spin_lock(&sbi->ll_gns_lock);
         if (sbi->ll_gns_state == LL_GNS_MOUNTING ||
             sbi->ll_gns_state == LL_GNS_FINISHED) {
                 /* 
-                 * check if another control thread is trying to mount some GNS
-                 * dentry too. Letting it know that we busy and make
-                 * ll_lookup_it() ti restart syscall and try again later.
+                 * check if another thread is trying to mount some GNS dentry
+                 * too. Letting it know that we busy and make ll_lookup_it() to
+                 * restart syscall and try again later.
                  */
                 spin_unlock(&sbi->ll_gns_lock);
-                CDEBUG(D_INODE, "GNS is in progress now, throwing "
-                       "-ERESTARTSYS to restart syscall and let "
-                       "it finish.\n");
-                RETURN(-EBUSY);
+                RETURN(-EAGAIN);
         }
         LASSERT(sbi->ll_gns_state == LL_GNS_IDLE);
 
+        if (mnt == NULL) {
+                CERROR("suid directory found, but no "
+                       "vfsmount available.\n");
+                RETURN(-EINVAL);
+        }
+
+        CDEBUG(D_INODE, "mounting dentry %p\n", dentry);
+
         /* mounting started */
         sbi->ll_gns_state = LL_GNS_MOUNTING;
         spin_unlock(&sbi->ll_gns_lock);
@@ -148,9 +151,9 @@ 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 -EBUSY here.
+         * 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.
          */
         dchild = ll_lookup_one_len(sbi->ll_gns_oname, dentry,
                                    strlen(sbi->ll_gns_oname));
@@ -255,7 +258,6 @@ ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
          * return instantly. --umka
          */
         rc = ll_gns_wait_for_mount(dentry, 1, GNS_WAIT_ATTEMPTS);
-        complete_all(&sbi->ll_gns_mount_finished);
         if (rc == 0) {
                 struct dentry *rdentry;
                 struct vfsmount *rmnt;
@@ -301,12 +303,6 @@ cleanup:
                         dput(dchild);
         case 1:
                 free_page((unsigned long)pathpage);
-                
-                /* 
-                 * waking up all waiters after gns state is set to
-                 * LL_GNS_MOUNTING
-                 */
-                complete_all(&sbi->ll_gns_mount_finished);
         case 0:
                 spin_lock(&sbi->ll_gns_lock);
                 sbi->ll_gns_state = LL_GNS_IDLE;
index 971fb04..647eb79 100644 (file)
@@ -99,7 +99,6 @@ struct ll_sb_info {
 
         unsigned long             ll_gns_tick;
         unsigned long             ll_gns_timeout;
-        struct completion         ll_gns_mount_finished;
 
         /* path to upcall */
         char                      ll_gns_upcall[PATH_MAX];
@@ -117,6 +116,7 @@ struct ll_gns_ctl {
 #define LL_GNS_IDLE               (1 << 0)
 #define LL_GNS_MOUNTING           (1 << 1)
 #define LL_GNS_FINISHED           (1 << 2)
+#define LL_GNS_DISABLED           (1 << 3)
 
 /* mounts checking flags */
 #define LL_GNS_UMOUNT             (1 << 0)
index 181d956..cda0ff6 100644 (file)
@@ -70,7 +70,6 @@ struct ll_sb_info *lustre_init_sbi(struct super_block *sb)
         spin_lock_init(&sbi->ll_gns_lock);
         INIT_LIST_HEAD(&sbi->ll_gns_sbi_head);
         init_waitqueue_head(&sbi->ll_gns_waitq);
-        init_completion(&sbi->ll_gns_mount_finished);
 
         /* this later may be reset via /proc/fs/... */
         memcpy(sbi->ll_gns_oname, ".mntinfo", strlen(".mntinfo"));
index 8354c32..6b86eb3 100644 (file)
@@ -414,6 +414,45 @@ static int ll_wr_gns_tick(struct file *file, const char *buffer,
         return count;
 }
 
+static int ll_rd_gns_enabled(char *page, char **start, off_t off,
+                             int count, int *eof, void *data)
+{
+        struct super_block *sb = (struct super_block *)data;
+        struct ll_sb_info *sbi = ll_s2sbi(sb);
+        int enabled = 0;
+
+        spin_lock(&sbi->ll_gns_lock);
+        enabled = (sbi->ll_gns_state == LL_GNS_DISABLED ? 0 : 1);
+        spin_unlock(&sbi->ll_gns_lock);
+
+        return snprintf(page, count, "%d\n", enabled);
+}
+
+static int ll_wr_gns_enabled(struct file *file, const char *buffer,
+                             unsigned long count, void *data)
+{
+        struct super_block *sb = (struct super_block *)data;
+        struct ll_sb_info *sbi = ll_s2sbi(sb);
+        int val, rc;
+
+        rc = lprocfs_write_helper(buffer, count, &val);
+        if (rc)
+                return rc;
+
+        spin_lock(&sbi->ll_gns_lock);
+        if (val == 0 && sbi->ll_gns_state == LL_GNS_IDLE) {
+                sbi->ll_gns_state = LL_GNS_DISABLED;
+                goto out;
+        }
+        if (val == 1 && sbi->ll_gns_state == LL_GNS_DISABLED) {
+                sbi->ll_gns_state = LL_GNS_IDLE;
+                goto out;
+        }
+out:
+        spin_unlock(&sbi->ll_gns_lock);
+        return count;
+}
+
 static struct lprocfs_vars lprocfs_obd_vars[] = {
         { "uuid",         ll_rd_sb_uuid,          0, 0 },
         //{ "mntpt_path",   ll_rd_path,             0, 0 },
@@ -439,6 +478,9 @@ static struct lprocfs_vars lprocfs_obd_vars[] = {
         { "gns_tick", ll_rd_gns_tick,
           ll_wr_gns_tick, 0 },
         
+        { "gns_enabled", ll_rd_gns_enabled,
+          ll_wr_gns_enabled, 0 },
+        
         { "gns_object_name", ll_rd_gns_object_name,
           ll_wr_gns_object_name, 0 },
         
index bb703c2..167e26d 100644 (file)
@@ -405,7 +405,7 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
             ((flags & LOOKUP_CONTINUE) || (orig_it & (IT_CHDIR | IT_OPEN))))
         {
                 rc = ll_gns_mount_object(dentry, nd->mnt);
-                if (rc == -EBUSY) {
+                if (rc == -EAGAIN) {
                         /* 
                          * making system to restart syscall as currently GNS is
                          * in mounting progress.
index a85f9e7..8c0318a 100644 (file)
@@ -243,9 +243,13 @@ setup_upcall() {
     local UPCALL=$1
     local MODE=$2
     local LOG=$3
-
+    local BG=$4
+    
+    test "x$BG" = "xBACKGROUND" && 
+       BG="&" || BG=""
+    
     test "x$MODE" = "xDEADLOCK" &&
-    INJECTION="touch \$MNTPATH/file"
+       INJECTION="touch \$MNTPATH/file"
     
     cat > $UPCALL <<- EOF
 #!/bin/sh
@@ -260,7 +264,7 @@ test "x\$OPTIONS" = "x" || "x\$MNTPATH" = "x" &&
 exit 1
 
 $INJECTION
-\$MOUNT \$OPTIONS \$MNTPATH > $LOG 2>&1
+\$MOUNT \$OPTIONS \$MNTPATH > $LOG 2>&1 $BG
 exit \$?
 EOF
     chmod +x $UPCALL
@@ -292,12 +296,14 @@ check_gns() {
     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 || return $rc
+    setup_upcall $UPCALL_PATH $UPCALL $LOG $BG || return $rc
+
     echo "======================== upcall script ==========================="
     cat $UPCALL_PATH 2>/dev/null || return $?
     echo "=================================================================="
@@ -412,6 +418,7 @@ setup_object() {
     local OBJPATH=$1
     local OBJECT=$2
     local CONTENT=$3
+    local EXTRA_OPT=$4
     
     mkdir -p $OBJPATH || return $?
     echo -n $CONTENT > $OBJPATH/$OBJECT || return $?
@@ -421,14 +428,15 @@ setup_object() {
     echo ""
     echo "================================================================="
     
-    chmod u+s $OBJPATH
+    chmod u+s $OBJPATH $EXTRA_OPT
     return $?
 }
 
 cleanup_object() {
     local OBJPATH=$1
+    local EXTRA_OPT=$2
 
-    chmod u-s $OBJPATH >/dev/null 2>&1
+    chmod u-s $OBJPATH $EXTRA_OPT
     umount $OBJPATH >/dev/null 2>&1
     rm -fr $OBJPATH >/dev/null 2>&1
 }
@@ -450,6 +458,18 @@ 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
+}
+
+disable_gns()
+{
+    echo "0" > /proc/fs/lustre/llite/fs0/gns_enabled || error
+    test "x$(cat /proc/fs/lustre/llite/fs0/gns_enabled)" = "x0" || error
+}
+
 test_1a() {
     local LOOP_DEV=$(find_free_loop 2>/dev/null)
     local LOOP_FILE="/tmp/gns_loop_1a"
@@ -466,20 +486,27 @@ test_1a() {
 
     echo "setting up GNS timeouts and mount object..."
     setup_gns $OBJECT $TIMOUT $TICK || error
+    
+    disable_gns
 
     echo "preparing mount object at $DIR/gns_test_1a/$OBJECT..."
     setup_object $DIR/gns_test_1a $OBJECT "-t ext2 $LOOP_DEV" || 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 || {
+           disable_gns
            cleanup_object $DIR/gns_test_1a
            cleanup_loop $LOOP_DEV $LOOP_FILE
            error
        }
     done
     
+    disable_gns
+
     cleanup_object $DIR/gns_test_1a
     cleanup_loop $LOOP_DEV $LOOP_FILE
 }
@@ -503,19 +530,26 @@ test_1b() {
     echo "setting up GNS timeouts and mount object..."
     setup_gns $OBJECT $TIMOUT $TICK || 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
+    
+    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
        }
     done
     
+    disable_gns
+
     cleanup_object $DIR/gns_test_1b
     cleanup_loop $LOOP_DEV $LOOP_FILE
 }
@@ -539,9 +573,13 @@ test_1c() {
     echo "setting up GNS timeouts and mount object..."
     setup_gns $OBJECT $TIMOUT $TICK || error
 
+    disable_gns
+
     echo "preparing mount object at $DIR/gns_test_1c/$OBJECT..."
     setup_object $DIR/gns_test_1c $OBJECT "-t ext2 $LOOP_DEV" || error
 
+    enable_gns
+
     echo ""
     echo "testing GNS with DEADLOCK upcall 4 times on the row"
     local i=0
@@ -552,12 +590,15 @@ test_1c() {
        test $(($i%2)) -eq 1 && MODE="DEADLOCK"
        
        check_gns $MODE $DIR/gns_test_1c $DIR/gns_test_1c $TIMOUT $TICK GENERIC || {
+           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
 }
@@ -581,9 +622,13 @@ test_1d() {
     echo "setting up GNS timeouts and mount object..."
     setup_gns $OBJECT $TIMOUT $TICK || error
 
+    disable_gns
+
     echo "preparing mount object at $DIR/gns_test_1d/$OBJECT..."
     setup_object $DIR/gns_test_1d $OBJECT "-t ext2 $LOOP_DEV" || error
 
+    enable_gns
+
     echo ""
     echo "testing GNS with GENERIC/DEADLOCK upcall 4 times on the row in CONCUR1 mode"
     local i=0
@@ -594,12 +639,15 @@ test_1d() {
        test $(($i%2)) -eq 1 && MODE="DEADLOCK"
        
        check_gns $MODE $DIR/gns_test_1d $DIR/gns_test_1d $TIMOUT $TICK CONCUR1 || {
+           disable_gns
            cleanup_object $DIR/gns_test_1d
            cleanup_loop $LOOP_DEV $LOOP_FILE
            error
        }
     done
     
+    disable_gns
+
     cleanup_object $DIR/gns_test_1d
     cleanup_loop $LOOP_DEV $LOOP_FILE
 }
@@ -623,21 +671,28 @@ test_1e() {
     echo "setting up GNS timeouts and mount object..."
     setup_gns $OBJECT $TIMOUT $TICK || error
 
+    disable_gns
+
     echo "preparing mount object at $DIR/gns_test_1e1/$OBJECT..."
     setup_object $DIR/gns_test_1e1 $OBJECT "-t ext2 $LOOP_DEV" || 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 || {
+       disable_gns
         cleanup_object $DIR/gns_test_1e1
         cleanup_object $DIR/gns_test_1e2
         cleanup_loop $LOOP_DEV $LOOP_FILE
         error
     }
     
+    disable_gns
+
     cleanup_object $DIR/gns_test_1e1
     cleanup_object $DIR/gns_test_1e2
     cleanup_loop $LOOP_DEV $LOOP_FILE
@@ -653,19 +708,25 @@ test_2a() {
     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..."
     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?"
     }
     
+    disable_gns
     chmod u-s $DIR/gns_test_2a
     rm -fr $DIR/gns_test_2a
 }
@@ -680,18 +741,24 @@ test_2b() {
     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..."
     mkdir -p $DIR/gns_test_2b/$OBJECT
     chmod u+s $DIR/gns_test_2b
     
+    enable_gns
+    
     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?"
     }
     
+    disable_gns
     chmod u-s $DIR/gns_test_2b
     rm -fr $DIR/gns_test_2b
 }
@@ -706,18 +773,24 @@ test_2c() {
     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..."
     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?"
     }
     
+    disable_gns
     chmod u-s $DIR/gns_test_2c
     rm -fr $DIR/gns_test_2c
 }
@@ -732,18 +805,24 @@ test_2d() {
     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..."
     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?"
     }
     
+    disable_gns
     chmod u-s $DIR/gns_test_2d
     rm -fr $DIR/gns_test_2d
 }
@@ -777,9 +856,9 @@ test_2e() {
 
 run_test 2e " odd conditions ('.' and '..' as mount object) ============="
 
-test_3a() {
+test_2f() {
     local LOOP_DEV=$(find_free_loop 2>/dev/null)
-    local LOOP_FILE="/tmp/gns_loop_3a"
+    local LOOP_FILE="/tmp/gns_loop_2f"
     local OBJECT=".mntinfo"
     local TIMOUT=5
     local TICK=1
@@ -794,25 +873,121 @@ test_3a() {
     echo "setting up GNS timeouts and mount object..."
     setup_gns $OBJECT $TIMOUT $TICK || error
 
-    echo "preparing mount object at $DIR/gns_test_3a/$OBJECT..."
-    setup_object $DIR/gns_test_3a $OBJECT "-t ext2 $LOOP_DEV" || error
+    disable_gns
+
+    echo "preparing mount object at $DIR/gns_test_2f/$OBJECT..."
+    setup_object $DIR/gns_test_2f $OBJECT "-t ext2 $LOOP_DEV" || error
+
+    enable_gns
 
     echo ""
     echo "testing GNS with DEADLOCK upcall in CONCUR3 mode"
     
     local MODE="DEADLOCK"
        
-    check_gns $MODE $DIR/gns_test_3a $DIR/gns_test_3a $TIMOUT $TICK CONCUR3 || {
-        cleanup_object $DIR/gns_test_3a
+    check_gns $MODE $DIR/gns_test_2f $DIR/gns_test_2f $TIMOUT $TICK CONCUR3 || {
+        disable_gns
+        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
+}
+
+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 OBJECT=".mntinfo"
+    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
+
+    echo "setting up GNS timeouts and mount object..."
+    setup_gns $OBJECT $TIMOUT $TICK || error
+
+    disable_gns
+
+    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
+
+    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 || {
+        disable_gns
+        cleanup_object $DIR/gns_test_2g
         cleanup_loop $LOOP_DEV $LOOP_FILE
         error
     }
     
-    cleanup_object $DIR/gns_test_3a
+    disable_gns
+
+    cleanup_object $DIR/gns_test_2g
+    cleanup_loop $LOOP_DEV $LOOP_FILE
+}
+
+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 OBJECT=".mntinfo"
+    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
+
+    echo "setting up GNS timeouts and mount object..."
+    setup_gns $OBJECT $TIMOUT $TICK || error
+
+    disable_gns
+
+    echo "preparing mount object at $DIR/gns_test_2h/$OBJECT..."
+    setup_object $DIR/gns_test_2h $OBJECT "-t ext2 $LOOP_DEV" || 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 BACKGROUND || {
+        disable_gns
+        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
 }
 
-run_test 3a " odd conditions (mount point is modifying during mount) ===="
+run_test 2h " odd conditions (mounting in background) ==================="
 
 TMPDIR=$OLDTMPDIR
 TMP=$OLDTMP