lkml.org 
[lkml]   [2019]   [Dec]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.4 174/177] rtc: disable uie before setting time and enable after
    Date
    From: Alexandre Belloni <alexandre.belloni@bootlin.com>

    commit 7e7c005b4b1f1f169bcc4b2c3a40085ecc663df2 upstream.

    When setting the time in the future with the uie timer enabled,
    rtc_timer_do_work will loop for a while because the expiration of the uie
    timer was way before the current RTC time and a new timer will be enqueued
    until the current rtc time is reached.

    If the uie timer is enabled, disable it before setting the time and enable
    it after expiring current timers (which may actually be an alarm).

    This is the safest thing to do to ensure the uie timer is still
    synchronized with the RTC, especially in the UIE emulation case.

    Reported-by: syzbot+08116743f8ad6f9a6de7@syzkaller.appspotmail.com
    Fixes: 6610e0893b8b ("RTC: Rework RTC code to use timerqueue for events")
    Link: https://lore.kernel.org/r/20191020231320.8191-1-alexandre.belloni@bootlin.com
    Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/rtc/interface.c | 19 ++++++++++++++++++-
    1 file changed, 18 insertions(+), 1 deletion(-)

    --- a/drivers/rtc/interface.c
    +++ b/drivers/rtc/interface.c
    @@ -125,7 +125,7 @@ EXPORT_SYMBOL_GPL(rtc_read_time);

    int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
    {
    - int err;
    + int err, uie;

    err = rtc_valid_tm(tm);
    if (err != 0)
    @@ -137,6 +137,17 @@ int rtc_set_time(struct rtc_device *rtc,

    rtc_subtract_offset(rtc, tm);

    +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
    + uie = rtc->uie_rtctimer.enabled || rtc->uie_irq_active;
    +#else
    + uie = rtc->uie_rtctimer.enabled;
    +#endif
    + if (uie) {
    + err = rtc_update_irq_enable(rtc, 0);
    + if (err)
    + return err;
    + }
    +
    err = mutex_lock_interruptible(&rtc->ops_lock);
    if (err)
    return err;
    @@ -153,6 +164,12 @@ int rtc_set_time(struct rtc_device *rtc,
    /* A timer might have just expired */
    schedule_work(&rtc->irqwork);

    + if (uie) {
    + err = rtc_update_irq_enable(rtc, 1);
    + if (err)
    + return err;
    + }
    +
    trace_rtc_set_time(rtc_tm_to_time64(tm), err);
    return err;
    }

    \
     
     \ /
      Last update: 2019-12-16 19:22    [W:2.212 / U:1.136 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site