1 // SPDX-License-Identifier: MIT or LGPL-2.1-only
2
3 #ifndef UBLKSRV_AIO_INC_H
4 #define UBLKSRV_AIO_INC_H
5
6 /*
7 * APIs for offloading IO handling in non-ublksrv context, refer to
8 * demo_event.c for how to use these APIs
9 */
10
11 #ifdef __cplusplus
12 extern "C" {
13 #endif
14
15 struct ublksrv_aio_ctx;
16 struct ublksrv_aio;
17
18 /*
19 * return value:
20 *
21 * > 0 : the request is done
22 * = 0 : submitted successfully, but not done
23 * < 0 : submitted not successfully
24 */
25 typedef int (ublksrv_aio_submit_fn)(struct ublksrv_aio_ctx *ctx,
26 struct ublksrv_aio *req);
27
28 #define ublksrv_aio_qid(val) ((val >> 13) & 0x7ff)
29 #define ublksrv_aio_tag(val) (val & 0x1fff)
30
ublksrv_aio_pid_tag(unsigned qid,unsigned tag)31 static inline unsigned ublksrv_aio_pid_tag(unsigned qid, unsigned tag)
32 {
33 return tag | (qid << 13);
34 }
35
36 struct ublksrv_aio {
37 struct ublksrv_io_desc io;
38 union {
39 int res; /* output */
40 int fd; /* input */
41 };
42
43 /* reserved 31 ~ 24, bit 23 ~ 13: qid, bit 12 ~ 0: tag */
44 unsigned id;
45 struct ublksrv_aio *next;
46 unsigned long data[0];
47 };
48
49 struct aio_list {
50 struct ublksrv_aio *head, *tail;
51 };
52
aio_list_init(struct aio_list * al)53 static inline void aio_list_init(struct aio_list *al)
54 {
55 al->head = al->tail = NULL;
56 }
57
aio_list_add(struct aio_list * al,struct ublksrv_aio * io)58 static inline void aio_list_add(struct aio_list *al, struct ublksrv_aio *io)
59 {
60 io->next = NULL;
61
62 if (al->tail)
63 al->tail->next = io;
64 else
65 al->head = io;
66 al->tail = io;
67 }
68
aio_list_splice(struct aio_list * n,struct aio_list * head)69 static inline void aio_list_splice(struct aio_list *n,
70 struct aio_list *head)
71 {
72 if (!n->head)
73 return;
74
75 if (head->tail)
76 head->tail->next = n->head;
77 else
78 head->head = n->head;
79
80 head->tail = n->tail;
81
82 aio_list_init(n);
83 }
84
aio_list_empty(const struct aio_list * al)85 static inline int aio_list_empty(const struct aio_list *al)
86 {
87 return al->head == NULL;
88 }
89
aio_list_pop(struct aio_list * al)90 static inline struct ublksrv_aio *aio_list_pop(struct aio_list *al)
91 {
92 struct ublksrv_aio *io = al->head;
93
94 if (io) {
95 al->head = io->next;
96 if (!al->head)
97 al->tail = NULL;
98
99 io->next = NULL;
100 }
101
102 return io;
103 }
104
105 struct ublksrv_aio_list {
106 pthread_spinlock_t lock;
107 struct aio_list list;
108 };
109
ublksrv_aio_init_list(struct ublksrv_aio_list * l)110 static inline void ublksrv_aio_init_list(struct ublksrv_aio_list *l)
111 {
112 pthread_spin_init(&l->lock, PTHREAD_PROCESS_PRIVATE);
113 aio_list_init(&l->list);
114 }
115
116 struct ublksrv_aio_ctx *ublksrv_aio_ctx_init(const struct ublksrv_dev *dev,
117 unsigned flags);
118 void ublksrv_aio_ctx_shutdown(struct ublksrv_aio_ctx *ctx);
119 void ublksrv_aio_ctx_deinit(struct ublksrv_aio_ctx *ctx);
120 struct ublksrv_aio *ublksrv_aio_alloc_req(struct ublksrv_aio_ctx *ctx,
121 int payload_size);
122 void ublksrv_aio_free_req(struct ublksrv_aio_ctx *ctx, struct ublksrv_aio *req);
123 void ublksrv_aio_submit_req(struct ublksrv_aio_ctx *ctx,
124 const struct ublksrv_queue *q, struct ublksrv_aio *req);
125 void ublksrv_aio_get_completed_reqs(struct ublksrv_aio_ctx *ctx,
126 const struct ublksrv_queue *q,
127 struct aio_list *al);
128 int ublksrv_aio_submit_worker(struct ublksrv_aio_ctx *ctx,
129 ublksrv_aio_submit_fn *fn, struct aio_list *submitted);
130 void ublksrv_aio_complete_worker(struct ublksrv_aio_ctx *ctx,
131 struct aio_list *completed);
132 void ublksrv_aio_handle_event(struct ublksrv_aio_ctx *ctx,
133 const struct ublksrv_queue *q);
134 int ublksrv_aio_get_efd(struct ublksrv_aio_ctx *ctx);
135 void ublksrv_aio_set_ctx_data(struct ublksrv_aio_ctx *ctx, void *data);
136 void *ublksrv_aio_get_ctx_data(struct ublksrv_aio_ctx *ctx);
137 bool ublksrv_aio_ctx_dead(struct ublksrv_aio_ctx *ctx);
138 const struct ublksrv_dev *ublksrv_aio_get_dev(struct ublksrv_aio_ctx *ctx);
139
140 #ifdef __cplusplus
141 }
142 #endif
143 #endif
144