Whamcloud - gitweb
LU-14508 lfs: make mirror operations preserve timestamps 09/42009/17
authorJohn L. Hammond <jhammond@whamcloud.com>
Thu, 11 Mar 2021 16:02:54 +0000 (10:02 -0600)
committerOleg Drokin <green@whamcloud.com>
Thu, 22 Jul 2021 01:50:00 +0000 (01:50 +0000)
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 <jhammond@whamcloud.com>
Signed-off-by: Bobi Jam <bobijam@whamcloud.com>
Change-Id: I5ef754e46cfbe82c731a709209576bbfcc73af3d
Reviewed-on: https://review.whamcloud.com/42009
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Bobi Jam <bobijam@hotmail.com>
Reviewed-by: Yingjin Qian <qian@ddn.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/mdd/mdd_object.c
lustre/tests/mirror_io.c
lustre/tests/sanity-flr.sh
lustre/utils/lfs.c

index f466e04..0328371 100644 (file)
@@ -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);
        }
index ab39f69..f4deaed 100644 (file)
@@ -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);
index b9a91c0..b285468 100644 (file)
@@ -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"
index 6bd5c21..fd9f0c7 100644 (file)
@@ -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: