From: Qian Yingjin Date: Sat, 19 Oct 2019 08:46:36 +0000 (+0800) Subject: LU-11971 utils: Send file creation time to clients X-Git-Tag: 2.13.54~98 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=186b97e68abbc45c0e8d5ae7e2a0d10aaa918db6 LU-11971 utils: Send file creation time to clients Both ext4 and ZFS allow storing the file creation time in the on-disk inode, and the new statx() API allows returning it to userspace, but as yet we do not have any mechanism to send it from the servers to the client. Add fields into struct mdt_body and an OBD_MD_FLBTIME flag to allow it to be requested and returned directly from MDTs. It does not need to get it from the OSTs or in the LVB since those objects are precreated and their creation time (birth time) is not accurate. This patch also adds support to lfs find to query on this field. Signed-off-by: Qian Yingjin Change-Id: Ib122b336695cde511fa6d8fb9eca95a4da701430 Reviewed-on: https://review.whamcloud.com/36507 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: Li Xi Reviewed-by: James Simmons Reviewed-by: Oleg Drokin --- diff --git a/lustre/doc/lfs-find.1 b/lustre/doc/lfs-find.1 index 9181355..ab4271b 100644 --- a/lustre/doc/lfs-find.1 +++ b/lustre/doc/lfs-find.1 @@ -5,6 +5,7 @@ lfs-find \- Lustre client utility to list files with specific attributes .B lfs find \fR<\fIdirectory\fR|\fIfilename \fR...> [[\fB!\fR] \fB--atime\fR|\fB-A\fR [\fB-+\fR]\fIn[smhdwy]\fR] [[\fB!\fR] \fB--blocks\fR|\fB-b\fR [\fB+-\fR]\fIn\fR] + [[\fB!\fR] \fB--btime\fR|\fB--Btime\fR|\fB-B\fR [\fB+-\fR]\fIn[smhdwy]\fR] [[\fB!\fR] \fB--ctime\fR|\fB-C\fR [\fB+-\fR]\fIn[smhdwy]\fR] [[\fB!\fR] \fB--component-count|\fB--comp-count\fR [\fB+-\fR]\fIn\fR] [[\fB!\fR] \fB--component-end|\fB--comp-end\fR|\fB-E\fR [\fB+-\fR]\fIn\fR[\fBKMGTPE\fR]] @@ -67,6 +68,11 @@ Blocks allocated by the file is \fIn\fR Kibibytes (if no units are given), \fIn\fR 512-byte \fBb\fRlocks, or \fBK\fRibi-, \fBM\fRebi-, \fBG\fRibi-, \fBT\fRebi-, \fBP\fRebi-, or \fBE\fRbi-bytes if that suffix is given. .TP +.BR --btime | --Btime | -B +File was created \fIn\fR*24 hours ago, see +--atime +for full details and options. +.TP .BR --ctime | -C File's status was last changed \fIn\fR*24 hours ago, see --atime @@ -209,6 +215,7 @@ ll ll llw(2i). a The access time of the file \fIreference\fR +b|B The birth time of the file \fIreference\fR c The inode status change time of \fIreference\fR m The modification time of the file \fIreference\fR t \fIreference\fR is interpreted directly as a time @@ -231,7 +238,10 @@ with unspecified times at the start of that minute or day, unspecified dates being "today", and "@%s" or "%s" the seconds since the Unix epoch (see .BR strftime (3) for details of the time formats). Otherwise, it will report an error. - +If you try to use the birth time of a reference file, and the birth +time cannot be determined, a fatal error message results. If you +specify a test which refers to the birth time of files being examined, +this test will fail for any files where the birth time is unknown. .TP .BR --ost | -O File has an object on the specified OST(s). The OST names can be specified diff --git a/lustre/include/lu_object.h b/lustre/include/lu_object.h index e656d94..a9fa482 100644 --- a/lustre/include/lu_object.h +++ b/lustre/include/lu_object.h @@ -397,35 +397,37 @@ struct lu_attr { * * \see enum la_valid */ - __u64 la_valid; + __u64 la_valid; /** size in bytes */ - __u64 la_size; + __u64 la_size; /** modification time in seconds since Epoch */ s64 la_mtime; /** access time in seconds since Epoch */ s64 la_atime; /** change time in seconds since Epoch */ s64 la_ctime; + /** create time in seconds since Epoch */ + s64 la_btime; /** 512-byte blocks allocated to object */ - __u64 la_blocks; + __u64 la_blocks; /** permission bits and file type */ - __u32 la_mode; + __u32 la_mode; /** owner id */ - __u32 la_uid; + __u32 la_uid; /** group id */ - __u32 la_gid; + __u32 la_gid; /** object flags */ - __u32 la_flags; + __u32 la_flags; /** number of persistent references to this object */ - __u32 la_nlink; + __u32 la_nlink; /** blk bits of the object*/ - __u32 la_blkbits; + __u32 la_blkbits; /** blk size of the object*/ - __u32 la_blksize; + __u32 la_blksize; /** real device */ - __u32 la_rdev; + __u32 la_rdev; /** project id */ - __u32 la_projid; + __u32 la_projid; /** set layout version to OST objects. */ __u32 la_layout_version; }; diff --git a/lustre/include/lustre/lustreapi.h b/lustre/include/lustre/lustreapi.h index a9ecd8d..009a622 100644 --- a/lustre/include/lustre/lustreapi.h +++ b/lustre/include/lustre/lustreapi.h @@ -196,6 +196,7 @@ enum { NEWERXY_ATIME = 0, /* neweraY */ NEWERXY_MTIME = 1, /* newermY */ NEWERXY_CTIME = 2, /* newercY */ + NEWERXY_BTIME = 3, /* newerbY | newerBY */ NEWERXY_MAX, }; @@ -208,7 +209,7 @@ struct find_param { time_t fp_atime; time_t fp_mtime; time_t fp_ctime; - /* {a,m,c}sign cannot be bitfields due to using pointers to + /* {a,m,c,b}sign cannot be bitfields due to using pointers to * access them during argument parsing. */ int fp_asign; int fp_msign; @@ -291,12 +292,13 @@ struct find_param { fp_exclude_ext_size:1, fp_lazy:1, fp_newerxy:1, - fp_unused_bit2:1, /* All of these unused bit */ - fp_unused_bit3:1, /* fields available to use.*/ - fp_unused_bit4:1, /* Once all unused fields */ - fp_unused_bit5:1, /* are used we need to add */ - fp_unused_bit6:1, /* a separate flag field at*/ - fp_unused_bit7:1; /* the end of the struct. */ + fp_exclude_btime:1, + fp_unused_bit3:1, /* All of these unused bit */ + fp_unused_bit4:1, /* fields available to use.*/ + fp_unused_bit5:1, /* Once all unused fields */ + fp_unused_bit6:1, /* are used we need to add */ + fp_unused_bit7:1; /* a separate flag field at*/ + /* the end of the struct. */ enum llapi_layout_verbose fp_verbose; int fp_quiet; @@ -362,6 +364,9 @@ struct find_param { * fp_newery[NEWERXY_MAX][1]: ! -- newerXY reference */ time_t fp_newery[NEWERXY_MAX][2]; + + time_t fp_btime; + int fp_bsign; }; int llapi_ostlist(char *path, struct find_param *param); diff --git a/lustre/include/uapi/linux/lustre/lustre_idl.h b/lustre/include/uapi/linux/lustre/lustre_idl.h index 57d2afe..9b5eb9f 100644 --- a/lustre/include/uapi/linux/lustre/lustre_idl.h +++ b/lustre/include/uapi/linux/lustre/lustre_idl.h @@ -1300,6 +1300,8 @@ lov_mds_md_max_stripe_count(__kernel_size_t buf_size, __u32 lmm_magic) #define OBD_MD_FLLAZYSIZE (0x0400000000000000ULL) /* Lazy size */ #define OBD_MD_FLLAZYBLOCKS (0x0800000000000000ULL) /* Lazy blocks */ +#define OBD_MD_FLBTIME (0x1000000000000000ULL) /* birth time */ + #define OBD_MD_FLALLQUOTA (OBD_MD_FLUSRQUOTA | \ OBD_MD_FLGRPQUOTA | \ OBD_MD_FLPRJQUOTA) @@ -1309,7 +1311,7 @@ lov_mds_md_max_stripe_count(__kernel_size_t buf_size, __u32 lmm_magic) OBD_MD_FLMODE | OBD_MD_FLTYPE | OBD_MD_FLUID | \ OBD_MD_FLGID | OBD_MD_FLFLAGS | OBD_MD_FLNLINK | \ OBD_MD_FLPARENT | OBD_MD_FLRDEV | OBD_MD_FLGROUP | \ - OBD_MD_FLPROJID) + OBD_MD_FLPROJID | OBD_MD_FLBTIME) #define OBD_MD_FLXATTRALL (OBD_MD_FLXATTR | OBD_MD_FLXATTRLS) @@ -1814,8 +1816,8 @@ struct mdt_body { __u32 mbo_projid; __u64 mbo_dom_size; /* size of DOM component */ __u64 mbo_dom_blocks; /* blocks consumed by DOM component */ - __u64 mbo_padding_8; /* also fix lustre_swab_mdt_body */ - __u64 mbo_padding_9; + __u64 mbo_btime; + __u64 mbo_padding_9; /* also fix lustre_swab_mdt_body */ __u64 mbo_padding_10; }; /* 216 */ diff --git a/lustre/include/uapi/linux/lustre/lustre_user.h b/lustre/include/uapi/linux/lustre/lustre_user.h index 93fc33a..65e41f1 100644 --- a/lustre/include/uapi/linux/lustre/lustre_user.h +++ b/lustre/include/uapi/linux/lustre/lustre_user.h @@ -1389,6 +1389,7 @@ enum la_valid { LA_LAYOUT_VERSION = 1 << 16, /* 0x10000 */ LA_LSIZE = 1 << 17, /* 0x20000 */ LA_LBLOCKS = 1 << 18, /* 0x40000 */ + LA_BTIME = 1 << 19, /* 0x80000 */ /** * Attributes must be transmitted to OST objects */ diff --git a/lustre/llite/dir.c b/lustre/llite/dir.c index cf6e43c..da83791 100644 --- a/lustre/llite/dir.c +++ b/lustre/llite/dir.c @@ -1804,11 +1804,12 @@ out_rmdir: stx.stx_atime.tv_sec = body->mbo_atime; stx.stx_ctime.tv_sec = body->mbo_ctime; stx.stx_mtime.tv_sec = body->mbo_mtime; + stx.stx_btime.tv_sec = body->mbo_btime; stx.stx_rdev_major = MAJOR(body->mbo_rdev); stx.stx_rdev_minor = MINOR(body->mbo_rdev); stx.stx_dev_major = MAJOR(inode->i_sb->s_dev); stx.stx_dev_minor = MINOR(inode->i_sb->s_dev); - stx.stx_mask |= STATX_BASIC_STATS; + stx.stx_mask |= STATX_BASIC_STATS | STATX_BTIME; /* * For a striped directory, the size and blocks returned diff --git a/lustre/mdt/mdt_handler.c b/lustre/mdt/mdt_handler.c index aa843fe..0f3ff88 100644 --- a/lustre/mdt/mdt_handler.c +++ b/lustre/mdt/mdt_handler.c @@ -727,6 +727,10 @@ void mdt_pack_attr2body(struct mdt_thread_info *info, struct mdt_body *b, b->mbo_ctime = attr->la_ctime; b->mbo_valid |= OBD_MD_FLCTIME; } + if (attr->la_valid & LA_BTIME) { + b->mbo_btime = attr->la_btime; + b->mbo_valid |= OBD_MD_FLBTIME; + } if (attr->la_valid & LA_FLAGS) { b->mbo_flags = attr->la_flags; b->mbo_valid |= OBD_MD_FLFLAGS; diff --git a/lustre/osd-ldiskfs/osd_handler.c b/lustre/osd-ldiskfs/osd_handler.c index e3006f6..8337dd2 100644 --- a/lustre/osd-ldiskfs/osd_handler.c +++ b/lustre/osd-ldiskfs/osd_handler.c @@ -2594,11 +2594,12 @@ static void osd_inode_getattr(const struct lu_env *env, attr->la_valid |= LA_ATIME | LA_MTIME | LA_CTIME | LA_MODE | LA_SIZE | LA_BLOCKS | LA_UID | LA_GID | LA_PROJID | LA_FLAGS | LA_NLINK | LA_RDEV | - LA_BLKSIZE | LA_TYPE; + LA_BLKSIZE | LA_TYPE | LA_BTIME; attr->la_atime = inode->i_atime.tv_sec; attr->la_mtime = inode->i_mtime.tv_sec; attr->la_ctime = inode->i_ctime.tv_sec; + attr->la_btime = LDISKFS_I(inode)->i_crtime.tv_sec; attr->la_mode = inode->i_mode; attr->la_size = i_size_read(inode); attr->la_blocks = inode->i_blocks; diff --git a/lustre/osd-zfs/osd_internal.h b/lustre/osd-zfs/osd_internal.h index 443a1ed..737ec68 100644 --- a/lustre/osd-zfs/osd_internal.h +++ b/lustre/osd-zfs/osd_internal.h @@ -181,6 +181,7 @@ struct osa_attr { uint64_t atime[2]; uint64_t mtime[2]; uint64_t ctime[2]; + uint64_t btime[2]; }; diff --git a/lustre/osd-zfs/osd_object.c b/lustre/osd-zfs/osd_object.c index cc8f1da..f28bcb7 100644 --- a/lustre/osd-zfs/osd_object.c +++ b/lustre/osd-zfs/osd_object.c @@ -194,12 +194,14 @@ static int __osd_object_attr_get(const struct lu_env *env, struct osd_device *o, LASSERT(obj->oo_dn != NULL); - la->la_valid |= LA_ATIME | LA_MTIME | LA_CTIME | LA_MODE | LA_TYPE | - LA_SIZE | LA_UID | LA_GID | LA_FLAGS | LA_NLINK; + la->la_valid |= LA_ATIME | LA_MTIME | LA_CTIME | LA_BTIME | LA_MODE | + LA_TYPE | LA_SIZE | LA_UID | LA_GID | LA_FLAGS | + LA_NLINK; SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_ATIME(o), NULL, osa->atime, 16); SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_MTIME(o), NULL, osa->mtime, 16); SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_CTIME(o), NULL, osa->ctime, 16); + SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_CRTIME(o), NULL, osa->btime, 16); SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_MODE(o), NULL, &osa->mode, 8); SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_SIZE(o), NULL, &osa->size, 8); SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_LINKS(o), NULL, &osa->nlink, 8); @@ -234,6 +236,7 @@ static int __osd_object_attr_get(const struct lu_env *env, struct osd_device *o, la->la_atime = osa->atime[0]; la->la_mtime = osa->mtime[0]; la->la_ctime = osa->ctime[0]; + la->la_btime = osa->btime[0]; la->la_mode = osa->mode; la->la_uid = osa->uid; la->la_gid = osa->gid; @@ -1525,7 +1528,6 @@ int __osd_attr_init(const struct lu_env *env, struct osd_device *osd, sa_bulk_attr_t *bulk = osd_oti_get(env)->oti_attr_bulk; struct osa_attr *osa = &osd_oti_get(env)->oti_osa; uint64_t gen; - uint64_t crtime[2]; inode_timespec_t now; int cnt; int rc; @@ -1537,7 +1539,7 @@ int __osd_attr_init(const struct lu_env *env, struct osd_device *osd, gen = dmu_tx_get_txg(tx); gethrestime(&now); - ZFS_TIME_ENCODE(&now, crtime); + ZFS_TIME_ENCODE(&now, osa->btime); osa->atime[0] = la->la_atime; osa->ctime[0] = la->la_ctime; @@ -1587,7 +1589,7 @@ int __osd_attr_init(const struct lu_env *env, struct osd_device *osd, SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_ATIME(osd), NULL, osa->atime, 16); SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_MTIME(osd), NULL, osa->mtime, 16); SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_CTIME(osd), NULL, osa->ctime, 16); - SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_CRTIME(osd), NULL, crtime, 16); + SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_CRTIME(osd), NULL, osa->btime, 16); SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_LINKS(osd), NULL, &osa->nlink, 8); #ifdef ZFS_PROJINHERIT if (osd->od_projectused_dn) diff --git a/lustre/osd-zfs/osd_xattr.c b/lustre/osd-zfs/osd_xattr.c index 0db69f3..91ed638 100644 --- a/lustre/osd-zfs/osd_xattr.c +++ b/lustre/osd-zfs/osd_xattr.c @@ -430,7 +430,7 @@ int __osd_sa_attr_init(const struct lu_env *env, struct osd_object *obj, struct osa_attr *osa = &osd_oti_get(env)->oti_osa; struct lu_buf *lb = &osd_oti_get(env)->oti_xattr_lbuf; struct osd_device *osd = osd_obj2dev(obj); - uint64_t crtime[2], gen; + uint64_t gen; inode_timespec_t now; size_t size; int rc, cnt; @@ -440,8 +440,10 @@ int __osd_sa_attr_init(const struct lu_env *env, struct osd_object *obj, gen = dmu_tx_get_txg(oh->ot_tx); gethrestime(&now); - ZFS_TIME_ENCODE(&now, crtime); + ZFS_TIME_ENCODE(&now, osa->btime); + obj->oo_attr.la_valid |= LA_BTIME; + obj->oo_attr.la_btime = osa->btime[0]; osa->atime[0] = obj->oo_attr.la_atime; osa->ctime[0] = obj->oo_attr.la_ctime; osa->mtime[0] = obj->oo_attr.la_mtime; @@ -475,7 +477,7 @@ int __osd_sa_attr_init(const struct lu_env *env, struct osd_object *obj, SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_ATIME(osd), NULL, osa->atime, 16); SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_MTIME(osd), NULL, osa->mtime, 16); SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_CTIME(osd), NULL, osa->ctime, 16); - SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_CRTIME(osd), NULL, crtime, 16); + SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_CRTIME(osd), NULL, osa->btime, 16); SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_LINKS(osd), NULL, &osa->nlink, 8); #ifdef ZFS_PROJINHERIT if (osd->od_projectused_dn) diff --git a/lustre/ptlrpc/pack_generic.c b/lustre/ptlrpc/pack_generic.c index 8cc0ff6..973e3f0 100644 --- a/lustre/ptlrpc/pack_generic.c +++ b/lustre/ptlrpc/pack_generic.c @@ -1987,7 +1987,7 @@ void lustre_swab_mdt_body(struct mdt_body *b) __swab32s(&b->mbo_projid); __swab64s(&b->mbo_dom_size); __swab64s(&b->mbo_dom_blocks); - BUILD_BUG_ON(offsetof(typeof(*b), mbo_padding_8) == 0); + __swab64s(&b->mbo_btime); BUILD_BUG_ON(offsetof(typeof(*b), mbo_padding_9) == 0); BUILD_BUG_ON(offsetof(typeof(*b), mbo_padding_10) == 0); } diff --git a/lustre/ptlrpc/wiretest.c b/lustre/ptlrpc/wiretest.c index 3b5431b..e069b60 100644 --- a/lustre/ptlrpc/wiretest.c +++ b/lustre/ptlrpc/wiretest.c @@ -2493,10 +2493,10 @@ void lustre_assert_wire_constants(void) (long long)(int)offsetof(struct mdt_body, mbo_dom_blocks)); LASSERTF((int)sizeof(((struct mdt_body *)0)->mbo_dom_blocks) == 8, "found %lld\n", (long long)(int)sizeof(((struct mdt_body *)0)->mbo_dom_blocks)); - LASSERTF((int)offsetof(struct mdt_body, mbo_padding_8) == 192, "found %lld\n", - (long long)(int)offsetof(struct mdt_body, mbo_padding_8)); - LASSERTF((int)sizeof(((struct mdt_body *)0)->mbo_padding_8) == 8, "found %lld\n", - (long long)(int)sizeof(((struct mdt_body *)0)->mbo_padding_8)); + LASSERTF((int)offsetof(struct mdt_body, mbo_btime) == 192, "found %lld\n", + (long long)(int)offsetof(struct mdt_body, mbo_btime)); + LASSERTF((int)sizeof(((struct mdt_body *)0)->mbo_btime) == 8, "found %lld\n", + (long long)(int)sizeof(((struct mdt_body *)0)->mbo_btime)); LASSERTF((int)offsetof(struct mdt_body, mbo_padding_9) == 200, "found %lld\n", (long long)(int)offsetof(struct mdt_body, mbo_padding_9)); LASSERTF((int)sizeof(((struct mdt_body *)0)->mbo_padding_9) == 8, "found %lld\n", diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index fb540aa..1b32ad1 100755 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -5880,18 +5880,26 @@ test_newerXY_base() { local negref if [ $y == "t" ]; then - ref="\"$(date +"%Y-%m-%d %H:%M:%S")\"" + if [ $x == "b" ]; then + ref="\"$(do_facet mds1 date +"%Y-%m-%d\ %H:%M:%S")\"" + else + ref="\"$(date +"%Y-%m-%d %H:%M:%S")\"" + fi else - ref=$DIR/$tfile.newer + ref=$DIR/$tfile.newer.$x$y touch $ref || error "touch $ref failed" fi sleep 2 setup_56 $dir $NUMFILES $NUMDIRS "-i0 -c1" "-i0 -c1" sleep 2 if [ $y == "t" ]; then - negref="\"$(date +"%Y-%m-%d %H:%M:%S")\"" + if [ $x == "b" ]; then + negref="\"$(do_facet mds1 date +"%Y-%m-%d\ %H:%M:%S")\"" + else + negref="\"$(date +"%Y-%m-%d %H:%M:%S")\"" + fi else - negref=$DIR/$tfile.newerneg + negref=$DIR/$tfile.negnewer.$x$y touch $negref || error "touch $negref failed" fi @@ -5916,6 +5924,7 @@ test_newerXY_base() { } test_56oc() { + test_newerXY_base "b" "t" test_newerXY_base "a" "a" test_newerXY_base "a" "m" test_newerXY_base "a" "c" @@ -5925,12 +5934,96 @@ test_56oc() { test_newerXY_base "c" "a" test_newerXY_base "c" "m" test_newerXY_base "c" "c" + test_newerXY_base "b" "b" test_newerXY_base "a" "t" test_newerXY_base "m" "t" test_newerXY_base "c" "t" + test_newerXY_base "b" "t" } run_test 56oc "check lfs find -newerXY work" +btime_supported() { + local dir=$DIR/$tdir + local rc + + mkdir -p $dir + touch $dir/$tfile + $LFS find $dir -btime -1d -type f + rc=$? + rm -rf $dir + return $rc +} + +test_56od() { + [ $MDS1_VERSION -lt $(version_code 2.13.53) ] && + ! btime_supported && skip "btime unsupported on MDS" + + [ $CLIENT_VERSION -lt $(version_code 2.13.53) ] && + ! btime_supported && skip "btime unsupported on clients" + + local dir=$DIR/$tdir + local ref=$DIR/$tfile.ref + local negref=$DIR/$tfile.negref + + mkdir $dir || error "mkdir $dir failed" + touch $dir/$tfile.n1 || error "touch $dir/$tfile.n1 failed" + touch $dir/$tfile.n2 || error "touch $dir/$tfile.n2 failed" + mkdir $dir/$tdir.n1 || error "mkdir $dir/$tdir.n1 failed" + mkdir $dir/$tdir.n2 || error "mkdir $dir/$tdir.n2 failed" + touch $ref || error "touch $ref failed" + # sleep 3 seconds at least + sleep 3 + + local before=$(do_facet mds1 date +%s) + local skew=$(($(date +%s) - before + 1)) + + if (( skew < 0 && skew > -5 )); then + sleep $((0 - skew + 1)) + skew=0 + fi + + # Set the dir stripe params to limit files all on MDT0, + # otherwise we need to calc the max clock skew between + # the client and MDTs. + setup_56 $dir/d.btime $NUMFILES $NUMDIRS "-i0 -c1" "-i0 -c1" + sleep 2 + touch $negref || error "touch $negref failed" + + local cmd="$LFS find $dir -newerbb $ref ! -newerbb $negref -type f" + local nums=$($cmd | wc -l) + local expected=$(((NUMFILES + 1) * NUMDIRS)) + + [ $nums -eq $expected ] || + error "'$cmd' wrong: found $nums, expected $expected" + + cmd="$LFS find $dir -newerbb $ref ! -newerbb $negref -type d" + nums=$($cmd | wc -l) + expected=$((NUMFILES + 1)) + [ $nums -eq $expected ] || + error "'$cmd' wrong: found $nums, expected $expected" + + [ $skew -lt 0 ] && return + + local after=$(do_facet mds1 date +%s) + local age=$((after - before + 1 + skew)) + + cmd="$LFS find $dir -btime -${age}s -type f" + nums=$($cmd | wc -l) + expected=$(((NUMFILES + 1) * NUMDIRS)) + + echo "Clock skew between client and server: $skew, age:$age" + [ $nums -eq $expected ] || + error "'$cmd' wrong: found $nums, expected $expected" + + expected=$(($NUMDIRS + 1)) + cmd="$LFS find $dir -btime -${age}s -type d" + nums=$($cmd | wc -l) + [ $nums -eq $expected ] || + error "'$cmd' wrong: found $nums, expected $expected" + rm -f $ref $negref || error "Failed to remove $ref $negref" +} +run_test 56od "check lfs find -btime with units" + test_56p() { [ $RUNAS_ID -eq $UID ] && skip_env "RUNAS_ID = UID = $UID -- skipping" diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index 4407f56..1490ffe 100644 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -457,8 +457,9 @@ command_t cmdlist[] = { "find files matching given attributes recursively in directory tree.\n" "usage: find ...\n" " [[!] --atime|-A [+-]N[smhdwy]] [[!] --ctime|-C [+-]N[smhdwy]]\n" - " [[!] --mtime|-M [+-]N[smhdwy]] [[!] --blocks|-b N]\n" - " [[!] --newer[XY] ]\n" + " [[!] --mtime|-M [+-]N[smhdwy]]\n" + " [[!] --btime|--Btime|-B [+-]N[smhdwy]]\n" + " [[!] --newer[XY] ] [[!] --blocks|-b N]\n" " [--maxdepth|-D N] [[!] --mdt-index|--mdt|-m ]\n" " [[!] --name|-n ] [[!] --ost|-O ]\n" " [--print|-P] [--print0|-0] [[!] --size|-s [+-]N[bkMGTPE]]\n" @@ -3069,6 +3070,7 @@ static int lfs_setstripe_internal(int argc, char **argv, /* find { .val = 'A', .name = "atime", .has_arg = required_argument }*/ /* --block is only valid in migrate mode */ { .val = 'b', .name = "block", .has_arg = no_argument }, +/* find { .val = 'B', .name = "btime", .has_arg = required_argument }*/ { .val = LFS_COMP_ADD_OPT, .name = "comp-add", .has_arg = no_argument }, { .val = LFS_COMP_ADD_OPT, @@ -4168,6 +4170,8 @@ static int lfs_find(int argc, char **argv) struct option long_opts[] = { { .val = 'A', .name = "atime", .has_arg = required_argument }, { .val = 'b', .name = "blocks", .has_arg = required_argument }, + { .val = 'B', .name = "btime", .has_arg = required_argument }, + { .val = 'B', .name = "Btime", .has_arg = required_argument }, { .val = LFS_COMP_COUNT_OPT, .name = "comp-count", .has_arg = required_argument }, { .val = LFS_COMP_COUNT_OPT, @@ -4196,23 +4200,49 @@ static int lfs_find(int argc, char **argv) { .val = LFS_NEWERXY_OPT, .name = "newerac", .has_arg = required_argument}, { .val = LFS_NEWERXY_OPT, + .name = "newerab", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, .name = "newerma", .has_arg = required_argument}, { .val = LFS_NEWERXY_OPT, .name = "newermm", .has_arg = required_argument}, { .val = LFS_NEWERXY_OPT, .name = "newermc", .has_arg = required_argument}, { .val = LFS_NEWERXY_OPT, + .name = "newermb", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, .name = "newerca", .has_arg = required_argument}, { .val = LFS_NEWERXY_OPT, .name = "newercm", .has_arg = required_argument}, { .val = LFS_NEWERXY_OPT, .name = "newercc", .has_arg = required_argument}, { .val = LFS_NEWERXY_OPT, + .name = "newercb", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerba", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerbm", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerbc", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerbb", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerBa", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerBm", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerBc", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerBB", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, .name = "newerat", .has_arg = required_argument}, { .val = LFS_NEWERXY_OPT, .name = "newermt", .has_arg = required_argument}, { .val = LFS_NEWERXY_OPT, .name = "newerct", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerbt", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerBt", .has_arg = required_argument}, { .val = 'c', .name = "stripe-count", .has_arg = required_argument }, { .val = 'c', .name = "stripe_count", .has_arg = required_argument }, { .val = 'C', .name = "ctime", .has_arg = required_argument }, @@ -4278,8 +4308,8 @@ static int lfs_find(int argc, char **argv) /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */ while ((c = getopt_long_only(argc, argv, - "-0A:b:c:C:D:E:g:G:H:i:L:m:M:n:N:O:Ppqrs:S:t:T:u:U:vz:", - long_opts, &optidx)) >= 0) { + "-0A:b:B:c:C:D:E:g:G:H:i:L:m:M:n:N:O:Ppqrs:S:t:T:u:U:vz:", + long_opts, &optidx)) >= 0) { xtime = NULL; xsign = NULL; if (neg_opt) @@ -4318,6 +4348,13 @@ static int lfs_find(int argc, char **argv) xtime = ¶m.fp_atime; xsign = ¶m.fp_asign; param.fp_exclude_atime = !!neg_opt; + /* no break, this falls through to 'B' for btime */ + case 'B': + if (c == 'B') { + xtime = ¶m.fp_btime; + xsign = ¶m.fp_bsign; + param.fp_exclude_btime = !!neg_opt; + } /* no break, this falls through to 'C' for ctime */ case 'C': if (c == 'C') { @@ -4562,6 +4599,24 @@ static int lfs_find(int argc, char **argv) } ref = mktime(&tm); + } else if (y == 'b' || y == 'B') { + lstatx_t stx; + + rc = llapi_get_lum_file(optarg, NULL, &stx, + NULL, 0); + if (rc || !(stx.stx_mask & STATX_BTIME)) { + if (!(stx.stx_mask & STATX_BTIME)) + ret = -EOPNOTSUPP; + else + ret = -errno; + fprintf(stderr, + "%s: get btime failed '%s': %s\n", + progname, optarg, + strerror(-ret)); + goto err; + } + + ref = stx.stx_btime.tv_sec; } else { struct stat statbuf; @@ -4603,6 +4658,10 @@ static int lfs_find(int argc, char **argv) case 'c': xidx = NEWERXY_CTIME; break; + case 'b': + case 'B': + xidx = NEWERXY_BTIME; + break; default: fprintf(stderr, "%s: invalid X argument: '%c'\n", @@ -4974,6 +5033,8 @@ static int lfs_getstripe_internal(int argc, char **argv, struct option long_opts[] = { /* find { .val = 'A', .name = "atime", .has_arg = required_argument }*/ /* find { .val = 'b', .name = "blocks", .has_arg = required_argument }*/ +/* find { .val = 'B', .name = "btime", .has_arg = required_argument }*/ +/* find { .val = 'B', .name = "Btime", .has_arg = required_argument }*/ { .val = LFS_COMP_COUNT_OPT, .name = "comp-count", .has_arg = no_argument }, { .val = LFS_COMP_COUNT_OPT, diff --git a/lustre/utils/liblustreapi.c b/lustre/utils/liblustreapi.c index 5c0e16b..16e140c 100644 --- a/lustre/utils/liblustreapi.c +++ b/lustre/utils/liblustreapi.c @@ -4019,7 +4019,7 @@ static int find_time_check(struct find_param *param, int mds) return rc; } -static int find_newerxy_check(struct find_param *param, int mds) +static int find_newerxy_check(struct find_param *param, int mds, bool from_mdt) { struct lov_user_mds_data *lmd = param->fp_lmd; int i; @@ -4066,6 +4066,27 @@ static int find_newerxy_check(struct find_param *param, int mds) if (rc == 1) rc = rc2; } + + /* + * File birth time (btime) can get from MDT directly. + * if @from_mdt is true, it means the input file attributs are + * obtained directly from MDT. + * Thus, if @from_mdt is false, we should skip the following + * btime check. + */ + if (!from_mdt) + continue; + + if (param->fp_newery[NEWERXY_BTIME][i]) { + if (!(lmd->lmd_stx.stx_mask & STATX_BTIME)) + return -EOPNOTSUPP; + + rc2 = find_value_cmp(lmd->lmd_stx.stx_btime.tv_sec, + param->fp_newery[NEWERXY_BTIME][i], + -1, i, 0, 0); + if (rc2 < 0) + return rc2; + } } return rc; @@ -4584,7 +4605,8 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp, /* Request MDS for the stat info if some of these parameters need * to be compared. */ if (param->fp_obd_uuid || param->fp_mdt_uuid || - param->fp_check_uid || param->fp_check_gid || param->fp_newerxy || + param->fp_check_uid || param->fp_check_gid || + param->fp_newerxy || param->fp_btime || param->fp_atime || param->fp_mtime || param->fp_ctime || param->fp_check_size || param->fp_check_blocks || find_check_lmm_info(param) || @@ -4870,14 +4892,32 @@ obd_matches: goto decided; } + if (param->fp_btime) { + if (!(lmd->lmd_stx.stx_mask & STATX_BTIME)) { + ret = -EOPNOTSUPP; + goto out; + } + + decision = find_value_cmp(lmd->lmd_stx.stx_btime.tv_sec, + param->fp_btime, param->fp_bsign, + param->fp_exclude_btime, + param->fp_time_margin, 0); + if (decision == -1) + goto decided; + } + if (param->fp_newerxy) { int for_mds; for_mds = lustre_fs ? (S_ISREG(lmd->lmd_stx.stx_mode) && stripe_count) : 0; - decision = find_newerxy_check(param, for_mds); + decision = find_newerxy_check(param, for_mds, true); if (decision == -1) goto decided; + if (decision < 0) { + ret = decision; + goto out; + } } flags = param->fp_lmd->lmd_flags; @@ -4940,10 +4980,13 @@ obd_matches: goto decided; if (param->fp_newerxy) { - decision = find_newerxy_check(param, 0); + decision = find_newerxy_check(param, 0, false); if (decision == -1) goto decided; - + if (decision < 0) { + ret = decision; + goto out; + } } } diff --git a/lustre/utils/liblustreapi_layout.c b/lustre/utils/liblustreapi_layout.c index c2cd0ad..5dfd6f4 100644 --- a/lustre/utils/liblustreapi_layout.c +++ b/lustre/utils/liblustreapi_layout.c @@ -3426,7 +3426,9 @@ int llapi_get_lum_file_fd(int dir_fd, const char *fname, __u64 *valid, if (rc) return rc; - *valid = lmd->lmd_flags; + if (valid) + *valid = lmd->lmd_flags; + if (statx) memcpy(statx, &lmd->lmd_stx, sizeof(*statx)); diff --git a/lustre/utils/wiretest.c b/lustre/utils/wiretest.c index cadc201..3c9a431 100644 --- a/lustre/utils/wiretest.c +++ b/lustre/utils/wiretest.c @@ -2519,10 +2519,10 @@ void lustre_assert_wire_constants(void) (long long)(int)offsetof(struct mdt_body, mbo_dom_blocks)); LASSERTF((int)sizeof(((struct mdt_body *)0)->mbo_dom_blocks) == 8, "found %lld\n", (long long)(int)sizeof(((struct mdt_body *)0)->mbo_dom_blocks)); - LASSERTF((int)offsetof(struct mdt_body, mbo_padding_8) == 192, "found %lld\n", - (long long)(int)offsetof(struct mdt_body, mbo_padding_8)); - LASSERTF((int)sizeof(((struct mdt_body *)0)->mbo_padding_8) == 8, "found %lld\n", - (long long)(int)sizeof(((struct mdt_body *)0)->mbo_padding_8)); + LASSERTF((int)offsetof(struct mdt_body, mbo_btime) == 192, "found %lld\n", + (long long)(int)offsetof(struct mdt_body, mbo_btime)); + LASSERTF((int)sizeof(((struct mdt_body *)0)->mbo_btime) == 8, "found %lld\n", + (long long)(int)sizeof(((struct mdt_body *)0)->mbo_btime)); LASSERTF((int)offsetof(struct mdt_body, mbo_padding_9) == 200, "found %lld\n", (long long)(int)offsetof(struct mdt_body, mbo_padding_9)); LASSERTF((int)sizeof(((struct mdt_body *)0)->mbo_padding_9) == 8, "found %lld\n",