/* * Copyright (c) 2020 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * * $Id: //eng/vdo-releases/aluminum/src/c++/vdo/kernel/workQueue.h#2 $ */ #ifndef ALBIREO_WORK_QUEUE_H #define ALBIREO_WORK_QUEUE_H #include #include /* for TASK_COMM_LEN */ #include "kernelTypes.h" #include "util/funnelQueue.h" enum { MAX_QUEUE_NAME_LEN = TASK_COMM_LEN, /** Maximum number of action definitions per work queue type */ WORK_QUEUE_ACTION_COUNT = 8, /** Number of priority values available */ WORK_QUEUE_PRIORITY_COUNT = 4, }; struct kvdoWorkItem { /** Entry link for lock-free work queue */ FunnelQueueEntry workQueueEntryLink; /** Function to be called */ KvdoWorkFunction work; /** Optional alternate function for display in queue stats */ void *statsFunction; /** An index into the statistics table; filled in by workQueueStats code */ unsigned int statTableIndex; /** * The action code given to setupWorkItem, from which a priority will be * determined. **/ unsigned int action; /** The work queue in which the item is enqueued, or NULL if not enqueued. */ KvdoWorkQueue *myQueue; /** * Time at which to execute in jiffies for a delayed work item, or zero to * queue for execution ASAP. **/ Jiffies executionTime; /** List management for delayed or expired work items */ KvdoWorkItem *next; /** Time of enqueueing, in ns, for recording queue (waiting) time stats */ uint64_t enqueueTime; }; /** * Table entries defining an action. * * Actions are intended to distinguish general classes of activity for * prioritization purposes, but not necessarily to indicate specific work * functions. They are indicated to setupWorkItem numerically, using an * enumerator defined per kind of work queue -- bio submission work queue * actions use BioQAction, cpu actions use CPUQAction, etc. For example, for * the CPU work queues, data compression can be prioritized separately from * final cleanup processing of a KVIO or from dedupe verification; base code * threads prioritize all VIO callback invocation the same, but separate from * sync or heartbeat operations. The bio acknowledgement work queue, on the * other hand, only does one thing, so it only defines one action code. * * Action codes values must be small integers, 0 through * WORK_QUEUE_ACTION_COUNT-1, and should not be duplicated for a queue type. * * A table of KvdoWorkQueueAction entries embedded in KvdoWorkQueueType * specifies the name, code, and priority for each type of action in the work * queue. The table can have at most WORK_QUEUE_ACTION_COUNT entries, but a * NULL name indicates an earlier end to the table. * * Priorities may be specified as values from 0 through * WORK_QUEUE_PRIORITY_COUNT-1, higher values indicating higher priority. * Priorities are just strong suggestions; it's possible for a lower-priority * work item scheduled right after a high-priority one to be run first, if the * worker thread happens to be scanning its queues at just the wrong moment, * but the high-priority item will be picked up next. * * Internally, the priorities in this table are used to initialize another * table in the constructed work queue object, and in internal builds, * device-mapper messages can be sent to change the priority for an action, * identified by name, in a running VDO device. Doing so does not affect the * priorities for other devices, or for future VDO device creation. **/ typedef struct kvdoWorkQueueAction { /** Name of the action */ char *name; /** The action code (per-type enum) */ unsigned int code; /** The initial priority for this action */ unsigned int priority; } KvdoWorkQueueAction; typedef void (*KvdoWorkQueueFunction)(void *); /** * Static attributes of a work queue that are fixed at compile time * for a given call site. (Attributes that may be computed at run time * are passed as separate arguments.) **/ typedef struct kvdoWorkQueueType { /** A function to call in the new thread before servicing requests */ KvdoWorkQueueFunction start; /** A function to call in the new thread when shutting down */ KvdoWorkQueueFunction finish; /** A function to call in the new thread after running out of work */ KvdoWorkQueueFunction suspend; /** Table of actions for this work queue */ KvdoWorkQueueAction actionTable[WORK_QUEUE_ACTION_COUNT]; } KvdoWorkQueueType; /** * Create a work queue. * * If multiple threads are requested, work items will be distributed to them in * round-robin fashion. * * @param [in] threadNamePrefix The per-device prefix to use in thread names * @param [in] name The queue name * @param [in] parentKobject The parent sysfs node * @param [in] owner The kernel layer owning the work queue * @param [in] private Private data of the queue for use by work * items or other queue-specific functions * @param [in] type The work queue type defining the lifecycle * functions, queue actions, priorities, and * timeout behavior * @param [in] threadCount Number of service threads to set up * @param [out] queuePtr Where to store the queue handle * * @return VDO_SUCCESS or an error code **/ int makeWorkQueue(const char *threadNamePrefix, const char *name, struct kobject *parentKobject, KernelLayer *owner, void *private, const KvdoWorkQueueType *type, unsigned int threadCount, KvdoWorkQueue **queuePtr); /** * Set up the fields of a work queue item. * * Before the first setup call (setupWorkItem or setupWorkItemWithTimeout), the * work item must have been initialized to all-zero. Resetting a * previously-used work item does not require another memset. * * The action code is typically defined in a work-queue-type-specific * enumeration; see the description of KvdoWorkQueueAction. * * @param item The work item to initialize * @param work The function pointer to execute * @param statsFunction A function pointer to record for stats, or NULL * @param action Action code, for determination of priority **/ void setupWorkItem(KvdoWorkItem *item, KvdoWorkFunction work, void *statsFunction, unsigned int action); /** * Add a work item to a work queue. * * If the work item has a timeout that has already passed, the timeout * handler function may be invoked at this time. * * @param queue The queue handle * @param item The work item to be processed **/ void enqueueWorkQueue(KvdoWorkQueue *queue, KvdoWorkItem *item); /** * Add a work item to a work queue, to be run at a later point in time. * * Currently delayed work items are used only in a very limited fashion -- at * most one at a time for any of the work queue types that use them -- and some * shortcuts have been taken that assume that that's the case. Multiple delayed * work items should work, but they will execute in the order they were * enqueued. * * @param queue The queue handle * @param item The work item to be processed * @param executionTime When to run the work item (jiffies) **/ void enqueueWorkQueueDelayed(KvdoWorkQueue *queue, KvdoWorkItem *item, Jiffies executionTime); /** * Shut down a work queue's worker thread. * * Alerts the worker thread that it should shut down, and then waits * for it to do so. * * There should not be any new enqueueing of work items done once this * function is called. Any pending delayed work items will be * processed, as scheduled, before the worker thread shuts down, but * they must not re-queue themselves to run again. * * @param queue The work queue to shut down **/ void finishWorkQueue(KvdoWorkQueue *queue); /** * Free a work queue and null out the reference to it. * * @param queuePtr Where the queue handle is found **/ void freeWorkQueue(KvdoWorkQueue **queuePtr); /** * Print work queue state and statistics to the kernel log. * * @param queue The work queue to examine **/ void dumpWorkQueue(KvdoWorkQueue *queue); /** * Write to the buffer some info about the work item, for logging. * Since the common use case is dumping info about a lot of work items * to syslog all at once, the format favors brevity over readability. * * @param item The work item * @param buffer The message buffer to fill in * @param length The length of the message buffer **/ void dumpWorkItemToBuffer(KvdoWorkItem *item, char *buffer, size_t length); /** * Initialize work queue internals at module load time. **/ void initWorkQueueOnce(void); /** * Checks whether two work items have the same action codes * * @param item1 The first item * @param item2 The second item * * @return TRUE if the actions are the same, FALSE otherwise */ static inline bool areWorkItemActionsEqual(KvdoWorkItem *item1, KvdoWorkItem *item2) { return item1->action == item2->action; } /** * Returns the private data for the current thread's work queue. * * @return The private data pointer, or NULL if none or if the current * thread is not a work queue thread. **/ void *getWorkQueuePrivateData(void); /** * Updates the private data pointer for the current thread's work queue. * * @param newData The new private data pointer **/ void setWorkQueuePrivateData(void *newData); /** * Returns the work queue pointer for the current thread, if any. * * @return The work queue pointer or NULL **/ KvdoWorkQueue *getCurrentWorkQueue(void); /** * Returns the kernel layer that owns the work queue. * * @param queue The work queue * * @return The owner pointer supplied at work queue creation **/ KernelLayer *getWorkQueueOwner(KvdoWorkQueue *queue); #endif /* ALBIREO_WORK_QUEUE_H */