From bccd5937447f8a2c9db0e4a92e5ecb641b8ce7de Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 13 Nov 2025 15:32:15 +0100 Subject: lib/vsprintf: Add specifier for printing struct timespec64 A handful drivers want to print a content of the struct timespec64 in a format of %lld:%09ld. In order to make their lives easier, add the respecting specifier directly to the printf() implementation. Signed-off-by: Andy Shevchenko Reviewed-by: Petr Mladek Tested-by: Petr Mladek Link: https://patch.msgid.link/20251113150217.3030010-2-andriy.shevchenko@linux.intel.com Signed-off-by: Petr Mladek --- lib/tests/printf_kunit.c | 4 ++++ lib/vsprintf.c | 28 +++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/tests/printf_kunit.c b/lib/tests/printf_kunit.c index bc54cca2d7a6..7617e5b8b02c 100644 --- a/lib/tests/printf_kunit.c +++ b/lib/tests/printf_kunit.c @@ -504,6 +504,7 @@ time_and_date(struct kunit *kunittest) }; /* 2019-01-04T15:32:23 */ time64_t t = 1546615943; + struct timespec64 ts = { .tv_sec = t, .tv_nsec = 11235813 }; test("(%pt?)", "%pt", &tm); test("2018-11-26T05:35:43", "%ptR", &tm); @@ -522,6 +523,9 @@ time_and_date(struct kunit *kunittest) test("0119-00-04 15:32:23", "%ptTsr", &t); test("15:32:23|2019-01-04", "%ptTts|%ptTds", &t, &t); test("15:32:23|0119-00-04", "%ptTtrs|%ptTdrs", &t, &t); + + test("2019-01-04T15:32:23.011235813", "%ptS", &ts); + test("1546615943.011235813", "%ptSp", &ts); } static void diff --git a/lib/vsprintf.c b/lib/vsprintf.c index eb0cb11d0d12..cdfb9224e0ad 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -1992,6 +1992,28 @@ char *time64_str(char *buf, char *end, const time64_t time, return rtc_str(buf, end, &rtc_time, spec, fmt); } +static noinline_for_stack +char *timespec64_str(char *buf, char *end, const struct timespec64 *ts, + struct printf_spec spec, const char *fmt) +{ + static const struct printf_spec default_dec09_spec = { + .base = 10, + .field_width = 9, + .precision = -1, + .flags = ZEROPAD, + }; + + if (fmt[2] == 'p') + buf = number(buf, end, ts->tv_sec, default_dec_spec); + else + buf = time64_str(buf, end, ts->tv_sec, spec, fmt); + if (buf < end) + *buf = '.'; + buf++; + + return number(buf, end, ts->tv_nsec, default_dec09_spec); +} + static noinline_for_stack char *time_and_date(char *buf, char *end, void *ptr, struct printf_spec spec, const char *fmt) @@ -1999,6 +2021,8 @@ char *time_and_date(char *buf, char *end, void *ptr, struct printf_spec spec, switch (fmt[1]) { case 'R': return rtc_str(buf, end, (const struct rtc_time *)ptr, spec, fmt); + case 'S': + return timespec64_str(buf, end, (const struct timespec64 *)ptr, spec, fmt); case 'T': return time64_str(buf, end, *(const time64_t *)ptr, spec, fmt); default: @@ -2462,9 +2486,11 @@ early_param("no_hash_pointers", no_hash_pointers_enable); * - 'd[234]' For a dentry name (optionally 2-4 last components) * - 'D[234]' Same as 'd' but for a struct file * - 'g' For block_device name (gendisk + partition number) - * - 't[RT][dt][r][s]' For time and date as represented by: + * - 't[RST][dt][r][s]' For time and date as represented by: * R struct rtc_time + * S struct timespec64 * T time64_t + * - 'tSp' For time represented by struct timespec64 printed as . * - 'C' For a clock, it prints the name (Common Clock Framework) or address * (legacy clock framework) of the clock * - 'G' For flags to be printed as a collection of symbolic strings that would -- cgit v1.2.3