kernel/unwind/deferred.c

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

File Facts

System
Linux kernel
Corpus path
kernel/unwind/deferred.c
Extension
.c
Size
10061 bytes
Lines
366
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

srcu_read_lock_held(&unwind_srcu)) {
		if (test_bit(work->bit, &bits)) {
			work->func(work, &trace, cookie);
			if (info->cache)
				info->cache->unwind_completed |= BIT(work->bit);
		}
	}
}

static void unwind_deferred_task_work(struct callback_head *head)
{
	process_unwind_deferred(current);
}

void unwind_deferred_task_exit(struct task_struct *task)
{
	struct unwind_task_info *info = &current->unwind_info;

	if (!unwind_pending(info))
		return;

	process_unwind_deferred(task);

	task_work_cancel(task, &info->work);
}

/**
 * unwind_deferred_request - Request a user stacktrace on task kernel exit
 * @work: Unwind descriptor requesting the trace
 * @cookie: The cookie of the first request made for this task
 *
 * Schedule a user space unwind to be done in task work before exiting the
 * kernel.
 *
 * The returned @cookie output is the generated cookie of the very first
 * request for a user space stacktrace for this task since it entered the
 * kernel. It can be from a request by any caller of this infrastructure.
 * Its value will also be passed to the callback function.  It can be
 * used to stitch kernel and user stack traces together in post-processing.
 *
 * It's valid to call this function multiple times for the same @work within
 * the same task entry context.  Each call will return the same cookie
 * while the task hasn't left the kernel. If the callback is not pending
 * because it has already been previously called for the same entry context,
 * it will be called again with the same stack trace and cookie.
 *
 * Return: 0 if the callback successfully was queued.
 *         1 if the callback is pending or was already executed.
 *         Negative if there's an error.
 *         @cookie holds the cookie of the first request by any user
 */
int unwind_deferred_request(struct unwind_work *work, u64 *cookie)
{
	struct unwind_task_info *info = &current->unwind_info;
	int twa_mode = TWA_RESUME;
	unsigned long old, bits;
	unsigned long bit;
	int ret;

	*cookie = 0;

	if ((current->flags & (PF_KTHREAD | PF_EXITING)) ||
	    !user_mode(task_pt_regs(current)))
		return -EINVAL;

	/*
	 * NMI requires having safe cmpxchg operations.
	 * Trigger a warning to make it obvious that an architecture
	 * is using this in NMI when it should not be.
	 */
	if (in_nmi()) {
		if (WARN_ON_ONCE(!CAN_USE_IN_NMI))
			return -EINVAL;
		twa_mode = TWA_NMI_CURRENT;
	}

	/* Do not allow cancelled works to request again */
	bit = READ_ONCE(work->bit);
	if (WARN_ON_ONCE(bit < 0))
		return -EINVAL;

	/* Only need the mask now */
	bit = BIT(bit);

	guard(irqsave)();

	*cookie = get_cookie(info);

	old = atomic_long_read(&info->unwind_mask);

Annotation

Implementation Notes