From: John L. Hammond Date: Thu, 11 Mar 2021 16:02:54 +0000 (-0600) Subject: LU-14508 lfs: make mirror operations preserve timestamps X-Git-Tag: 2.14.53~30 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=9f672d8a71d8f77d2e807f1d4df926239ade8ebd LU-14508 lfs: make mirror operations preserve timestamps Save and try to restore the file timestamps around the various mirror operations. Add sanity-flr tests 61[abc] to verify this. Signed-off-by: John L. Hammond Signed-off-by: Bobi Jam Change-Id: I5ef754e46cfbe82c731a709209576bbfcc73af3d Reviewed-on: https://review.whamcloud.com/42009 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Bobi Jam Reviewed-by: Yingjin Qian Reviewed-by: Oleg Drokin --- diff --git a/lustre/mdd/mdd_object.c b/lustre/mdd/mdd_object.c index f466e04..0328371 100644 --- a/lustre/mdd/mdd_object.c +++ b/lustre/mdd/mdd_object.c @@ -870,8 +870,10 @@ static int mdd_fix_attr(const struct lu_env *env, struct mdd_object *obj, } if (la->la_valid & LA_CTIME) { - /* The pure setattr, it has the priority over what is - * already set, do not drop it if ctime is equal. */ + /** + * The pure setattr, it has the priority over what is + * already set, do not drop it if ctime is equal. + */ if (la->la_ctime < oattr->la_ctime) la->la_valid &= ~(LA_ATIME | LA_MTIME | LA_CTIME); } diff --git a/lustre/tests/mirror_io.c b/lustre/tests/mirror_io.c index ab39f69..f4deaed 100644 --- a/lustre/tests/mirror_io.c +++ b/lustre/tests/mirror_io.c @@ -550,6 +550,8 @@ static void mirror_resync(int argc, char *argv[]) rc = llapi_lease_set(fd, ioc); syserr(rc <= 0, "llapi_lease_set resync failed"); + if (rc <= 0) + llapi_lease_release(fd); free(ioc); close(fd); diff --git a/lustre/tests/sanity-flr.sh b/lustre/tests/sanity-flr.sh index b9a91c0..b285468 100644 --- a/lustre/tests/sanity-flr.sh +++ b/lustre/tests/sanity-flr.sh @@ -2710,6 +2710,146 @@ test_60b() { } run_test 60b "mirror merge/split cancel client's in-memory layout gen" +get_times_61() { + stat --format='%X %Y %Z' $file || error "$file: cannot get times" +} + +check_times_61() { + local file=$1 + local -a old=( $2 $3 $4 ) + local -a new + + new=( $(get_times_61 $file) ) + ((${old[0]} == ${new[0]})) || + error "$file: atime: old '${old[0]}' != new '${new[0]}'" + + ((${old[1]} == ${new[1]})) || + error "$file: mtime: old '${old[1]}' != new '${new[1]}'" +} + +test_61a() { # LU-14508 + local file=$DIR/$tdir/$tfile + local -a tim + local nap=5 + + mkdir -p $DIR/$tdir + echo "create $file" + $LFS setstripe -E1M -Eeof $file || error "setstripe $file failed" + echo "create $file-2" + $LFS setstripe -E2M -Eeof $file-2 || error "setstripe $file-2 failed" + + echo XXX > $file || error "write $file failed" + chown $RUNAS_ID $DIR/$tdir $file || error "chown $file failed" + + echo "sleep $nap seconds, then cat $tfile" + sleep $nap + cat $file || error "cat $file failed" + + echo "sleep $nap seconds, then re-write $tfile" + sleep $nap + echo XXXX > $file || error "write $file failed" + cp -p $file $file-2 || error "copy $file-2 failed" + + echo "sleep $nap seconds" + sleep $nap + + tim=( $(get_times_61 $file) ) + + echo "mirror merge $tfile-2 to $tfile and test timestamps" + $LFS mirror extend -N -f $file-2 $file || + error "cannot mirror merge $file-2 to $file" + check_times_61 $file ${tim[@]} + + echo "mirror extend $tfile and test timestamps" + $LFS mirror extend -N -c1 -i1 $file || + error "cannot extend mirror $file" + check_times_61 $file ${tim[@]} + + echo "migrate $tfile and test timestamps" + $LFS migrate -n $file || error "cannot migrate $file" + check_times_61 $file ${tim[@]} + + echo "normal user migrate $tfile and test timestamps" + $RUNAS $LFS migrate -n $file || error "cannot migrate $file" + check_times_61 $file ${tim[@]} +} +run_test 61a "mirror extend and migrate preserve timestamps" + +test_61b() { # LU-14508 + local file=$DIR/$tdir/$tfile + local -a tim + local nap=5 + + mkdir -p $DIR/$tdir + echo "create $file" + echo XXX > $file || error "create $file failed" + chown $RUNAS_ID $DIR/$tdir $file || error "chown $file failed" + + echo "sleep $nap seconds, then cat $tfile" + sleep $nap + cat $file || error "cat $file failed" + + echo "sleep $nap seconds, then re-write $tfile" + sleep $nap + echo XXXX > $file || error "write $file failed" + + echo "sleep $nap seconds, then test timestamps" + sleep $nap + + tim=( $(get_times_61 $file) ) + + echo "mirror extend $tfile and test timestamps" + $LFS mirror extend -N -c1 -i1 $file || + error "cannot extend mirror $file" + check_times_61 $file ${tim[@]} + + echo "mirror split $tfile and test timestamps" + $LFS mirror split -d --mirror-id=1 $file || + error "cannot split mirror 1 off $file" + check_times_61 $file ${tim[@]} + + echo "normal user mirror extend $tfile and test timestamps" + $RUNAS $LFS mirror extend -N -c1 -i1 $file || + error "cannot extend mirror $file" + check_times_61 $file ${tim[@]} +} +run_test 61b "mirror extend and split preserve timestamps" + +test_61c() { # LU-14508 + local file=$DIR/$tdir/$tfile + local -a tim + local nap=5 + + mkdir -p $DIR/$tdir + echo "create $file" + echo XXX > $file || error "create $file failed" + chown $RUNAS_ID $DIR/$tdir $file || error "chown $file failed" + + echo "sleep $nap seconds, then cat $tfile" + sleep $nap + cat $file || error "cat $file failed" + + echo "sleep $nap seconds, then mirror extend $tfile and write it" + sleep $nap + $LFS mirror extend -N -c1 -i1 $file || + error "cannot extend mirror $file" + echo XXXX > $file || error "write $file failed" + + echo "sleep $nap seconds, then resync $tfile and test timestamps" + tim=( $(get_times_61 $file) ) + sleep $nap + $LFS mirror resync $file || error "cannot resync mirror $file" + check_times_61 $file ${tim[@]} + + echo XXXXXX > $file || error "write $tfile failed" + + echo "normal user resync $tfile and test timestamps" + tim=( $(get_times_61 $file) ) + $RUNAS $LFS mirror resync $file || error "cannot resync mirror $file" + check_times_61 $file ${tim[@]} +} +run_test 61c "mirror resync preserves timestamps" + test_70() { local tf=$DIR/$tdir/$tfile @@ -2796,8 +2936,8 @@ resync_file_200() { echo -n "resync file $tf with '$cmd' .." if [[ $lock_taken = "true" ]]; then - flock -x 200 -c "$cmd $tf &> /dev/null" && - echo "done" || echo "failed" + flock -x 200 + $cmd $tf &> /dev/null && echo "done" || echo "failed" flock -u 200 else $cmd $tf &> /dev/null && echo "done" || echo "failed" diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index 6bd5c21..fd9f0c7 100644 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -817,7 +817,7 @@ migrate_open_files(const char *name, __u64 migration_flags, /* even if the file is only read, WR mode is nedeed to allow * layout swap on fd */ - rflags = O_RDWR; + rflags = O_RDWR | O_NOATIME; if (!(migration_flags & MIGRATION_NONDIRECT)) rflags |= O_DIRECT; fd = open(name, rflags); @@ -1021,29 +1021,30 @@ out: return rc; } -static int migrate_copy_timestamps(int fd, int fdv) +static int migrate_set_timestamps(int fd, const struct stat *st) { - struct stat st; - - if (fstat(fd, &st) == 0) { - struct timeval tv[2] = { - {.tv_sec = st.st_atime}, - {.tv_sec = st.st_mtime} - }; - - return futimes(fdv, tv); - } + struct timeval tv[2] = { + {.tv_sec = st->st_atime}, + {.tv_sec = st->st_mtime} + }; - return -errno; + return futimes(fd, tv); } static int migrate_block(int fd, int fdv) { + struct stat st; __u64 dv1; int gid; int rc; int rc2; + rc = fstat(fd, &st); + if (rc < 0) { + error_loc = "cannot stat source file"; + return -errno; + } + rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH); if (rc < 0) { error_loc = "cannot get dataversion"; @@ -1072,9 +1073,9 @@ static int migrate_block(int fd, int fdv) } /* Make sure we keep original atime/mtime values */ - rc = migrate_copy_timestamps(fd, fdv); + rc = migrate_set_timestamps(fdv, &st); if (rc < 0) { - error_loc = "timestamp copy failed"; + error_loc = "set target file timestamp failed"; goto out_unlock; } @@ -1127,10 +1128,17 @@ static int check_lease(int fd) static int migrate_nonblock(int fd, int fdv) { + struct stat st; __u64 dv1; __u64 dv2; int rc; + rc = fstat(fd, &st); + if (rc < 0) { + error_loc = "cannot stat source file"; + return -errno; + } + rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH); if (rc < 0) { error_loc = "cannot get data version"; @@ -1156,12 +1164,11 @@ static int migrate_nonblock(int fd, int fdv) } /* Make sure we keep original atime/mtime values */ - rc = migrate_copy_timestamps(fd, fdv); + rc = migrate_set_timestamps(fdv, &st); if (rc < 0) { - error_loc = "timestamp copy failed"; - return rc; + error_loc = "set target file timestamp failed"; + return -errno; } - return 0; } @@ -1891,10 +1898,9 @@ static int mirror_extend_file(const char *fname, const char *victim_file, goto out; } - /* Make sure we keep original atime/mtime values */ - rc = migrate_copy_timestamps(fd, fdv); + rc = migrate_set_timestamps(fd, &stbuf); if (rc < 0) { - error_loc = "cannot copy timestamp"; + error_loc = "cannot set source file timestamp"; goto out; } @@ -1939,6 +1945,7 @@ static int mirror_extend_layout(char *name, struct llapi_layout *m_layout, { struct llapi_layout *f_layout = NULL; struct ll_ioc_lease *data = NULL; + struct stat st; int fd = -1; int fdv = -1; int rc = 0; @@ -1975,12 +1982,24 @@ static int mirror_extend_layout(char *name, struct llapi_layout *m_layout, goto out; } + rc = fstat(fd, &st); + if (rc < 0) { + error_loc = "cannot stat source file"; + goto out; + } + rc = migrate_nonblock(fd, fdv); if (rc < 0) { llapi_lease_release(fd); goto out; } + rc = migrate_set_timestamps(fd, &st); + if (rc < 0) { + error_loc = "cannot set source file timestamp"; + goto out; + } + /* Atomically put lease, merge layouts and close. */ data = calloc(1, offsetof(typeof(*data), lil_ids[1])); if (!data) { @@ -10682,6 +10701,13 @@ int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc, fprintf(stderr, "%s: '%s' llapi_mirror_resync_many: %s.\n", progname, fname, strerror(-rc)); + rc = migrate_set_timestamps(fd, &stbuf); + if (rc < 0) { + fprintf(stderr, "%s: '%s' cannot set timestamps: %s\n", + progname, fname, strerror(-rc)); + goto free_layout; + } + /* need to do the lease unlock even resync fails */ ioc->lil_mode = LL_LEASE_UNLCK; ioc->lil_flags = LL_LEASE_RESYNC_DONE; @@ -10702,9 +10728,14 @@ int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc, /* rc2 == 0 means lost lease lock */ if (rc2 == 0 && rc == 0) rc = -EBUSY; + else + rc = rc2; fprintf(stderr, "%s: resync file '%s' failed: %s.\n", progname, fname, rc2 == 0 ? "lost lease lock" : strerror(-rc2)); + + llapi_lease_release(fd); + goto free_layout; } free_layout: