Whamcloud - gitweb
Branch b1_8
authorw.li <w.li>
Fri, 21 Aug 2009 01:29:07 +0000 (01:29 +0000)
committerw.li <w.li>
Fri, 21 Aug 2009 01:29:07 +0000 (01:29 +0000)
b=19743
i=tappro
i=nathan.rutman,robert.read (non-test part)

Attachment 25260: lfs path2fid.  Add a "path2fid <path>" command to
lfs(1).  Ported from HEAD (Bug 17187 and 19856).

Attachment 25261: lctl getobjversion.  Add a new lctl(8) command,
"getobjversion <fid>", to get the version of an object.  Currently, only
versions of MDT objects can be retrieved.

Attachment 24412: replay-vbr rmultiop.  Make the command sequence an
argument, as required by the new replay-vbr tests.  Fix rmultiop_stop's
return code which would always be zero.

Attachment 25094: replay-vbr tests.  Move rmultiop_{start,stop} to top.
Add a zconf_mount_clients to balance the former zconf_umount_clients.
Add new tests 0* and 2b (2 renamed to 2a).

13 files changed:
lustre/include/lustre/liblustreapi.h
lustre/include/lustre/lustre_idl.h
lustre/include/lustre/lustre_user.h
lustre/include/lustre_lib.h
lustre/llite/dir.c
lustre/llite/file.c
lustre/mds/mds_lov.c
lustre/tests/replay-vbr.sh
lustre/utils/lctl.c
lustre/utils/lfs.c
lustre/utils/liblustreapi.c
lustre/utils/obd.c
lustre/utils/obdctl.h

index 8138208..4594968 100644 (file)
@@ -168,6 +168,8 @@ extern int parse_size(char *optarg, unsigned long long *size,
                       unsigned long long *size_units, int bytes_spec);
 extern void llapi_ping_target(char *obd_type, char *obd_name,
                               char *obd_uuid, void *args);
+extern int llapi_path2fid(const char *path, lustre_fid *fid);
+
 struct mntent;
 #define HAVE_LLAPI_IS_LUSTRE_MNT
 extern int llapi_is_lustre_mnt(struct mntent *mnt);
index d9559fb..9540c58 100644 (file)
@@ -799,21 +799,6 @@ enum lu_dirent_attrs {
 
 extern void lustre_swab_ll_fid (struct ll_fid *fid);
 
-struct lu_fid {
-        __u64 f_seq;  /* holds fid sequence. Lustre should support 2^64
-                       * objects, thus even if one sequence has one object we
-                       * reach this value. */
-        __u32 f_oid;  /* fid number within its sequence. */
-        __u32 f_ver;  /* holds fid version. */
-};
-
-#define DFID "[0x%16.16"LPF64"x/0x%8.8x:0x%8.8x]"
-
-#define PFID(fid)     \
-        fid_seq(fid), \
-        fid_oid(fid), \
-        fid_ver(fid)
-
 enum {
         /** put FID sequence at this offset in ldlm_res_id. */
         LUSTRE_RES_ID_SEQ_OFF = 0,
index c88602d..1cbd013 100644 (file)
@@ -99,6 +99,8 @@ struct obd_statfs;
 #define LL_IOC_LLOOP_INFO               _IOWR('f', 168, OBD_IOC_DATA_TYPE)
 #define LL_IOC_LLOOP_DETACH_BYDEV       _IOWR('f', 169, OBD_IOC_DATA_TYPE)
 
+#define LL_IOC_PATH2FID                 _IOR ('f', 173, long)
+
 #define LL_STATFS_MDC           1
 #define LL_STATFS_LOV           2
 
@@ -235,6 +237,35 @@ static inline char *obd_uuid2str(struct obd_uuid *uuid)
         return (char *)(uuid->uuid);
 }
 
+struct lu_fid {
+        __u64 f_seq;  /* holds fid sequence. Lustre should support 2^64
+                       * objects, thus even if one sequence has one object we
+                       * reach this value. */
+        __u32 f_oid;  /* fid number within its sequence. */
+        __u32 f_ver;  /* holds fid version. */
+};
+
+/* Userspace should treat lu_fid as opaque, and only use the following methods
+   to print or parse them.  Other functions (e.g. compare, swab) could be moved
+   here from lustre_idl.h if needed. */
+typedef struct lu_fid lustre_fid;
+
+/* printf display format
+   e.g. printf("file FID is "DFID"\n", PFID(fid)); */
+#define DFID "["LPX64":0x%x:0x%x]"
+#define PFID(fid)     \
+        fid_seq(fid), \
+        fid_oid(fid), \
+        fid_ver(fid)
+
+/* scanf input parse format -- strip '[' first.
+   e.g. sscanf(fidstr, SFID, RFID(&fid)); */
+#define SFID "0x%llx:0x%x:0x%x"
+#define RFID(fid)     \
+        &((fid)->f_seq), \
+        &((fid)->f_oid), \
+        &((fid)->f_ver)
+
 /* these must be explicitly translated into linux Q_* in ll_dir_ioctl */
 #define LUSTRE_Q_QUOTAON    0x800002     /* turn quotas on */
 #define LUSTRE_Q_QUOTAOFF   0x800003     /* turn quotas off */
index 0f1aa74..d8efcf1 100644 (file)
@@ -518,6 +518,8 @@ static inline void obd_ioctl_freedata(char *buf, int len)
 #define ECHO_IOC_ENQUEUE               _IOWR('f', 202, OBD_IOC_DATA_TYPE)
 #define ECHO_IOC_CANCEL                _IOWR('f', 203, OBD_IOC_DATA_TYPE)
 
+#define OBD_IOC_GET_OBJ_VERSION        _IOR('f', 210, OBD_IOC_DATA_TYPE)
+
 /* XXX _IOWR('f', 250, long) has been defined in
  * lnet/include/libcfs/kp30.h for debug, don't use it
  */
index 6737947..9f96bfe 100644 (file)
@@ -1584,6 +1584,13 @@ static int ll_dir_ioctl(struct inode *inode, struct file *file,
                         RETURN (-EFAULT);
                 RETURN(0);
         }
+        case LL_IOC_PATH2FID: {
+                if (copy_to_user((void *)arg, ll_inode_lu_fid(inode),
+                                 sizeof(struct lu_fid)))
+                        RETURN(-EFAULT);
+
+                RETURN(0);
+        }
         default:
                 RETURN(obd_iocontrol(cmd, sbi->ll_osc_exp,0,NULL,(void *)arg));
         }
