kernel/kcsan/core.c

Source file repositories/reference/linux-study-clean/kernel/kcsan/core.c

File Facts

System
Linux kernel
Corpus path
kernel/kcsan/core.c
Extension
.c
Size
48788 bytes
Lines
1372
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 (value_change == KCSAN_VALUE_CHANGE_MAYBE) {
			if (access_mask != 0) {
				/*
				 * For access with access_mask, we require a
				 * value-change, as it is likely that races on
				 * ~access_mask bits are expected.
				 */
				value_change = KCSAN_VALUE_CHANGE_FALSE;
			} else if (size > 8 || is_assert) {
				/* Always assume a value-change. */
				value_change = KCSAN_VALUE_CHANGE_TRUE;
			}
		}

		/*
		 * No need to increment 'data_races' counter, as the racing
		 * thread already did.
		 *
		 * Count 'assert_failures' for each failed ASSERT access,
		 * therefore both this thread and the racing thread may
		 * increment this counter.
		 */
		if (is_assert && value_change == KCSAN_VALUE_CHANGE_TRUE)
			atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_ASSERT_FAILURES]);

		kcsan_report_known_origin(ptr, size, type, ip,
					  value_change, watchpoint - watchpoints,
					  old, new, access_mask);
	} else if (value_change == KCSAN_VALUE_CHANGE_TRUE) {
		/* Inferring a race, since the value should not have changed. */

		atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_RACES_UNKNOWN_ORIGIN]);
		if (is_assert)
			atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_ASSERT_FAILURES]);

		if (IS_ENABLED(CONFIG_KCSAN_REPORT_RACE_UNKNOWN_ORIGIN) || is_assert) {
			kcsan_report_unknown_origin(ptr, size, type, ip,
						    old, new, access_mask);
		}
	}

	/*
	 * Remove watchpoint; must be after reporting, since the slot may be
	 * reused after this point.
	 */
	remove_watchpoint(watchpoint);
	atomic_long_dec(&kcsan_counters[KCSAN_COUNTER_USED_WATCHPOINTS]);

out_unlock:
	if (!interrupt_watcher)
		local_irq_restore(irq_flags);
	kcsan_restore_irqtrace(current);
	ctx->disable_scoped--;

	/*
	 * Reordered accesses cannot be used for value change detection,
	 * therefore never consider for reordering if access_mask is set.
	 * ASSERT_EXCLUSIVE are not real accesses, ignore them as well.
	 */
	if (!access_mask && !is_assert)
		set_reorder_access(ctx, ptr, size, type, ip);
out:
	user_access_restore(ua_flags);
}

static __always_inline void
check_access(const volatile void *ptr, size_t size, int type, unsigned long ip)
{
	atomic_long_t *watchpoint;
	long encoded_watchpoint;

	/*
	 * Do nothing for 0 sized check; this comparison will be optimized out
	 * for constant sized instrumentation (__tsan_{read,write}N).
	 */
	if (unlikely(size == 0))
		return;

again:
	/*
	 * Avoid user_access_save in fast-path: find_watchpoint is safe without
	 * user_access_save, as the address that ptr points to is only used to
	 * check if a watchpoint exists; ptr is never dereferenced.
	 */
	watchpoint = find_watchpoint((unsigned long)ptr, size,
				     !(type & KCSAN_ACCESS_WRITE),
				     &encoded_watchpoint);
	/*
	 * It is safe to check kcsan_is_enabled() after find_watchpoint in the
	 * slow-path, as long as no state changes that cause a race to be

Annotation

Implementation Notes