]> git.proxmox.com Git - mirror_qemu.git/blame - block/archipelago.c
block/archipelago: Implement bdrv_parse_filename()
[mirror_qemu.git] / block / archipelago.c
CommitLineData
c9a12e75
CN
1/*
2 * QEMU Block driver for Archipelago
3 *
4 * Copyright (C) 2014 Chrysostomos Nanakos <cnanakos@grnet.gr>
5 *
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
8 *
9 */
10
11/*
12 * VM Image on Archipelago volume is specified like this:
13 *
14 * file.driver=archipelago,file.volume=<volumename>
15 * [,file.mport=<mapperd_port>[,file.vport=<vlmcd_port>]
16 * [,file.segment=<segment_name>]]
17 *
70537a85
CN
18 * or
19 *
20 * file=archipelago:<volumename>[/mport=<mapperd_port>[:vport=<vlmcd_port>][:
21 * segment=<segment_name>]]
22 *
c9a12e75
CN
23 * 'archipelago' is the protocol.
24 *
25 * 'mport' is the port number on which mapperd is listening. This is optional
26 * and if not specified, QEMU will make Archipelago to use the default port.
27 *
28 * 'vport' is the port number on which vlmcd is listening. This is optional
29 * and if not specified, QEMU will make Archipelago to use the default port.
30 *
31 * 'segment' is the name of the shared memory segment Archipelago stack
32 * is using. This is optional and if not specified, QEMU will make Archipelago
33 * to use the default value, 'archipelago'.
34 *
35 * Examples:
36 *
37 * file.driver=archipelago,file.volume=my_vm_volume
38 * file.driver=archipelago,file.volume=my_vm_volume,file.mport=123
39 * file.driver=archipelago,file.volume=my_vm_volume,file.mport=123,
70537a85 40 * file.vport=1234
c9a12e75 41 * file.driver=archipelago,file.volume=my_vm_volume,file.mport=123,
70537a85
CN
42 * file.vport=1234,file.segment=my_segment
43 *
44 * or
45 *
46 * file=archipelago:my_vm_volume
47 * file=archipelago:my_vm_volume/mport=123
48 * file=archipelago:my_vm_volume/mport=123:vport=1234
49 * file=archipelago:my_vm_volume/mport=123:vport=1234:segment=my_segment
50 *
c9a12e75
CN
51 */
52
70537a85 53#include "qemu-common.h"
c9a12e75
CN
54#include "block/block_int.h"
55#include "qemu/error-report.h"
56#include "qemu/thread.h"
57#include "qapi/qmp/qint.h"
58#include "qapi/qmp/qstring.h"
59#include "qapi/qmp/qjson.h"
60
61#include <inttypes.h>
62#include <xseg/xseg.h>
63#include <xseg/protocol.h>
64
65#define ARCHIP_FD_READ 0
66#define ARCHIP_FD_WRITE 1
67#define MAX_REQUEST_SIZE 524288
68
69#define ARCHIPELAGO_OPT_VOLUME "volume"
70#define ARCHIPELAGO_OPT_SEGMENT "segment"
71#define ARCHIPELAGO_OPT_MPORT "mport"
72#define ARCHIPELAGO_OPT_VPORT "vport"
73#define ARCHIPELAGO_DFL_MPORT 1001
74#define ARCHIPELAGO_DFL_VPORT 501
75
76#define archipelagolog(fmt, ...) \
77 do { \
78 fprintf(stderr, "archipelago\t%-24s: " fmt, __func__, ##__VA_ARGS__); \
79 } while (0)
80
81typedef enum {
82 ARCHIP_OP_READ,
83 ARCHIP_OP_WRITE,
84 ARCHIP_OP_FLUSH,
85 ARCHIP_OP_VOLINFO,
86} ARCHIPCmd;
87
88typedef struct ArchipelagoAIOCB {
89 BlockDriverAIOCB common;
90 QEMUBH *bh;
91 struct BDRVArchipelagoState *s;
92 QEMUIOVector *qiov;
93 ARCHIPCmd cmd;
94 bool cancelled;
95 int status;
96 int64_t size;
97 int64_t ret;
98} ArchipelagoAIOCB;
99
100typedef struct BDRVArchipelagoState {
101 ArchipelagoAIOCB *event_acb;
102 char *volname;
103 char *segment_name;
104 uint64_t size;
105 /* Archipelago specific */
106 struct xseg *xseg;
107 struct xseg_port *port;
108 xport srcport;
109 xport sport;
110 xport mportno;
111 xport vportno;
112 QemuMutex archip_mutex;
113 QemuCond archip_cond;
114 bool is_signaled;
115 /* Request handler specific */
116 QemuThread request_th;
117 QemuCond request_cond;
118 QemuMutex request_mutex;
119 bool th_is_signaled;
120 bool stopping;
121} BDRVArchipelagoState;
122
123typedef struct ArchipelagoSegmentedRequest {
124 size_t count;
125 size_t total;
126 int ref;
127 int failed;
128} ArchipelagoSegmentedRequest;
129
130typedef struct AIORequestData {
131 const char *volname;
132 off_t offset;
133 size_t size;
134 uint64_t bufidx;
135 int ret;
136 int op;
137 ArchipelagoAIOCB *aio_cb;
138 ArchipelagoSegmentedRequest *segreq;
139} AIORequestData;
140
141static void qemu_archipelago_complete_aio(void *opaque);
142
143static void init_local_signal(struct xseg *xseg, xport sport, xport srcport)
144{
145 if (xseg && (sport != srcport)) {
146 xseg_init_local_signal(xseg, srcport);
147 sport = srcport;
148 }
149}
150
151static void archipelago_finish_aiocb(AIORequestData *reqdata)
152{
153 if (reqdata->aio_cb->ret != reqdata->segreq->total) {
154 reqdata->aio_cb->ret = -EIO;
155 } else if (reqdata->aio_cb->ret == reqdata->segreq->total) {
156 reqdata->aio_cb->ret = 0;
157 }
158 reqdata->aio_cb->bh = aio_bh_new(
159 bdrv_get_aio_context(reqdata->aio_cb->common.bs),
160 qemu_archipelago_complete_aio, reqdata
161 );
162 qemu_bh_schedule(reqdata->aio_cb->bh);
163}
164
165static int wait_reply(struct xseg *xseg, xport srcport, struct xseg_port *port,
166 struct xseg_request *expected_req)
167{
168 struct xseg_request *req;
169 xseg_prepare_wait(xseg, srcport);
170 void *psd = xseg_get_signal_desc(xseg, port);
171 while (1) {
172 req = xseg_receive(xseg, srcport, X_NONBLOCK);
173 if (req) {
174 if (req != expected_req) {
175 archipelagolog("Unknown received request\n");
176 xseg_put_request(xseg, req, srcport);
177 } else if (!(req->state & XS_SERVED)) {
178 return -1;
179 } else {
180 break;
181 }
182 }
183 xseg_wait_signal(xseg, psd, 100000UL);
184 }
185 xseg_cancel_wait(xseg, srcport);
186 return 0;
187}
188
189static void xseg_request_handler(void *state)
190{
191 BDRVArchipelagoState *s = (BDRVArchipelagoState *) state;
192 void *psd = xseg_get_signal_desc(s->xseg, s->port);
193 qemu_mutex_lock(&s->request_mutex);
194
195 while (!s->stopping) {
196 struct xseg_request *req;
197 void *data;
198 xseg_prepare_wait(s->xseg, s->srcport);
199 req = xseg_receive(s->xseg, s->srcport, X_NONBLOCK);
200 if (req) {
201 AIORequestData *reqdata;
202 ArchipelagoSegmentedRequest *segreq;
203 xseg_get_req_data(s->xseg, req, (void **)&reqdata);
204
205 switch (reqdata->op) {
206 case ARCHIP_OP_READ:
207 data = xseg_get_data(s->xseg, req);
208 segreq = reqdata->segreq;
209 segreq->count += req->serviced;
210
211 qemu_iovec_from_buf(reqdata->aio_cb->qiov, reqdata->bufidx,
212 data,
213 req->serviced);
214
215 xseg_put_request(s->xseg, req, s->srcport);
216
217 if ((__sync_add_and_fetch(&segreq->ref, -1)) == 0) {
218 if (!segreq->failed) {
219 reqdata->aio_cb->ret = segreq->count;
220 archipelago_finish_aiocb(reqdata);
221 g_free(segreq);
222 } else {
223 g_free(segreq);
224 g_free(reqdata);
225 }
226 } else {
227 g_free(reqdata);
228 }
229 break;
230 case ARCHIP_OP_WRITE:
231 case ARCHIP_OP_FLUSH:
232 segreq = reqdata->segreq;
233 segreq->count += req->serviced;
234 xseg_put_request(s->xseg, req, s->srcport);
235
236 if ((__sync_add_and_fetch(&segreq->ref, -1)) == 0) {
237 if (!segreq->failed) {
238 reqdata->aio_cb->ret = segreq->count;
239 archipelago_finish_aiocb(reqdata);
240 g_free(segreq);
241 } else {
242 g_free(segreq);
243 g_free(reqdata);
244 }
245 } else {
246 g_free(reqdata);
247 }
248 break;
249 case ARCHIP_OP_VOLINFO:
250 s->is_signaled = true;
251 qemu_cond_signal(&s->archip_cond);
252 break;
253 }
254 } else {
255 xseg_wait_signal(s->xseg, psd, 100000UL);
256 }
257 xseg_cancel_wait(s->xseg, s->srcport);
258 }
259
260 s->th_is_signaled = true;
261 qemu_cond_signal(&s->request_cond);
262 qemu_mutex_unlock(&s->request_mutex);
263 qemu_thread_exit(NULL);
264}
265
266static int qemu_archipelago_xseg_init(BDRVArchipelagoState *s)
267{
268 if (xseg_initialize()) {
269 archipelagolog("Cannot initialize XSEG\n");
270 goto err_exit;
271 }
272
273 s->xseg = xseg_join("posix", s->segment_name,
274 "posixfd", NULL);
275 if (!s->xseg) {
276 archipelagolog("Cannot join XSEG shared memory segment\n");
277 goto err_exit;
278 }
279 s->port = xseg_bind_dynport(s->xseg);
280 s->srcport = s->port->portno;
281 init_local_signal(s->xseg, s->sport, s->srcport);
282 return 0;
283
284err_exit:
285 return -1;
286}
287
288static int qemu_archipelago_init(BDRVArchipelagoState *s)
289{
290 int ret;
291
292 ret = qemu_archipelago_xseg_init(s);
293 if (ret < 0) {
294 error_report("Cannot initialize XSEG. Aborting...\n");
295 goto err_exit;
296 }
297
298 qemu_cond_init(&s->archip_cond);
299 qemu_mutex_init(&s->archip_mutex);
300 qemu_cond_init(&s->request_cond);
301 qemu_mutex_init(&s->request_mutex);
302 s->th_is_signaled = false;
303 qemu_thread_create(&s->request_th, "xseg_io_th",
304 (void *) xseg_request_handler,
305 (void *) s, QEMU_THREAD_JOINABLE);
306
307err_exit:
308 return ret;
309}
310
311static void qemu_archipelago_complete_aio(void *opaque)
312{
313 AIORequestData *reqdata = (AIORequestData *) opaque;
314 ArchipelagoAIOCB *aio_cb = (ArchipelagoAIOCB *) reqdata->aio_cb;
315
316 qemu_bh_delete(aio_cb->bh);
317 aio_cb->common.cb(aio_cb->common.opaque, aio_cb->ret);
318 aio_cb->status = 0;
319
320 if (!aio_cb->cancelled) {
321 qemu_aio_release(aio_cb);
322 }
323 g_free(reqdata);
324}
325
70537a85
CN
326static void xseg_find_port(char *pstr, const char *needle, xport *aport)
327{
328 const char *a;
329 char *endptr = NULL;
330 unsigned long port;
331 if (strstart(pstr, needle, &a)) {
332 if (strlen(a) > 0) {
333 port = strtoul(a, &endptr, 10);
334 if (strlen(endptr)) {
335 *aport = -2;
336 return;
337 }
338 *aport = (xport) port;
339 }
340 }
341}
342
343static void xseg_find_segment(char *pstr, const char *needle,
344 char **segment_name)
345{
346 const char *a;
347 if (strstart(pstr, needle, &a)) {
348 if (strlen(a) > 0) {
349 *segment_name = g_strdup(a);
350 }
351 }
352}
353
354static void parse_filename_opts(const char *filename, Error **errp,
355 char **volume, char **segment_name,
356 xport *mport, xport *vport)
357{
358 const char *start;
359 char *tokens[4], *ds;
360 int idx;
361 xport lmport = NoPort, lvport = NoPort;
362
363 strstart(filename, "archipelago:", &start);
364
365 ds = g_strdup(start);
366 tokens[0] = strtok(ds, "/");
367 tokens[1] = strtok(NULL, ":");
368 tokens[2] = strtok(NULL, ":");
369 tokens[3] = strtok(NULL, "\0");
370
371 if (!strlen(tokens[0])) {
372 error_setg(errp, "volume name must be specified first");
373 g_free(ds);
374 return;
375 }
376
377 for (idx = 1; idx < 4; idx++) {
378 if (tokens[idx] != NULL) {
379 if (strstart(tokens[idx], "mport=", NULL)) {
380 xseg_find_port(tokens[idx], "mport=", &lmport);
381 }
382 if (strstart(tokens[idx], "vport=", NULL)) {
383 xseg_find_port(tokens[idx], "vport=", &lvport);
384 }
385 if (strstart(tokens[idx], "segment=", NULL)) {
386 xseg_find_segment(tokens[idx], "segment=", segment_name);
387 }
388 }
389 }
390
391 if ((lmport == -2) || (lvport == -2)) {
392 error_setg(errp, "mport and/or vport must be set");
393 g_free(ds);
394 return;
395 }
396 *volume = g_strdup(tokens[0]);
397 *mport = lmport;
398 *vport = lvport;
399 g_free(ds);
400}
401
402static void archipelago_parse_filename(const char *filename, QDict *options,
403 Error **errp)
404{
405 const char *start;
406 char *volume = NULL, *segment_name = NULL;
407 xport mport = NoPort, vport = NoPort;
408
409 if (qdict_haskey(options, ARCHIPELAGO_OPT_VOLUME)
410 || qdict_haskey(options, ARCHIPELAGO_OPT_SEGMENT)
411 || qdict_haskey(options, ARCHIPELAGO_OPT_MPORT)
412 || qdict_haskey(options, ARCHIPELAGO_OPT_VPORT)) {
413 error_setg(errp, "volume/mport/vport/segment and a file name may not"
414 " be specified at the same time");
415 return;
416 }
417
418 if (!strstart(filename, "archipelago:", &start)) {
419 error_setg(errp, "File name must start with 'archipelago:'");
420 return;
421 }
422
423 if (!strlen(start) || strstart(start, "/", NULL)) {
424 error_setg(errp, "volume name must be specified");
425 return;
426 }
427
428 parse_filename_opts(filename, errp, &volume, &segment_name, &mport, &vport);
429
430 if (volume) {
431 qdict_put(options, ARCHIPELAGO_OPT_VOLUME, qstring_from_str(volume));
432 g_free(volume);
433 }
434 if (segment_name) {
435 qdict_put(options, ARCHIPELAGO_OPT_SEGMENT,
436 qstring_from_str(segment_name));
437 g_free(segment_name);
438 }
439 if (mport != NoPort) {
440 qdict_put(options, ARCHIPELAGO_OPT_MPORT, qint_from_int(mport));
441 }
442 if (vport != NoPort) {
443 qdict_put(options, ARCHIPELAGO_OPT_VPORT, qint_from_int(vport));
444 }
445}
446
c9a12e75
CN
447static QemuOptsList archipelago_runtime_opts = {
448 .name = "archipelago",
449 .head = QTAILQ_HEAD_INITIALIZER(archipelago_runtime_opts.head),
450 .desc = {
451 {
452 .name = ARCHIPELAGO_OPT_VOLUME,
453 .type = QEMU_OPT_STRING,
454 .help = "Name of the volume image",
455 },
456 {
457 .name = ARCHIPELAGO_OPT_SEGMENT,
458 .type = QEMU_OPT_STRING,
459 .help = "Name of the Archipelago shared memory segment",
460 },
461 {
462 .name = ARCHIPELAGO_OPT_MPORT,
463 .type = QEMU_OPT_NUMBER,
464 .help = "Archipelago mapperd port number"
465 },
466 {
467 .name = ARCHIPELAGO_OPT_VPORT,
468 .type = QEMU_OPT_NUMBER,
469 .help = "Archipelago vlmcd port number"
470
471 },
472 { /* end of list */ }
473 },
474};
475
476static int qemu_archipelago_open(BlockDriverState *bs,
477 QDict *options,
478 int bdrv_flags,
479 Error **errp)
480{
481 int ret = 0;
482 const char *volume, *segment_name;
483 QemuOpts *opts;
484 Error *local_err = NULL;
485 BDRVArchipelagoState *s = bs->opaque;
486
487 opts = qemu_opts_create(&archipelago_runtime_opts, NULL, 0, &error_abort);
488 qemu_opts_absorb_qdict(opts, options, &local_err);
489 if (local_err) {
490 error_propagate(errp, local_err);
491 ret = -EINVAL;
492 goto err_exit;
493 }
494
495 s->mportno = qemu_opt_get_number(opts, ARCHIPELAGO_OPT_MPORT,
496 ARCHIPELAGO_DFL_MPORT);
497 s->vportno = qemu_opt_get_number(opts, ARCHIPELAGO_OPT_VPORT,
498 ARCHIPELAGO_DFL_VPORT);
499
500 segment_name = qemu_opt_get(opts, ARCHIPELAGO_OPT_SEGMENT);
501 if (segment_name == NULL) {
502 s->segment_name = g_strdup("archipelago");
503 } else {
504 s->segment_name = g_strdup(segment_name);
505 }
506
507 volume = qemu_opt_get(opts, ARCHIPELAGO_OPT_VOLUME);
508 if (volume == NULL) {
509 error_setg(errp, "archipelago block driver requires the 'volume'"
510 " option");
511 ret = -EINVAL;
512 goto err_exit;
513 }
514 s->volname = g_strdup(volume);
515
516 /* Initialize XSEG, join shared memory segment */
517 ret = qemu_archipelago_init(s);
518 if (ret < 0) {
519 error_setg(errp, "cannot initialize XSEG and join shared "
520 "memory segment");
521 goto err_exit;
522 }
523
524 qemu_opts_del(opts);
525 return 0;
526
527err_exit:
528 g_free(s->volname);
529 g_free(s->segment_name);
530 qemu_opts_del(opts);
531 return ret;
532}
533
534static void qemu_archipelago_close(BlockDriverState *bs)
535{
536 int r, targetlen;
537 char *target;
538 struct xseg_request *req;
539 BDRVArchipelagoState *s = bs->opaque;
540
541 s->stopping = true;
542
543 qemu_mutex_lock(&s->request_mutex);
544 while (!s->th_is_signaled) {
545 qemu_cond_wait(&s->request_cond,
546 &s->request_mutex);
547 }
548 qemu_mutex_unlock(&s->request_mutex);
549 qemu_thread_join(&s->request_th);
550 qemu_cond_destroy(&s->request_cond);
551 qemu_mutex_destroy(&s->request_mutex);
552
553 qemu_cond_destroy(&s->archip_cond);
554 qemu_mutex_destroy(&s->archip_mutex);
555
556 targetlen = strlen(s->volname);
557 req = xseg_get_request(s->xseg, s->srcport, s->vportno, X_ALLOC);
558 if (!req) {
559 archipelagolog("Cannot get XSEG request\n");
560 goto err_exit;
561 }
562 r = xseg_prep_request(s->xseg, req, targetlen, 0);
563 if (r < 0) {
564 xseg_put_request(s->xseg, req, s->srcport);
565 archipelagolog("Cannot prepare XSEG close request\n");
566 goto err_exit;
567 }
568
569 target = xseg_get_target(s->xseg, req);
570 memcpy(target, s->volname, targetlen);
571 req->size = req->datalen;
572 req->offset = 0;
573 req->op = X_CLOSE;
574
575 xport p = xseg_submit(s->xseg, req, s->srcport, X_ALLOC);
576 if (p == NoPort) {
577 xseg_put_request(s->xseg, req, s->srcport);
578 archipelagolog("Cannot submit XSEG close request\n");
579 goto err_exit;
580 }
581
582 xseg_signal(s->xseg, p);
583 wait_reply(s->xseg, s->srcport, s->port, req);
584
585 xseg_put_request(s->xseg, req, s->srcport);
586
587err_exit:
588 g_free(s->volname);
589 g_free(s->segment_name);
590 xseg_quit_local_signal(s->xseg, s->srcport);
591 xseg_leave_dynport(s->xseg, s->port);
592 xseg_leave(s->xseg);
593}
594
595static void qemu_archipelago_aio_cancel(BlockDriverAIOCB *blockacb)
596{
597 ArchipelagoAIOCB *aio_cb = (ArchipelagoAIOCB *) blockacb;
598 aio_cb->cancelled = true;
599 while (aio_cb->status == -EINPROGRESS) {
600 aio_poll(bdrv_get_aio_context(aio_cb->common.bs), true);
601 }
602 qemu_aio_release(aio_cb);
603}
604
605static const AIOCBInfo archipelago_aiocb_info = {
606 .aiocb_size = sizeof(ArchipelagoAIOCB),
607 .cancel = qemu_archipelago_aio_cancel,
608};
609
610static int archipelago_submit_request(BDRVArchipelagoState *s,
611 uint64_t bufidx,
612 size_t count,
613 off_t offset,
614 ArchipelagoAIOCB *aio_cb,
615 ArchipelagoSegmentedRequest *segreq,
616 int op)
617{
618 int ret, targetlen;
619 char *target;
620 void *data = NULL;
621 struct xseg_request *req;
622 AIORequestData *reqdata = g_malloc(sizeof(AIORequestData));
623
624 targetlen = strlen(s->volname);
625 req = xseg_get_request(s->xseg, s->srcport, s->vportno, X_ALLOC);
626 if (!req) {
627 archipelagolog("Cannot get XSEG request\n");
628 goto err_exit2;
629 }
630 ret = xseg_prep_request(s->xseg, req, targetlen, count);
631 if (ret < 0) {
632 archipelagolog("Cannot prepare XSEG request\n");
633 goto err_exit;
634 }
635 target = xseg_get_target(s->xseg, req);
636 if (!target) {
637 archipelagolog("Cannot get XSEG target\n");
638 goto err_exit;
639 }
640 memcpy(target, s->volname, targetlen);
641 req->size = count;
642 req->offset = offset;
643
644 switch (op) {
645 case ARCHIP_OP_READ:
646 req->op = X_READ;
647 break;
648 case ARCHIP_OP_WRITE:
649 req->op = X_WRITE;
650 break;
651 case ARCHIP_OP_FLUSH:
652 req->op = X_FLUSH;
653 break;
654 }
655 reqdata->volname = s->volname;
656 reqdata->offset = offset;
657 reqdata->size = count;
658 reqdata->bufidx = bufidx;
659 reqdata->aio_cb = aio_cb;
660 reqdata->segreq = segreq;
661 reqdata->op = op;
662
663 xseg_set_req_data(s->xseg, req, reqdata);
664 if (op == ARCHIP_OP_WRITE) {
665 data = xseg_get_data(s->xseg, req);
666 if (!data) {
667 archipelagolog("Cannot get XSEG data\n");
668 goto err_exit;
669 }
670 qemu_iovec_to_buf(aio_cb->qiov, bufidx, data, count);
671 }
672
673 xport p = xseg_submit(s->xseg, req, s->srcport, X_ALLOC);
674 if (p == NoPort) {
675 archipelagolog("Could not submit XSEG request\n");
676 goto err_exit;
677 }
678 xseg_signal(s->xseg, p);
679 return 0;
680
681err_exit:
682 g_free(reqdata);
683 xseg_put_request(s->xseg, req, s->srcport);
684 return -EIO;
685err_exit2:
686 g_free(reqdata);
687 return -EIO;
688}
689
690static int archipelago_aio_segmented_rw(BDRVArchipelagoState *s,
691 size_t count,
692 off_t offset,
693 ArchipelagoAIOCB *aio_cb,
694 int op)
695{
696 int i, ret, segments_nr, last_segment_size;
697 ArchipelagoSegmentedRequest *segreq;
698
699 segreq = g_malloc(sizeof(ArchipelagoSegmentedRequest));
700
701 if (op == ARCHIP_OP_FLUSH) {
702 segments_nr = 1;
703 segreq->ref = segments_nr;
704 segreq->total = count;
705 segreq->count = 0;
706 segreq->failed = 0;
707 ret = archipelago_submit_request(s, 0, count, offset, aio_cb,
708 segreq, ARCHIP_OP_FLUSH);
709 if (ret < 0) {
710 goto err_exit;
711 }
712 return 0;
713 }
714
715 segments_nr = (int)(count / MAX_REQUEST_SIZE) + \
716 ((count % MAX_REQUEST_SIZE) ? 1 : 0);
717 last_segment_size = (int)(count % MAX_REQUEST_SIZE);
718
719 segreq->ref = segments_nr;
720 segreq->total = count;
721 segreq->count = 0;
722 segreq->failed = 0;
723
724 for (i = 0; i < segments_nr - 1; i++) {
725 ret = archipelago_submit_request(s, i * MAX_REQUEST_SIZE,
726 MAX_REQUEST_SIZE,
727 offset + i * MAX_REQUEST_SIZE,
728 aio_cb, segreq, op);
729
730 if (ret < 0) {
731 goto err_exit;
732 }
733 }
734
735 if ((segments_nr > 1) && last_segment_size) {
736 ret = archipelago_submit_request(s, i * MAX_REQUEST_SIZE,
737 last_segment_size,
738 offset + i * MAX_REQUEST_SIZE,
739 aio_cb, segreq, op);
740 } else if ((segments_nr > 1) && !last_segment_size) {
741 ret = archipelago_submit_request(s, i * MAX_REQUEST_SIZE,
742 MAX_REQUEST_SIZE,
743 offset + i * MAX_REQUEST_SIZE,
744 aio_cb, segreq, op);
745 } else if (segments_nr == 1) {
746 ret = archipelago_submit_request(s, 0, count, offset, aio_cb,
747 segreq, op);
748 }
749
750 if (ret < 0) {
751 goto err_exit;
752 }
753
754 return 0;
755
756err_exit:
757 __sync_add_and_fetch(&segreq->failed, 1);
758 if (segments_nr == 1) {
759 if (__sync_add_and_fetch(&segreq->ref, -1) == 0) {
760 g_free(segreq);
761 }
762 } else {
763 if ((__sync_add_and_fetch(&segreq->ref, -segments_nr + i)) == 0) {
764 g_free(segreq);
765 }
766 }
767
768 return ret;
769}
770
771static BlockDriverAIOCB *qemu_archipelago_aio_rw(BlockDriverState *bs,
772 int64_t sector_num,
773 QEMUIOVector *qiov,
774 int nb_sectors,
775 BlockDriverCompletionFunc *cb,
776 void *opaque,
777 int op)
778{
779 ArchipelagoAIOCB *aio_cb;
780 BDRVArchipelagoState *s = bs->opaque;
781 int64_t size, off;
782 int ret;
783
784 aio_cb = qemu_aio_get(&archipelago_aiocb_info, bs, cb, opaque);
785 aio_cb->cmd = op;
786 aio_cb->qiov = qiov;
787
788 aio_cb->ret = 0;
789 aio_cb->s = s;
790 aio_cb->cancelled = false;
791 aio_cb->status = -EINPROGRESS;
792
793 off = sector_num * BDRV_SECTOR_SIZE;
794 size = nb_sectors * BDRV_SECTOR_SIZE;
795 aio_cb->size = size;
796
797 ret = archipelago_aio_segmented_rw(s, size, off,
798 aio_cb, op);
799 if (ret < 0) {
800 goto err_exit;
801 }
802 return &aio_cb->common;
803
804err_exit:
805 error_report("qemu_archipelago_aio_rw(): I/O Error\n");
806 qemu_aio_release(aio_cb);
807 return NULL;
808}
809
810static BlockDriverAIOCB *qemu_archipelago_aio_readv(BlockDriverState *bs,
811 int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
812 BlockDriverCompletionFunc *cb, void *opaque)
813{
814 return qemu_archipelago_aio_rw(bs, sector_num, qiov, nb_sectors, cb,
815 opaque, ARCHIP_OP_READ);
816}
817
818static BlockDriverAIOCB *qemu_archipelago_aio_writev(BlockDriverState *bs,
819 int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
820 BlockDriverCompletionFunc *cb, void *opaque)
821{
822 return qemu_archipelago_aio_rw(bs, sector_num, qiov, nb_sectors, cb,
823 opaque, ARCHIP_OP_WRITE);
824}
825
826static int64_t archipelago_volume_info(BDRVArchipelagoState *s)
827{
828 uint64_t size;
829 int ret, targetlen;
830 struct xseg_request *req;
831 struct xseg_reply_info *xinfo;
832 AIORequestData *reqdata = g_malloc(sizeof(AIORequestData));
833
834 const char *volname = s->volname;
835 targetlen = strlen(volname);
836 req = xseg_get_request(s->xseg, s->srcport, s->mportno, X_ALLOC);
837 if (!req) {
838 archipelagolog("Cannot get XSEG request\n");
839 goto err_exit2;
840 }
841 ret = xseg_prep_request(s->xseg, req, targetlen,
842 sizeof(struct xseg_reply_info));
843 if (ret < 0) {
844 archipelagolog("Cannot prepare XSEG request\n");
845 goto err_exit;
846 }
847 char *target = xseg_get_target(s->xseg, req);
848 if (!target) {
849 archipelagolog("Cannot get XSEG target\n");
850 goto err_exit;
851 }
852 memcpy(target, volname, targetlen);
853 req->size = req->datalen;
854 req->offset = 0;
855 req->op = X_INFO;
856
857 reqdata->op = ARCHIP_OP_VOLINFO;
858 reqdata->volname = volname;
859 xseg_set_req_data(s->xseg, req, reqdata);
860
861 xport p = xseg_submit(s->xseg, req, s->srcport, X_ALLOC);
862 if (p == NoPort) {
863 archipelagolog("Cannot submit XSEG request\n");
864 goto err_exit;
865 }
866 xseg_signal(s->xseg, p);
867 qemu_mutex_lock(&s->archip_mutex);
868 while (!s->is_signaled) {
869 qemu_cond_wait(&s->archip_cond, &s->archip_mutex);
870 }
871 s->is_signaled = false;
872 qemu_mutex_unlock(&s->archip_mutex);
873
874 xinfo = (struct xseg_reply_info *) xseg_get_data(s->xseg, req);
875 size = xinfo->size;
876 xseg_put_request(s->xseg, req, s->srcport);
877 g_free(reqdata);
878 s->size = size;
879 return size;
880
881err_exit:
882 xseg_put_request(s->xseg, req, s->srcport);
883err_exit2:
884 g_free(reqdata);
885 return -EIO;
886}
887
888static int64_t qemu_archipelago_getlength(BlockDriverState *bs)
889{
890 int64_t ret;
891 BDRVArchipelagoState *s = bs->opaque;
892
893 ret = archipelago_volume_info(s);
894 return ret;
895}
896
897static BlockDriverAIOCB *qemu_archipelago_aio_flush(BlockDriverState *bs,
898 BlockDriverCompletionFunc *cb, void *opaque)
899{
900 return qemu_archipelago_aio_rw(bs, 0, NULL, 0, cb, opaque,
901 ARCHIP_OP_FLUSH);
902}
903
904static BlockDriver bdrv_archipelago = {
905 .format_name = "archipelago",
906 .protocol_name = "archipelago",
907 .instance_size = sizeof(BDRVArchipelagoState),
70537a85 908 .bdrv_parse_filename = archipelago_parse_filename,
c9a12e75
CN
909 .bdrv_file_open = qemu_archipelago_open,
910 .bdrv_close = qemu_archipelago_close,
911 .bdrv_getlength = qemu_archipelago_getlength,
912 .bdrv_aio_readv = qemu_archipelago_aio_readv,
913 .bdrv_aio_writev = qemu_archipelago_aio_writev,
914 .bdrv_aio_flush = qemu_archipelago_aio_flush,
915 .bdrv_has_zero_init = bdrv_has_zero_init_1,
916};
917
918static void bdrv_archipelago_init(void)
919{
920 bdrv_register(&bdrv_archipelago);
921}
922
923block_init(bdrv_archipelago_init);