index 4c238a0..bcac1ff 100644 (file)
@@ -2944,6 +2944,13 @@ error:
                         RETURN (-EFAULT);
                 RETURN(0);
         }
+        case LL_IOC_PATH2FID: {
+                if (copy_to_user((void *)arg, ll_inode_lu_fid(inode),
+                                 sizeof(struct lu_fid)))
+                        RETURN(-EFAULT);
+
+                RETURN(0);
+        }
 
         /* We need to special case any other ioctls we want to handle,
          * to send them to the MDS/OST as appropriate and to properly
index 58c15cb..1004d3d 100644 (file)
@@ -937,6 +937,29 @@ int mds_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
                 mds_allow_cli(obd, 0);
                 RETURN(0);
 
+        case OBD_IOC_GET_OBJ_VERSION: {
+                struct ll_fid *fid = (struct ll_fid *) data->ioc_inlbuf1;
+                struct dentry *dentry;
+                struct lustre_handle lockh;
+                int lockm = LCK_CR;
+                __u64 version;
+
+                dentry = mds_fid2locked_dentry(obd, fid, NULL, lockm, &lockh,
+                                               NULL, 0, MDS_INODELOCK_UPDATE);
+                if (IS_ERR(dentry)) {
+                        rc = PTR_ERR(dentry);
+                        RETURN(rc);
+                }
+                version = fsfilt_get_version(obd, dentry->d_inode);
+                ldlm_lock_decref(&lockh, lockm);
+                l_dput(dentry);
+                if (version < 0)
+                        rc = (int) version;
+                else
+                        *(__u64 *) data->ioc_inlbuf2 = version;
+                RETURN(rc);
+        }
+
         default:
                 CDEBUG(D_INFO, "unknown command %x\n", cmd);
                 RETURN(-EINVAL);
index 0087434..836b438 100644 (file)
@@ -34,6 +34,535 @@ rm -rf $DIR/[df][0-9]*
 
 [ "$DAEMONFILE" ] && $LCTL debug_daemon start $DAEMONFILE $DAEMONSIZE
 
+rmultiop_start() {
+    local client=$1
+    local file=$2
+    local cmds=$3
+
+    # We need to run do_node in bg, because pdsh does not exit
+    # if child process of run script exists.
+    # I.e. pdsh does not exit when runmultiop_bg_pause exited,
+    # because of multiop_bg_pause -> $MULTIOP_PROG &
+    # By the same reason we need sleep a bit after do_nodes starts
+    # to let runmultiop_bg_pause start muliop and
+    # update /tmp/multiop_bg.pid ;
+    # The rm /tmp/multiop_bg.pid guarantees here that
+    # we have the updated by runmultiop_bg_pause
+    # /tmp/multiop_bg.pid file
+
+    local pid_file=$TMP/multiop_bg.pid.$$
+    do_node $client "rm -f $pid_file && MULTIOP_PID_FILE=$pid_file LUSTRE= runmultiop_bg_pause $file $cmds" &
+    local pid=$!
+    sleep 3
+    local multiop_pid
+    multiop_pid=$(do_node $client cat $pid_file)
+    [ -n "$multiop_pid" ] || error "$client : Can not get multiop_pid from $pid_file "
+    eval export $(client_var_name $client)_multiop_pid=$multiop_pid
+    eval export $(client_var_name $client)_do_node_pid=$pid
+    local var=$(client_var_name $client)_multiop_pid
+    echo client $client multiop_bg started multiop_pid=${!var}
+    return $?
+}
+
+rmultiop_stop() {
+    local client=$1
+    local multiop_pid=$(client_var_name $client)_multiop_pid
+    local do_node_pid=$(client_var_name $client)_do_node_pid
+
+    echo "Stopping multiop_pid=${!multiop_pid} (kill ${!multiop_pid} on $client)"
+    do_node $client kill -USR1 ${!multiop_pid}
+
+    wait ${!do_node_pid}
+}
+
+get_version() {
+    local client=$1
+    local file=$2
+    local fid
+
+    fid=$(do_node $client $LFS path2fid $file)
+    do_facet mds $LCTL --device $mds_svc getobjversion $fid
+}
+
+test_0a() {
+    local file=$DIR/$tfile
+    local pre
+    local post
+
+    do_node $CLIENT1 mcreate $file
+    pre=$(get_version $CLIENT1 $file)
+    do_node $CLIENT1 openfile -f O_RDWR $file
+    post=$(get_version $CLIENT1 $file)
+    if (($pre != $post)); then
+        error "version changed unexpectedly: pre $pre, post $post"
+    fi
+}
+run_test 0a "VBR: open and close do not change versions"
+
+test_0b() {
+    do_facet mds "$LCTL set_param mds.${mds_svc}.sync_permission=0"
+    do_node $CLIENT1 mkdir -p -m 755 $DIR/$tdir
+
+    replay_barrier mds
+    do_node $CLIENT2 chmod 777 $DIR/$tdir
+    do_node $CLIENT1 openfile -f O_RDWR:O_CREAT $DIR/$tdir/$tfile
+    zconf_umount $CLIENT2 $MOUNT
+    facet_failover mds
+
+    do_node $CLIENT1 df $MOUNT && error "$CLIENT1 not evicted"
+    if ! do_node $CLIENT1 $CHECKSTAT -a $DIR/$tdir/$tfile; then
+        error "open succeeded unexpectedly"
+    fi
+    zconf_mount $CLIENT2 $MOUNT
+}
+run_test 0b "VBR: open (O_CREAT) checks version of parent"
+
+test_0c() {
+    do_facet mds "$LCTL set_param mds.${mds_svc}.sync_permission=0"
+    do_node $CLIENT1 mkdir -p -m 755 $DIR/$tdir
+    do_node $CLIENT1 openfile -f O_RDWR:O_CREAT -m 0644 $DIR/$tdir/$tfile
+
+    replay_barrier mds
+    do_node $CLIENT2 chmod 777 $DIR/$tdir
+    do_node $CLIENT2 chmod 666 $DIR/$tdir/$tfile
+    rmultiop_start $CLIENT1 $DIR/$tdir/$tfile o_c
+    zconf_umount $CLIENT2 $MOUNT
+    facet_failover mds
+
+    do_node $CLIENT1 df $MOUNT || error "$CLIENT1 evicted"
+    rmultiop_stop $CLIENT1 || error "close failed"
+    zconf_mount $CLIENT2 $MOUNT
+}
+run_test 0c "VBR: open (non O_CREAT) does not checks versions"
+
+test_0d() {
+    local pre
+    local post
+
+    pre=$(get_version $CLIENT1 $DIR)
+    do_node $CLIENT1 mkfifo $DIR/$tfile
+    post=$(get_version $CLIENT1 $DIR)
+    if (($pre == $post)); then
+        error "version not changed: pre $pre, post $post"
+    fi
+}
+run_test 0d "VBR: create changes version of parent"
+
+test_0e() {
+    do_facet mds "$LCTL set_param mds.${mds_svc}.sync_permission=0"
+    do_node $CLIENT1 mkdir -p -m 755 $DIR/$tdir
+
+    replay_barrier mds
+    do_node $CLIENT2 chmod 777 $DIR/$tdir
+    do_node $CLIENT1 mkfifo $DIR/$tdir/$tfile
+    zconf_umount $CLIENT2 $MOUNT
+    facet_failover mds
+
+    do_node $CLIENT1 df $MOUNT && error "$CLIENT1 not evicted"
+    if ! do_node $CLIENT1 $CHECKSTAT -a $DIR/$tdir/$tfile; then
+        error "create succeeded unexpectedly"
+    fi
+    zconf_mount $CLIENT2 $MOUNT
+}
+run_test 0e "VBR: create checks version of parent"
+
+test_0f() {
+    local pre
+    local post
+
+    do_node $CLIENT1 mcreate $DIR/$tfile
+    pre=$(get_version $CLIENT1 $DIR)
+    do_node $CLIENT1 rm $DIR/$tfile
+    post=$(get_version $CLIENT1 $DIR)
+    if (($pre == $post)); then
+        error "version not changed: pre $pre, post $post"
+    fi
+}
+run_test 0f "VBR: unlink changes version of parent"
+
+test_0g() {
+    do_facet mds "$LCTL set_param mds.${mds_svc}.sync_permission=0"
+    do_node $CLIENT1 mkdir -p -m 755 $DIR/$tdir
+    do_node $CLIENT1 mcreate $DIR/$tdir/$tfile
+
+    replay_barrier mds
+    do_node $CLIENT2 chmod 777 $DIR/$tdir
+    do_node $CLIENT1 rm $DIR/$tdir/$tfile
+    zconf_umount $CLIENT2 $MOUNT
+    facet_failover mds
+
+    do_node $CLIENT1 df $MOUNT && error "$CLIENT1 not evicted"
+    if do_node $CLIENT1 $CHECKSTAT -a $DIR/$tdir/$tfile; then
+        error "unlink succeeded unexpectedly"
+    fi
+    zconf_mount $CLIENT2 $MOUNT
+}
+run_test 0g "VBR: unlink checks version of parent"
+
+test_0h() {
+    local file=$DIR/$tfile
+    local pre
+    local post
+
+    do_node $CLIENT1 mcreate $file
+    pre=$(get_version $CLIENT1 $file)
+    do_node $CLIENT1 chown $RUNAS_ID $file
+    post=$(get_version $CLIENT1 $file)
+    if (($pre == $post)); then
+        error "version not changed: pre $pre, post $post"
+    fi
+}
+run_test 0h "VBR: setattr of UID changes versions"
+
+test_0i() {
+    local file=$DIR/$tfile
+    local pre
+    local post
+
+    do_node $CLIENT1 mcreate $file
+    pre=$(get_version $CLIENT1 $file)
+    do_node $CLIENT1 chown :$RUNAS_ID $file
+    post=$(get_version $CLIENT1 $file)
+    if (($pre == $post)); then
+        error "version not changed: pre $pre, post $post"
+    fi
+}
+run_test 0i "VBR: setattr of GID changes versions"
+
+test_0j() {
+    local file=$DIR/$tfile
+
+    do_facet mds "$LCTL set_param mds.${mds_svc}.sync_permission=0"
+    do_node $CLIENT1 mcreate $file
+
+    replay_barrier mds
+    do_node $CLIENT2 chown :$RUNAS_ID $file
+    do_node $CLIENT1 chown $RUNAS_ID $file
+    zconf_umount $CLIENT2 $MOUNT
+    facet_failover mds
+
+    do_node $CLIENT1 df $MOUNT && error "$CLIENT1 not evicted"
+    if ! do_node $CLIENT1 $CHECKSTAT -u \\\#$UID $file; then
+        error "setattr of UID succeeded unexpectedly"
+    fi
+    zconf_mount $CLIENT2 $MOUNT
+}
+run_test 0j "VBR: setattr of UID checks versions"
+
+test_0k() {
+    local file=$DIR/$tfile
+
+    do_facet mds "$LCTL set_param mds.${mds_svc}.sync_permission=0"
+    do_node $CLIENT1 mcreate $file
+
+    replay_barrier mds
+    do_node $CLIENT2 chown $RUNAS_ID $file
+    do_node $CLIENT1 chown :$RUNAS_ID $file
+    zconf_umount $CLIENT2 $MOUNT
+    facet_failover mds
+
+    do_node $CLIENT1 df $MOUNT && error "$CLIENT1 not evicted"
+    if ! do_node $CLIENT1 $CHECKSTAT -g \\\#$UID $file; then
+        error "setattr of GID succeeded unexpectedly"
+    fi
+    zconf_mount $CLIENT2 $MOUNT
+}
+run_test 0k "VBR: setattr of GID checks versions"
+
+test_0l() {
+    local file=$DIR/$tfile
+    local pre
+    local post
+
+    do_node $CLIENT1 openfile -f O_RDWR:O_CREAT -m 0644 $file
+    pre=$(get_version $CLIENT1 $file)
+    do_node $CLIENT1 chmod 666 $file
+    post=$(get_version $CLIENT1 $file)
+    if (($pre == $post)); then
+        error "version not changed: pre $pre, post $post"
+    fi
+}
+run_test 0l "VBR: setattr of permission changes versions"
+
+test_0m() {
+    local file=$DIR/$tfile
+
+    do_facet mds "$LCTL set_param mds.${mds_svc}.sync_permission=0"
+    do_node $CLIENT1 openfile -f O_RDWR:O_CREAT -m 0644 $file
+
+    replay_barrier mds
+    do_node $CLIENT2 chown :$RUNAS_ID $file
+    do_node $CLIENT1 chmod 666 $file
+    zconf_umount $CLIENT2 $MOUNT
+    facet_failover mds
+
+    do_node $CLIENT1 df $MOUNT && error "$CLIENT1 not evicted"
+    if ! do_node $CLIENT1 $CHECKSTAT -p 0644 $file; then
+        error "setattr of permission succeeded unexpectedly"
+    fi
+    zconf_mount $CLIENT2 $MOUNT
+}
+run_test 0m "VBR: setattr of permission checks versions"
+
+test_0n() {
+    local file=$DIR/$tfile
+    local pre
+    local post
+
+    do_node $CLIENT1 mcreate $file
+    pre=$(get_version $CLIENT1 $file)
+    do_node $CLIENT1 chattr +i $file
+    post=$(get_version $CLIENT1 $file)
+    do_node $CLIENT1 chattr -i $file
+    if (($pre == $post)); then
+        error "version not changed: pre $pre, post $post"
+    fi
+}
+run_test 0n "VBR: setattr of flags changes versions"
+
+checkattr() {
+    local client=$1
+    local attr=$2
+    local file=$3
+    local rc
+
+    if ((${#attr} != 1)); then
+        error "checking multiple attributes not implemented yet"
+    fi
+    do_node $client lsattr $file | cut -d ' ' -f 1 | grep -q $attr
+}
+
+test_0o() {
+    local file=$DIR/$tfile
+    local rc
+
+    do_facet mds "$LCTL set_param mds.${mds_svc}.sync_permission=0"
+    do_node $CLIENT1 openfile -f O_RDWR:O_CREAT -m 0644 $file
+
+    replay_barrier mds
+    do_node $CLIENT2 chmod 666 $file
+    do_node $CLIENT1 chattr +i $file
+    zconf_umount $CLIENT2 $MOUNT
+    facet_failover mds
+
+    do_node $CLIENT1 df $MOUNT && error "$CLIENT1 not evicted"
+    checkattr $CLIENT1 i $file
+    rc=$?
+    do_node $CLIENT1 chattr -i $file
+    if [ $rc -eq 0 ]; then
+        error "setattr of flags succeeded unexpectedly"
+    fi
+    zconf_mount $CLIENT2 $MOUNT
+}
+run_test 0o "VBR: setattr of flags checks versions"
+
+test_0p() {
+    local file=$DIR/$tfile
+    local pre
+    local post
+    local ad_orig
+
+    ad_orig=$(do_facet mds "$LCTL get_param mds.${mds_svc}.atime_diff")
+    do_facet mds "$LCTL set_param mds.${mds_svc}.atime_diff=0"
+    do_node $CLIENT1 mcreate $file
+    pre=$(get_version $CLIENT1 $file)
+    do_node $CLIENT1 touch $file
+    post=$(get_version $CLIENT1 $file)
+    #
+    # We don't fail MDS in this test.  atime_diff shall be
+    # restored to its original value.
+    #
+    do_facet mds "$LCTL set_param $ad_orig"
+    if (($pre != $post)); then
+        error "version changed unexpectedly: pre $pre, post $post"
+    fi
+}
+run_test 0p "VBR: setattr of times does not change versions"
+
+test_0q() {
+    local file=$DIR/$tfile
+    local pre
+    local post
+
+    do_node $CLIENT1 mcreate $file
+    pre=$(get_version $CLIENT1 $file)
+    do_node $CLIENT1 truncate $file 1
+    post=$(get_version $CLIENT1 $file)
+    if (($pre != $post)); then
+        error "version changed unexpectedly: pre $pre, post $post"
+    fi
+}
+run_test 0q "VBR: setattr of size does not change versions"
+
+test_0r() {
+    local file=$DIR/$tfile
+    local mtime_pre
+    local mtime_post
+    local mtime
+
+    do_facet mds "$LCTL set_param mds.${mds_svc}.sync_permission=0"
+    do_facet mds "$LCTL set_param mds.${mds_svc}.atime_diff=0"
+    do_node $CLIENT1 openfile -f O_RDWR:O_CREAT -m 0644 $file
+
+    replay_barrier mds
+    do_node $CLIENT2 chmod 666 $file
+    do_node $CLIENT1 truncate $file 1
+    sleep 1
+    mtime_pre=$(do_node $CLIENT1 stat --format=%Y $file)
+    do_node $CLIENT1 touch $file
+    mtime_post=$(do_node $CLIENT1 stat --format=%Y $file)
+    zconf_umount $CLIENT2 $MOUNT
+    facet_failover mds
+
+    do_node $CLIENT1 df $MOUNT || error "$CLIENT1 evicted"
+    if (($mtime_pre >= $mtime_post)); then
+        error "time not changed: pre $mtime_pre, post $mtime_post"
+    fi
+    if ! do_node $CLIENT1 $CHECKSTAT -s 1 $file; then
+        error "setattr of size failed"
+    fi
+    mtime=$(do_node $CLIENT1 stat --format=%Y $file)
+    if (($mtime != $mtime_post)); then
+        error "setattr of times failed: expected $mtime_post, got $mtime"
+    fi
+    zconf_mount $CLIENT2 $MOUNT
+}
+run_test 0r "VBR: setattr of times and size does not check versions"
+
+test_0s() {
+    local pre
+    local post
+    local tp_pre
+    local tp_post
+
+    do_node $CLIENT1 mcreate $DIR/$tfile
+    do_node $CLIENT1 mkdir -p $DIR/$tdir
+    pre=$(get_version $CLIENT1 $DIR/$tfile)
+    tp_pre=$(get_version $CLIENT1 $DIR/$tdir)
+    do_node $CLIENT1 link $DIR/$tfile $DIR/$tdir/$tfile
+    post=$(get_version $CLIENT1 $DIR/$tfile)
+    tp_post=$(get_version $CLIENT1 $DIR/$tdir)
+    if (($pre == $post)); then
+        error "version of source not changed: pre $pre, post $post"
+    fi
+    if (($tp_pre == $tp_post)); then
+        error "version of target parent not changed: pre $tp_pre, post $tp_post"
+    fi
+}
+run_test 0s "VBR: link changes versions of source and target parent"
+
+test_0t() {
+    do_facet mds "$LCTL set_param mds.${mds_svc}.sync_permission=0"
+    do_node $CLIENT1 mcreate $DIR/$tfile
+    do_node $CLIENT1 mkdir -p -m 755 $DIR/$tdir
+
+    replay_barrier mds
+    do_node $CLIENT2 chmod 777 $DIR/$tdir
+    do_node $CLIENT1 link $DIR/$tfile $DIR/$tdir/$tfile
+    zconf_umount $CLIENT2 $MOUNT
+    facet_failover mds
+
+    do_node $CLIENT1 df $MOUNT && error "$CLIENT1 not evicted"
+    if ! do_node $CLIENT1 $CHECKSTAT -a $DIR/$tdir/$tfile; then
+        error "link should fail"
+    fi
+    zconf_mount $CLIENT2 $MOUNT
+}
+run_test 0t "VBR: link checks version of target parent"
+
+test_0u() {
+    do_facet mds "$LCTL set_param mds.${mds_svc}.sync_permission=0"
+    do_node $CLIENT1 openfile -f O_RDWR:O_CREAT -m 0644 $DIR/$tfile
+    do_node $CLIENT1 mkdir -p $DIR/$tdir
+
+    replay_barrier mds
+    do_node $CLIENT2 chmod 666 $DIR/$tfile
+    do_node $CLIENT1 link $DIR/$tfile $DIR/$tdir/$tfile
+    zconf_umount $CLIENT2 $MOUNT
+    facet_failover mds
+
+    do_node $CLIENT1 df $MOUNT && error "$CLIENT1 not evicted"
+    if ! do_node $CLIENT1 $CHECKSTAT -a $DIR/$tdir/$tfile; then
+        error "link should fail"
+    fi
+    zconf_mount $CLIENT2 $MOUNT
+}
+run_test 0u "VBR: link checks version of source"
+
+test_0v() {
+    local sp_pre
+    local tp_pre
+    local sp_post
+    local tp_post
+
+    do_node $CLIENT1 mcreate $DIR/$tfile
+    do_node $CLIENT1 mkdir -p $DIR/$tdir
+    sp_pre=$(get_version $CLIENT1 $DIR)
+    tp_pre=$(get_version $CLIENT1 $DIR/$tdir)
+    do_node $CLIENT1 mv $DIR/$tfile $DIR/$tdir/$tfile
+    sp_post=$(get_version $CLIENT1 $DIR)
+    tp_post=$(get_version $CLIENT1 $DIR/$tdir)
+    if (($sp_pre == $sp_post)); then
+        error "version of source parent not changed: pre $sp_pre, post $sp_post"
+    fi
+    if (($tp_pre == $tp_post)); then
+        error "version of target parent not changed: pre $tp_pre, post $tp_post"
+    fi
+}
+run_test 0v "VBR: rename changes versions of source parent and target parent"
+
+test_0w() {
+    local pre
+    local post
+
+    do_node $CLIENT1 mcreate $DIR/$tfile
+    pre=$(get_version $CLIENT1 $DIR)
+    do_node $CLIENT1 mv $DIR/$tfile $DIR/$tfile-new
+    post=$(get_version $CLIENT1 $DIR)
+    if (($pre == $post)); then
+        error "version of parent not changed: pre $pre, post $post"
+    fi
+}
+run_test 0w "VBR: rename within same dir changes version of parent"
+
+test_0x() {
+    do_facet mds "$LCTL set_param mds.${mds_svc}.sync_permission=0"
+    do_node $CLIENT1 mcreate $DIR/$tfile
+    do_node $CLIENT1 mkdir -p -m 755 $DIR/$tdir
+
+    replay_barrier mds
+    do_node $CLIENT2 chmod 777 $DIR
+    do_node $CLIENT1 mv $DIR/$tfile $DIR/$tdir/$tfile
+    zconf_umount $CLIENT2 $MOUNT
+    facet_failover mds
+
+    do_node $CLIENT1 df $MOUNT && error "$CLIENT1 not evicted"
+    if do_node $CLIENT1 $CHECKSTAT -a $DIR/$tfile; then
+        error "rename should fail"
+    fi
+    zconf_mount $CLIENT2 $MOUNT
+}
+run_test 0x "VBR: rename checks version of source parent"
+
+test_0y() {
+    do_facet mds "$LCTL set_param mds.${mds_svc}.sync_permission=0"
+    do_node $CLIENT1 mcreate $DIR/$tfile
+    do_node $CLIENT1 mkdir -p -m 755 $DIR/$tdir
+
+    replay_barrier mds
+    do_node $CLIENT2 chmod 777 $DIR/$tdir
+    do_node $CLIENT1 mv $DIR/$tfile $DIR/$tdir/$tfile
+    zconf_umount $CLIENT2 $MOUNT
+    facet_failover mds
+
+    do_node $CLIENT1 df $MOUNT && error "$CLIENT1 not evicted"
+    if do_node $CLIENT1 $CHECKSTAT -a $DIR/$tfile; then
+        error "rename should fail"
+    fi
+    zconf_mount $CLIENT2 $MOUNT
+}
+run_test 0y "VBR: rename checks version of target parent"
+
 [ "$CLIENTS" ] && zconf_umount_clients $CLIENTS $DIR
 
 test_1() {
@@ -64,7 +593,7 @@ test_1() {
 }
 run_test 1 "VBR: client during replay doesn't affect another one"
 
-test_2() {
+test_2a() { # was test_2
     #ls -al $DIR/$tdir/$tfile
 
     zconf_mount_clients $CLIENT1 $DIR
@@ -94,7 +623,78 @@ test_2() {
     zconf_umount_clients $CLIENTS $DIR
     return 0
 }
-run_test 2 "VBR: lost data due to missed REMOTE client during replay"
+run_test 2a "VBR: lost data due to missed REMOTE client during replay"
+
+#
+# This test uses three Lustre clients on two hosts.
+#
+#   Lustre Client 1:    $CLIENT1:$MOUNT     ($DIR)
+#   Lustre Client 2:    $CLIENT2:$MOUNT2    ($DIR2)
+#   Lustre Client 3:    $CLIENT2:$MOUNT1    ($DIR1)
+#
+test_2b() {
+    local pre
+    local post
+
+    do_facet mds "$LCTL set_param mds.${mds_svc}.sync_permission=0"
+    zconf_mount $CLIENT1 $MOUNT
+    zconf_mount $CLIENT2 $MOUNT2
+    zconf_mount $CLIENT2 $MOUNT1
+    do_node $CLIENT1 openfile -f O_RDWR:O_CREAT -m 0644 $DIR/$tfile-a
+    do_node $CLIENT1 openfile -f O_RDWR:O_CREAT -m 0644 $DIR/$tfile-b
+
+    #
+    # Save an MDT transaction number before recovery.
+    #
+    pre=$(get_version $CLIENT1 $DIR/$tfile-a)
+
+    #
+    # Comments on the replay sequence state the expected result
+    # of each request.
+    #
+    #   "R"     Replayed.
+    #   "U"     Unable to replay.
+    #   "J"     Rejected.
+    #
+    replay_barrier mds
+    do_node $CLIENT1 chmod 666 $DIR/$tfile-a            # R
+    do_node $CLIENT2 chmod 666 $DIR1/$tfile-b           # R
+    do_node $CLIENT2 chown :$RUNAS_ID $DIR2/$tfile-a    # U
+    do_node $CLIENT1 chown $RUNAS_ID $DIR/$tfile-a      # J
+    do_node $CLIENT2 truncate $DIR2/$tfile-b 1          # U
+    do_node $CLIENT2 chown :$RUNAS_ID $DIR1/$tfile-b    # R
+    do_node $CLIENT1 chown $RUNAS_ID $DIR/$tfile-b      # R
+    zconf_umount $CLIENT2 $MOUNT2
+    facet_failover mds
+
+    do_node $CLIENT1 df $MOUNT && error "$CLIENT1:$MOUNT not evicted"
+    do_node $CLIENT2 df $MOUNT1 || error "$CLIENT2:$MOUNT1 evicted"
+
+    #
+    # Check the MDT epoch.  $post must be the first transaction
+    # number assigned after recovery.
+    #
+    do_node $CLIENT2 touch $DIR1/$tfile
+    post=$(get_version $CLIENT2 $DIR1/$tfile)
+    if (($(($pre >> 32)) == $((post >> 32)))); then
+        error "epoch not changed: pre $pre, post $post"
+    fi
+    if (($(($post & 0x00000000ffffffff)) != 1)); then
+        error "transno should restart from one: got $post"
+    fi
+
+    do_node $CLIENT2 stat $DIR1/$tfile-a
+    do_node $CLIENT2 stat $DIR1/$tfile-b
+
+    do_node $CLIENT2 $CHECKSTAT -p 0666 -u \\\#$UID -g \\\#$UID \
+            $DIR1/$tfile-a || error "$DIR/$tfile-a: unexpected state"
+    do_node $CLIENT2 $CHECKSTAT -p 0666 -u \\\#$RUNAS_ID -g \\\#$RUNAS_ID \
+            $DIR1/$tfile-b || error "$DIR/$tfile-b: unexpected state"
+
+    zconf_umount $CLIENT2 $MOUNT1
+    zconf_umount $CLIENT1 $MOUNT
+}
+run_test 2b "VBR: 3 clients: some, none, and all reqs replayed"
 
 test_3a() {
     zconf_mount_clients $CLIENT1 $DIR
@@ -458,46 +1058,6 @@ test_7a() {
 }
 run_test 7a "fail MDS, delayed recovery, fail MDS"
 
-rmultiop_start() {
-    local client=$1
-    local file=$2
-
-    # We need to run do_node in bg, because pdsh does not exit
-    # if child process of run script exists.
-    # I.e. pdsh does not exit when runmultiop_bg_pause exited,
-    # because of multiop_bg_pause -> $MULTIOP_PROG &
-    # By the same reason we need sleep a bit after do_nodes starts 
-    # to let runmultiop_bg_pause start muliop and
-    # update /tmp/multiop_bg.pid ;
-    # The rm /tmp/multiop_bg.pid guarantees here that 
-    # we have the updated by runmultiop_bg_pause
-    # /tmp/multiop_bg.pid file
-
-    local pid_file=$TMP/multiop_bg.pid.$$
-    do_node $client "rm -f $pid_file && MULTIOP_PID_FILE=$pid_file LUSTRE= runmultiop_bg_pause $file O_tSc" & 
-    local pid=$!
-    sleep 3
-    local multiop_pid
-    multiop_pid=$(do_node $client cat $pid_file)
-    [ -n "$multiop_pid" ] || error "$client : Can not get multiop_pid from $pid_file "
-    eval export $(client_var_name $client)_multiop_pid=$multiop_pid
-    eval export $(client_var_name $client)_do_node_pid=$pid
-    local var=$(client_var_name $client)_multiop_pid
-    echo client $client multiop_bg started multiop_pid=${!var}
-    return $?
-}
-
-rmultiop_stop() {
-    local client=$1
-    local multiop_pid=$(client_var_name $client)_multiop_pid
-    local do_node_pid=$(client_var_name $client)_do_node_pid
-
-    echo "Stopping multiop_pid=${!multiop_pid} (kill ${!multiop_pid} on $client)"
-    do_node $client kill -USR1 ${!multiop_pid}
-
-    wait ${!do_node_pid} || true
-}
-
 test_8a() {
     delayed_recovery_enabled || { skip "No delayed recovery support"; return 0; }
 
@@ -507,7 +1067,7 @@ test_8a() {
     zconf_mount_clients $CLIENT1 $DIR
     zconf_mount_clients $CLIENT2 $DIR
 
-    rmultiop_start $CLIENT2 $DIR/$tfile || return 1
+    rmultiop_start $CLIENT2 $DIR/$tfile O_tSc || return 1
     do_node $CLIENT2 rm -f $DIR/$tfile
     replay_barrier mds
     rmultiop_stop $CLIENT2 || return 2
@@ -534,7 +1094,7 @@ test_8b() {
     zconf_mount_clients $CLIENT1 $DIR
     zconf_mount_clients $CLIENT2 $DIR
 
-    rmultiop_start $CLIENT2 $DIR/$tfile || return 1
+    rmultiop_start $CLIENT2 $DIR/$tfile O_tSc || return 1
     replay_barrier mds
     do_node $CLIENT1 rm -f $DIR/$tfile
 
@@ -561,7 +1121,7 @@ test_8c() {
     zconf_mount_clients $CLIENT1 $DIR
     zconf_mount_clients $CLIENT2 $DIR
 
-    rmultiop_start $CLIENT2 $DIR/$tfile || return 1
+    rmultiop_start $CLIENT2 $DIR/$tfile O_tSc || return 1
     replay_barrier mds
     do_node $CLIENT1 rm -f $DIR/$tfile
     rmultiop_stop $CLIENT2 || return 2
@@ -588,8 +1148,8 @@ test_8d() {
     zconf_mount_clients $CLIENT1 $DIR
     zconf_mount_clients $CLIENT2 $DIR
 
-    rmultiop_start $CLIENT1 $DIR/$tfile || return 1
-    rmultiop_start $CLIENT2 $DIR/$tfile || return 2
+    rmultiop_start $CLIENT1 $DIR/$tfile O_tSc || return 1
+    rmultiop_start $CLIENT2 $DIR/$tfile O_tSc || return 2
     replay_barrier mds
     do_node $CLIENT1 rm -f $DIR/$tfile
     rmultiop_stop $CLIENT2 || return 3
@@ -717,6 +1277,8 @@ test_10 () {
 }
 run_test 10 "mds version recovery; $CLIENTCOUNT clients"
 
+[ "$CLIENTS" ] && zconf_mount_clients $CLIENTS $DIR
+
 equals_msg `basename $0`: test complete, cleaning up
 #SLEEP=$((`date +%s` - $NOW))
 #[ $SLEEP -lt $TIMEOUT ] && sleep $SLEEP
index 81e2cff..3deb1a9 100644 (file)
@@ -291,6 +291,9 @@ command_t cmdlist[] = {
         {"memhog", jt_ptl_memhog, 0,
          "memory pressure testing\n"
          "usage: memhog <page count> [<gfp flags>]"},
+        {"getobjversion", jt_get_obj_version, 0,
+         "get the version of an object on servers\n"
+         "usage: getobjversion <fid>"},
 
         {"==== obsolete (DANGEROUS) ====", jt_noop, 0, "obsolete (DANGEROUS)"},
         /* some test scripts still use these */
