Commit 3a4a0367 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull RCU fix from Neeraj Upadhyay:
 "Fix a regression introduced by commit b41642c8 ("rcu: Fix
  rcu_read_unlock() deadloop due to IRQ work") which results in boot
  hang as reported by kernel test bot at [1].

  This issue happens because RCU re-initializes the deferred QS IRQ work
  everytime it is queued. With commit b41642c8, the IRQ work
  re-initialization can happen while it is already queued. This results
  in IRQ work being requeued to itself. When IRQ work finally fires, as
  it is requeued to itself, it is repeatedly executed and results in
  hang.

  Fix this with initializing the IRQ work only once before the CPU
  boots"

Link: https://lore.kernel.org/rcu/202508071303.c1134cce-lkp@intel.com/ [1]

* tag 'rcu.fixes.6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/rcu/linux:
  rcu: Fix racy re-initialization of irq_work causing hangs
parents 91325f31 61399e0c
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -4262,6 +4262,8 @@ int rcutree_prepare_cpu(unsigned int cpu)
	rdp->rcu_iw_gp_seq = rdp->gp_seq - 1;
	trace_rcu_grace_period(rcu_state.name, rdp->gp_seq, TPS("cpuonl"));
	raw_spin_unlock_irqrestore_rcu_node(rnp, flags);

	rcu_preempt_deferred_qs_init(rdp);
	rcu_spawn_rnp_kthreads(rnp);
	rcu_spawn_cpu_nocb_kthread(cpu);
	ASSERT_EXCLUSIVE_WRITER(rcu_state.n_online_cpus);
+1 −0
Original line number Diff line number Diff line
@@ -488,6 +488,7 @@ static int rcu_print_task_exp_stall(struct rcu_node *rnp);
static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp);
static void rcu_flavor_sched_clock_irq(int user);
static void dump_blkd_tasks(struct rcu_node *rnp, int ncheck);
static void rcu_preempt_deferred_qs_init(struct rcu_data *rdp);
static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags);
static void rcu_preempt_boost_start_gp(struct rcu_node *rnp);
static bool rcu_is_callbacks_kthread(struct rcu_data *rdp);
+6 −2
Original line number Diff line number Diff line
@@ -763,8 +763,6 @@ static void rcu_read_unlock_special(struct task_struct *t)
			    cpu_online(rdp->cpu)) {
				// Get scheduler to re-evaluate and call hooks.
				// If !IRQ_WORK, FQS scan will eventually IPI.
				rdp->defer_qs_iw =
					IRQ_WORK_INIT_HARD(rcu_preempt_deferred_qs_handler);
				rdp->defer_qs_iw_pending = DEFER_QS_PENDING;
				irq_work_queue_on(&rdp->defer_qs_iw, rdp->cpu);
			}
@@ -904,6 +902,10 @@ dump_blkd_tasks(struct rcu_node *rnp, int ncheck)
	}
}

static void rcu_preempt_deferred_qs_init(struct rcu_data *rdp)
{
	rdp->defer_qs_iw = IRQ_WORK_INIT_HARD(rcu_preempt_deferred_qs_handler);
}
#else /* #ifdef CONFIG_PREEMPT_RCU */

/*
@@ -1103,6 +1105,8 @@ dump_blkd_tasks(struct rcu_node *rnp, int ncheck)
	WARN_ON_ONCE(!list_empty(&rnp->blkd_tasks));
}

static void rcu_preempt_deferred_qs_init(struct rcu_data *rdp) { }

#endif /* #else #ifdef CONFIG_PREEMPT_RCU */

/*