From ccb80012481fd8d16c7557c00bb54c42103eef9d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 16 Oct 2019 16:47:44 +0200 Subject: [PATCH 01/11] clocksource/drivers/timer-of: Convert last full_name to %pOF Commit 469869d18a886e04 ("clocksource: Convert to using %pOF instead of full_name") converted all but the one just added before by commit 32f2fea6e77e64cd ("clocksource/drivers/timer-of: Handle of_irq_get_byname() result correctly"). Signed-off-by: Geert Uytterhoeven Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20191016144747.29538-2-geert+renesas@glider.be --- drivers/clocksource/timer-of.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c index d8c2bd4391d0..384394205a12 100644 --- a/drivers/clocksource/timer-of.c +++ b/drivers/clocksource/timer-of.c @@ -55,8 +55,8 @@ static __init int timer_of_irq_init(struct device_node *np, if (of_irq->name) { of_irq->irq = ret = of_irq_get_byname(np, of_irq->name); if (ret < 0) { - pr_err("Failed to get interrupt %s for %s\n", - of_irq->name, np->full_name); + pr_err("Failed to get interrupt %s for %pOF\n", + of_irq->name, np); return ret; } } else { From 4411464d6f8b5e5759637235a6f2b2a85c2be0f1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 16 Oct 2019 16:47:45 +0200 Subject: [PATCH 02/11] clocksource/drivers/timer-of: Use unique device name instead of timer If a hardware-specific driver does not provide a name, the timer-of core falls back to device_node.name. Due to generic DT node naming policies, that name is almost always "timer", and thus doesn't identify the actual timer used. Fix this by using device_node.full_name instead, which includes the unit addrees. Example impact on /proc/timer_list: -Clock Event Device: timer +Clock Event Device: timer@fcfec400 Signed-off-by: Geert Uytterhoeven Reviewed-by: Rob Herring Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20191016144747.29538-3-geert+renesas@glider.be --- drivers/clocksource/timer-of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c index 384394205a12..8c11bd743dd0 100644 --- a/drivers/clocksource/timer-of.c +++ b/drivers/clocksource/timer-of.c @@ -190,7 +190,7 @@ int __init timer_of_init(struct device_node *np, struct timer_of *to) } if (!to->clkevt.name) - to->clkevt.name = np->name; + to->clkevt.name = np->full_name; to->np = np; From 227314239a5e87fb531cbf3bd8953b2d1d2694bd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 16 Oct 2019 16:47:46 +0200 Subject: [PATCH 03/11] clocksource/drivers/renesas-ostm: Convert to timer_of Convert the Renesas OSTM driver to use the timer_of framework. This reduces the driver object size by 367 bytes (with gcc 7.4.0). Signed-off-by: Geert Uytterhoeven Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20191016144747.29538-4-geert+renesas@glider.be --- drivers/clocksource/Kconfig | 1 + drivers/clocksource/renesas-ostm.c | 187 +++++++++++------------------ 2 files changed, 72 insertions(+), 116 deletions(-) diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index f35a53ce8988..5fdd76cb1768 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -528,6 +528,7 @@ config SH_TIMER_MTU2 config RENESAS_OSTM bool "Renesas OSTM timer driver" if COMPILE_TEST select CLKSRC_MMIO + select TIMER_OF help Enables the support for the Renesas OSTM. diff --git a/drivers/clocksource/renesas-ostm.c b/drivers/clocksource/renesas-ostm.c index 37c39b901bb1..46012d905604 100644 --- a/drivers/clocksource/renesas-ostm.c +++ b/drivers/clocksource/renesas-ostm.c @@ -6,14 +6,14 @@ * Copyright (C) 2017 Chris Brandt */ -#include -#include #include #include #include #include #include +#include "timer-of.h" + /* * The OSTM contains independent channels. * The first OSTM channel probed will be set up as a free running @@ -24,12 +24,6 @@ * driven clock event. */ -struct ostm_device { - void __iomem *base; - unsigned long ticks_per_jiffy; - struct clock_event_device ced; -}; - static void __iomem *system_clock; /* For sched_clock() */ /* OSTM REGISTERS */ @@ -47,41 +41,32 @@ static void __iomem *system_clock; /* For sched_clock() */ #define CTL_ONESHOT 0x02 #define CTL_FREERUN 0x02 -static struct ostm_device *ced_to_ostm(struct clock_event_device *ced) +static void ostm_timer_stop(struct timer_of *to) { - return container_of(ced, struct ostm_device, ced); -} - -static void ostm_timer_stop(struct ostm_device *ostm) -{ - if (readb(ostm->base + OSTM_TE) & TE) { - writeb(TT, ostm->base + OSTM_TT); + if (readb(timer_of_base(to) + OSTM_TE) & TE) { + writeb(TT, timer_of_base(to) + OSTM_TT); /* * Read back the register simply to confirm the write operation * has completed since I/O writes can sometimes get queued by * the bus architecture. */ - while (readb(ostm->base + OSTM_TE) & TE) + while (readb(timer_of_base(to) + OSTM_TE) & TE) ; } } -static int __init ostm_init_clksrc(struct ostm_device *ostm, unsigned long rate) +static int __init ostm_init_clksrc(struct timer_of *to) { - /* - * irq not used (clock sources don't use interrupts) - */ + ostm_timer_stop(to); - ostm_timer_stop(ostm); + writel(0, timer_of_base(to) + OSTM_CMP); + writeb(CTL_FREERUN, timer_of_base(to) + OSTM_CTL); + writeb(TS, timer_of_base(to) + OSTM_TS); - writel(0, ostm->base + OSTM_CMP); - writeb(CTL_FREERUN, ostm->base + OSTM_CTL); - writeb(TS, ostm->base + OSTM_TS); - - return clocksource_mmio_init(ostm->base + OSTM_CNT, - "ostm", rate, - 300, 32, clocksource_mmio_readl_up); + return clocksource_mmio_init(timer_of_base(to) + OSTM_CNT, "ostm", + timer_of_rate(to), 300, 32, + clocksource_mmio_readl_up); } static u64 notrace ostm_read_sched_clock(void) @@ -89,87 +74,75 @@ static u64 notrace ostm_read_sched_clock(void) return readl(system_clock); } -static void __init ostm_init_sched_clock(struct ostm_device *ostm, - unsigned long rate) +static void __init ostm_init_sched_clock(struct timer_of *to) { - system_clock = ostm->base + OSTM_CNT; - sched_clock_register(ostm_read_sched_clock, 32, rate); + system_clock = timer_of_base(to) + OSTM_CNT; + sched_clock_register(ostm_read_sched_clock, 32, timer_of_rate(to)); } static int ostm_clock_event_next(unsigned long delta, - struct clock_event_device *ced) + struct clock_event_device *ced) { - struct ostm_device *ostm = ced_to_ostm(ced); + struct timer_of *to = to_timer_of(ced); - ostm_timer_stop(ostm); + ostm_timer_stop(to); - writel(delta, ostm->base + OSTM_CMP); - writeb(CTL_ONESHOT, ostm->base + OSTM_CTL); - writeb(TS, ostm->base + OSTM_TS); + writel(delta, timer_of_base(to) + OSTM_CMP); + writeb(CTL_ONESHOT, timer_of_base(to) + OSTM_CTL); + writeb(TS, timer_of_base(to) + OSTM_TS); return 0; } static int ostm_shutdown(struct clock_event_device *ced) { - struct ostm_device *ostm = ced_to_ostm(ced); + struct timer_of *to = to_timer_of(ced); - ostm_timer_stop(ostm); + ostm_timer_stop(to); return 0; } static int ostm_set_periodic(struct clock_event_device *ced) { - struct ostm_device *ostm = ced_to_ostm(ced); + struct timer_of *to = to_timer_of(ced); if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced)) - ostm_timer_stop(ostm); + ostm_timer_stop(to); - writel(ostm->ticks_per_jiffy - 1, ostm->base + OSTM_CMP); - writeb(CTL_PERIODIC, ostm->base + OSTM_CTL); - writeb(TS, ostm->base + OSTM_TS); + writel(timer_of_period(to) - 1, timer_of_base(to) + OSTM_CMP); + writeb(CTL_PERIODIC, timer_of_base(to) + OSTM_CTL); + writeb(TS, timer_of_base(to) + OSTM_TS); return 0; } static int ostm_set_oneshot(struct clock_event_device *ced) { - struct ostm_device *ostm = ced_to_ostm(ced); + struct timer_of *to = to_timer_of(ced); - ostm_timer_stop(ostm); + ostm_timer_stop(to); return 0; } static irqreturn_t ostm_timer_interrupt(int irq, void *dev_id) { - struct ostm_device *ostm = dev_id; + struct clock_event_device *ced = dev_id; - if (clockevent_state_oneshot(&ostm->ced)) - ostm_timer_stop(ostm); + if (clockevent_state_oneshot(ced)) + ostm_timer_stop(to_timer_of(ced)); /* notify clockevent layer */ - if (ostm->ced.event_handler) - ostm->ced.event_handler(&ostm->ced); + if (ced->event_handler) + ced->event_handler(ced); return IRQ_HANDLED; } -static int __init ostm_init_clkevt(struct ostm_device *ostm, int irq, - unsigned long rate) +static int __init ostm_init_clkevt(struct timer_of *to) { - struct clock_event_device *ced = &ostm->ced; - int ret = -ENXIO; + struct clock_event_device *ced = &to->clkevt; - ret = request_irq(irq, ostm_timer_interrupt, - IRQF_TIMER | IRQF_IRQPOLL, - "ostm", ostm); - if (ret) { - pr_err("ostm: failed to request irq\n"); - return ret; - } - - ced->name = "ostm"; ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC; ced->set_state_shutdown = ostm_shutdown; ced->set_state_periodic = ostm_set_periodic; @@ -178,79 +151,61 @@ static int __init ostm_init_clkevt(struct ostm_device *ostm, int irq, ced->shift = 32; ced->rating = 300; ced->cpumask = cpumask_of(0); - clockevents_config_and_register(ced, rate, 0xf, 0xffffffff); + clockevents_config_and_register(ced, timer_of_rate(to), 0xf, + 0xffffffff); return 0; } static int __init ostm_init(struct device_node *np) { - struct ostm_device *ostm; - int ret = -EFAULT; - struct clk *ostm_clk = NULL; - int irq; - unsigned long rate; + struct timer_of *to; + int ret; - ostm = kzalloc(sizeof(*ostm), GFP_KERNEL); - if (!ostm) + to = kzalloc(sizeof(*to), GFP_KERNEL); + if (!to) return -ENOMEM; - ostm->base = of_iomap(np, 0); - if (!ostm->base) { - pr_err("ostm: failed to remap I/O memory\n"); - goto err; + to->flags = TIMER_OF_BASE | TIMER_OF_CLOCK; + if (system_clock) { + /* + * clock sources don't use interrupts, clock events do + */ + to->flags |= TIMER_OF_IRQ; + to->of_irq.flags = IRQF_TIMER | IRQF_IRQPOLL; + to->of_irq.handler = ostm_timer_interrupt; } - irq = irq_of_parse_and_map(np, 0); - if (irq < 0) { - pr_err("ostm: Failed to get irq\n"); - goto err; - } - - ostm_clk = of_clk_get(np, 0); - if (IS_ERR(ostm_clk)) { - pr_err("ostm: Failed to get clock\n"); - ostm_clk = NULL; - goto err; - } - - ret = clk_prepare_enable(ostm_clk); - if (ret) { - pr_err("ostm: Failed to enable clock\n"); - goto err; - } - - rate = clk_get_rate(ostm_clk); - ostm->ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ); + ret = timer_of_init(np, to); + if (ret) + goto err_free; /* * First probed device will be used as system clocksource. Any * additional devices will be used as clock events. */ if (!system_clock) { - ret = ostm_init_clksrc(ostm, rate); - - if (!ret) { - ostm_init_sched_clock(ostm, rate); - pr_info("ostm: used for clocksource\n"); - } + ret = ostm_init_clksrc(to); + if (ret) + goto err_cleanup; + ostm_init_sched_clock(to); + pr_info("ostm: used for clocksource\n"); } else { - ret = ostm_init_clkevt(ostm, irq, rate); + ret = ostm_init_clkevt(to); + if (ret) + goto err_cleanup; - if (!ret) - pr_info("ostm: used for clock events\n"); - } - -err: - if (ret) { - clk_disable_unprepare(ostm_clk); - iounmap(ostm->base); - kfree(ostm); - return ret; + pr_info("ostm: used for clock events\n"); } return 0; + +err_cleanup: + timer_of_cleanup(to); +err_free: + kfree(to); + return ret; } TIMER_OF_DECLARE(ostm, "renesas,ostm", ostm_init); From b35a5e5961f814799b75a97a16c9b51e0d477c06 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 16 Oct 2019 16:47:47 +0200 Subject: [PATCH 04/11] clocksource/drivers/renesas-ostm: Use unique device name instead of ostm Currently all OSTM devices are called "ostm", also in kernel messages. As there can be multiple instances in an SoC, this can confuse the user. Hence construct a unique name from the DT node name, like is done for platform devices. On RSK+RZA1, the boot log changes like: -clocksource: ostm: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 57352151442 ns +clocksource: timer@fcfec000: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 57352151442 ns sched_clock: 32 bits at 33MHz, resolution 30ns, wraps every 64440619504ns -ostm: used for clocksource -ostm: used for clock events +/soc/timer@fcfec000: used for clocksource +/soc/timer@fcfec400: used for clock events ... -clocksource: Switched to clocksource ostm +clocksource: Switched to clocksource timer@fcfec000 Signed-off-by: Geert Uytterhoeven Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20191016144747.29538-5-geert+renesas@glider.be --- drivers/clocksource/renesas-ostm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/clocksource/renesas-ostm.c b/drivers/clocksource/renesas-ostm.c index 46012d905604..3d06ba66008c 100644 --- a/drivers/clocksource/renesas-ostm.c +++ b/drivers/clocksource/renesas-ostm.c @@ -64,9 +64,9 @@ static int __init ostm_init_clksrc(struct timer_of *to) writeb(CTL_FREERUN, timer_of_base(to) + OSTM_CTL); writeb(TS, timer_of_base(to) + OSTM_TS); - return clocksource_mmio_init(timer_of_base(to) + OSTM_CNT, "ostm", - timer_of_rate(to), 300, 32, - clocksource_mmio_readl_up); + return clocksource_mmio_init(timer_of_base(to) + OSTM_CNT, + to->np->full_name, timer_of_rate(to), 300, + 32, clocksource_mmio_readl_up); } static u64 notrace ostm_read_sched_clock(void) @@ -190,13 +190,13 @@ static int __init ostm_init(struct device_node *np) goto err_cleanup; ostm_init_sched_clock(to); - pr_info("ostm: used for clocksource\n"); + pr_info("%pOF: used for clocksource\n", np); } else { ret = ostm_init_clkevt(to); if (ret) goto err_cleanup; - pr_info("ostm: used for clock events\n"); + pr_info("%pOF: used for clock events\n", np); } return 0; From 6e001f6a4cc73cd06fc7b8c633bc4906c33dd8ad Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Wed, 16 Oct 2019 20:43:30 +0800 Subject: [PATCH 05/11] clocksource/drivers/asm9260: Add a check for of_clk_get asm9260_timer_init misses a check for of_clk_get. Add a check for it and print errors like other clocksource drivers. Signed-off-by: Chuhong Yuan Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20191016124330.22211-1-hslester96@gmail.com --- drivers/clocksource/asm9260_timer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/clocksource/asm9260_timer.c b/drivers/clocksource/asm9260_timer.c index 9f09a59161e7..5b39d3701fa3 100644 --- a/drivers/clocksource/asm9260_timer.c +++ b/drivers/clocksource/asm9260_timer.c @@ -194,6 +194,10 @@ static int __init asm9260_timer_init(struct device_node *np) } clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + pr_err("Failed to get clk!\n"); + return PTR_ERR(clk); + } ret = clk_prepare_enable(clk); if (ret) { From 56144737e67329c9aaed15f942d46a6302e2e3d8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 6 Nov 2019 09:48:04 -0800 Subject: [PATCH 06/11] hrtimer: Annotate lockless access to timer->state syzbot reported various data-race caused by hrtimer_is_queued() reading timer->state. A READ_ONCE() is required there to silence the warning. Also add the corresponding WRITE_ONCE() when timer->state is set. In remove_hrtimer() the hrtimer_is_queued() helper is open coded to avoid loading timer->state twice. KCSAN reported these cases: BUG: KCSAN: data-race in __remove_hrtimer / tcp_pacing_check write to 0xffff8880b2a7d388 of 1 bytes by interrupt on cpu 0: __remove_hrtimer+0x52/0x130 kernel/time/hrtimer.c:991 __run_hrtimer kernel/time/hrtimer.c:1496 [inline] __hrtimer_run_queues+0x250/0x600 kernel/time/hrtimer.c:1576 hrtimer_run_softirq+0x10e/0x150 kernel/time/hrtimer.c:1593 __do_softirq+0x115/0x33f kernel/softirq.c:292 run_ksoftirqd+0x46/0x60 kernel/softirq.c:603 smpboot_thread_fn+0x37d/0x4a0 kernel/smpboot.c:165 kthread+0x1d4/0x200 drivers/block/aoe/aoecmd.c:1253 ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:352 read to 0xffff8880b2a7d388 of 1 bytes by task 24652 on cpu 1: tcp_pacing_check net/ipv4/tcp_output.c:2235 [inline] tcp_pacing_check+0xba/0x130 net/ipv4/tcp_output.c:2225 tcp_xmit_retransmit_queue+0x32c/0x5a0 net/ipv4/tcp_output.c:3044 tcp_xmit_recovery+0x7c/0x120 net/ipv4/tcp_input.c:3558 tcp_ack+0x17b6/0x3170 net/ipv4/tcp_input.c:3717 tcp_rcv_established+0x37e/0xf50 net/ipv4/tcp_input.c:5696 tcp_v4_do_rcv+0x381/0x4e0 net/ipv4/tcp_ipv4.c:1561 sk_backlog_rcv include/net/sock.h:945 [inline] __release_sock+0x135/0x1e0 net/core/sock.c:2435 release_sock+0x61/0x160 net/core/sock.c:2951 sk_stream_wait_memory+0x3d7/0x7c0 net/core/stream.c:145 tcp_sendmsg_locked+0xb47/0x1f30 net/ipv4/tcp.c:1393 tcp_sendmsg+0x39/0x60 net/ipv4/tcp.c:1434 inet_sendmsg+0x6d/0x90 net/ipv4/af_inet.c:807 sock_sendmsg_nosec net/socket.c:637 [inline] sock_sendmsg+0x9f/0xc0 net/socket.c:657 BUG: KCSAN: data-race in __remove_hrtimer / __tcp_ack_snd_check write to 0xffff8880a3a65588 of 1 bytes by interrupt on cpu 0: __remove_hrtimer+0x52/0x130 kernel/time/hrtimer.c:991 __run_hrtimer kernel/time/hrtimer.c:1496 [inline] __hrtimer_run_queues+0x250/0x600 kernel/time/hrtimer.c:1576 hrtimer_run_softirq+0x10e/0x150 kernel/time/hrtimer.c:1593 __do_softirq+0x115/0x33f kernel/softirq.c:292 invoke_softirq kernel/softirq.c:373 [inline] irq_exit+0xbb/0xe0 kernel/softirq.c:413 exiting_irq arch/x86/include/asm/apic.h:536 [inline] smp_apic_timer_interrupt+0xe6/0x280 arch/x86/kernel/apic/apic.c:1137 apic_timer_interrupt+0xf/0x20 arch/x86/entry/entry_64.S:830 read to 0xffff8880a3a65588 of 1 bytes by task 22891 on cpu 1: __tcp_ack_snd_check+0x415/0x4f0 net/ipv4/tcp_input.c:5265 tcp_ack_snd_check net/ipv4/tcp_input.c:5287 [inline] tcp_rcv_established+0x750/0xf50 net/ipv4/tcp_input.c:5708 tcp_v4_do_rcv+0x381/0x4e0 net/ipv4/tcp_ipv4.c:1561 sk_backlog_rcv include/net/sock.h:945 [inline] __release_sock+0x135/0x1e0 net/core/sock.c:2435 release_sock+0x61/0x160 net/core/sock.c:2951 sk_stream_wait_memory+0x3d7/0x7c0 net/core/stream.c:145 tcp_sendmsg_locked+0xb47/0x1f30 net/ipv4/tcp.c:1393 tcp_sendmsg+0x39/0x60 net/ipv4/tcp.c:1434 inet_sendmsg+0x6d/0x90 net/ipv4/af_inet.c:807 sock_sendmsg_nosec net/socket.c:637 [inline] sock_sendmsg+0x9f/0xc0 net/socket.c:657 __sys_sendto+0x21f/0x320 net/socket.c:1952 __do_sys_sendto net/socket.c:1964 [inline] __se_sys_sendto net/socket.c:1960 [inline] __x64_sys_sendto+0x89/0xb0 net/socket.c:1960 do_syscall_64+0xcc/0x370 arch/x86/entry/common.c:290 Reported by Kernel Concurrency Sanitizer on: CPU: 1 PID: 24652 Comm: syz-executor.3 Not tainted 5.4.0-rc3+ #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 [ tglx: Added comments ] Reported-by: syzbot Signed-off-by: Eric Dumazet Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20191106174804.74723-1-edumazet@google.com --- include/linux/hrtimer.h | 14 ++++++++++---- kernel/time/hrtimer.c | 11 +++++++---- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 1b9a51a1bccb..1f98b52118f0 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -456,12 +456,18 @@ extern u64 hrtimer_next_event_without(const struct hrtimer *exclude); extern bool hrtimer_active(const struct hrtimer *timer); -/* - * Helper function to check, whether the timer is on one of the queues +/** + * hrtimer_is_queued = check, whether the timer is on one of the queues + * @timer: Timer to check + * + * Returns: True if the timer is queued, false otherwise + * + * The function can be used lockless, but it gives only a current snapshot. */ -static inline int hrtimer_is_queued(struct hrtimer *timer) +static inline bool hrtimer_is_queued(struct hrtimer *timer) { - return timer->state & HRTIMER_STATE_ENQUEUED; + /* The READ_ONCE pairs with the update functions of timer->state */ + return !!(READ_ONCE(timer->state) & HRTIMER_STATE_ENQUEUED); } /* diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index 65605530ee34..7f31932216a1 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -966,7 +966,8 @@ static int enqueue_hrtimer(struct hrtimer *timer, base->cpu_base->active_bases |= 1 << base->index; - timer->state = HRTIMER_STATE_ENQUEUED; + /* Pairs with the lockless read in hrtimer_is_queued() */ + WRITE_ONCE(timer->state, HRTIMER_STATE_ENQUEUED); return timerqueue_add(&base->active, &timer->node); } @@ -988,7 +989,8 @@ static void __remove_hrtimer(struct hrtimer *timer, struct hrtimer_cpu_base *cpu_base = base->cpu_base; u8 state = timer->state; - timer->state = newstate; + /* Pairs with the lockless read in hrtimer_is_queued() */ + WRITE_ONCE(timer->state, newstate); if (!(state & HRTIMER_STATE_ENQUEUED)) return; @@ -1013,8 +1015,9 @@ static void __remove_hrtimer(struct hrtimer *timer, static inline int remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, bool restart) { - if (hrtimer_is_queued(timer)) { - u8 state = timer->state; + u8 state = timer->state; + + if (state & HRTIMER_STATE_ENQUEUED) { int reprogram; /* From 20d087368d38c7350a4519a3b316ef7eb2504692 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 8 Nov 2019 21:34:25 +0100 Subject: [PATCH 07/11] time: Optimize ns_to_timespec64() ns_to_timespec64() calls div_s64_rem(), which is a rather slow function on 32-bit architectures, as it cannot take advantage of the do_div() optimizations for constant arguments. Open-code the div_s64_rem() function in ns_to_timespec64(), so a constant divider can be passed into the optimized div_u64_rem() function. Signed-off-by: Arnd Bergmann Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20191108203435.112759-3-arnd@arndb.de --- kernel/time/time.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/kernel/time/time.c b/kernel/time/time.c index 5c54ca632d08..45a358953f09 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -550,18 +550,21 @@ EXPORT_SYMBOL(set_normalized_timespec64); */ struct timespec64 ns_to_timespec64(const s64 nsec) { - struct timespec64 ts; + struct timespec64 ts = { 0, 0 }; s32 rem; - if (!nsec) - return (struct timespec64) {0, 0}; - - ts.tv_sec = div_s64_rem(nsec, NSEC_PER_SEC, &rem); - if (unlikely(rem < 0)) { - ts.tv_sec--; - rem += NSEC_PER_SEC; + if (likely(nsec > 0)) { + ts.tv_sec = div_u64_rem(nsec, NSEC_PER_SEC, &rem); + ts.tv_nsec = rem; + } else if (nsec < 0) { + /* + * With negative times, tv_sec points to the earlier + * second, and tv_nsec counts the nanoseconds since + * then, so tv_nsec is always a positive number. + */ + ts.tv_sec = -div_u64_rem(-nsec - 1, NSEC_PER_SEC, &rem) - 1; + ts.tv_nsec = NSEC_PER_SEC - rem - 1; } - ts.tv_nsec = rem; return ts; } From 1d6acc18fee71a0db6e4fbbfbdb247e0bd5b0655 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Tue, 15 Oct 2019 13:03:39 +0530 Subject: [PATCH 08/11] time: Fix spelling mistake in comment witin => within Signed-off-by: Mukesh Ojha Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/1571124819-9639-1-git-send-email-mojha@codeaurora.org --- kernel/time/time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/time/time.c b/kernel/time/time.c index 45a358953f09..ea6e7e47cc37 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -179,7 +179,7 @@ int do_sys_settimeofday64(const struct timespec64 *tv, const struct timezone *tz return error; if (tz) { - /* Verify we're witin the +-15 hrs range */ + /* Verify we're within the +-15 hrs range */ if (tz->tz_minuteswest > 15*60 || tz->tz_minuteswest < -15*60) return -EINVAL; From 3bbc53f4ae1686b501d92d4a5fd400f4958c8a98 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 7 Nov 2019 10:19:24 +0100 Subject: [PATCH 09/11] hrtimer: Remove the comment about not used HRTIMER_SOFTIRQ The softirq `HRTIMER_SOFTIRQ' was not used since commit c6eb3f70d448 ("hrtimer: Get rid of hrtimer softirq"). But it got used again, beginning with commit 5da70160462e ("hrtimer: Implement support for softirq based hrtimers"), which did not remove the comment. Remove it now. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20191107091924.13410-1-bigeasy@linutronix.de --- include/linux/interrupt.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 89fc59dab57d..963c3c695784 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -520,8 +520,7 @@ enum IRQ_POLL_SOFTIRQ, TASKLET_SOFTIRQ, SCHED_SOFTIRQ, - HRTIMER_SOFTIRQ, /* Unused, but kept as tools rely on the - numbering. Sigh! */ + HRTIMER_SOFTIRQ, RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */ NR_SOFTIRQS From cf25e24db61cc9df42c47485a2ec2bff4e9a3692 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Nov 2019 11:07:58 +0100 Subject: [PATCH 10/11] time: Rename tsk->real_start_time to ->start_boottime Since it stores CLOCK_BOOTTIME, not, as the name suggests, CLOCK_REALTIME, let's rename ->real_start_time to ->start_bootime. Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar --- fs/exec.c | 2 +- fs/proc/array.c | 2 +- include/linux/sched.h | 2 +- kernel/fork.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index 555e93c7dec8..f4d0f3acf861 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1132,7 +1132,7 @@ static int de_thread(struct task_struct *tsk) * also take its birthdate (always earlier than our own). */ tsk->start_time = leader->start_time; - tsk->real_start_time = leader->real_start_time; + tsk->start_boottime = leader->start_boottime; BUG_ON(!same_thread_group(leader, tsk)); BUG_ON(has_group_leader_pid(tsk)); diff --git a/fs/proc/array.c b/fs/proc/array.c index 46dcb6f0eccf..5efaf3708ec6 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -533,7 +533,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, nice = task_nice(task); /* convert nsec -> ticks */ - start_time = nsec_to_clock_t(task->real_start_time); + start_time = nsec_to_clock_t(task->start_boottime); seq_put_decimal_ull(m, "", pid_nr_ns(pid, ns)); seq_puts(m, " ("); diff --git a/include/linux/sched.h b/include/linux/sched.h index 67a1d86981a9..254128952eab 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -857,7 +857,7 @@ struct task_struct { u64 start_time; /* Boot based time in nsecs: */ - u64 real_start_time; + u64 start_boottime; /* MM fault and swap info: this can arguably be seen as either mm-specific or thread-specific: */ unsigned long min_flt; diff --git a/kernel/fork.c b/kernel/fork.c index bcdf53125210..1392ee8f4848 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -2130,7 +2130,7 @@ static __latent_entropy struct task_struct *copy_process( */ p->start_time = ktime_get_ns(); - p->real_start_time = ktime_get_boottime_ns(); + p->start_boottime = ktime_get_boottime_ns(); /* * Make it visible to the rest of the system, but dont wake it up yet. From 7b8474466ed97be458c825f34a85f2c2b84c3f95 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 21 Nov 2019 00:03:03 +0000 Subject: [PATCH 11/11] time: Zero the upper 32-bits in __kernel_timespec on 32-bit On compat interfaces, the high order bits of nanoseconds should be zeroed out. This is because the application code or the libc do not guarantee zeroing of these. If used without zeroing, kernel might be at risk of using timespec values incorrectly. Originally it was handled correctly, but lost during is_compat_syscall() cleanup. Revert the condition back to check CONFIG_64BIT. Fixes: 98f76206b335 ("compat: Cleanup in_compat_syscall() callers") Reported-by: Ben Hutchings Signed-off-by: Dmitry Safonov Signed-off-by: Thomas Gleixner Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20191121000303.126523-1-dima@arista.com --- kernel/time/time.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/time/time.c b/kernel/time/time.c index 5c54ca632d08..83f403e7a15c 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -881,7 +881,8 @@ int get_timespec64(struct timespec64 *ts, ts->tv_sec = kts.tv_sec; /* Zero out the padding for 32 bit systems or in compat mode */ - if (IS_ENABLED(CONFIG_64BIT_TIME) && in_compat_syscall()) + if (IS_ENABLED(CONFIG_64BIT_TIME) && (!IS_ENABLED(CONFIG_64BIT) || + in_compat_syscall())) kts.tv_nsec &= 0xFFFFFFFFUL; ts->tv_nsec = kts.tv_nsec;