From: Prarit Bhargava <prarit@redhat.com>
To: Petr Mladek <pmladek@suse.com>
Cc: linux-kernel@vger.kernel.org,
John Stultz <john.stultz@linaro.org>,
Xunlei Pang <pang.xunlei@linaro.org>,
Thomas Gleixner <tglx@linutronix.de>,
Baolin Wang <baolin.wang@linaro.org>,
Andrew Morton <akpm@linux-foundation.org>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Tejun Heo <tj@kernel.org>,
Peter Hurley <peter@hurleysoftware.com>,
Vasily Averin <vvs@virtuozzo.com>, Joe Perches <joe@perches.com>
Subject: Re: [PATCH 2/2] printk, Add printk.clock kernel parameter
Date: Thu, 07 Jan 2016 10:38:37 -0500 [thread overview]
Message-ID: <568E867D.8060904@redhat.com> (raw)
In-Reply-To: <20160107145702.GD731@pathway.suse.cz>
On 01/07/2016 09:57 AM, Petr Mladek wrote:
> On Wed 2016-01-06 08:00:34, Prarit Bhargava wrote:
>> This patch introduces printk.clock=[local|boot|real|tai] allowing a
>> user to specify an adjusted clock to use with printk timestamps. The
>> hardware clock, or the existing functionality, is preserved by default.
>>
>> If the timekeeper_lock (used to protect writes from reads) is under
>> contention, the last known good time is output again and "??" is used as
>> the last two digits of time. This avoids contention issues with a CPU
>> panicking while another CPU is writing time data.
>>
>> ---
>> include/linux/time64.h | 2 +
>> kernel/printk/printk.c | 105 ++++++++++++++++++++++++++++++++++++++++++++----
>> 2 files changed, 99 insertions(+), 8 deletions(-)
>>
>> diff --git a/include/linux/time64.h b/include/linux/time64.h
>> index 367d5af..f4a35d9 100644
>> --- a/include/linux/time64.h
>> +++ b/include/linux/time64.h
>> @@ -39,6 +39,8 @@ struct itimerspec64 {
>> #define TIME64_MAX ((s64)~((u64)1 << 63))
>> #define KTIME_MAX ((s64)~((u64)1 << 63))
>> #define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC)
>> +/* Maximum value returned by ktime_to_ns() */
>> +#define KTIME_MAX_NS ((u64)((U64_MAX>>1)))
>
> Please, use KTIME_NS_MAX to use the same naming scheme as
> KTIME_SEC_MAX.
>
> Well, I would return 0 when the time is not known. See also below.
>
>> #if __BITS_PER_LONG == 64
>>
>> diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
>> index 2ce8826..ffc05ee 100644
>> --- a/kernel/printk/printk.c
>> +++ b/kernel/printk/printk.c
>> @@ -419,6 +419,83 @@ 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_try_real_ns(void)
>> +{
>> + return ktime_try_real_ns();
>> +}
>> +
>> +static u64 printk_try_boot_ns(void)
>> +{
>> + return ktime_try_boot_ns();
>> +}
>> +
>> +static u64 printk_try_tai_ns(void)
>> +{
>> + return ktime_try_tai_ns();
>> +}
>
> Do we need these wrappers? Why not using ktime_try_xxx_ns() directly?
> You already use local_clock().
Unfortunately ktime_* are inlined functions, and I've mimicked the currently
coding style there.
In any case I'm doing a v2 with different functions. I'll see if making this
stuff not-inlined is any better.
>
>
>> +static int printk_clock_param_set(const char *val,
>> + const struct kernel_param *kp)
>> +{
>> + char *printk_clock_new = strstrip((char *)val);
>> + int ret;
>> +
>> + /* check if change is needed */
>> + if (!strcmp(printk_clock_new, printk_clock))
>> + return 0;
>> +
>> + if (!strncmp("local", printk_clock_new, 5)) {
>> + ret = param_set_charp(printk_clock_new, kp);
>> + if (ret)
>> + return ret;
>> + printk_clock_fn = &local_clock;
>> + } else if (!strncmp("real", printk_clock_new, 4)) {
>> + ret = param_set_charp(printk_clock_new, kp);
>> + if (ret)
>> + return ret;
>> + printk_clock_fn = &printk_try_real_ns;
>> + } else if (!strncmp("boot", printk_clock_new, 4)) {
>> + ret = param_set_charp(printk_clock_new, kp);
>> + if (ret)
>> + return ret;
>> + printk_clock_fn = &printk_try_boot_ns;
>> + } else if (!strncmp("tai", printk_clock_new, 3)) {
>> + ret = param_set_charp(printk_clock_new, kp);
>> + if (ret)
>> + return ret;
>> + printk_clock_fn = &printk_try_tai_ns;
>> + }
>> +
>> + /* Did the clock change ? */
>> + if (strcmp(printk_clock_new, printk_clock))
>> + return -EINVAL;
>
> I wonder if we need this extra check. It might be enough to
> print the error message in the final "else" above.
I was trying to catch a local to local change or a real to real change.
But yeah ... I could sort of do that in the final else above.
>
>> + pr_info("printk: timestamp set to %s clock.\n", printk_clock);
>> + return 0;
>> +}
>> +
>> +static struct kernel_param_ops printk_clock_param_ops = {
>> + .set = printk_clock_param_set,
>> + .get = param_get_charp,
>> +};
>> +
>> +module_param_cb(clock, &printk_clock_param_ops, &printk_clock, 0644);
>> +MODULE_PARM_DESC(clock, "Clock used for printk timestamps. Can be local (hardware/default), boot, real, or tai.\n");
>
> I have problems to parse this. It seems that the most common style
> used for possible values is to putthem into brackets. I wonder
> if this is better readable.
>
> MODULE_PARM_DESC(clock, "Clock used for printk timestamps (local = default, boot, real, tai).");
>
Ah, thanks! :) I was wondering if there was a coding style preference there
when I wrote this up.
>
>> +
>> /* 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,
>> @@ -467,7 +544,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_timestamp();
>
> Hmm, one problem is that each clock returns another type of time.
> "local" and "boot" clocks returns the number of ns since the boot.
> While "real" and "tai" clocks returns the number of ns since 1.1.1970
> or so.
>
> The tools reading the timestamps are confused by this. For example,
> I get this:
>
> $> echo boot >/sys/module/printk/parameters/clock
> $> echo local >/sys/module/printk/parameters/clock
> $> echo real >/sys/module/printk/parameters/clock
> $> echo tai >/sys/module/printk/parameters/clock
> $> dmesg | tail -6
> [ 6.976593] e1000: eth0 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: RX
> [ 6.977168] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
> [ 77.500483] printk: timestamp set to boot clock.
> [ 81.419957] printk: timestamp set to local clock.
> [1452177961.544909] printk: timestamp set to real clock.
> [1452177965.224824] printk: timestamp set to tai clock.
> $> dmesg -T | tail -6
> [Thu Jan 7 15:44:41 2016] e1000: eth0 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: RX
> [Thu Jan 7 15:44:41 2016] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
> [Thu Jan 7 15:45:52 2016] printk: timestamp set to boot clock.
> [Thu Jan 7 15:45:56 2016] printk: timestamp set to local clock.
> [Fri Jan 13 06:30:36 2062] printk: timestamp set to real clock.
> [Fri Jan 13 06:30:40 2062] printk: timestamp set to tai clock.
>
> Please, note that the last messages looks as they are printed in
> a far far future ;-)
Heh :) I didn't even think of testing that. I'll have to think about that a
bit more. systemd logging must assume boot time/local time. I'll ping those
guys with a patch if/when the next version of this gets accepted.
Thanks for catching this.
>
>
>> memset(log_dict(msg) + dict_len, 0, pad_len);
>> msg->len = size;
>>
>> @@ -1039,18 +1116,30 @@ module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR);
>>
>> static size_t print_time(u64 ts, char *buf)
>> {
>> - unsigned long rem_nsec;
>> + unsigned long rem;
>> + size_t size;
>>
>> if (!printk_time)
>> return 0;
>>
>> - rem_nsec = do_div(ts, 1000000000);
>> + if (ts == KTIME_MAX_NS)
>> + ts = last_time_stamp;
>>
>> - if (!buf)
>> - return snprintf(NULL, 0, "[%5lu.000000] ", (unsigned long)ts);
>> + if (buf) {
>> + size = INT_MAX;
>> + rem = do_div(ts, 1000000000) / 1000;
>> + } else {
>> + size = 0;
>> + rem = 0;
>> + }
>>
>> - return sprintf(buf, "[%5lu.%06lu] ",
>> - (unsigned long)ts, rem_nsec / 1000);
>> + if (ts != KTIME_MAX_NS) {
>> + return snprintf(buf, size, "[%5lu.%06lu] ",
>> + (unsigned long)ts, rem);
>> + }
>> + /* return last_time_stamp with ?? warning */
>> + return snprintf(buf, size, "[%5lu.%04lu??] ",
>> + (unsigned long)ts, rem);
>
> I am not sure if this is worth the effort. All other tools parsing the
> log will be confused by this. Also there are tools that read the ring
> buffer dirrectly, e.g. "crash" reading a crashdump. They will need to
> get updated to handle KTIME_MAX_NS correctly.
Yep -- the thread contains suggestions on how to avoid all of this by using the
NMI safe ktime_* calls (and implementing new ones). I'm going to do that which
should nicely clean all of this up.
Thanks for the review Petr,
P.
next prev parent reply other threads:[~2016-01-07 15:38 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-01-06 13:00 [PATCH 0/2] printk, Add a " Prarit Bhargava
2016-01-06 13:00 ` [PATCH 1/2] kernel, timekeeping, add trylock option to ktime_get_with_offset() Prarit Bhargava
2016-01-06 16:04 ` Jiri Bohac
2016-01-06 16:27 ` Prarit Bhargava
2016-01-06 16:25 ` Petr Mladek
2016-01-06 17:28 ` John Stultz
2016-01-06 17:33 ` John Stultz
2016-01-06 18:06 ` Prarit Bhargava
2016-01-06 18:10 ` Thomas Gleixner
2016-01-06 17:34 ` Thomas Gleixner
2016-01-06 18:09 ` Prarit Bhargava
2016-01-06 18:12 ` Thomas Gleixner
2016-01-06 19:04 ` John Stultz
2016-01-06 19:06 ` Prarit Bhargava
2016-01-06 13:00 ` [PATCH 2/2] printk, Add printk.clock kernel parameter Prarit Bhargava
2016-01-07 14:57 ` Petr Mladek
2016-01-07 15:38 ` Prarit Bhargava [this message]
2016-01-07 15:52 ` Petr Mladek
2016-01-08 9:04 ` Thomas Gleixner
2016-01-06 17:09 ` [PATCH 0/2] printk, Add a " Joe Perches
2016-01-13 12:34 [PATCH 0/2] printk, Add printk.clock kernel parameter [v2] Prarit Bhargava
2016-01-13 12:34 ` [PATCH 2/2] printk, Add printk.clock kernel parameter Prarit Bhargava
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=568E867D.8060904@redhat.com \
--to=prarit@redhat.com \
--cc=akpm@linux-foundation.org \
--cc=baolin.wang@linaro.org \
--cc=gregkh@linuxfoundation.org \
--cc=joe@perches.com \
--cc=john.stultz@linaro.org \
--cc=linux-kernel@vger.kernel.org \
--cc=pang.xunlei@linaro.org \
--cc=peter@hurleysoftware.com \
--cc=pmladek@suse.com \
--cc=tglx@linutronix.de \
--cc=tj@kernel.org \
--cc=vvs@virtuozzo.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome