@@ -3188,8 +3188,10 @@
ratelimit - ratelimit the logging
Default: ratelimit
- printk.time= Show timing data prefixed to each printk message line
- Format: <bool> (1/Y/y=enable, 0/N/n=disable)
+ printk.time= Show timestamp prefixed to each printk message line
+ Format: <string>
+ (0/N/n/disable, 1/Y/y/local,
+ b/boot, m/monotonic, r/realtime)
processor.max_cstate= [HW,ACPI]
Limit processor to maximum C-state
@@ -239,6 +239,7 @@ static inline u64 ktime_get_raw_ns(void)
extern u64 ktime_get_mono_fast_ns(void);
extern u64 ktime_get_raw_fast_ns(void);
extern u64 ktime_get_boot_fast_ns(void);
+extern u64 ktime_get_real_offset(void);
/*
* Timespec interfaces utilizing the ktime based ones
@@ -576,6 +576,9 @@ static u32 truncate_msg(u16 *text_len, u16 *trunc_msg_len,
return msg_used_size(*text_len + *trunc_msg_len, 0, pad_len);
}
+static u64 printk_set_timestamp(void);
+static u64 (*printk_get_ts)(void) = printk_set_timestamp;
+
/* insert record into the buffer, discard old ones, update heads */
static int log_store(int facility, int level,
enum log_flags flags, u64 ts_nsec,
@@ -624,7 +627,7 @@ static int log_store(int facility, int level,
if (ts_nsec > 0)
msg->ts_nsec = ts_nsec;
else
- msg->ts_nsec = local_clock();
+ msg->ts_nsec = printk_get_ts();
memset(log_dict(msg) + dict_len, 0, pad_len);
msg->len = size;
@@ -1202,14 +1205,141 @@ static inline void boot_delay_msec(int level)
}
#endif
-static bool printk_time = IS_ENABLED(CONFIG_PRINTK_TIME);
-module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR);
+static int printk_time = CONFIG_PRINTK_TIME_VAL;
+static int printk_time_source;
+
+/**
+ * enum timestamp_sources - Timestamp sources for printk() messages.
+ * @PRINTK_TIME_UNDEFINED: Timestamp undefined. This option is not selectable
+ * from the configs, and is used as a reference in the code.
+ * @PRINTK_TIME_DISABLE: No time stamp.
+ * @PRINTK_TIME_LOCAL: Local hardware clock timestamp.
+ * @PRINTK_TIME_BOOT: Boottime clock timestamp.
+ * @PRINTK_TIME_MONO: Monotonic clock timestamp.
+ * @PRINTK_TIME_REAL: Realtime clock timestamp. On 32-bit
+ * systems selecting the real clock printk timestamp may lead to unlikely
+ * situations where a timestamp is wrong because the real time offset is read
+ * without the protection of a sequence lock when printk_get_ts() is set to
+ * printk_get_real_ns().
+ */
+enum timestamp_sources {
+ PRINTK_TIME_UNDEFINED = 0,
+ PRINTK_TIME_DISABLE = 1,
+ PRINTK_TIME_LOCAL = 2,
+ PRINTK_TIME_BOOT = 3,
+ PRINTK_TIME_MONO = 4,
+ PRINTK_TIME_REAL = 5,
+};
+
+static const char * const timestamp_sources_str[6] = {
+ "undefined",
+ "disabled",
+ "local",
+ "boottime",
+ "monotonic",
+ "realtime",
+};
+
+/**
+ * printk_get_real_ns: - Return a realtime timestamp for printk messages
+ * On 32-bit systems selecting the real clock printk timestamp may lead to
+ * unlikely situations where a timestamp is wrong because the real time offset
+ * is read without the protection of a sequence lock.
+ */
+static u64 printk_get_real_ns(void)
+{
+ return ktime_get_mono_fast_ns() + ktime_get_real_offset();
+}
+
+static u64 printk_set_timestamp(void)
+{
+ switch (printk_time) {
+ case PRINTK_TIME_LOCAL:
+ case PRINTK_TIME_DISABLE:
+ printk_get_ts = local_clock;
+ break;
+ case PRINTK_TIME_BOOT:
+ printk_get_ts = ktime_get_boot_fast_ns;
+ break;
+ case PRINTK_TIME_MONO:
+ printk_get_ts = ktime_get_mono_fast_ns;
+ break;
+ case PRINTK_TIME_REAL:
+ printk_get_ts = printk_get_real_ns;
+ break;
+ }
+ return printk_get_ts();
+}
+
+static int printk_time_set(const char *val, const struct kernel_param *kp)
+{
+ char *param = strstrip((char *)val);
+ int _printk_time = PRINTK_TIME_UNDEFINED;
+ int ts;
+
+ if (strlen(param) == 1) {
+ /* Preserve legacy boolean settings */
+ if ((param[0] == '0') || (param[0] == 'n') ||
+ (param[0] == 'N'))
+ _printk_time = PRINTK_TIME_DISABLE;
+ if ((param[0] == '1') || (param[0] == 'y') ||
+ (param[0] == 'Y'))
+ _printk_time = PRINTK_TIME_LOCAL;
+ }
+ if (_printk_time == PRINTK_TIME_UNDEFINED) {
+ for (ts = 0; ts < ARRAY_SIZE(timestamp_sources_str); ts++) {
+ if (!strncmp(timestamp_sources_str[ts], param,
+ strlen(param))) {
+ _printk_time = ts;
+ break;
+ }
+ }
+ }
+ if (_printk_time == PRINTK_TIME_UNDEFINED) {
+ pr_warn("printk: invalid timestamp option %s\n", param);
+ return -EINVAL;
+ }
+
+ /*
+ * Only allow enabling and disabling of the current printk_time
+ * setting. Changing it from one setting to another confuses
+ * userspace.
+ */
+ if (printk_time_source == PRINTK_TIME_UNDEFINED)
+ printk_time_source = _printk_time;
+ else if ((printk_time_source != _printk_time) &&
+ (_printk_time != PRINTK_TIME_DISABLE)) {
+ pr_warn("printk: timestamp can only be set to 0, disabled, or %s\n",
+ timestamp_sources_str[printk_time_source]);
+ return -EINVAL;
+ }
+
+ printk_time = _printk_time;
+ if (printk_time_source > PRINTK_TIME_DISABLE)
+ printk_set_timestamp();
+
+ pr_info("printk: timestamp set to %s\n",
+ timestamp_sources_str[printk_time]);
+ return 0;
+}
+
+static int printk_time_get(char *buffer, const struct kernel_param *kp)
+{
+ return scnprintf(buffer, PAGE_SIZE, "%s",
+ timestamp_sources_str[printk_time]);
+}
+
+static struct kernel_param_ops printk_time_ops = {
+ .set = printk_time_set,
+ .get = printk_time_get,
+};
+module_param_cb(time, &printk_time_ops, NULL, 0644);
static size_t print_time(u64 ts, char *buf)
{
unsigned long rem_nsec;
- if (!printk_time)
+ if (printk_time == PRINTK_TIME_DISABLE)
return 0;
rem_nsec = do_div(ts, 1000000000);
@@ -1643,7 +1773,7 @@ static bool cont_add(int facility, int level, enum log_flags flags, const char *
cont.facility = facility;
cont.level = level;
cont.owner = current;
- cont.ts_nsec = local_clock();
+ cont.ts_nsec = printk_get_ts();
cont.flags = flags;
}
@@ -1873,6 +2003,9 @@ static size_t msg_print_text(const struct printk_log *msg,
bool syslog, char *buf, size_t size) { return 0; }
static bool suppress_message_printing(int level) { return false; }
+#define PRINTK_TIME_UNDEFINED 0
+static int printk_time;
+static int printk_time_source;
#endif /* CONFIG_PRINTK */
#ifdef CONFIG_EARLY_PRINTK
@@ -2659,6 +2792,10 @@ static int __init printk_late_init(void)
struct console *con;
int ret;
+ /* initialize printk_time settings */
+ if (printk_time_source == PRINTK_TIME_UNDEFINED)
+ printk_time_source = printk_time;
+
for_each_console(con) {
if (!keep_bootcon && con->flags & CON_BOOT) {
/*
@@ -508,6 +508,11 @@ u64 notrace ktime_get_boot_fast_ns(void)
}
EXPORT_SYMBOL_GPL(ktime_get_boot_fast_ns);
+u64 ktime_get_real_offset(void)
+{
+ return ktime_to_ns(tk_core.timekeeper.offs_real);
+}
+
/**
* halt_fast_timekeeper - Prevent fast timekeeper from accessing clocksource.
* @tk: Timekeeper to snapshot.
@@ -8,12 +8,64 @@ config PRINTK_TIME
messages to be added to the output of the syslog() system
call and at the console.
+choice
+ prompt "printk default clock timestamp"
+ default PRINTK_TIME_LOCAL if PRINTK_TIME
+ default PRINTK_TIME_DISABLE if !PRINTK_TIME
+ help
+ This option is selected by setting one of
+ PRINTK_TIME_[DISABLE|LOCAL|BOOT|MONO|REAL] and causes time stamps of
+ the printk() messages to be added to the output of the syslog()
+ system call and at the console.
+
The timestamp is always recorded internally, and exported
to /dev/kmsg. This flag just specifies if the timestamp should
be included, not that the timestamp is recorded.
The behavior is also controlled by the kernel command line
- parameter printk.time=1. See Documentation/admin-guide/kernel-parameters.rst
+ parameter printk.time. See
+ Documentation/admin-guide/kernel-parameters.rst
+
+config PRINTK_TIME_DISABLE
+ bool "Disabled" if !PRINTK_TIME
+ help
+ Selecting this option disables the time stamps of printk().
+
+config PRINTK_TIME_LOCAL
+ bool "Local Clock" if PRINTK_TIME
+ help
+ Selecting this option causes the time stamps of printk() to be
+ stamped with the unadjusted hardware clock.
+
+config PRINTK_TIME_BOOT
+ bool "CLOCK_BOOTTIME" if PRINTK_TIME
+ help
+ Selecting this option causes the time stamps of printk() to be
+ stamped with the adjusted boottime clock.
+
+config PRINTK_TIME_MONO
+ bool "CLOCK_MONOTONIC" if PRINTK_TIME
+ help
+ Selecting this option causes the time stamps of printk() to be
+ stamped with the adjusted monotonic clock.
+
+config PRINTK_TIME_REAL
+ bool "CLOCK_REALTIME" if PRINTK_TIME
+ help
+ Selecting this option causes the time stamps of printk() to be
+ stamped with the adjusted realtime clock.
+endchoice
+
+config PRINTK_TIME_TYPE
+ int
+ depends on PRINTK
+ range 1 5
+ default 1 if PRINTK_TIME_DISABLE
+ default 2 if PRINTK_TIME_LOCAL
+ default 3 if PRINTK_TIME_BOOT
+ default 4 if PRINTK_TIME_MONO
+ default 5 if PRINTK_TIME_REAL
+
config CONSOLE_LOGLEVEL_DEFAULT
int "Default console loglevel (1-15)"