@@ -114,6 +114,23 @@ static struct tk_fast tk_fast_raw ____cacheline_aligned = {
114114 .base [1 ] = FAST_TK_INIT ,
115115};
116116
117+ /*
118+ * Multigrain timestamps require tracking the latest fine-grained timestamp
119+ * that has been issued, and never returning a coarse-grained timestamp that is
120+ * earlier than that value.
121+ *
122+ * mg_floor represents the latest fine-grained time that has been handed out as
123+ * a file timestamp on the system. This is tracked as a monotonic ktime_t, and
124+ * converted to a realtime clock value on an as-needed basis.
125+ *
126+ * Maintaining mg_floor ensures the multigrain interfaces never issue a
127+ * timestamp earlier than one that has been previously issued.
128+ *
129+ * The exception to this rule is when there is a backward realtime clock jump. If
130+ * such an event occurs, a timestamp can appear to be earlier than a previous one.
131+ */
132+ static __cacheline_aligned_in_smp atomic64_t mg_floor ;
133+
117134static inline void tk_normalize_xtime (struct timekeeper * tk )
118135{
119136 while (tk -> tkr_mono .xtime_nsec >= ((u64 )NSEC_PER_SEC << tk -> tkr_mono .shift )) {
@@ -2394,6 +2411,94 @@ void ktime_get_coarse_real_ts64(struct timespec64 *ts)
23942411}
23952412EXPORT_SYMBOL (ktime_get_coarse_real_ts64 );
23962413
2414+ /**
2415+ * ktime_get_coarse_real_ts64_mg - return latter of coarse grained time or floor
2416+ * @ts: timespec64 to be filled
2417+ *
2418+ * Fetch the global mg_floor value, convert it to realtime and compare it
2419+ * to the current coarse-grained time. Fill @ts with whichever is
2420+ * latest. Note that this is a filesystem-specific interface and should be
2421+ * avoided outside of that context.
2422+ */
2423+ void ktime_get_coarse_real_ts64_mg (struct timespec64 * ts )
2424+ {
2425+ struct timekeeper * tk = & tk_core .timekeeper ;
2426+ u64 floor = atomic64_read (& mg_floor );
2427+ ktime_t f_real , offset , coarse ;
2428+ unsigned int seq ;
2429+
2430+ do {
2431+ seq = read_seqcount_begin (& tk_core .seq );
2432+ * ts = tk_xtime (tk );
2433+ offset = tk_core .timekeeper .offs_real ;
2434+ } while (read_seqcount_retry (& tk_core .seq , seq ));
2435+
2436+ coarse = timespec64_to_ktime (* ts );
2437+ f_real = ktime_add (floor , offset );
2438+ if (ktime_after (f_real , coarse ))
2439+ * ts = ktime_to_timespec64 (f_real );
2440+ }
2441+
2442+ /**
2443+ * ktime_get_real_ts64_mg - attempt to update floor value and return result
2444+ * @ts: pointer to the timespec to be set
2445+ *
2446+ * Get a monotonic fine-grained time value and attempt to swap it into
2447+ * mg_floor. If that succeeds then accept the new floor value. If it fails
2448+ * then another task raced in during the interim time and updated the
2449+ * floor. Since any update to the floor must be later than the previous
2450+ * floor, either outcome is acceptable.
2451+ *
2452+ * Typically this will be called after calling ktime_get_coarse_real_ts64_mg(),
2453+ * and determining that the resulting coarse-grained timestamp did not effect
2454+ * a change in ctime. Any more recent floor value would effect a change to
2455+ * ctime, so there is no need to retry the atomic64_try_cmpxchg() on failure.
2456+ *
2457+ * @ts will be filled with the latest floor value, regardless of the outcome of
2458+ * the cmpxchg. Note that this is a filesystem specific interface and should be
2459+ * avoided outside of that context.
2460+ */
2461+ void ktime_get_real_ts64_mg (struct timespec64 * ts )
2462+ {
2463+ struct timekeeper * tk = & tk_core .timekeeper ;
2464+ ktime_t old = atomic64_read (& mg_floor );
2465+ ktime_t offset , mono ;
2466+ unsigned int seq ;
2467+ u64 nsecs ;
2468+
2469+ do {
2470+ seq = read_seqcount_begin (& tk_core .seq );
2471+
2472+ ts -> tv_sec = tk -> xtime_sec ;
2473+ mono = tk -> tkr_mono .base ;
2474+ nsecs = timekeeping_get_ns (& tk -> tkr_mono );
2475+ offset = tk_core .timekeeper .offs_real ;
2476+ } while (read_seqcount_retry (& tk_core .seq , seq ));
2477+
2478+ mono = ktime_add_ns (mono , nsecs );
2479+
2480+ /*
2481+ * Attempt to update the floor with the new time value. As any
2482+ * update must be later then the existing floor, and would effect
2483+ * a change to ctime from the perspective of the current task,
2484+ * accept the resulting floor value regardless of the outcome of
2485+ * the swap.
2486+ */
2487+ if (atomic64_try_cmpxchg (& mg_floor , & old , mono )) {
2488+ ts -> tv_nsec = 0 ;
2489+ timespec64_add_ns (ts , nsecs );
2490+ timekeeping_inc_mg_floor_swaps ();
2491+ } else {
2492+ /*
2493+ * Another task changed mg_floor since "old" was fetched.
2494+ * "old" has been updated with the latest value of "mg_floor".
2495+ * That value is newer than the previous floor value, which
2496+ * is enough to effect a change to ctime. Accept it.
2497+ */
2498+ * ts = ktime_to_timespec64 (ktime_add (old , offset ));
2499+ }
2500+ }
2501+
23972502void ktime_get_coarse_ts64 (struct timespec64 * ts )
23982503{
23992504 struct timekeeper * tk = & tk_core .timekeeper ;
0 commit comments