From: w.li Date: Fri, 21 Aug 2009 01:29:07 +0000 (+0000) Subject: Branch b1_8 X-Git-Tag: v1_8_2_01~1^2~161 X-Git-Url: https://git.whamcloud.com/gitweb?a=commitdiff_plain;h=f401a23adc8ec31cdcb67fbb7aefcb0bc8e7bbee;p=fs%2Flustre-release.git Branch b1_8 b=19743 i=tappro i=nathan.rutman,robert.read (non-test part) Attachment 25260: lfs path2fid. Add a "path2fid " command to lfs(1). Ported from HEAD (Bug 17187 and 19856). Attachment 25261: lctl getobjversion. Add a new lctl(8) command, "getobjversion ", 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). --- diff --git a/lustre/include/lustre/liblustreapi.h b/lustre/include/lustre/liblustreapi.h index 8138208..4594968 100644 --- a/lustre/include/lustre/liblustreapi.h +++ b/lustre/include/lustre/liblustreapi.h @@ -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); diff --git a/lustre/include/lustre/lustre_idl.h b/lustre/include/lustre/lustre_idl.h index d9559fb..9540c58 100644 --- a/lustre/include/lustre/lustre_idl.h +++ b/lustre/include/lustre/lustre_idl.h @@ -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, diff --git a/lustre/include/lustre/lustre_user.h b/lustre/include/lustre/lustre_user.h index c88602d..1cbd013 100644 --- a/lustre/include/lustre/lustre_user.h +++ b/lustre/include/lustre/lustre_user.h @@ -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 */ diff --git a/lustre/include/lustre_lib.h b/lustre/include/lustre_lib.h index 0f1aa74..d8efcf1 100644 --- a/lustre/include/lustre_lib.h +++ b/lustre/include/lustre_lib.h @@ -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 */ diff --git a/lustre/llite/dir.c b/lustre/llite/dir.c index 6737947..9f96bfe 100644 --- a/lustre/llite/dir.c +++ b/lustre/llite/dir.c @@ -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)); } diff --git a/lustre/llite/file.c b/lustre/llite/file.c index 4c238a0..bcac1ff 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -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 diff --git a/lustre/mds/mds_lov.c b/lustre/mds/mds_lov.c index 58c15cb..1004d3d 100644 --- a/lustre/mds/mds_lov.c +++ b/lustre/mds/mds_lov.c @@ -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); diff --git a/lustre/tests/replay-vbr.sh b/lustre/tests/replay-vbr.sh index 0087434..836b438 100644 --- a/lustre/tests/replay-vbr.sh +++ b/lustre/tests/replay-vbr.sh @@ -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 diff --git a/lustre/utils/lctl.c b/lustre/utils/lctl.c index 81e2cff..3deb1a9 100644 --- a/lustre/utils/lctl.c +++ b/lustre/utils/lctl.c @@ -291,6 +291,9 @@ command_t cmdlist[] = { {"memhog", jt_ptl_memhog, 0, "memory pressure testing\n" "usage: memhog []"}, + {"getobjversion", jt_get_obj_version, 0, + "get the version of an object on servers\n" + "usage: getobjversion "}, {"==== obsolete (DANGEROUS) ====", jt_noop, 0, "obsolete (DANGEROUS)"}, /* some test scripts still use these */ diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index ffbf2c4..d743d44 100644 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -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] "}, #endif + {"path2fid", lfs_path2fid, 0, "Display the fid for a given path.\n" + "usage: path2fid "}, {"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; \ diff --git a/lustre/utils/liblustreapi.c b/lustre/utils/liblustreapi.c index cf910d2..9653cfe 100644 --- a/lustre/utils/liblustreapi.c +++ b/lustre/utils/liblustreapi.c @@ -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; +} diff --git a/lustre/utils/obd.c b/lustre/utils/obd.c index 8e78102..1ce3fc8 100644 --- a/lustre/utils/obd.c +++ b/lustre/utils/obd.c @@ -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) { diff --git a/lustre/utils/obdctl.h b/lustre/utils/obdctl.h index eeb1bb8..0a61a5e 100644 --- a/lustre/utils/obdctl.h +++ b/lustre/utils/obdctl.h @@ -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);