Printk changes for 5.8

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEESH4wyp42V4tXvYsjUqAMR0iAlPIFAl7U1TIACgkQUqAMR0iA
 lPI0mQ//TcVlRJgts/iwv0M2Simje28t9tziOHgWmEeiyGwE7vwDPDzt8QFiKzBa
 IrJ5iTRMtCrEF+eapqeH4g+Ve4Npm5Cobl8/h9JEiVu3SNC48TuaiUzU3+Bfl1zV
 vcDfZtN9QD1/CdLGlyKO75xjkCOaJRCFnx5ToXnd3llshMKI2XebUCnEH4TDe6Fz
 NGTjJL4kCPwzmae++UhlMfKwkayBtNbqcLkaTb7d67Tw2DcuuIVixUER77oC9QPN
 SfxdS07s0UVc4C9bCVe3KtYZR5YU/riOjKNJNutzP3JDtQNugywrrtI0qBwEisqM
 puMJ3xLeLssTn10FJxRK9ewRlXy2zT9mmcCuaVU6LtiyGnHOuEwIU+Ewu0itiJGu
 JuFovsNqTvOiZqFP7+pkDktOjffF2hsY/a6NxHr6aof8CrdO2w9dmCAgzGvnwV1N
 /zlmmPSEigVLz47eeivIIdQrPUejrEV7g1wOYYApnIlNCmGjdkGnXKNaUrLGDehQ
 QIlpx1uvmhntjiw1hTSbOV7KOQxLGtuy6DWLYC7uHD3H3aGDQyQO8dZYXSfOY1Qu
 cvQ/K8ykW0Kq2JKEHjkwSRHKDpxhvbQg7N5JCHQA49ahdZD3O5bOfeTofw+7nFO0
 j9g2Qv6nWFjLbAIAFtqjh6wz0UtGNoTl2cqQswsS10wlDcsq8vs=
 =pUBG
 -----END PGP SIGNATURE-----

Merge tag 'printk-for-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux

Pull printk updates from Petr Mladek:

 - Benjamin Herrenschmidt solved a problem with non-matched console
   aliases by first checking consoles defined on the command line. It is
   a more conservative approach than the previous attempts.

 - Benjamin also made sure that the console accessible via /dev/console
   always has CON_CONSDEV flag.

 - Andy Shevchenko added the %ptT modifier for printing struct time64_t.
   It extends the existing %ptR handling for struct rtc_time.

 - Bruno Meneguele fixed /dev/kmsg error value returned by unsupported
   SEEK_CUR.

 - Tetsuo Handa removed unused pr_cont_once().

... and a few small fixes.

* tag 'printk-for-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux:
  printk: Remove pr_cont_once()
  printk: handle blank console arguments passed in.
  kernel/printk: add kmsg SEEK_CUR handling
  printk: Fix a typo in comment "interator"->"iterator"
  usb: pulse8-cec: Switch to use %ptT
  ARM: bcm2835: Switch to use %ptT
  lib/vsprintf: Print time64_t in human readable format
  lib/vsprintf: update comment about simple_strto<foo>() functions
  printk: Correctly set CON_CONSDEV even when preferred console was not registered
  printk: Fix preferred console selection with multiple matches
  printk: Move console matching logic into a separate function
  printk: Convert a use of sprintf to snprintf in console_unlock
This commit is contained in:
Linus Torvalds 2020-06-01 12:13:30 -07:00
commit ca1f5df23f
10 changed files with 163 additions and 85 deletions

View File

@ -56,6 +56,11 @@ Description: The /dev/kmsg character device node provides userspace access
seek after the last record available at the time seek after the last record available at the time
the last SYSLOG_ACTION_CLEAR was issued. the last SYSLOG_ACTION_CLEAR was issued.
Due to the record nature of this interface with a "read all"
behavior and the specific positions each seek operation sets,
SEEK_CUR is not supported, returning -ESPIPE (invalid seek) to
errno whenever requested.
The output format consists of a prefix carrying the syslog The output format consists of a prefix carrying the syslog
prefix including priority and facility, the 64 bit message prefix including priority and facility, the 64 bit message
sequence number and the monotonic timestamp in microseconds, sequence number and the monotonic timestamp in microseconds,

View File

