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;
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);
/*
* 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));
* 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;
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;
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 },
{ "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 },
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
exit 1
$INJECTION
-\$MOUNT \$OPTIONS \$MNTPATH > $LOG 2>&1
+\$MOUNT \$OPTIONS \$MNTPATH > $LOG 2>&1 $BG
exit \$?
EOF
chmod +x $UPCALL
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 "=================================================================="
local OBJPATH=$1
local OBJECT=$2
local CONTENT=$3
+ local EXTRA_OPT=$4
mkdir -p $OBJPATH || return $?
echo -n $CONTENT > $OBJPATH/$OBJECT || return $?
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
}
}
+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"
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
}
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
}
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
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
}
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
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
}
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
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
}
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
}
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
}
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
}
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
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