Commit a0211af5 authored by Yu Liao's avatar Yu Liao Committed by Xiongfeng Wang
Browse files

rtc: Fix race when disable/enable UIE in rtc_set_time()

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBV6W4



--------------------------------

When the RTC_SET_TIME and RTC_RD_TIME threads run in parallel,
there is no guarantee that uie_rtctimer.enabled is equal to the
previously read uie when executing rtc->ops->set_time.

Fix this by keeping reading uie state, disabling uie, setting
rtc time and enabling uie in critical sections.

Fixes: 7e7c005b ("rtc: disable uie before setting time and enable after")
Signed-off-by: default avatarYu Liao <liaoyu15@huawei.com>
Signed-off-by: default avatarXiongfeng Wang <wangxiongfeng2@huawei.com>
parent e28c0bf7
Loading
Loading
Loading
Loading
+12 −16
Original line number Diff line number Diff line
@@ -139,20 +139,18 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)

	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);
	err = mutex_lock_interruptible(&rtc->ops_lock);
	if (err)
		return err;
	}

	err = mutex_lock_interruptible(&rtc->ops_lock);
	if (err)
	uie = rtc->uie_rtctimer.enabled;
	if (uie) {
		err = __rtc_update_irq_enable(rtc, 0);
		if (err) {
			mutex_unlock(&rtc->ops_lock);
			return err;
		}
	}

	if (!rtc->ops)
		err = -ENODEV;
@@ -169,16 +167,14 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
		err = -EINVAL;

	pm_stay_awake(rtc->dev.parent);

	if (uie)
		err = __rtc_update_irq_enable(rtc, 1);

	mutex_unlock(&rtc->ops_lock);
	/* 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;
}