index ffbf2c4..d743d44 100644 (file)
@@ -97,6 +97,7 @@ static int lfs_quotainv(int argc, char **argv);
 #endif
 static int lfs_join(int argc, char **argv);
 static int lfs_poollist(int argc, char **argv);
+static int lfs_path2fid(int argc, char **argv);
 
 /* all avaialable commands */
 command_t cmdlist[] = {
@@ -192,6 +193,8 @@ command_t cmdlist[] = {
         {"quotainv", lfs_quotainv, 0, "Invalidate quota data.\n"
          "usage: quotainv [-u|-g] <filesystem>"},
 #endif
+        {"path2fid", lfs_path2fid, 0, "Display the fid for a given path.\n"
+         "usage: path2fid <path>"},
         {"help", Parser_help, 0, "help"},
         {"exit", Parser_quit, 0, "quit"},
         {"quit", Parser_quit, 0, "quit"},
@@ -865,6 +868,28 @@ static int lfs_osts(int argc, char **argv)
         return rc;
 }
 
+static int lfs_path2fid(int argc, char **argv)
+{
+        char *path;
+        lustre_fid fid;
+        int rc;
+
+        if (argc != 2)
+                return CMD_HELP;
+
+        path = argv[1];
+        rc = llapi_path2fid(path, &fid);
+        if (rc) {
+                fprintf(stderr, "can't get fid for %s: %s\n", path,
+                        strerror(errno = -rc));
+                return rc;
+        }
+
+        printf(DFID"\n", PFID(&fid));
+
+        return 0;
+}
+
 #define COOK(value)                                                     \
 ({                                                                      \
         int radix = 0;                                                  \
index cf910d2..9653cfe 100644 (file)
@@ -2095,3 +2095,17 @@ out:
         free(buf);
         return ret;
 }
+
+int llapi_path2fid(const char *path, lustre_fid *fid)
+{
+        int fd, rc;
+
+        fd = open(path, O_RDONLY);
+        if (fd < 0)
+                return -errno;
+
+        rc = ioctl(fd, LL_IOC_PATH2FID, fid);
+
+        close(fd);
+        return rc;
+}
index 8e78102..1ce3fc8 100644 (file)
@@ -3144,6 +3144,57 @@ out:
         return rc;
 }
 
+int jt_get_obj_version(int argc, char **argv)
+{
+        struct ll_fid fid;
+        struct obd_ioctl_data data;
+        __u64 version;
+        char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf, *fidstr;
+        struct lu_fid f;
+        int rc;
+
+        if (argc != 2)
+                return CMD_HELP;
+
+        fidstr = argv[1];
+        while (*fidstr == '[')
+                fidstr++;
+        sscanf(fidstr, SFID, RFID(&f));
+        /*
+         * fid_is_sane is not suitable here.  We rely on
+         * mds_fid2locked_dentry to report on insane FIDs.
+         */
+        fid.id = f.f_seq;
+        fid.generation = f.f_oid;
+        fid.f_type = f.f_ver;
+
+        memset(&data, 0, sizeof data);
+        data.ioc_dev = cur_device;
+        data.ioc_inlbuf1 = (char *) &fid;
+        data.ioc_inllen1 = sizeof fid;
+        data.ioc_inlbuf2 = (char *) &version;
+        data.ioc_inllen2 = sizeof version;
+
+        memset(buf, 0, sizeof *buf);
+        rc = obd_ioctl_pack(&data, &buf, sizeof rawbuf);
+        if (rc) {
+                fprintf(stderr, "error: %s: packing ioctl arguments: %s\n",
+                        jt_cmdname(argv[0]), strerror(-rc));
+                return rc;
+        }
+
+        rc = l_ioctl(OBD_DEV_ID, OBD_IOC_GET_OBJ_VERSION, buf);
+        if (rc == -1) {
+                fprintf(stderr, "error: %s: ioctl: %s\n",
+                        jt_cmdname(argv[0]), strerror(errno));
+                return -errno;
+        }
+
+        obd_ioctl_unpack(&data, buf, sizeof rawbuf);
+        printf("0x%llx\n", version);
+        return 0;
+}
+
 void  llapi_ping_target(char *obd_type, char *obd_name,
                         char *obd_uuid, void *args)
 {
index eeb1bb8..0a61a5e 100644 (file)
@@ -81,6 +81,7 @@ int jt_obd_recover(int argc, char **argv);
 int jt_obd_mdc_lookup(int argc, char **argv);
 int jt_get_version(int argc, char **argv);
 int jt_cfg_dump_log(int argc, char **argv);
+int jt_get_obj_version(int argc, char **argv);
 
 int jt_llog_catlist(int argc, char **argv);
 int jt_llog_info(int argc, char **argv);