Commit c945b4da authored by Vineeth Pillai's avatar Vineeth Pillai Committed by Paul E. McKenney
Browse files

rcu: Shrinker for lazy rcu



The shrinker is used to speed up the free'ing of memory potentially held
by RCU lazy callbacks. RCU kernel module test cases show this to be
effective. Test is introduced in a later patch.

Signed-off-by: default avatarVineeth Pillai <vineeth@bitbyteword.org>
Signed-off-by: default avatarJoel Fernandes (Google) <joel@joelfernandes.org>
Signed-off-by: default avatarPaul E. McKenney <paulmck@kernel.org>
parent 3d222a0c
Loading
Loading
Loading
Loading
+52 −0
Original line number Diff line number Diff line
@@ -1312,6 +1312,55 @@ int rcu_nocb_cpu_offload(int cpu)
}
EXPORT_SYMBOL_GPL(rcu_nocb_cpu_offload);

static unsigned long
lazy_rcu_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
{
	int cpu;
	unsigned long count = 0;

	/* Snapshot count of all CPUs */
	for_each_possible_cpu(cpu) {
		struct rcu_data *rdp = per_cpu_ptr(&rcu_data, cpu);

		count +=  READ_ONCE(rdp->lazy_len);
	}

	return count ? count : SHRINK_EMPTY;
}

static unsigned long
lazy_rcu_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
{
	int cpu;
	unsigned long flags;
	unsigned long count = 0;

	/* Snapshot count of all CPUs */
	for_each_possible_cpu(cpu) {
		struct rcu_data *rdp = per_cpu_ptr(&rcu_data, cpu);
		int _count = READ_ONCE(rdp->lazy_len);

		if (_count == 0)
			continue;
		rcu_nocb_lock_irqsave(rdp, flags);
		WRITE_ONCE(rdp->lazy_len, 0);
		rcu_nocb_unlock_irqrestore(rdp, flags);
		wake_nocb_gp(rdp, false);
		sc->nr_to_scan -= _count;
		count += _count;
		if (sc->nr_to_scan <= 0)
			break;
	}
	return count ? count : SHRINK_STOP;
}

static struct shrinker lazy_rcu_shrinker = {
	.count_objects = lazy_rcu_shrink_count,
	.scan_objects = lazy_rcu_shrink_scan,
	.batch = 0,
	.seeks = DEFAULT_SEEKS,
};

void __init rcu_init_nohz(void)
{
	int cpu;
@@ -1342,6 +1391,9 @@ void __init rcu_init_nohz(void)
	if (!rcu_state.nocb_is_setup)
		return;

	if (register_shrinker(&lazy_rcu_shrinker, "rcu-lazy"))
		pr_err("Failed to register lazy_rcu shrinker!\n");

	if (!cpumask_subset(rcu_nocb_mask, cpu_possible_mask)) {
		pr_info("\tNote: kernel parameter 'rcu_nocbs=', 'nohz_full', or 'isolcpus=' contains nonexistent CPUs.\n");
		cpumask_and(rcu_nocb_mask, cpu_possible_mask,