@ -482,21 +482,23 @@ Examples (OF)::
%pfwf /ocp@68000000/i2c@48072000/camera@10/port/endpoint - Full name %pfwf /ocp@68000000/i2c@48072000/camera@10/port/endpoint - Full name
%pfwP endpoint - Node name %pfwP endpoint - Node name
Time and date (struct rtc_time) Time and date
------------------------------- -------------
:: ::
%ptR YYYY-mm-ddTHH:MM:SS %pt[RT] YYYY-mm-ddTHH:MM:SS
%ptRd YYYY-mm-dd %pt[RT]d YYYY-mm-dd
%ptRt HH:MM:SS %pt[RT]t HH:MM:SS
%ptR[dt][r] %pt[RT][dt][r]
For printing date and time as represented by struct rtc_time structure in For printing date and time as represented by
human readable format. R struct rtc_time structure
T time64_t type
in human readable format.
By default year will be incremented by 1900 and month by 1. Use %ptRr (raw) By default year will be incremented by 1900 and month by 1.
to suppress this behaviour. Use %pt[RT]r (raw) to suppress this behaviour.
Passed by reference. Passed by reference.

View File

@ -182,16 +182,10 @@ rpi_firmware_print_firmware_revision(struct rpi_firmware *fw)
RPI_FIRMWARE_GET_FIRMWARE_REVISION, RPI_FIRMWARE_GET_FIRMWARE_REVISION,
&packet, sizeof(packet)); &packet, sizeof(packet));
if (ret == 0) { if (ret)
struct tm tm; return;
time64_to_tm(packet, 0, &tm); dev_info(fw->cl.dev, "Attached to firmware from %ptT\n", &packet);
dev_info(fw->cl.dev,
"Attached to firmware from %04ld-%02d-%02d %02d:%02d\n",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min);
}
} }
static void static void

View File

