kernel/watchdog_perf.c

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

File Facts

System
Linux kernel
Corpus path
kernel/watchdog_perf.c
Extension
.c
Size
7999 bytes
Lines
315
Domain
Core OS
Bucket
Scheduler, Processes, Timers, Sync, And Syscalls
Inferred role
Core OS: implementation source
Status
source 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

static inline bool watchdog_check_timestamp(void) { return true; }
static inline void watchdog_init_timestamp(void) { }
#endif

static struct perf_event_attr wd_hw_attr = {
	.type		= PERF_TYPE_HARDWARE,
	.config		= PERF_COUNT_HW_CPU_CYCLES,
	.size		= sizeof(struct perf_event_attr),
	.pinned		= 1,
	.disabled	= 1,
};

static struct perf_event_attr fallback_wd_hw_attr = {
	.type		= PERF_TYPE_HARDWARE,
	.config		= PERF_COUNT_HW_CPU_CYCLES,
	.size		= sizeof(struct perf_event_attr),
	.pinned		= 1,
	.disabled	= 1,
};

/* Callback function for perf event subsystem */
static void watchdog_overflow_callback(struct perf_event *event,
				       struct perf_sample_data *data,
				       struct pt_regs *regs)
{
	/* Ensure the watchdog never gets throttled */
	event->hw.interrupts = 0;

	if (panic_in_progress())
		return;

	if (!watchdog_check_timestamp())
		return;

	watchdog_hardlockup_check(smp_processor_id(), regs);
}

static struct perf_event *hardlockup_detector_event_create(unsigned int cpu)
{
	struct perf_event_attr *wd_attr;
	struct perf_event *evt;

	wd_attr = &wd_hw_attr;
	wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh);

	/* Try to register using hardware perf events */
	evt = perf_event_create_kernel_counter(wd_attr, cpu, NULL,
					       watchdog_overflow_callback, NULL);
	if (IS_ERR(evt)) {
		wd_attr = &fallback_wd_hw_attr;
		wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh);
		evt = perf_event_create_kernel_counter(wd_attr, cpu, NULL,
						       watchdog_overflow_callback, NULL);
	}

	return evt;
}

/**
 * watchdog_hardlockup_enable - Enable the local event
 * @cpu: The CPU to enable hard lockup on.
 */
void watchdog_hardlockup_enable(unsigned int cpu)
{
	struct perf_event *evt;

	WARN_ON_ONCE(cpu != smp_processor_id());

	evt = hardlockup_detector_event_create(cpu);
	if (IS_ERR(evt)) {
		pr_debug("Perf event create on CPU %d failed with %ld\n", cpu,
			 PTR_ERR(evt));
		return;
	}

	/* use original value for check */
	if (!atomic_fetch_inc(&watchdog_cpus))
		pr_info("Enabled. Permanently consumes one hw-PMU counter.\n");

	WARN_ONCE(this_cpu_read(watchdog_ev), "unexpected watchdog_ev leak");
	this_cpu_write(watchdog_ev, evt);

	watchdog_init_timestamp();
	perf_event_enable(evt);
}

/**
 * watchdog_hardlockup_disable - Disable the local event
 * @cpu: The CPU to enable hard lockup on.
 */

Annotation

Implementation Notes