Whamcloud - gitweb
LU-13374 mdd: fix close time update race with set-in-past 50/54450/8
authorVitaly Fertman <c17818@cray.com>
Mon, 18 Mar 2024 21:33:25 +0000 (00:33 +0300)
committerOleg Drokin <green@whamcloud.com>
Tue, 23 Apr 2024 19:46:23 +0000 (19:46 +0000)
Do not update mtime on close if ctime is not increased.

Save the time when atime was last changed, in case this is
set-in-past, to not lose it on a later LSOM update on close.

HPE-bug-id: LUS-12186
Fixes: d2f7cb7934a0 ("LU-12026 mdt: MDS stores atime|mtime|ctime")
Signed-off-by: Vitaly Fertman <vitaly.fertman@hpe.com>
Change-Id: I070578a30f9bf548eec18a34ba6a06f1cb16909e
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/54450
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Nikitas Angelinas <nikitas.angelinas@hpe.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
lustre/mdd/mdd_internal.h
lustre/mdd/mdd_object.c
lustre/tests/sanityn.sh

index e8e00f3..3e61fda 100644 (file)
@@ -185,6 +185,7 @@ struct mdd_object {
        u32                     mod_count;
        u32                     mod_valid;
        ktime_t                 mod_cltime;
+       s64                     mod_atime_set;
        unsigned long           mod_flags;
        struct list_head        mod_users;  /**< unique user opens */
 };
index f9f9147..130b4cb 100644 (file)
@@ -721,20 +721,26 @@ static int mdd_fix_attr(const struct lu_env *env, struct mdd_object *obj,
                RETURN(rc);
        }
 
-       if (flags & MDS_CLOSE_UPDATE_TIMES &&
-           la->la_valid & (LA_ATIME | LA_MTIME | LA_CTIME)) {
-               /* This is an atime/mtime/ctime attribute update for
-                * close RPCs.
-                */
+       if (flags & MDS_CLOSE_UPDATE_TIMES) {
+               /* This is an atime/mtime/ctime update for close RPCs. */
+               if (!(la->la_valid & LA_CTIME) ||
+                   (la->la_ctime <= oattr->la_ctime))
+                       la->la_valid &= ~(LA_MTIME | LA_CTIME);
+
                if (la->la_valid & LA_ATIME &&
-                   la->la_atime <= (oattr->la_atime +
-                               mdd_obj2mdd_dev(obj)->mdd_atime_diff))
+                   (la->la_atime <= obj->mod_atime_set ||
+                    la->la_atime <= (oattr->la_atime +
+                                     mdd_obj2mdd_dev(obj)->mdd_atime_diff)))
                        la->la_valid &= ~LA_ATIME;
-               if (la->la_valid & LA_CTIME && la->la_ctime <= oattr->la_ctime)
-                       la->la_valid &= ~LA_CTIME;
+               else
+                       obj->mod_atime_set = la->la_atime;
                if (la->la_valid & LA_MTIME && la->la_mtime <= oattr->la_mtime)
                        la->la_valid &= ~LA_MTIME;
                RETURN(0);
+       } else if ((la->la_valid & LA_ATIME) && (la->la_valid & LA_CTIME)) {
+               /* save the time when atime was changed, in case this is
+                * set-in-past, to not lose it later on close. */
+               obj->mod_atime_set = la->la_ctime;
        }
 
        /* Check if flags change. */
@@ -1273,7 +1279,9 @@ int mdd_attr_set(const struct lu_env *env, struct md_object *obj,
                RETURN(rc);
 
        *la_copy = ma->ma_attr;
+       mdd_write_lock(env, mdd_obj, DT_TGT_CHILD);
        rc = mdd_fix_attr(env, mdd_obj, attr, la_copy, ma);
+       mdd_write_unlock(env, mdd_obj);
        if (rc)
                RETURN(rc);
 
index 1efffbc..1ff7369 100755 (executable)
@@ -1086,6 +1086,31 @@ test_26b() {
 }
 run_test 26b "sync mtime between ost and mds"
 
+test_26c() {
+       (( $MDS1_VERSION >= $(version_code 2.15.61) )) ||
+               skip "Need MDS version at least 2.15.61"
+
+       multiop_bg_pause $DIR1/$tfile O_c || error "multiop failed"
+       MULTIPID=$!
+       touch -am -d @978261179 $DIR2/$tfile
+       kill -USR1 $MULTIPID
+       wait $MULTIPID || error "wait for PID $MULTIPID failed"
+       sleep 1
+
+       echo
+       stat $DIR/$tfile
+       local times="$(stat -c"%X %Y" $DIR/$tfile)"
+       [[ "$times" == "978261179 978261179" ]] ||
+               error "[am]times are not set in past on $DIR: $times"
+       echo
+       stat $DIR2/$tfile
+       local times="$(stat -c"%X %Y" $DIR2/$tfile)"
+       [[ "$times" == "978261179 978261179" ]] ||
+               error "[am]times are not set in past on $DIR2: $times"
+       echo
+}
+run_test 26c "set-in-past on open file is not lost on close"
+
 test_27() {
        cancel_lru_locks $OSC
        lctl clear