@ -661,7 +661,6 @@ static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio,
u8 *data = pulse8->data + 1; u8 *data = pulse8->data + 1;
u8 cmd[2]; u8 cmd[2];
int err; int err;
struct tm tm;
time64_t date; time64_t date;
pulse8->vers = 0; pulse8->vers = 0;
@ -682,10 +681,7 @@ static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio,
if (err) if (err)
return err; return err;
date = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; date = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
time64_to_tm(date, 0, &tm); dev_info(pulse8->dev, "Firmware build date %ptT\n", &date);
dev_info(pulse8->dev, "Firmware build date %04ld.%02d.%02d %02d:%02d:%02d\n",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
dev_dbg(pulse8->dev, "Persistent config:\n"); dev_dbg(pulse8->dev, "Persistent config:\n");
cmd[0] = MSGCODE_GET_AUTO_ENABLED; cmd[0] = MSGCODE_GET_AUTO_ENABLED;

View File

@ -134,7 +134,7 @@ static inline int con_debug_leave(void)
*/ */
#define CON_PRINTBUFFER (1) #define CON_PRINTBUFFER (1)
#define CON_CONSDEV (2) /* Last on the command line */ #define CON_CONSDEV (2) /* Preferred console, /dev/console */
#define CON_ENABLED (4) #define CON_ENABLED (4)
#define CON_BOOT (8) #define CON_BOOT (8)
#define CON_ANYTIME (16) /* Safe to call when cpu is offline */ #define CON_ANYTIME (16) /* Safe to call when cpu is offline */

View File

@ -384,8 +384,7 @@ extern int kptr_restrict;
printk_once(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__) printk_once(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
#define pr_info_once(fmt, ...) \ #define pr_info_once(fmt, ...) \
printk_once(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__) printk_once(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
#define pr_cont_once(fmt, ...) \ /* no pr_cont_once, don't do that... */
printk_once(KERN_CONT pr_fmt(fmt), ##__VA_ARGS__)
#if defined(DEBUG) #if defined(DEBUG)
#define pr_devel_once(fmt, ...) \ #define pr_devel_once(fmt, ...) \

View File

@ -6,6 +6,7 @@ struct console_cmdline
{ {
char name[16]; /* Name of the driver */ char name[16]; /* Name of the driver */
int index; /* Minor dev. to use */ int index; /* Minor dev. to use */
bool user_specified; /* Specified by command line vs. platform */
char *options; /* Options for the driver */ char *options; /* Options for the driver */
#ifdef CONFIG_A11Y_BRAILLE_CONSOLE #ifdef CONFIG_A11Y_BRAILLE_CONSOLE
char *brl_options; /* Options for braille driver */ char *brl_options; /* Options for braille driver */

View File

@ -280,6 +280,7 @@ static struct console *exclusive_console;
static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
static int preferred_console = -1; static int preferred_console = -1;
static bool has_preferred_console;
int console_set_on_cmdline; int console_set_on_cmdline;
EXPORT_SYMBOL(console_set_on_cmdline); EXPORT_SYMBOL(console_set_on_cmdline);
@ -974,6 +975,16 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
user->idx = log_next_idx; user->idx = log_next_idx;
user->seq = log_next_seq; user->seq = log_next_seq;
break; break;
case SEEK_CUR:
/*
* It isn't supported due to the record nature of this
* interface: _SET _DATA and _END point to very specific
* record positions, while _CUR would be more useful in case
* of a byte-based log. Because of that, return the default
* errno value for invalid seek operation.
*/
ret = -ESPIPE;
break;
default: default:
ret = -EINVAL; ret = -EINVAL;
} }
@ -2140,7 +2151,7 @@ asmlinkage __visible void early_printk(const char *fmt, ...)
#endif #endif
static int __add_preferred_console(char *name, int idx, char *options, static int __add_preferred_console(char *name, int idx, char *options,
char *brl_options) char *brl_options, bool user_specified)
{ {
struct console_cmdline *c; struct console_cmdline *c;
int i; int i;
@ -2155,6 +2166,8 @@ static int __add_preferred_console(char *name, int idx, char *options,
if (strcmp(c->name, name) == 0 && c->index == idx) { if (strcmp(c->name, name) == 0 && c->index == idx) {
if (!brl_options) if (!brl_options)
preferred_console = i; preferred_console = i;
if (user_specified)
c->user_specified = true;
return 0; return 0;
} }
} }
@ -2164,6 +2177,7 @@ static int __add_preferred_console(char *name, int idx, char *options,
preferred_console = i; preferred_console = i;
strlcpy(c->name, name, sizeof(c->name)); strlcpy(c->name, name, sizeof(c->name));
c->options = options; c->options = options;
c->user_specified = user_specified;
braille_set_options(c, brl_options); braille_set_options(c, brl_options);
c->index = idx; c->index = idx;
@ -2190,6 +2204,9 @@ static int __init console_setup(char *str)
char *s, *options, *brl_options = NULL; char *s, *options, *brl_options = NULL;
int idx; int idx;
if (str[0] == 0)
return 1;
if (_braille_console_setup(&str, &brl_options)) if (_braille_console_setup(&str, &brl_options))
return 1; return 1;
@ -2218,7 +2235,7 @@ static int __init console_setup(char *str)
idx = simple_strtoul(s, NULL, 10); idx = simple_strtoul(s, NULL, 10);
*s = 0; *s = 0;
__add_preferred_console(buf, idx, options, brl_options); __add_preferred_console(buf, idx, options, brl_options, true);
console_set_on_cmdline = 1; console_set_on_cmdline = 1;
return 1; return 1;
} }
@ -2239,7 +2256,7 @@ __setup("console=", console_setup);
*/ */
int add_preferred_console(char *name, int idx, char *options) int add_preferred_console(char *name, int idx, char *options)
{ {
return __add_preferred_console(name, idx, options, NULL); return __add_preferred_console(name, idx, options, NULL, false);
} }
bool console_suspend_enabled = true; bool console_suspend_enabled = true;
@ -2438,9 +2455,9 @@ again:
printk_safe_enter_irqsave(flags); printk_safe_enter_irqsave(flags);
raw_spin_lock(&logbuf_lock); raw_spin_lock(&logbuf_lock);
if (console_seq < log_first_seq) { if (console_seq < log_first_seq) {
len = sprintf(text, len = snprintf(text, sizeof(text),
"** %llu printk messages dropped **\n", "** %llu printk messages dropped **\n",
log_first_seq - console_seq); log_first_seq - console_seq);
/* messages are gone, move to first one */ /* messages are gone, move to first one */
console_seq = log_first_seq; console_seq = log_first_seq;
@ -2651,6 +2668,63 @@ static int __init keep_bootcon_setup(char *str)
early_param("keep_bootcon", keep_bootcon_setup); early_param("keep_bootcon", keep_bootcon_setup);
/*
* This is called by register_console() to try to match
* the newly registered console with any of the ones selected
* by either the command line or add_preferred_console() and
* setup/enable it.
*
* Care need to be taken with consoles that are statically
* enabled such as netconsole
*/
static int try_enable_new_console(struct console *newcon, bool user_specified)
{
struct console_cmdline *c;
int i;
for (i = 0, c = console_cmdline;
i < MAX_CMDLINECONSOLES && c->name[0];
i++, c++) {
if (c->user_specified != user_specified)
continue;
if (!newcon->match ||
newcon->match(newcon, c->name, c->index, c->options) != 0) {
/* default matching */
BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name));
if (strcmp(c->name, newcon->name) != 0)
continue;
if (newcon->index >= 0 &&
newcon->index != c->index)
continue;
if (newcon->index < 0)
newcon->index = c->index;
if (_braille_register_console(newcon, c))
return 0;
if (newcon->setup &&
newcon->setup(newcon, c->options) != 0)
return -EIO;
}
newcon->flags |= CON_ENABLED;
if (i == preferred_console) {
newcon->flags |= CON_CONSDEV;
has_preferred_console = true;
}
return 0;
}
/*
* Some consoles, such as pstore and netconsole, can be enabled even
* without matching. Accept the pre-enabled consoles only when match()
* and setup() had a change to be called.
*/
if (newcon->flags & CON_ENABLED && c->user_specified == user_specified)
return 0;
return -ENOENT;
}
/* /*
* The console driver calls this routine during kernel initialization * The console driver calls this routine during kernel initialization
* to register the console printing procedure with printk() and to * to register the console printing procedure with printk() and to
@ -2672,11 +2746,9 @@ early_param("keep_bootcon", keep_bootcon_setup);
*/ */
void register_console(struct console *newcon) void register_console(struct console *newcon)
{ {
int i;
unsigned long flags; unsigned long flags;
struct console *bcon = NULL; struct console *bcon = NULL;
struct console_cmdline *c; int err;
static bool has_preferred;
for_each_console(bcon) { for_each_console(bcon) {
if (WARN(bcon == newcon, "console '%s%d' already registered\n", if (WARN(bcon == newcon, "console '%s%d' already registered\n",
@ -2701,15 +2773,15 @@ void register_console(struct console *newcon)
if (console_drivers && console_drivers->flags & CON_BOOT) if (console_drivers && console_drivers->flags & CON_BOOT)
bcon = console_drivers; bcon = console_drivers;
if (!has_preferred || bcon || !console_drivers) if (!has_preferred_console || bcon || !console_drivers)
has_preferred = preferred_console >= 0; has_preferred_console = preferred_console >= 0;
/* /*
* See if we want to use this console driver. If we * See if we want to use this console driver. If we
* didn't select a console we take the first one * didn't select a console we take the first one
* that registers here. * that registers here.
*/ */
if (!has_preferred) { if (!has_preferred_console) {
if (newcon->index < 0) if (newcon->index < 0)
newcon->index = 0; newcon->index = 0;
if (newcon->setup == NULL || if (newcon->setup == NULL ||
@ -2717,47 +2789,20 @@ void register_console(struct console *newcon)
newcon->flags |= CON_ENABLED; newcon->flags |= CON_ENABLED;
if (newcon->device) { if (newcon->device) {
newcon->flags |= CON_CONSDEV; newcon->flags |= CON_CONSDEV;
has_preferred = true; has_preferred_console = true;
} }
} }
} }
/* /* See if this console matches one we selected on the command line */
* See if this console matches one we selected on err = try_enable_new_console(newcon, true);
* the command line.
*/
for (i = 0, c = console_cmdline;
i < MAX_CMDLINECONSOLES && c->name[0];
i++, c++) {
if (!newcon->match ||
newcon->match(newcon, c->name, c->index, c->options) != 0) {
/* default matching */
BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name));
if (strcmp(c->name, newcon->name) != 0)
continue;
if (newcon->index >= 0 &&
newcon->index != c->index)
continue;
if (newcon->index < 0)
newcon->index = c->index;
if (_braille_register_console(newcon, c)) /* If not, try to match against the platform default(s) */
return; if (err == -ENOENT)
err = try_enable_new_console(newcon, false);
if (newcon->setup && /* printk() messages are not printed to the Braille console. */
newcon->setup(newcon, c->options) != 0) if (err || newcon->flags & CON_BRL)
break;
}
newcon->flags |= CON_ENABLED;
if (i == preferred_console) {
newcon->flags |= CON_CONSDEV;
has_preferred = true;
}
break;
}
if (!(newcon->flags & CON_ENABLED))
return; return;
/* /*
@ -2779,6 +2824,8 @@ void register_console(struct console *newcon)
console_drivers = newcon; console_drivers = newcon;
if (newcon->next) if (newcon->next)
newcon->next->flags &= ~CON_CONSDEV; newcon->next->flags &= ~CON_CONSDEV;
/* Ensure this flag is always set for the head of the list */
newcon->flags |= CON_CONSDEV;
} else { } else {
newcon->next = console_drivers->next; newcon->next = console_drivers->next;
console_drivers->next = newcon; console_drivers->next = newcon;
@ -3384,7 +3431,7 @@ out:
EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer); EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer);
/** /**
* kmsg_dump_rewind_nolock - reset the interator (unlocked version) * kmsg_dump_rewind_nolock - reset the iterator (unlocked version)
* @dumper: registered kmsg dumper * @dumper: registered kmsg dumper
* *
* Reset the dumper's iterator so that kmsg_dump_get_line() and * Reset the dumper's iterator so that kmsg_dump_get_line() and
@ -3402,7 +3449,7 @@ void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper)
} }
/** /**
* kmsg_dump_rewind - reset the interator * kmsg_dump_rewind - reset the iterator
* @dumper: registered kmsg dumper * @dumper: registered kmsg dumper
* *
* Reset the dumper's iterator so that kmsg_dump_get_line() and * Reset the dumper's iterator so that kmsg_dump_get_line() and

View File

@ -494,7 +494,7 @@ struct_va_format(void)
} }
static void __init static void __init
struct_rtc_time(void) time_and_date(void)
{ {
/* 1543210543 */ /* 1543210543 */
const struct rtc_time tm = { const struct rtc_time tm = {
@ -505,14 +505,21 @@ struct_rtc_time(void)
.tm_mon = 10, .tm_mon = 10,
.tm_year = 118, .tm_year = 118,
}; };
/* 2019-01-04T15:32:23 */
time64_t t = 1546615943;
test("(%ptR?)", "%pt", &tm); test("(%pt?)", "%pt", &tm);
test("2018-11-26T05:35:43", "%ptR", &tm); test("2018-11-26T05:35:43", "%ptR", &tm);
test("0118-10-26T05:35:43", "%ptRr", &tm); test("0118-10-26T05:35:43", "%ptRr", &tm);
test("05:35:43|2018-11-26", "%ptRt|%ptRd", &tm, &tm); test("05:35:43|2018-11-26", "%ptRt|%ptRd", &tm, &tm);
test("05:35:43|0118-10-26", "%ptRtr|%ptRdr", &tm, &tm); test("05:35:43|0118-10-26", "%ptRtr|%ptRdr", &tm, &tm);
test("05:35:43|2018-11-26", "%ptRttr|%ptRdtr", &tm, &tm); test("05:35:43|2018-11-26", "%ptRttr|%ptRdtr", &tm, &tm);
test("05:35:43 tr|2018-11-26 tr", "%ptRt tr|%ptRd tr", &tm, &tm); test("05:35:43 tr|2018-11-26 tr", "%ptRt tr|%ptRd tr", &tm, &tm);
test("2019-01-04T15:32:23", "%ptT", &t);
test("0119-00-04T15:32:23", "%ptTr", &t);
test("15:32:23|2019-01-04", "%ptTt|%ptTd", &t, &t);
test("15:32:23|0119-00-04", "%ptTtr|%ptTdr", &t, &t);
} }
static void __init static void __init
@ -678,7 +685,7 @@ test_pointer(void)
uuid(); uuid();
dentry(); dentry();
struct_va_format(); struct_va_format();
struct_rtc_time(); time_and_date();
struct_clk(); struct_clk();
bitmap(); bitmap();
netdev_features(); netdev_features();

View File

@ -34,6 +34,7 @@
#include <linux/dcache.h> #include <linux/dcache.h>
#include <linux/cred.h> #include <linux/cred.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/time.h>
#include <linux/uuid.h> #include <linux/uuid.h>
#include <linux/of.h> #include <linux/of.h>
#include <net/addrconf.h> #include <net/addrconf.h>
@ -58,7 +59,7 @@
* @endp: A pointer to the end of the parsed string will be placed here * @endp: A pointer to the end of the parsed string will be placed here
* @base: The number base to use * @base: The number base to use
* *
* This function is obsolete. Please use kstrtoull instead. * This function has caveats. Please use kstrtoull instead.
*/ */
unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base) unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)
{ {
@ -83,7 +84,7 @@ EXPORT_SYMBOL(simple_strtoull);
* @endp: A pointer to the end of the parsed string will be placed here * @endp: A pointer to the end of the parsed string will be placed here
* @base: The number base to use * @base: The number base to use
* *
* This function is obsolete. Please use kstrtoul instead. * This function has caveats. Please use kstrtoul instead.
*/ */
unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base)
{ {
@ -97,7 +98,7 @@ EXPORT_SYMBOL(simple_strtoul);
* @endp: A pointer to the end of the parsed string will be placed here * @endp: A pointer to the end of the parsed string will be placed here
* @base: The number base to use * @base: The number base to use
* *
* This function is obsolete. Please use kstrtol instead. * This function has caveats. Please use kstrtol instead.
*/ */
long simple_strtol(const char *cp, char **endp, unsigned int base) long simple_strtol(const char *cp, char **endp, unsigned int base)
{ {
@ -114,7 +115,7 @@ EXPORT_SYMBOL(simple_strtol);
* @endp: A pointer to the end of the parsed string will be placed here * @endp: A pointer to the end of the parsed string will be placed here
* @base: The number base to use * @base: The number base to use
* *
* This function is obsolete. Please use kstrtoll instead. * This function has caveats. Please use kstrtoll instead.
*/ */
long long simple_strtoll(const char *cp, char **endp, unsigned int base) long long simple_strtoll(const char *cp, char **endp, unsigned int base)
{ {
@ -1826,6 +1827,29 @@ char *rtc_str(char *buf, char *end, const struct rtc_time *tm,
return buf; return buf;
} }
static noinline_for_stack
char *time64_str(char *buf, char *end, const time64_t time,
struct printf_spec spec, const char *fmt)
{
struct rtc_time rtc_time;
struct tm tm;
time64_to_tm(time, 0, &tm);
rtc_time.tm_sec = tm.tm_sec;
rtc_time.tm_min = tm.tm_min;
rtc_time.tm_hour = tm.tm_hour;
rtc_time.tm_mday = tm.tm_mday;
rtc_time.tm_mon = tm.tm_mon;
rtc_time.tm_year = tm.tm_year;
rtc_time.tm_wday = tm.tm_wday;
rtc_time.tm_yday = tm.tm_yday;
rtc_time.tm_isdst = 0;
return rtc_str(buf, end, &rtc_time, spec, fmt);
}
static noinline_for_stack static noinline_for_stack
char *time_and_date(char *buf, char *end, void *ptr, struct printf_spec spec, char *time_and_date(char *buf, char *end, void *ptr, struct printf_spec spec,
const char *fmt) const char *fmt)
@ -1833,8 +1857,10 @@ char *time_and_date(char *buf, char *end, void *ptr, struct printf_spec spec,
switch (fmt[1]) { switch (fmt[1]) {
case 'R': case 'R':
return rtc_str(buf, end, (const struct rtc_time *)ptr, spec, fmt); return rtc_str(buf, end, (const struct rtc_time *)ptr, spec, fmt);
case 'T':
return time64_str(buf, end, *(const time64_t *)ptr, spec, fmt);
default: default:
return error_string(buf, end, "(%ptR?)", spec); return error_string(buf, end, "(%pt?)", spec);
} }
} }
@ -2150,8 +2176,9 @@ char *fwnode_string(char *buf, char *end, struct fwnode_handle *fwnode,
* - 'd[234]' For a dentry name (optionally 2-4 last components) * - 'd[234]' For a dentry name (optionally 2-4 last components)
* - 'D[234]' Same as 'd' but for a struct file * - 'D[234]' Same as 'd' but for a struct file
* - 'g' For block_device name (gendisk + partition number) * - 'g' For block_device name (gendisk + partition number)
* - 't[R][dt][r]' For time and date as represented: * - 't[RT][dt][r]' For time and date as represented by:
* R struct rtc_time * R struct rtc_time
* T time64_t
* - 'C' For a clock, it prints the name (Common Clock Framework) or address * - 'C' For a clock, it prints the name (Common Clock Framework) or address
* (legacy clock framework) of the clock * (legacy clock framework) of the clock
* - 'Cn' For a clock, it prints the name (Common Clock Framework) or address * - 'Cn' For a clock, it prints the name (Common Clock Framework) or address