Commit 6cfb70fb authored by Yu Liao's avatar Yu Liao
Browse files

tick/broadcast-hrtimer: Prevent the timer device on broadcast duty CPU from being disabled

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I8PL17


CVE: NA

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

It was found that running the LTP hotplug stress test on a aarch64
system could produce rcu_sched stall warnings.
The issue is the following:

CPU1 (owns the broadcast hrtimer)	CPU2

				tick_broadcast_enter()
				//shut down local timer device
				...
				tick_broadcast_exit()
				//exits with tick_broadcast_force_mask set,
				timer device remains disabled

				initiates offlining of CPU1
take_cpu_down()
//CPU1 shuts down and does
not send broadcast IPI anymore
				takedown_cpu()
				  hotplug_cpu__broadcast_tick_pull()
				  //move broadcast hrtimer to this CPU
				    clockevents_program_event()
				      bc_set_next()
					hrtimer_start()
					//does not call hrtimer_reprogram() to
					program timer device if expires equals
					dev->next_event, so the timer device
					remains disabled.

CPU2 takes over the broadcast duty but local timer device is disabled,
causing many CPUs to become stuck.

Fix this by calling tick_program_event() to reprogram the local timer
device in this scenario.

Signed-off-by: default avatarYu Liao <liaoyu15@huawei.com>
parent 00acfc98
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -42,6 +42,8 @@ static int bc_shutdown(struct clock_event_device *evt)
 */
static int bc_set_next(ktime_t expires, struct clock_event_device *bc)
{
	struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev);

	/*
	 * This is called either from enter/exit idle code or from the
	 * broadcast handler. In all cases tick_broadcast_lock is held.
@@ -62,6 +64,18 @@ static int bc_set_next(ktime_t expires, struct clock_event_device *bc)
	 * hrtimer_start() can call into tracing.
	 */
	RCU_NONIDLE( {

		/*
		 * This can be called from CPU offline operation to move broadcast
		 * assignment. If tick_broadcast_force_mask is set, the CPU local
		 * timer device may be disabled. And hrtimer_reprogram() will not
		 * called if the timer is not the first expiring timer. Reprogram
		 * the cpu local timer device to ensure we can take over the
		 * broadcast duty.
		 */
		if (tick_check_broadcast_expired() && expires >= dev->next_event)
			clockevents_program_event(dev, dev->next_event, 1);

		hrtimer_start(&bctimer, expires, HRTIMER_MODE_ABS_PINNED_HARD);
		/*
		 * The core tick broadcast mode expects bc->bound_on to be set