1*94c4a1e1SFrank Piva // SPDX-License-Identifier: MIT or LGPL-2.1-only
2*94c4a1e1SFrank Piva
3*94c4a1e1SFrank Piva #ifndef _GNU_SOURCE
4*94c4a1e1SFrank Piva #define _GNU_SOURCE
5*94c4a1e1SFrank Piva #endif
6*94c4a1e1SFrank Piva
7*94c4a1e1SFrank Piva #include "ublksrv_priv.h"
8*94c4a1e1SFrank Piva
9*94c4a1e1SFrank Piva #define aio_log ublk_log
10*94c4a1e1SFrank Piva
ublksrv_aio_submit_worker(struct ublksrv_aio_ctx * ctx,ublksrv_aio_submit_fn * fn,struct aio_list * done)11*94c4a1e1SFrank Piva int ublksrv_aio_submit_worker(struct ublksrv_aio_ctx *ctx,
12*94c4a1e1SFrank Piva ublksrv_aio_submit_fn *fn, struct aio_list *done)
13*94c4a1e1SFrank Piva {
14*94c4a1e1SFrank Piva struct ublksrv_aio *req = NULL;
15*94c4a1e1SFrank Piva unsigned long long data;
16*94c4a1e1SFrank Piva struct aio_list sl;
17*94c4a1e1SFrank Piva int total = 0;
18*94c4a1e1SFrank Piva bool more;
19*94c4a1e1SFrank Piva
20*94c4a1e1SFrank Piva aio_list_init(&sl);
21*94c4a1e1SFrank Piva again:
22*94c4a1e1SFrank Piva pthread_spin_lock(&ctx->submit.lock);
23*94c4a1e1SFrank Piva aio_list_splice(&ctx->submit.list, &sl);
24*94c4a1e1SFrank Piva pthread_spin_unlock(&ctx->submit.lock);
25*94c4a1e1SFrank Piva
26*94c4a1e1SFrank Piva while ((req = aio_list_pop(&sl))) {
27*94c4a1e1SFrank Piva int ret = fn(ctx, req);
28*94c4a1e1SFrank Piva
29*94c4a1e1SFrank Piva /*
30*94c4a1e1SFrank Piva * submission failed, so set result for this request,
31*94c4a1e1SFrank Piva * otherwise it is user's responsibility to set correct
32*94c4a1e1SFrank Piva * ->res after the request is completed
33*94c4a1e1SFrank Piva */
34*94c4a1e1SFrank Piva if (ret < 0) {
35*94c4a1e1SFrank Piva req->res = ret;
36*94c4a1e1SFrank Piva aio_log("ublk aio submission fail, %d\n", ret);
37*94c4a1e1SFrank Piva }
38*94c4a1e1SFrank Piva total += 1;
39*94c4a1e1SFrank Piva if (ret && done)
40*94c4a1e1SFrank Piva aio_list_add(done, req);
41*94c4a1e1SFrank Piva }
42*94c4a1e1SFrank Piva
43*94c4a1e1SFrank Piva ublk_ignore_result(read(ctx->efd, &data, 8));
44*94c4a1e1SFrank Piva
45*94c4a1e1SFrank Piva pthread_spin_lock(&ctx->submit.lock);
46*94c4a1e1SFrank Piva more = !aio_list_empty(&ctx->submit.list);
47*94c4a1e1SFrank Piva pthread_spin_unlock(&ctx->submit.lock);
48*94c4a1e1SFrank Piva if (more)
49*94c4a1e1SFrank Piva goto again;
50*94c4a1e1SFrank Piva
51*94c4a1e1SFrank Piva return total;
52*94c4a1e1SFrank Piva }
53*94c4a1e1SFrank Piva
move_to_queue_complete_list(struct ublksrv_aio_ctx * ctx,struct _ublksrv_queue * q,struct aio_list * list)54*94c4a1e1SFrank Piva static void move_to_queue_complete_list(struct ublksrv_aio_ctx *ctx,
55*94c4a1e1SFrank Piva struct _ublksrv_queue *q, struct aio_list *list)
56*94c4a1e1SFrank Piva {
57*94c4a1e1SFrank Piva struct ublksrv_aio_list *compl;
58*94c4a1e1SFrank Piva
59*94c4a1e1SFrank Piva if (aio_list_empty(list))
60*94c4a1e1SFrank Piva return;
61*94c4a1e1SFrank Piva
62*94c4a1e1SFrank Piva compl = &ctx->complete[q->q_id];
63*94c4a1e1SFrank Piva pthread_spin_lock(&compl->lock);
64*94c4a1e1SFrank Piva aio_list_splice(list, &compl->list);
65*94c4a1e1SFrank Piva pthread_spin_unlock(&compl->lock);
66*94c4a1e1SFrank Piva }
67*94c4a1e1SFrank Piva
ublksrv_aio_complete_worker(struct ublksrv_aio_ctx * ctx,struct aio_list * completed)68*94c4a1e1SFrank Piva void ublksrv_aio_complete_worker(struct ublksrv_aio_ctx *ctx,
69*94c4a1e1SFrank Piva struct aio_list *completed)
70*94c4a1e1SFrank Piva {
71*94c4a1e1SFrank Piva struct aio_list this, others;
72*94c4a1e1SFrank Piva struct ublksrv_aio *req = NULL;
73*94c4a1e1SFrank Piva struct _ublksrv_queue *this_q = NULL;
74*94c4a1e1SFrank Piva
75*94c4a1e1SFrank Piva if (aio_list_empty(completed))
76*94c4a1e1SFrank Piva return;
77*94c4a1e1SFrank Piva
78*94c4a1e1SFrank Piva if (ctx->flags & UBLKSRV_AIO_QUEUE_WIDE) {
79*94c4a1e1SFrank Piva const struct ublksrv_queue *tq = ublksrv_get_queue(ctx->dev,
80*94c4a1e1SFrank Piva ublksrv_aio_qid(completed->head->id));
81*94c4a1e1SFrank Piva
82*94c4a1e1SFrank Piva this_q = tq_to_local(tq);
83*94c4a1e1SFrank Piva move_to_queue_complete_list(ctx, this_q, completed);
84*94c4a1e1SFrank Piva ublksrv_queue_send_event(tq);
85*94c4a1e1SFrank Piva return;
86*94c4a1e1SFrank Piva }
87*94c4a1e1SFrank Piva
88*94c4a1e1SFrank Piva aio_list_init(&this);
89*94c4a1e1SFrank Piva aio_list_init(&others);
90*94c4a1e1SFrank Piva
91*94c4a1e1SFrank Piva while (!aio_list_empty(completed)) {
92*94c4a1e1SFrank Piva const struct ublksrv_queue *tq = ublksrv_get_queue(ctx->dev,
93*94c4a1e1SFrank Piva ublksrv_aio_qid(completed->head->id));
94*94c4a1e1SFrank Piva
95*94c4a1e1SFrank Piva this_q = tq_to_local(tq);
96*94c4a1e1SFrank Piva while ((req = aio_list_pop(completed))) {
97*94c4a1e1SFrank Piva const struct ublksrv_queue *q = ublksrv_get_queue(
98*94c4a1e1SFrank Piva ctx->dev, ublksrv_aio_qid(req->id));
99*94c4a1e1SFrank Piva
100*94c4a1e1SFrank Piva if (q == local_to_tq(this_q))
101*94c4a1e1SFrank Piva aio_list_add(&this, req);
102*94c4a1e1SFrank Piva else
103*94c4a1e1SFrank Piva aio_list_add(&others, req);
104*94c4a1e1SFrank Piva }
105*94c4a1e1SFrank Piva
106*94c4a1e1SFrank Piva move_to_queue_complete_list(ctx, this_q, &this);
107*94c4a1e1SFrank Piva ublksrv_queue_send_event(tq);
108*94c4a1e1SFrank Piva aio_list_splice(&others, completed);
109*94c4a1e1SFrank Piva }
110*94c4a1e1SFrank Piva }
111*94c4a1e1SFrank Piva
ublksrv_aio_ctx_init(const struct ublksrv_dev * dev,unsigned flags)112*94c4a1e1SFrank Piva struct ublksrv_aio_ctx *ublksrv_aio_ctx_init(const struct ublksrv_dev *dev,
113*94c4a1e1SFrank Piva unsigned flags)
114*94c4a1e1SFrank Piva {
115*94c4a1e1SFrank Piva unsigned nr_hw_queues = tdev_to_local(dev)->ctrl_dev->dev_info.nr_hw_queues;
116*94c4a1e1SFrank Piva struct ublksrv_aio_ctx *ctx;
117*94c4a1e1SFrank Piva int i;
118*94c4a1e1SFrank Piva
119*94c4a1e1SFrank Piva if (!(tdev_to_local(dev)->ctrl_dev->dev_info.ublksrv_flags & UBLKSRV_F_NEED_EVENTFD))
120*94c4a1e1SFrank Piva return NULL;
121*94c4a1e1SFrank Piva
122*94c4a1e1SFrank Piva ctx = calloc(1, sizeof(*ctx));
123*94c4a1e1SFrank Piva if (!ctx)
124*94c4a1e1SFrank Piva return NULL;
125*94c4a1e1SFrank Piva
126*94c4a1e1SFrank Piva ctx->complete = malloc(nr_hw_queues * sizeof(struct ublksrv_aio_list));
127*94c4a1e1SFrank Piva if (!ctx->complete) {
128*94c4a1e1SFrank Piva free(ctx);
129*94c4a1e1SFrank Piva return NULL;
130*94c4a1e1SFrank Piva }
131*94c4a1e1SFrank Piva for (i = 0; i < nr_hw_queues; i++)
132*94c4a1e1SFrank Piva ublksrv_aio_init_list(&ctx->complete[i]);
133*94c4a1e1SFrank Piva
134*94c4a1e1SFrank Piva ublksrv_aio_init_list(&ctx->submit);
135*94c4a1e1SFrank Piva
136*94c4a1e1SFrank Piva ctx->flags = flags;
137*94c4a1e1SFrank Piva ctx->dev = dev;
138*94c4a1e1SFrank Piva ctx->dead = false;
139*94c4a1e1SFrank Piva ctx->efd = eventfd(0, O_NONBLOCK);
140*94c4a1e1SFrank Piva
141*94c4a1e1SFrank Piva return ctx;
142*94c4a1e1SFrank Piva }
143*94c4a1e1SFrank Piva
144*94c4a1e1SFrank Piva /* called before pthread_join() of the pthread context */
ublksrv_aio_ctx_shutdown(struct ublksrv_aio_ctx * ctx)145*94c4a1e1SFrank Piva void ublksrv_aio_ctx_shutdown(struct ublksrv_aio_ctx *ctx)
146*94c4a1e1SFrank Piva {
147*94c4a1e1SFrank Piva unsigned long long data = 1;
148*94c4a1e1SFrank Piva int ret;
149*94c4a1e1SFrank Piva
150*94c4a1e1SFrank Piva ctx->dead = true;
151*94c4a1e1SFrank Piva ret = write(ctx->efd, &data, 8);
152*94c4a1e1SFrank Piva if (ret != 8)
153*94c4a1e1SFrank Piva ublk_err("%s:%d write fail %d/%d\n",
154*94c4a1e1SFrank Piva __func__, __LINE__, ret, 8);
155*94c4a1e1SFrank Piva }
156*94c4a1e1SFrank Piva
157*94c4a1e1SFrank Piva /* called afer pthread_join() of the pthread context returns */
ublksrv_aio_ctx_deinit(struct ublksrv_aio_ctx * ctx)158*94c4a1e1SFrank Piva void ublksrv_aio_ctx_deinit(struct ublksrv_aio_ctx *ctx)
159*94c4a1e1SFrank Piva {
160*94c4a1e1SFrank Piva close(ctx->efd);
161*94c4a1e1SFrank Piva free(ctx);
162*94c4a1e1SFrank Piva }
163*94c4a1e1SFrank Piva
ublksrv_aio_alloc_req(struct ublksrv_aio_ctx * ctx,int payload_size)164*94c4a1e1SFrank Piva struct ublksrv_aio *ublksrv_aio_alloc_req(struct ublksrv_aio_ctx *ctx,
165*94c4a1e1SFrank Piva int payload_size)
166*94c4a1e1SFrank Piva {
167*94c4a1e1SFrank Piva const int sz = (sizeof(struct ublksrv_aio) + payload_size + 7) & ~ 0x7;
168*94c4a1e1SFrank Piva
169*94c4a1e1SFrank Piva return (struct ublksrv_aio *)calloc(1, sz);
170*94c4a1e1SFrank Piva }
171*94c4a1e1SFrank Piva
ublksrv_aio_free_req(struct ublksrv_aio_ctx * ctx,struct ublksrv_aio * req)172*94c4a1e1SFrank Piva void ublksrv_aio_free_req(struct ublksrv_aio_ctx *ctx, struct ublksrv_aio *req)
173*94c4a1e1SFrank Piva {
174*94c4a1e1SFrank Piva free(req);
175*94c4a1e1SFrank Piva }
176*94c4a1e1SFrank Piva
ublksrv_aio_add_ctx_for_submit(struct _ublksrv_queue * q,struct ublksrv_aio_ctx * ctx)177*94c4a1e1SFrank Piva static bool ublksrv_aio_add_ctx_for_submit(struct _ublksrv_queue *q,
178*94c4a1e1SFrank Piva struct ublksrv_aio_ctx *ctx)
179*94c4a1e1SFrank Piva {
180*94c4a1e1SFrank Piva int i = 0;
181*94c4a1e1SFrank Piva
182*94c4a1e1SFrank Piva for (i = 0; i < q->nr_ctxs; i++) {
183*94c4a1e1SFrank Piva if (q->ctxs[i] == ctx)
184*94c4a1e1SFrank Piva return true;
185*94c4a1e1SFrank Piva }
186*94c4a1e1SFrank Piva
187*94c4a1e1SFrank Piva if (q->nr_ctxs < UBLKSRV_NR_CTX_BATCH - 1) {
188*94c4a1e1SFrank Piva q->ctxs[q->nr_ctxs++] = ctx;
189*94c4a1e1SFrank Piva return true;
190*94c4a1e1SFrank Piva }
191*94c4a1e1SFrank Piva
192*94c4a1e1SFrank Piva return false;
193*94c4a1e1SFrank Piva }
194*94c4a1e1SFrank Piva
ublksrv_aio_submit_req(struct ublksrv_aio_ctx * ctx,const struct ublksrv_queue * tq,struct ublksrv_aio * req)195*94c4a1e1SFrank Piva void ublksrv_aio_submit_req(struct ublksrv_aio_ctx *ctx,
196*94c4a1e1SFrank Piva const struct ublksrv_queue *tq, struct ublksrv_aio *req)
197*94c4a1e1SFrank Piva {
198*94c4a1e1SFrank Piva struct _ublksrv_queue *q = tq_to_local(tq);
199*94c4a1e1SFrank Piva unsigned long long data = 1;
200*94c4a1e1SFrank Piva
201*94c4a1e1SFrank Piva pthread_spin_lock(&ctx->submit.lock);
202*94c4a1e1SFrank Piva aio_list_add(&ctx->submit.list, req);
203*94c4a1e1SFrank Piva pthread_spin_unlock(&ctx->submit.lock);
204*94c4a1e1SFrank Piva
205*94c4a1e1SFrank Piva if (!ublksrv_aio_add_ctx_for_submit(q, ctx)) {
206*94c4a1e1SFrank Piva int ret = write(ctx->efd, &data, 8);
207*94c4a1e1SFrank Piva
208*94c4a1e1SFrank Piva if (ret != 8)
209*94c4a1e1SFrank Piva ublk_err("%s:%d write fail %d/%d\n",
210*94c4a1e1SFrank Piva __func__, __LINE__, ret, 8);
211*94c4a1e1SFrank Piva }
212*94c4a1e1SFrank Piva }
213*94c4a1e1SFrank Piva
ublksrv_aio_get_completed_reqs(struct ublksrv_aio_ctx * ctx,const struct ublksrv_queue * q,struct aio_list * al)214*94c4a1e1SFrank Piva void ublksrv_aio_get_completed_reqs(struct ublksrv_aio_ctx *ctx,
215*94c4a1e1SFrank Piva const struct ublksrv_queue *q,
216*94c4a1e1SFrank Piva struct aio_list *al)
217*94c4a1e1SFrank Piva {
218*94c4a1e1SFrank Piva struct ublksrv_aio_list *compl = &ctx->complete[q->q_id];
219*94c4a1e1SFrank Piva
220*94c4a1e1SFrank Piva pthread_spin_lock(&compl->lock);
221*94c4a1e1SFrank Piva aio_list_splice(&compl->list, al);
222*94c4a1e1SFrank Piva pthread_spin_unlock(&compl->lock);
223*94c4a1e1SFrank Piva }
224*94c4a1e1SFrank Piva
ublksrv_aio_handle_event(struct ublksrv_aio_ctx * ctx,const struct ublksrv_queue * q)225*94c4a1e1SFrank Piva void ublksrv_aio_handle_event(struct ublksrv_aio_ctx *ctx,
226*94c4a1e1SFrank Piva const struct ublksrv_queue *q)
227*94c4a1e1SFrank Piva {
228*94c4a1e1SFrank Piva struct ublksrv_aio_list *compl = &ctx->complete[q->q_id];
229*94c4a1e1SFrank Piva struct ublksrv_aio *req;
230*94c4a1e1SFrank Piva struct aio_list al;
231*94c4a1e1SFrank Piva
232*94c4a1e1SFrank Piva aio_list_init(&al);
233*94c4a1e1SFrank Piva pthread_spin_lock(&compl->lock);
234*94c4a1e1SFrank Piva aio_list_splice(&compl->list, &al);
235*94c4a1e1SFrank Piva ublksrv_queue_handled_event(q);
236*94c4a1e1SFrank Piva pthread_spin_unlock(&compl->lock);
237*94c4a1e1SFrank Piva
238*94c4a1e1SFrank Piva while ((req = aio_list_pop(&al))) {
239*94c4a1e1SFrank Piva ublksrv_complete_io(q, ublksrv_aio_tag(req->id),
240*94c4a1e1SFrank Piva req->res);
241*94c4a1e1SFrank Piva ublksrv_aio_free_req(ctx, req);
242*94c4a1e1SFrank Piva }
243*94c4a1e1SFrank Piva }
244*94c4a1e1SFrank Piva
ublksrv_aio_get_efd(struct ublksrv_aio_ctx * ctx)245*94c4a1e1SFrank Piva int ublksrv_aio_get_efd(struct ublksrv_aio_ctx *ctx)
246*94c4a1e1SFrank Piva {
247*94c4a1e1SFrank Piva return ctx->efd;
248*94c4a1e1SFrank Piva }
249*94c4a1e1SFrank Piva
ublksrv_aio_set_ctx_data(struct ublksrv_aio_ctx * ctx,void * data)250*94c4a1e1SFrank Piva void ublksrv_aio_set_ctx_data(struct ublksrv_aio_ctx *ctx, void *data)
251*94c4a1e1SFrank Piva {
252*94c4a1e1SFrank Piva ctx->ctx_data = data;
253*94c4a1e1SFrank Piva }
254*94c4a1e1SFrank Piva
ublksrv_aio_get_ctx_data(struct ublksrv_aio_ctx * ctx)255*94c4a1e1SFrank Piva void *ublksrv_aio_get_ctx_data(struct ublksrv_aio_ctx *ctx)
256*94c4a1e1SFrank Piva {
257*94c4a1e1SFrank Piva return ctx->ctx_data;
258*94c4a1e1SFrank Piva }
259*94c4a1e1SFrank Piva
ublksrv_aio_ctx_dead(struct ublksrv_aio_ctx * ctx)260*94c4a1e1SFrank Piva bool ublksrv_aio_ctx_dead(struct ublksrv_aio_ctx *ctx)
261*94c4a1e1SFrank Piva {
262*94c4a1e1SFrank Piva return ctx->dead;
263*94c4a1e1SFrank Piva }
264*94c4a1e1SFrank Piva
ublksrv_aio_get_dev(struct ublksrv_aio_ctx * ctx)265*94c4a1e1SFrank Piva const struct ublksrv_dev *ublksrv_aio_get_dev(struct ublksrv_aio_ctx *ctx)
266*94c4a1e1SFrank Piva {
267*94c4a1e1SFrank Piva return ctx->dev;
268*94c4a1e1SFrank Piva }
269