drivers/md/dm-vdo/wait-queue.c

Source file repositories/reference/linux-study-clean/drivers/md/dm-vdo/wait-queue.c

File Facts

System
Linux kernel
Corpus path
drivers/md/dm-vdo/wait-queue.c
Extension
.c
Size
6735 bytes
Lines
206
Domain
Driver Families
Bucket
drivers/md
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright 2023 Red Hat
 */

#include "wait-queue.h"

#include <linux/device-mapper.h>

#include "permassert.h"

#include "status-codes.h"

/**
 * vdo_waitq_enqueue_waiter() - Add a waiter to the tail end of a waitq.
 * @waitq: The vdo_wait_queue to which to add the waiter.
 * @waiter: The waiter to add to the waitq.
 *
 * The waiter must not already be waiting in a waitq.
 */
void vdo_waitq_enqueue_waiter(struct vdo_wait_queue *waitq, struct vdo_waiter *waiter)
{
	BUG_ON(waiter->next_waiter != NULL);

	if (waitq->last_waiter == NULL) {
		/*
		 * The waitq is empty, so form the initial circular list by self-linking the
		 * initial waiter.
		 */
		waiter->next_waiter = waiter;
	} else {
		/* Splice the new waiter in at the end of the waitq. */
		waiter->next_waiter = waitq->last_waiter->next_waiter;
		waitq->last_waiter->next_waiter = waiter;
	}

	/* In both cases, the waiter we added to the list becomes the last waiter. */
	waitq->last_waiter = waiter;
	waitq->length += 1;
}

/**
 * vdo_waitq_transfer_all_waiters() - Transfer all waiters from one waitq to
 *                                    a second waitq, emptying the first waitq.
 * @from_waitq: The waitq containing the waiters to move.
 * @to_waitq: The waitq that will receive the waiters from the first waitq.
 */
void vdo_waitq_transfer_all_waiters(struct vdo_wait_queue *from_waitq,
				    struct vdo_wait_queue *to_waitq)
{
	/* If the source waitq is empty, there's nothing to do. */
	if (!vdo_waitq_has_waiters(from_waitq))
		return;

	if (vdo_waitq_has_waiters(to_waitq)) {
		/*
		 * Both are non-empty. Splice the two circular lists together
		 * by swapping the next (head) pointers in the list tails.
		 */
		struct vdo_waiter *from_head = from_waitq->last_waiter->next_waiter;
		struct vdo_waiter *to_head = to_waitq->last_waiter->next_waiter;

		to_waitq->last_waiter->next_waiter = from_head;
		from_waitq->last_waiter->next_waiter = to_head;
	}

	to_waitq->last_waiter = from_waitq->last_waiter;
	to_waitq->length += from_waitq->length;
	vdo_waitq_init(from_waitq);
}

/**
 * vdo_waitq_notify_all_waiters() - Notify all the entries waiting in a waitq.
 * @waitq: The vdo_wait_queue containing the waiters to notify.
 * @callback: The function to call to notify each waiter, or NULL to invoke the callback field
 *            registered in each waiter.
 * @context: The context to pass to the callback function.
 *
 * Notifies all the entries waiting in a waitq to continue execution by invoking a callback
 * function on each of them in turn. The waitq is copied and emptied before invoking any callbacks,
 * and only the waiters that were in the waitq at the start of the call will be notified.
 */
void vdo_waitq_notify_all_waiters(struct vdo_wait_queue *waitq,
				  vdo_waiter_callback_fn callback, void *context)
{
	/*
	 * Copy and empty the waitq first, avoiding the possibility of an infinite
	 * loop if entries are returned to the waitq by the callback function.
	 */
	struct vdo_wait_queue waiters;

Annotation

Implementation Notes