kernel/rcu/srcutree.c

Source file repositories/reference/linux-study-clean/kernel/rcu/srcutree.c

File Facts

System
Linux kernel
Corpus path
kernel/rcu/srcutree.c
Extension
.c
Size
78978 bytes
Lines
2204
Domain
Core OS
Bucket
Scheduler, Processes, Timers, Sync, And Syscalls
Inferred role
Core OS: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

if (snp == &ssp->srcu_sup->node[0]) {
			/* Root node, special case. */
			snp->srcu_parent = NULL;
			continue;
		}

		/* Non-root node. */
		if (snp == ssp->srcu_sup->level[level + 1])
			level++;
		snp->srcu_parent = ssp->srcu_sup->level[level - 1] +
				   (snp - ssp->srcu_sup->level[level]) /
				   levelspread[level - 1];
	}

	/*
	 * Initialize the per-CPU srcu_data array, which feeds into the
	 * leaves of the srcu_node tree.
	 */
	level = rcu_num_lvls - 1;
	snp_first = ssp->srcu_sup->level[level];
	for_each_possible_cpu(cpu) {
		sdp = per_cpu_ptr(ssp->sda, cpu);
		sdp->mynode = &snp_first[cpu / levelspread[level]];
		for (snp = sdp->mynode; snp != NULL; snp = snp->srcu_parent) {
			if (snp->grplo < 0)
				snp->grplo = cpu;
			snp->grphi = cpu;
		}
		sdp->grpmask = 1UL << (cpu - sdp->mynode->grplo);
	}
	smp_store_release(&ssp->srcu_sup->srcu_size_state, SRCU_SIZE_WAIT_BARRIER);
	return true;
}

/*
 * Initialize non-compile-time initialized fields, including the
 * associated srcu_node and srcu_data structures.  The is_static parameter
 * tells us that ->sda has already been wired up to srcu_data.
 */
static int init_srcu_struct_fields(struct srcu_struct *ssp, bool is_static)
{
	if (!is_static)
		ssp->srcu_sup = kzalloc_obj(*ssp->srcu_sup);
	if (!ssp->srcu_sup)
		return -ENOMEM;
	if (!is_static)
		raw_spin_lock_init(&ACCESS_PRIVATE(ssp->srcu_sup, lock));
	ssp->srcu_sup->srcu_size_state = SRCU_SIZE_SMALL;
	ssp->srcu_sup->node = NULL;
	mutex_init(&ssp->srcu_sup->srcu_cb_mutex);
	mutex_init(&ssp->srcu_sup->srcu_gp_mutex);
	ssp->srcu_sup->srcu_gp_seq = SRCU_GP_SEQ_INITIAL_VAL;
	ssp->srcu_sup->srcu_barrier_seq = 0;
	mutex_init(&ssp->srcu_sup->srcu_barrier_mutex);
	atomic_set(&ssp->srcu_sup->srcu_barrier_cpu_cnt, 0);
	INIT_DELAYED_WORK(&ssp->srcu_sup->work, process_srcu);
	init_irq_work(&ssp->srcu_sup->irq_work, srcu_irq_work);
	ssp->srcu_sup->sda_is_static = is_static;
	if (!is_static) {
		ssp->sda = alloc_percpu(struct srcu_data);
		ssp->srcu_ctrp = &ssp->sda->srcu_ctrs[0];
	}
	if (!ssp->sda)
		goto err_free_sup;
	init_srcu_struct_data(ssp);
	ssp->srcu_sup->srcu_gp_seq_needed_exp = SRCU_GP_SEQ_INITIAL_VAL;
	ssp->srcu_sup->srcu_last_gp_end = ktime_get_mono_fast_ns();
	if (READ_ONCE(ssp->srcu_sup->srcu_size_state) == SRCU_SIZE_SMALL && SRCU_SIZING_IS_INIT()) {
		if (!preemptible())
			WRITE_ONCE(ssp->srcu_sup->srcu_size_state, SRCU_SIZE_ALLOC);
		else if (init_srcu_struct_nodes(ssp, GFP_KERNEL))
			WRITE_ONCE(ssp->srcu_sup->srcu_size_state, SRCU_SIZE_BIG);
		else
			goto err_free_sda;
	}
	ssp->srcu_sup->srcu_ssp = ssp;
	smp_store_release(&ssp->srcu_sup->srcu_gp_seq_needed,
			SRCU_GP_SEQ_INITIAL_VAL); /* Init done. */
	return 0;

err_free_sda:
	if (!is_static) {
		free_percpu(ssp->sda);
		ssp->sda = NULL;
	}
err_free_sup:
	if (!is_static) {
		kfree(ssp->srcu_sup);
		ssp->srcu_sup = NULL;
	}

Annotation

Implementation Notes