drivers/md/dm-vdo/funnel-workqueue.c

Source file repositories/reference/linux-study-clean/drivers/md/dm-vdo/funnel-workqueue.c

File Facts

System
Linux kernel
Corpus path
drivers/md/dm-vdo/funnel-workqueue.c
Extension
.c
Size
19927 bytes
Lines
643
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

struct vdo_work_queue {
	/* Name of just the work queue (e.g., "cpuQ12") */
	char *name;
	bool round_robin_mode;
	struct vdo_thread *owner;
	/* Life cycle functions, etc */
	const struct vdo_work_queue_type *type;
};

struct simple_work_queue {
	struct vdo_work_queue common;
	struct funnel_queue *priority_lists[VDO_WORK_Q_MAX_PRIORITY + 1];
	void *private;

	/*
	 * The fields above are unchanged after setup but often read, and are good candidates for
	 * caching -- and if the max priority is 2, just fit in one x86-64 cache line if aligned.
	 * The fields below are often modified as we sleep and wake, so we want a separate cache
	 * line for performance.
	 */

	/* Any (0 or 1) worker threads waiting for new work to do */
	wait_queue_head_t waiting_worker_threads ____cacheline_aligned;
	/* Hack to reduce wakeup calls if the worker thread is running */
	atomic_t idle;

	/* These are infrequently used so in terms of performance we don't care where they land. */
	struct task_struct *thread;
	/* Notify creator once worker has initialized */
	struct completion *started;
};

struct round_robin_work_queue {
	struct vdo_work_queue common;
	struct simple_work_queue **service_queues;
	unsigned int num_service_queues;
};

static inline struct simple_work_queue *as_simple_work_queue(struct vdo_work_queue *queue)
{
	return ((queue == NULL) ?
		NULL : container_of(queue, struct simple_work_queue, common));
}

static inline struct round_robin_work_queue *as_round_robin_work_queue(struct vdo_work_queue *queue)
{
	return ((queue == NULL) ?
		 NULL :
		 container_of(queue, struct round_robin_work_queue, common));
}

/* Processing normal completions. */

/*
 * Dequeue and return the next waiting completion, if any.
 *
 * We scan the funnel queues from highest priority to lowest, once; there is therefore a race
 * condition where a high-priority completion can be enqueued followed by a lower-priority one, and
 * we'll grab the latter (but we'll catch the high-priority item on the next call). If strict
 * enforcement of priorities becomes necessary, this function will need fixing.
 */
static struct vdo_completion *poll_for_completion(struct simple_work_queue *queue)
{
	int i;

	for (i = queue->common.type->max_priority; i >= 0; i--) {
		struct funnel_queue_entry *link = vdo_funnel_queue_poll(queue->priority_lists[i]);

		if (link != NULL)
			return container_of(link, struct vdo_completion, work_queue_entry_link);
	}

	return NULL;
}

static void enqueue_work_queue_completion(struct simple_work_queue *queue,
					  struct vdo_completion *completion)
{
	VDO_ASSERT_LOG_ONLY(completion->my_queue == NULL,
			    "completion %px (fn %px) to enqueue (%px) is not already queued (%px)",
			    completion, completion->callback, queue, completion->my_queue);
	if (completion->priority == VDO_WORK_Q_DEFAULT_PRIORITY)
		completion->priority = queue->common.type->default_priority;

	if (VDO_ASSERT(completion->priority <= queue->common.type->max_priority,
		       "priority is in range for queue") != VDO_SUCCESS)
		completion->priority = 0;

	completion->my_queue = &queue->common;

Annotation

Implementation Notes