PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
irp.h
Go to the documentation of this file.
1#pragma once
2
3#include <kernel/fs/path.h>
4#include <kernel/mem/mdl.h>
5#include <kernel/mem/pool.h>
6#include <kernel/sync/lock.h>
7#include <kernel/utils/ref.h>
8
9#include <assert.h>
10#include <stdatomic.h>
11#include <stddef.h>
12#include <stdlib.h>
13#include <sys/fs.h>
14#include <sys/ioring.h>
15#include <sys/list.h>
16#include <sys/math.h>
17#include <time.h>
18
19typedef struct file file_t;
20typedef struct process process_t;
21typedef struct vnode vnode_t;
22
23typedef struct irp irp_t;
24
25/**
26 * @brief I/O Request Packet.
27 * @defgroup kernel_io_irp I/O Request Packet
28 * @ingroup kernel_io
29 *
30 * The I/O Request Packet (IRP) is a lock-less, self-contained, layered, continuation-passing request that acts as the
31 * primary primitive used by the kernel for asynchronous operations.
32 *
33 * The IRP is designed to be generic enough to be used by any system in the kernel, however it is primarily used by the I/O ring system.
34 *
35 * @warning While the cancellation or completion of an IRP is thread safe, the setup of an IRP is not (as in pushing
36 * layers to it). It is assumed that only one thread is manipulating an IRP during its setup.
37 *
38 * ## Completion
39 *
40 * @todo Write the IRP documentation.
41 *
42 * ## Cancellation
43 *
44 * Cancelling an IRP can intuitively be considered equivalent to forcing the last completion to fail, thus resulting in
45 * all the other completions to fail as well.
46 *
47 * The current owner of a IRP is responsible for handling cancellation by specifying a cancellation callback via
48 * `irp_set_cancel()`. The current owner being the last target of a `irp_call()` or `irp_call_direct()`.
49 *
50 * When an IRP is cancelled or timed out the cancellation callback will be invoked and atomically exchanged with a
51 * `IRP_CANCELLED` sentinel value. At which point the owner should perform whatever logic is needed to cancel the IRP,
52 * if it is not possible immediately cancel the IRP it should return `ERR`.
53 *
54 * Below is an example of how to implement a completion with an associated cancellation callback:
55 *
56 * ```
57 * void my_completion(irp_t* irp, void* ctx)
58 * {
59 * // Do stuff...
60 *
61 * irp_complete(irp);
62 * }
63 *
64 * uint64_t my_cancel(irp_t* irp)
65 * {
66 * // Cancellation callback is automatically cleared.
67 *
68 * if (irp->err == ETIMEDOUT)
69 * {
70 * // We timed out.
71 * }
72 * if (irp->err == ECANCELED)
73 * {
74 * // We were explicitly cancelled.
75 * }
76 *
77 * // Do stuff...
78 *
79 * uint64_t result = ...;
80 * if (result == ERR) // If an error occurs we can reassign the cancellation callback.
81 * {
82 * irp_set_cancel(irp, my_cancel);
83 * return ERR;
84 * }
85 *
86 * return 0;
87 * }
88 * ```
89 *
90 * ## Error Values
91 *
92 * The IRP system uses the `err` field to indicate both the current state of the IRP as well as any error that may have
93 * occurred during its processing.
94 *
95 * Included below are a list of "special" values which the IRP system will set:
96 *
97 * - `EOK`: Operation completed successfully.
98 * - `ECANCELED`: Operation was cancelled.
99 * - `ETIMEDOUT`: Operation timed out.
100 *
101 * @see kernel_io for the ring system.
102 * @see [Wikipedia](https://en.wikipedia.org/wiki/I/O_request_packet) for more information about IRPs.
103 * @see [Microsoft _IRP](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_irp) for information
104 * on how Windows NT implements IRPs.
105 * @{
106 */
107
108/**
109 * @brief IRP complete callback type.
110 *
111 * @param irp The IRP.
112 * @param ctx The contxt pointer from the `irp_frame_t` structure.
113 */
114typedef void (*irp_complete_t)(irp_t* irp, void* ctx);
115
116/**
117 * @brief IRP cancellation callback type.
118 *
119 * @param irp The IRP.
120 * @return On success, `0`. On failure, `ERR`.
121 */
122typedef uint64_t (*irp_cancel_t)(irp_t* irp);
123
124/**
125 * @brief Sentinel value indicating that the IRP has been cancelled.
126 */
127#define IRP_CANCELLED ((irp_cancel_t)1)
128
130#define IRP_MJ_READ 0
131#define IRP_MJ_WRITE 1
132#define IRP_MJ_POLL 2
133#define IRP_MJ_MAX 3
134
136#define IRP_MN_NORMAL 0
137
138#define IRP_ARGS_MAX 4 ///< The maximum number of 64-bit arguments in an `irp_frame_t`.
139
140/**
141 * @brief IRP stack frame structure.
142 * @struct irp_frame_t
143 */
144typedef struct irp_frame
145{
146 irp_major_t major; ///< Major function number.
147 irp_minor_t minor; ///< Minor function number.
148 uint8_t _reserved[4];
149 irp_complete_t complete; ///< Completion callback.
150 void* ctx; ///< Local context.
151 vnode_t* vnode; ///< Vnode associated with the operation.
152 union {
153 struct
154 {
157 void* data;
161 struct
162 {
163 mdl_t* buffer;
164 uint64_t off;
165 void* data;
166 uint32_t len;
167 mode_t mode;
169 uint64_t args[IRP_ARGS_MAX]; ///< Generic arguments.
170 };
172
173static_assert(sizeof(irp_frame_t) == 64, "irp_frame_t is not 64 bytes");
174
175#define IRP_FRAME_MAX 5 ///< The maximum number of frames in a IRP stack.
176
177/**
178 * @brief I/O Request Packet structure.
179 * @struct irp_t
180 *
181 * The I/O Request Packet structure is designed to preallocate as much as possible such that in the common case there is
182 * no need for any allocation beyond the allocation of the IRP itself. This does require careful consideration of
183 * padding, alignment and field sizes to keep it within a reasonable size.
184 *
185 * @see kernel_io for more information for each possible verb.
186 */
187typedef struct ALIGNED(64) irp
188{
189 list_entry_t entry; ///< Used to store the IRP in various lists.
190 list_entry_t timeoutEntry; ///< Used to store the IRP in the timeout queue.
191 _Atomic(irp_cancel_t) cancel; ///< Cancellation callback, must be atomic to ensure an IRP is only cancelled once.
192 clock_t deadline; ///< The time at which the IRP will be removed from a timeout queue.
193 union {
194 size_t read;
195 size_t write;
196 uint64_t _raw;
197 } res;
198 mdl_t mdl; ///< A preallocated memory descriptor list for use by the IRP.
199 pool_idx_t index; ///< Index of the IRP in its pool.
200 pool_idx_t next; ///< Index of the next IRP in a chain or in the free list.
201 cpu_id_t cpu; ///< The CPU whose timeout queue the IRP is in.
202 uint8_t err; ///< The error code of the operation, also used to specify its current state.
203 uint8_t frame; ///< The index of the current frame in the stack.
204 irp_frame_t stack[IRP_FRAME_MAX]; ///< The frame stack, grows downwards.
205 sqe_t sqe; // A copy of the submission queue entry associated with this IRP.
206 uint8_t reserved[8];
207} irp_t;
208
209static_assert(sizeof(irp_t) == 512, "irp_t is not 512 bytes");
210
211/**
212 * @brief Request pool structure.
213 * @struct irp_pool
214 */
215typedef struct irp_pool
216{
217 void* ctx;
218 process_t* process; ///< Will only hold a reference if there is at least one active IRP.
219 atomic_size_t active;
221 irp_t irps[];
222} irp_pool_t;
223
224/**
225 * @brief IRP function type.
226 */
227typedef void (*irp_func_t)(irp_t* irp);
228
229/**
230 * @brief IRP vtable structure.
231 * @struct irp_vtable_t
232 */
233typedef struct irp_vtable
234{
237
238/**
239 * @brief Allocate a new IRP pool.
240 *
241 * @param size The amount of requests to allocate.
242 * @param process The process that will own the IRPs allocated from this pool.
243 * @param ctx The context of the IRP pool.
244 * @return On success, a pointer to the new IRP pool. On failure, `NULL` and `errno` is set.
245 */
246irp_pool_t* irp_pool_new(size_t size, process_t* process, void* ctx);
247
248/**
249 * @brief Free a IRP pool.
250 *
251 * @param pool The IRP pool to free.
252 */
253void irp_pool_free(irp_pool_t* pool);
254
255/**
256 * @brief Add an IRP to a per-CPU timeout queue.
257 *
258 * @param irp The IRP to add.
259 * @param timeout The timeout of the IRP.
260 */
261void irp_timeout_add(irp_t* irp, clock_t timeout);
262
263/**
264 * @brief Remove an IRP from its per-CPU timeout queue.
265 *
266 * @param irp The IRP to remove.
267 */
268void irp_timeout_remove(irp_t* irp);
269
270/**
271 * @brief Check and handle expired IRP timeouts on the current CPU.
272 */
273void irp_timeouts_check(void);
274
275/**
276 * @brief Allocate a new IRP from a pool.
277 *
278 * The pool that the IRP was allocated from, and its context, can be retrieved using the `irp_get_pool()`
279 * function.
280 *
281 * @param pool The IRP pool.
282 * @return On success, a pointer to the allocated IRP. On failure, `NULL` and `errno` is set.
283 */
284irp_t* irp_new(irp_pool_t* pool);
285
286/**
287 * @brief Retrieve a memory descriptor list and associate it with an IRP.
288 *
289 * All MDLs associated with a IRP will be cleaned up when finished.
290 *
291 * @param irp The IRP to associate the MDL with.
292 * @param addr The virtual address of the memory region to add to the MDL, or `NULL` for a blank MDL.
293 * @param size The size of the memory region.
294 * @return On success, a pointer to the MDL. On failure, `NULL` and `errno` is set.
295 */
296mdl_t* irp_get_mdl(irp_t* irp, const void* addr, size_t size);
297
298/**
299 * @brief Retrieve the IRP pool that an IRP was allocated from.
300 *
301 * @param irp The IRP.
302 * @return The IRP pool.
303 */
304static inline irp_pool_t* irp_get_pool(irp_t* irp)
305{
306 return CONTAINER_OF(irp, irp_pool_t, irps[irp->index]);
307}
308
309/**
310 * @brief Retrieve the context of the IRP pool that an IRP was allocated from.
311 *
312 * @param irp The IRP.
313 * @return The context.
314 */
315static inline void* irp_get_ctx(irp_t* irp)
316{
317 return irp_get_pool(irp)->ctx;
318}
319
320/**
321 * @brief Retrieve the process that owns an IRP.
322 *
323 * @param irp The IRP.
324 * @return The process.
325 */
326static inline process_t* irp_get_process(irp_t* irp)
327{
328 return irp_get_pool(irp)->process;
329}
330
331/**
332 * @brief Retrieve the next IRP in a chain and advance the chain.
333 *
334 * @param irp The current IRP.
335 * @return The next IRP, or `NULL` if there is no next IRP.
336 */
337static inline irp_t* irp_chain_next(irp_t* irp)
338{
339 irp_pool_t* pool = irp_get_pool(irp);
340 if (irp->next == POOL_IDX_MAX)
341 {
342 return NULL;
343 }
344
345 irp_t* next = &pool->irps[irp->next];
346 irp->next = next->next;
347 next->next = POOL_IDX_MAX;
348 return next;
349}
350
351/**
352 * @brief Attempt to cancel an IRP.
353 *
354 * @param irp The IRP to cancel.
355 * @return On success, `0`. On failure, `ERR` and `errno` is set.
356 */
358
359/**
360 * @brief Set the cancellation callback for an IRP.
361 *
362 * @param irp The IRP.
363 * @param cancel The cancellation callback.
364 * @return The previous cancellation callback.
365 */
367{
368 irp_cancel_t expected = atomic_load(&irp->cancel);
369 while (expected != IRP_CANCELLED)
370 {
371 if (atomic_compare_exchange_weak(&irp->cancel, &expected, cancel))
372 {
373 return expected;
374 }
375 }
376 return IRP_CANCELLED;
377}
378
379/**
380 * @brief Retrieve the current frame in the IRP stack.
381 *
382 * @param irp The IRP to retrieve the frame from.
383 * @return The current frame.
384 */
385static inline irp_frame_t* irp_current(irp_t* irp)
386{
387 assert(irp->frame < IRP_FRAME_MAX);
388 return &irp->stack[irp->frame];
389}
390
391/**
392 * @brief Retrieve the next frame in the IRP stack.
393 *
394 * @param irp The IRP to retrieve the frame from.
395 * @return The next frame, or `NULL` if we are at the bottom of the stack.
396 */
397static inline irp_frame_t* irp_next(irp_t* irp)
398{
399 if (irp->frame == 0)
400 {
401 return NULL;
402 }
403 return &irp->stack[irp->frame - 1];
404}
405
406/**
407 * @brief Copy the current frame in the IRP stack to the next.
408 *
409 * @param irp The IRP.
410 */
411static inline void irp_copy_to_next(irp_t* irp)
412{
413 irp_frame_t* current = irp_current(irp);
414 irp_frame_t* next = irp_next(irp);
415
416 if (next->vnode != NULL)
417 {
418 UNREF(next->vnode);
419 next->vnode = NULL;
420 }
421
422 *next = *current;
423 next->vnode = NULL;
424 next->complete = NULL;
425 next->ctx = NULL;
426}
427
428/**
429 * @brief Skip the current stack frame, meaning the next call will run in the same stack frame.
430 *
431 * @param irp The IRP.
432 */
433static inline void irp_skip(irp_t* irp)
434{
435 irp_frame_t* frame = irp_current(irp);
436 if (frame->vnode != NULL)
437 {
438 UNREF(frame->vnode);
439 frame->vnode = NULL;
440 }
441 assert(irp->frame < IRP_FRAME_MAX);
442 irp->frame++;
443}
444
445/**
446 * @brief Send an IRP to a specified vnode.
447 *
448 * Will advance the IRP stack.
449 *
450 * @param irp The IRP to send.
451 * @param vnode The vnode to associated with the next IRP stack frame.
452 */
453void irp_call(irp_t* irp, vnode_t* vnode);
454
455/**
456 * @brief Send an IRP to a specified function directly.
457 *
458 * Will advance the IRP stack.
459 *
460 * @param irp The IRP to send.
461 * @param func The function to call.
462 */
463void irp_call_direct(irp_t* irp, irp_func_t func);
464
465/**
466 * @brief Complete the current frame in the IRP stack.
467 *
468 * If the current frame does not have a completion, it will automatically complete the next frame in the stack.
469 *
470 * If the last frame is reached, the IRP is considered finished. Which will causing its resources to be freed and for
471 * the IRP to be returned to its pool.
472 *
473 * @param irp The IRP to complete.
474 */
475void irp_complete(irp_t* irp);
476
477/**
478 * @brief Set the completion callback and context for the next frame in the IRP stack.
479 *
480 * @param irp The IRP to set.
481 * @param complete The completion callback.
482 * @param ctx The context pointer to pass to the completion callback.
483 */
484static inline void irp_set_complete(irp_t* irp, irp_complete_t complete, void* ctx)
485{
486 irp_frame_t* next = irp_next(irp);
487 next->complete = complete;
488 next->ctx = ctx;
489}
490
491/**
492 * @brief Helper to set an error code and complete the IRP.
493 *
494 * @param irp The IRP to error.
495 * @param err The error code to set.
496 */
497static inline void irp_error(irp_t* irp, uint8_t err)
498{
499 irp->err = err;
500 irp_complete(irp);
501}
502
503/**
504 * @brief Prepares the next IRP stack frame for a generic operation.
505 *
506 * @param irp The IRP.
507 * @param major The major function number.
508 * @param arg0 Generic argument 0.
509 * @param arg1 Generic argument 1.
510 * @param arg2 Generic argument 2.
511 * @param arg3 Generic argument 3.
512 */
513static inline void irp_prepare_generic(irp_t* irp, irp_major_t major, uint64_t arg0, uint64_t arg1, uint64_t arg2,
514 uint64_t arg3)
515{
516 irp_frame_t* next = irp_next(irp);
517 assert(next != NULL);
518
519 next->major = major;
520 next->args[0] = arg0;
521 next->args[1] = arg1;
522 next->args[2] = arg2;
523 next->args[3] = arg3;
524}
525
526/**
527 * @brief Prepares the next IRP stack frame for a read operation.
528 *
529 * @param irp The IRP.
530 * @param buffer The memory descriptor list to read into.
531 * @param data The buffer to read into.
532 * @param off The offset in the file to read from.
533 * @param len The number of bytes to read.
534 * @param mode The mode.
535 */
536static inline void irp_prepare_read(irp_t* irp, mdl_t* buffer, void* data, uint64_t off, uint32_t len, mode_t mode)
537{
538 irp_frame_t* next = irp_next(irp);
539 assert(next != NULL);
540
541 next->major = IRP_MJ_READ;
542 next->read.buffer = buffer;
543 next->read.data = data;
544 next->read.off = off;
545 next->read.len = len;
546 next->read.mode = mode;
547}
548
549/**
550 * @brief Prepares the next IRP stack frame for a write operation.
551 *
552 * @param irp The IRP.
553 * @param buffer The memory descriptor list to write from.
554 * @param data The buffer to write from.
555 * @param off The offset in the file to write to.
556 * @param len The number of bytes to write.
557 * @param mode The mode.
558 */
559static inline void irp_prepare_write(irp_t* irp, mdl_t* buffer, void* data, uint64_t off, uint32_t len, mode_t mode)
560{
561 irp_frame_t* next = irp_next(irp);
562 assert(next != NULL);
563
564 next->major = IRP_MJ_WRITE;
565 next->write.buffer = buffer;
566 next->write.data = data;
567 next->write.off = off;
568 next->write.len = len;
569 next->write.mode = mode;
570}
571
572/** @} */
#define assert(expression)
Definition assert.h:29
EFI_PHYSICAL_ADDRESS buffer
Definition main.c:237
static fd_t data
Definition dwm.c:21
uint16_t cpu_id_t
Type used to identify a CPU.
Definition cpu.h:65
mode_t
Path flags and permissions.
Definition path.h:79
static void irp_set_complete(irp_t *irp, irp_complete_t complete, void *ctx)
Set the completion callback and context for the next frame in the IRP stack.
Definition irp.h:484
void irp_timeouts_check(void)
Check and handle expired IRP timeouts on the current CPU.
Definition irp.c:160
static void irp_prepare_read(irp_t *irp, mdl_t *buffer, void *data, uint64_t off, uint32_t len, mode_t mode)
Prepares the next IRP stack frame for a read operation.
Definition irp.h:536
static void * irp_get_ctx(irp_t *irp)
Retrieve the context of the IRP pool that an IRP was allocated from.
Definition irp.h:315
#define IRP_CANCELLED
Sentinel value indicating that the IRP has been cancelled.
Definition irp.h:127
void irp_complete(irp_t *irp)
Complete the current frame in the IRP stack.
Definition irp.c:355
irp_t * irp_new(irp_pool_t *pool)
Allocate a new IRP from a pool.
Definition irp.c:211
static irp_frame_t * irp_current(irp_t *irp)
Retrieve the current frame in the IRP stack.
Definition irp.h:385
static irp_frame_t * irp_next(irp_t *irp)
Retrieve the next frame in the IRP stack.
Definition irp.h:397
uint16_t irp_minor_t
Definition irp.h:135
uint64_t(* irp_cancel_t)(irp_t *irp)
IRP cancellation callback type.
Definition irp.h:122
struct irp irp_t
Definition irp.h:23
static void irp_prepare_generic(irp_t *irp, irp_major_t major, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3)
Prepares the next IRP stack frame for a generic operation.
Definition irp.h:513
#define IRP_FRAME_MAX
The maximum number of frames in a IRP stack.
Definition irp.h:175
irp_pool_t * irp_pool_new(size_t size, process_t *process, void *ctx)
Allocate a new IRP pool.
Definition irp.c:32
void irp_call_direct(irp_t *irp, irp_func_t func)
Send an IRP to a specified function directly.
Definition irp.c:314
static irp_cancel_t irp_set_cancel(irp_t *irp, irp_cancel_t cancel)
Set the cancellation callback for an IRP.
Definition irp.h:366
static void irp_skip(irp_t *irp)
Skip the current stack frame, meaning the next call will run in the same stack frame.
Definition irp.h:433
void irp_pool_free(irp_pool_t *pool)
Free a IRP pool.
Definition irp.c:62
static irp_t * irp_chain_next(irp_t *irp)
Retrieve the next IRP in a chain and advance the chain.
Definition irp.h:337
static void irp_copy_to_next(irp_t *irp)
Copy the current frame in the IRP stack to the next.
Definition irp.h:411
#define IRP_ARGS_MAX
The maximum number of 64-bit arguments in an irp_frame_t.
Definition irp.h:138
static void irp_error(irp_t *irp, uint8_t err)
Helper to set an error code and complete the IRP.
Definition irp.h:497
static void irp_prepare_write(irp_t *irp, mdl_t *buffer, void *data, uint64_t off, uint32_t len, mode_t mode)
Prepares the next IRP stack frame for a write operation.
Definition irp.h:559
#define IRP_MJ_READ
Definition irp.h:130
static process_t * irp_get_process(irp_t *irp)
Retrieve the process that owns an IRP.
Definition irp.h:326
void(* irp_complete_t)(irp_t *irp, void *ctx)
IRP complete callback type.
Definition irp.h:114
static irp_pool_t * irp_get_pool(irp_t *irp)
Retrieve the IRP pool that an IRP was allocated from.
Definition irp.h:304
void irp_call(irp_t *irp, vnode_t *vnode)
Send an IRP to a specified vnode.
Definition irp.c:283
void irp_timeout_remove(irp_t *irp)
Remove an IRP from its per-CPU timeout queue.
Definition irp.c:97
#define IRP_MJ_WRITE
Definition irp.h:131
uint64_t irp_cancel(irp_t *irp)
Attempt to cancel an IRP.
Definition irp.c:331
uint16_t irp_major_t
Definition irp.h:129
void(* irp_func_t)(irp_t *irp)
IRP function type.
Definition irp.h:227
mdl_t * irp_get_mdl(irp_t *irp, const void *addr, size_t size)
Retrieve a memory descriptor list and associate it with an IRP.
Definition irp.c:241
#define IRP_MJ_MAX
Definition irp.h:133
void irp_timeout_add(irp_t *irp, clock_t timeout)
Add an IRP to a per-CPU timeout queue.
Definition irp.c:67
#define POOL_IDX_MAX
The maximum index value for pool.
Definition pool.h:29
uint16_t pool_idx_t
Pool index type.
Definition pool.h:27
#define UNREF(ptr)
Decrement reference count.
Definition ref.h:109
#define ALIGNED(alignment)
GCC aligned attribute.
Definition defs.h:23
size_t write(fd_t fd, const void *buffer, size_t count)
System call for writing to files.
Definition write.c:8
size_t read(fd_t fd, void *buffer, size_t count)
System call for reading from files.
Definition read.c:8
#define NULL
Pointer error value.
Definition NULL.h:25
#define CONTAINER_OF(ptr, type, member)
Container of macro.
__UINT64_TYPE__ clock_t
A nanosecond time.
Definition clock_t.h:13
static page_stack_t * stack
Definition pmm.c:40
static atomic_long next
Definition main.c:12
#define atomic_compare_exchange_weak(object, expected, desired)
Definition stdatomic.h:280
#define _Atomic(T)
Definition stdatomic.h:59
#define atomic_load(object)
Definition stdatomic.h:288
__UINT32_TYPE__ uint32_t
Definition stdint.h:15
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINT8_TYPE__ uint8_t
Definition stdint.h:11
__UINT16_TYPE__ uint16_t
Definition stdint.h:13
File structure.
Definition file.h:39
IRP stack frame structure.
Definition irp.h:145
mdl_t * buffer
Definition irp.h:155
void * data
Definition irp.h:157
mode_t mode
Definition irp.h:159
vnode_t * vnode
Vnode associated with the operation.
Definition irp.h:151
irp_complete_t complete
Completion callback.
Definition irp.h:149
uint32_t len
Definition irp.h:158
uint64_t off
Definition irp.h:156
void * ctx
Local context.
Definition irp.h:150
irp_major_t major
Major function number.
Definition irp.h:146
irp_minor_t minor
Minor function number.
Definition irp.h:147
void * ctx
Definition irp.h:217
pool_t pool
Definition irp.h:220
process_t * process
Will only hold a reference if there is at least one active IRP.
Definition irp.h:218
atomic_size_t active
Definition irp.h:219
irp_t irps[]
Definition irp.h:221
Request pool structure.
I/O Request Packet structure.
IRP vtable structure.
Definition irp.h:234
A entry in a doubly linked list.
Definition list.h:37
Memory Descriptor List structure.
Definition mdl.h:55
Pool structure.
Definition pool.h:38
Process structure.
Definition process.h:76
Asynchronous submission queue entry (SQE).
Definition ioring.h:89
vnode structure.
Definition vnode.h:48