1
2
3
4
5
6
7
8
9
10
11#include "qemu/osdep.h"
12#include "qemu/units.h"
13#include <glusterfs/api/glfs.h>
14#include "block/block_int.h"
15#include "block/qdict.h"
16#include "qapi/error.h"
17#include "qapi/qmp/qdict.h"
18#include "qapi/qmp/qerror.h"
19#include "qemu/uri.h"
20#include "qemu/error-report.h"
21#include "qemu/module.h"
22#include "qemu/option.h"
23#include "qemu/cutils.h"
24
25#ifdef CONFIG_GLUSTERFS_FTRUNCATE_HAS_STAT
26# define glfs_ftruncate(fd, offset) glfs_ftruncate(fd, offset, NULL, NULL)
27#endif
28
29#define GLUSTER_OPT_FILENAME "filename"
30#define GLUSTER_OPT_VOLUME "volume"
31#define GLUSTER_OPT_PATH "path"
32#define GLUSTER_OPT_TYPE "type"
33#define GLUSTER_OPT_SERVER_PATTERN "server."
34#define GLUSTER_OPT_HOST "host"
35#define GLUSTER_OPT_PORT "port"
36#define GLUSTER_OPT_TO "to"
37#define GLUSTER_OPT_IPV4 "ipv4"
38#define GLUSTER_OPT_IPV6 "ipv6"
39#define GLUSTER_OPT_SOCKET "socket"
40#define GLUSTER_OPT_DEBUG "debug"
41#define GLUSTER_DEFAULT_PORT 24007
42#define GLUSTER_DEBUG_DEFAULT 4
43#define GLUSTER_DEBUG_MAX 9
44#define GLUSTER_OPT_LOGFILE "logfile"
45#define GLUSTER_LOGFILE_DEFAULT "-"
46
47
48
49
50
51#define GLUSTER_MAX_TRANSFER (512 * MiB)
52
53#define GERR_INDEX_HINT "hint: check in 'server' array index '%d'\n"
54
55typedef struct GlusterAIOCB {
56 int64_t size;
57 int ret;
58 Coroutine *coroutine;
59 AioContext *aio_context;
60} GlusterAIOCB;
61
62typedef struct BDRVGlusterState {
63 struct glfs *glfs;
64 struct glfs_fd *fd;
65 char *logfile;
66 bool supports_seek_data;
67 int debug;
68} BDRVGlusterState;
69
70typedef struct BDRVGlusterReopenState {
71 struct glfs *glfs;
72 struct glfs_fd *fd;
73} BDRVGlusterReopenState;
74
75
76typedef struct GlfsPreopened {
77 char *volume;
78 glfs_t *fs;
79 int ref;
80} GlfsPreopened;
81
82typedef struct ListElement {
83 QLIST_ENTRY(ListElement) list;
84 GlfsPreopened saved;
85} ListElement;
86
87static QLIST_HEAD(, ListElement) glfs_list;
88
89static QemuOptsList qemu_gluster_create_opts = {
90 .name = "qemu-gluster-create-opts",
91 .head = QTAILQ_HEAD_INITIALIZER(qemu_gluster_create_opts.head),
92 .desc = {
93 {
94 .name = BLOCK_OPT_SIZE,
95 .type = QEMU_OPT_SIZE,
96 .help = "Virtual disk size"
97 },
98 {
99 .name = BLOCK_OPT_PREALLOC,
100 .type = QEMU_OPT_STRING,
101 .help = "Preallocation mode (allowed values: off"
102#ifdef CONFIG_GLUSTERFS_FALLOCATE
103 ", falloc"
104#endif
105#ifdef CONFIG_GLUSTERFS_ZEROFILL
106 ", full"
107#endif
108 ")"
109 },
110 {
111 .name = GLUSTER_OPT_DEBUG,
112 .type = QEMU_OPT_NUMBER,
113 .help = "Gluster log level, valid range is 0-9",
114 },
115 {
116 .name = GLUSTER_OPT_LOGFILE,
117 .type = QEMU_OPT_STRING,
118 .help = "Logfile path of libgfapi",
119 },
120 { }
121 }
122};
123
124static QemuOptsList runtime_opts = {
125 .name = "gluster",
126 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
127 .desc = {
128 {
129 .name = GLUSTER_OPT_FILENAME,
130 .type = QEMU_OPT_STRING,
131 .help = "URL to the gluster image",
132 },
133 {
134 .name = GLUSTER_OPT_DEBUG,
135 .type = QEMU_OPT_NUMBER,
136 .help = "Gluster log level, valid range is 0-9",
137 },
138 {
139 .name = GLUSTER_OPT_LOGFILE,
140 .type = QEMU_OPT_STRING,
141 .help = "Logfile path of libgfapi",
142 },
143 { }
144 },
145};
146
147static QemuOptsList runtime_json_opts = {
148 .name = "gluster_json",
149 .head = QTAILQ_HEAD_INITIALIZER(runtime_json_opts.head),
150 .desc = {
151 {
152 .name = GLUSTER_OPT_VOLUME,
153 .type = QEMU_OPT_STRING,
154 .help = "name of gluster volume where VM image resides",
155 },
156 {
157 .name = GLUSTER_OPT_PATH,
158 .type = QEMU_OPT_STRING,
159 .help = "absolute path to image file in gluster volume",
160 },
161 {
162 .name = GLUSTER_OPT_DEBUG,
163 .type = QEMU_OPT_NUMBER,
164 .help = "Gluster log level, valid range is 0-9",
165 },
166 { }
167 },
168};
169
170static QemuOptsList runtime_type_opts = {
171 .name = "gluster_type",
172 .head = QTAILQ_HEAD_INITIALIZER(runtime_type_opts.head),
173 .desc = {
174 {
175 .name = GLUSTER_OPT_TYPE,
176 .type = QEMU_OPT_STRING,
177 .help = "inet|unix",
178 },
179 { }
180 },
181};
182
183static QemuOptsList runtime_unix_opts = {
184 .name = "gluster_unix",
185 .head = QTAILQ_HEAD_INITIALIZER(runtime_unix_opts.head),
186 .desc = {
187 {
188 .name = GLUSTER_OPT_SOCKET,
189 .type = QEMU_OPT_STRING,
190 .help = "socket file path (legacy)",
191 },
192 {
193 .name = GLUSTER_OPT_PATH,
194 .type = QEMU_OPT_STRING,
195 .help = "socket file path (QAPI)",
196 },
197 { }
198 },
199};
200
201static QemuOptsList runtime_inet_opts = {
202 .name = "gluster_inet",
203 .head = QTAILQ_HEAD_INITIALIZER(runtime_inet_opts.head),
204 .desc = {
205 {
206 .name = GLUSTER_OPT_TYPE,
207 .type = QEMU_OPT_STRING,
208 .help = "inet|unix",
209 },
210 {
211 .name = GLUSTER_OPT_HOST,
212 .type = QEMU_OPT_STRING,
213 .help = "host address (hostname/ipv4/ipv6 addresses)",
214 },
215 {
216 .name = GLUSTER_OPT_PORT,
217 .type = QEMU_OPT_STRING,
218 .help = "port number on which glusterd is listening (default 24007)",
219 },
220 {
221 .name = "to",
222 .type = QEMU_OPT_NUMBER,
223 .help = "max port number, not supported by gluster",
224 },
225 {
226 .name = "ipv4",
227 .type = QEMU_OPT_BOOL,
228 .help = "ipv4 bool value, not supported by gluster",
229 },
230 {
231 .name = "ipv6",
232 .type = QEMU_OPT_BOOL,
233 .help = "ipv6 bool value, not supported by gluster",
234 },
235 { }
236 },
237};
238
239static void glfs_set_preopened(const char *volume, glfs_t *fs)
240{
241 ListElement *entry = NULL;
242
243 entry = g_new(ListElement, 1);
244
245 entry->saved.volume = g_strdup(volume);
246
247 entry->saved.fs = fs;
248 entry->saved.ref = 1;
249
250 QLIST_INSERT_HEAD(&glfs_list, entry, list);
251}
252
253static glfs_t *glfs_find_preopened(const char *volume)
254{
255 ListElement *entry = NULL;
256
257 QLIST_FOREACH(entry, &glfs_list, list) {
258 if (strcmp(entry->saved.volume, volume) == 0) {
259 entry->saved.ref++;
260 return entry->saved.fs;
261 }
262 }
263
264 return NULL;
265}
266
267static void glfs_clear_preopened(glfs_t *fs)
268{
269 ListElement *entry = NULL;
270 ListElement *next;
271
272 if (fs == NULL) {
273 return;
274 }
275
276 QLIST_FOREACH_SAFE(entry, &glfs_list, list, next) {
277 if (entry->saved.fs == fs) {
278 if (--entry->saved.ref) {
279 return;
280 }
281
282 QLIST_REMOVE(entry, list);
283
284 glfs_fini(entry->saved.fs);
285 g_free(entry->saved.volume);
286 g_free(entry);
287 }
288 }
289}
290
291static int parse_volume_options(BlockdevOptionsGluster *gconf, char *path)
292{
293 char *p, *q;
294
295 if (!path) {
296 return -EINVAL;
297 }
298
299
300 p = q = path + strspn(path, "/");
301 p += strcspn(p, "/");
302 if (*p == '\0') {
303 return -EINVAL;
304 }
305 gconf->volume = g_strndup(q, p - q);
306
307
308 p += strspn(p, "/");
309 if (*p == '\0') {
310 return -EINVAL;
311 }
312 gconf->path = g_strdup(p);
313 return 0;
314}
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf,
349 const char *filename)
350{
351 SocketAddress *gsconf;
352 URI *uri;
353 QueryParams *qp = NULL;
354 bool is_unix = false;
355 int ret = 0;
356
357 uri = uri_parse(filename);
358 if (!uri) {
359 return -EINVAL;
360 }
361
362 gsconf = g_new0(SocketAddress, 1);
363 QAPI_LIST_PREPEND(gconf->server, gsconf);
364
365
366 if (!uri->scheme || !strcmp(uri->scheme, "gluster")) {
367 gsconf->type = SOCKET_ADDRESS_TYPE_INET;
368 } else if (!strcmp(uri->scheme, "gluster+tcp")) {
369 gsconf->type = SOCKET_ADDRESS_TYPE_INET;
370 } else if (!strcmp(uri->scheme, "gluster+unix")) {
371 gsconf->type = SOCKET_ADDRESS_TYPE_UNIX;
372 is_unix = true;
373 } else if (!strcmp(uri->scheme, "gluster+rdma")) {
374 gsconf->type = SOCKET_ADDRESS_TYPE_INET;
375 warn_report("rdma feature is not supported, falling back to tcp");
376 } else {
377 ret = -EINVAL;
378 goto out;
379 }
380
381 ret = parse_volume_options(gconf, uri->path);
382 if (ret < 0) {
383 goto out;
384 }
385
386 qp = query_params_parse(uri->query);
387 if (qp->n > 1 || (is_unix && !qp->n) || (!is_unix && qp->n)) {
388 ret = -EINVAL;
389 goto out;
390 }
391
392 if (is_unix) {
393 if (uri->server || uri->port) {
394 ret = -EINVAL;
395 goto out;
396 }
397 if (strcmp(qp->p[0].name, "socket")) {
398 ret = -EINVAL;
399 goto out;
400 }
401 gsconf->u.q_unix.path = g_strdup(qp->p[0].value);
402 } else {
403 gsconf->u.inet.host = g_strdup(uri->server ? uri->server : "localhost");
404 if (uri->port) {
405 gsconf->u.inet.port = g_strdup_printf("%d", uri->port);
406 } else {
407 gsconf->u.inet.port = g_strdup_printf("%d", GLUSTER_DEFAULT_PORT);
408 }
409 }
410
411out:
412 if (qp) {
413 query_params_free(qp);
414 }
415 uri_free(uri);
416 return ret;
417}
418
419static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
420 Error **errp)
421{
422 struct glfs *glfs;
423 int ret;
424 int old_errno;
425 SocketAddressList *server;
426 unsigned long long port;
427
428 glfs = glfs_find_preopened(gconf->volume);
429 if (glfs) {
430 return glfs;
431 }
432
433 glfs = glfs_new(gconf->volume);
434 if (!glfs) {
435 goto out;
436 }
437
438 glfs_set_preopened(gconf->volume, glfs);
439
440 for (server = gconf->server; server; server = server->next) {
441 switch (server->value->type) {
442 case SOCKET_ADDRESS_TYPE_UNIX:
443 ret = glfs_set_volfile_server(glfs, "unix",
444 server->value->u.q_unix.path, 0);
445 break;
446 case SOCKET_ADDRESS_TYPE_INET:
447 if (parse_uint_full(server->value->u.inet.port, &port, 10) < 0 ||
448 port > 65535) {
449 error_setg(errp, "'%s' is not a valid port number",
450 server->value->u.inet.port);
451 errno = EINVAL;
452 goto out;
453 }
454 ret = glfs_set_volfile_server(glfs, "tcp",
455 server->value->u.inet.host,
456 (int)port);
457 break;
458 case SOCKET_ADDRESS_TYPE_VSOCK:
459 case SOCKET_ADDRESS_TYPE_FD:
460 default:
461 abort();
462 }
463
464 if (ret < 0) {
465 goto out;
466 }
467 }
468
469 ret = glfs_set_logging(glfs, gconf->logfile, gconf->debug);
470 if (ret < 0) {
471 goto out;
472 }
473
474 ret = glfs_init(glfs);
475 if (ret) {
476 error_setg(errp, "Gluster connection for volume %s, path %s failed"
477 " to connect", gconf->volume, gconf->path);
478 for (server = gconf->server; server; server = server->next) {
479 if (server->value->type == SOCKET_ADDRESS_TYPE_UNIX) {
480 error_append_hint(errp, "hint: failed on socket %s ",
481 server->value->u.q_unix.path);
482 } else {
483 error_append_hint(errp, "hint: failed on host %s and port %s ",
484 server->value->u.inet.host,
485 server->value->u.inet.port);
486 }
487 }
488
489 error_append_hint(errp, "Please refer to gluster logs for more info\n");
490
491
492 if (errno == 0) {
493 errno = EINVAL;
494 }
495
496 goto out;
497 }
498 return glfs;
499
500out:
501 if (glfs) {
502 old_errno = errno;
503 glfs_clear_preopened(glfs);
504 errno = old_errno;
505 }
506 return NULL;
507}
508
509
510
511
512static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
513 QDict *options, Error **errp)
514{
515 QemuOpts *opts;
516 SocketAddress *gsconf = NULL;
517 SocketAddressList **tail;
518 QDict *backing_options = NULL;
519 Error *local_err = NULL;
520 char *str = NULL;
521 const char *ptr;
522 int i, type, num_servers;
523
524
525 opts = qemu_opts_create(&runtime_json_opts, NULL, 0, &error_abort);
526 if (!qemu_opts_absorb_qdict(opts, options, errp)) {
527 goto out;
528 }
529
530 num_servers = qdict_array_entries(options, GLUSTER_OPT_SERVER_PATTERN);
531 if (num_servers < 1) {
532 error_setg(&local_err, QERR_MISSING_PARAMETER, "server");
533 goto out;
534 }
535
536 ptr = qemu_opt_get(opts, GLUSTER_OPT_VOLUME);
537 if (!ptr) {
538 error_setg(&local_err, QERR_MISSING_PARAMETER, GLUSTER_OPT_VOLUME);
539 goto out;
540 }
541 gconf->volume = g_strdup(ptr);
542
543 ptr = qemu_opt_get(opts, GLUSTER_OPT_PATH);
544 if (!ptr) {
545 error_setg(&local_err, QERR_MISSING_PARAMETER, GLUSTER_OPT_PATH);
546 goto out;
547 }
548 gconf->path = g_strdup(ptr);
549 qemu_opts_del(opts);
550 tail = &gconf->server;
551
552 for (i = 0; i < num_servers; i++) {
553 str = g_strdup_printf(GLUSTER_OPT_SERVER_PATTERN"%d.", i);
554 qdict_extract_subqdict(options, &backing_options, str);
555
556
557 opts = qemu_opts_create(&runtime_type_opts, NULL, 0, &error_abort);
558 if (!qemu_opts_absorb_qdict(opts, backing_options, errp)) {
559 goto out;
560 }
561
562 ptr = qemu_opt_get(opts, GLUSTER_OPT_TYPE);
563 if (!ptr) {
564 error_setg(&local_err, QERR_MISSING_PARAMETER, GLUSTER_OPT_TYPE);
565 error_append_hint(&local_err, GERR_INDEX_HINT, i);
566 goto out;
567
568 }
569 gsconf = g_new0(SocketAddress, 1);
570 if (!strcmp(ptr, "tcp")) {
571 ptr = "inet";
572 }
573 type = qapi_enum_parse(&SocketAddressType_lookup, ptr, -1, NULL);
574 if (type != SOCKET_ADDRESS_TYPE_INET
575 && type != SOCKET_ADDRESS_TYPE_UNIX) {
576 error_setg(&local_err,
577 "Parameter '%s' may be 'inet' or 'unix'",
578 GLUSTER_OPT_TYPE);
579 error_append_hint(&local_err, GERR_INDEX_HINT, i);
580 goto out;
581 }
582 gsconf->type = type;
583 qemu_opts_del(opts);
584
585 if (gsconf->type == SOCKET_ADDRESS_TYPE_INET) {
586
587 opts = qemu_opts_create(&runtime_inet_opts, NULL, 0, &error_abort);
588 if (!qemu_opts_absorb_qdict(opts, backing_options, errp)) {
589 goto out;
590 }
591
592 ptr = qemu_opt_get(opts, GLUSTER_OPT_HOST);
593 if (!ptr) {
594 error_setg(&local_err, QERR_MISSING_PARAMETER,
595 GLUSTER_OPT_HOST);
596 error_append_hint(&local_err, GERR_INDEX_HINT, i);
597 goto out;
598 }
599 gsconf->u.inet.host = g_strdup(ptr);
600 ptr = qemu_opt_get(opts, GLUSTER_OPT_PORT);
601 if (!ptr) {
602 error_setg(&local_err, QERR_MISSING_PARAMETER,
603 GLUSTER_OPT_PORT);
604 error_append_hint(&local_err, GERR_INDEX_HINT, i);
605 goto out;
606 }
607 gsconf->u.inet.port = g_strdup(ptr);
608
609
610
611
612 ptr = qemu_opt_get(opts, GLUSTER_OPT_TO);
613 if (ptr) {
614 gsconf->u.inet.has_to = true;
615 }
616 ptr = qemu_opt_get(opts, GLUSTER_OPT_IPV4);
617 if (ptr) {
618 gsconf->u.inet.has_ipv4 = true;
619 }
620 ptr = qemu_opt_get(opts, GLUSTER_OPT_IPV6);
621 if (ptr) {
622 gsconf->u.inet.has_ipv6 = true;
623 }
624 if (gsconf->u.inet.has_to) {
625 error_setg(&local_err, "Parameter 'to' not supported");
626 goto out;
627 }
628 if (gsconf->u.inet.has_ipv4 || gsconf->u.inet.has_ipv6) {
629 error_setg(&local_err, "Parameters 'ipv4/ipv6' not supported");
630 goto out;
631 }
632 qemu_opts_del(opts);
633 } else {
634
635 opts = qemu_opts_create(&runtime_unix_opts, NULL, 0, &error_abort);
636 if (!qemu_opts_absorb_qdict(opts, backing_options, errp)) {
637 goto out;
638 }
639
640 ptr = qemu_opt_get(opts, GLUSTER_OPT_PATH);
641 if (!ptr) {
642 ptr = qemu_opt_get(opts, GLUSTER_OPT_SOCKET);
643 } else if (qemu_opt_get(opts, GLUSTER_OPT_SOCKET)) {
644 error_setg(&local_err,
645 "Conflicting parameters 'path' and 'socket'");
646 error_append_hint(&local_err, GERR_INDEX_HINT, i);
647 goto out;
648 }
649 if (!ptr) {
650 error_setg(&local_err, QERR_MISSING_PARAMETER,
651 GLUSTER_OPT_PATH);
652 error_append_hint(&local_err, GERR_INDEX_HINT, i);
653 goto out;
654 }
655 gsconf->u.q_unix.path = g_strdup(ptr);
656 qemu_opts_del(opts);
657 }
658
659 QAPI_LIST_APPEND(tail, gsconf);
660 gsconf = NULL;
661
662 qobject_unref(backing_options);
663 backing_options = NULL;
664 g_free(str);
665 str = NULL;
666 }
667
668 return 0;
669
670out:
671 error_propagate(errp, local_err);
672 qapi_free_SocketAddress(gsconf);
673 qemu_opts_del(opts);
674 g_free(str);
675 qobject_unref(backing_options);
676 errno = EINVAL;
677 return -errno;
678}
679
680
681
682static int qemu_gluster_parse(BlockdevOptionsGluster *gconf,
683 const char *filename,
684 QDict *options, Error **errp)
685{
686 int ret;
687 if (filename) {
688 ret = qemu_gluster_parse_uri(gconf, filename);
689 if (ret < 0) {
690 error_setg(errp, "invalid URI %s", filename);
691 error_append_hint(errp, "Usage: file=gluster[+transport]://"
692 "[host[:port]]volume/path[?socket=...]"
693 "[,file.debug=N]"
694 "[,file.logfile=/path/filename.log]\n");
695 return ret;
696 }
697 } else {
698 ret = qemu_gluster_parse_json(gconf, options, errp);
699 if (ret < 0) {
700 error_append_hint(errp, "Usage: "
701 "-drive driver=qcow2,file.driver=gluster,"
702 "file.volume=testvol,file.path=/path/a.qcow2"
703 "[,file.debug=9]"
704 "[,file.logfile=/path/filename.log],"
705 "file.server.0.type=inet,"
706 "file.server.0.host=1.2.3.4,"
707 "file.server.0.port=24007,"
708 "file.server.1.transport=unix,"
709 "file.server.1.path=/var/run/glusterd.socket ..."
710 "\n");
711 return ret;
712 }
713 }
714
715 return 0;
716}
717
718static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
719 const char *filename,
720 QDict *options, Error **errp)
721{
722 int ret;
723
724 ret = qemu_gluster_parse(gconf, filename, options, errp);
725 if (ret < 0) {
726 errno = -ret;
727 return NULL;
728 }
729
730 return qemu_gluster_glfs_init(gconf, errp);
731}
732
733
734
735
736static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret,
737#ifdef CONFIG_GLUSTERFS_IOCB_HAS_STAT
738 struct glfs_stat *pre, struct glfs_stat *post,
739#endif
740 void *arg)
741{
742 GlusterAIOCB *acb = (GlusterAIOCB *)arg;
743
744 if (!ret || ret == acb->size) {
745 acb->ret = 0;
746 } else if (ret < 0) {
747 acb->ret = -errno;
748 } else {
749 acb->ret = -EIO;
750 }
751
752 aio_co_schedule(acb->aio_context, acb->coroutine);
753}
754
755static void qemu_gluster_parse_flags(int bdrv_flags, int *open_flags)
756{
757 assert(open_flags != NULL);
758
759 *open_flags |= O_BINARY;
760
761 if (bdrv_flags & BDRV_O_RDWR) {
762 *open_flags |= O_RDWR;
763 } else {
764 *open_flags |= O_RDONLY;
765 }
766
767 if ((bdrv_flags & BDRV_O_NOCACHE)) {
768 *open_flags |= O_DIRECT;
769 }
770}
771
772
773
774
775
776
777
778
779static bool qemu_gluster_test_seek(struct glfs_fd *fd)
780{
781 off_t ret = 0;
782
783#if defined SEEK_HOLE && defined SEEK_DATA
784 off_t eof;
785
786 eof = glfs_lseek(fd, 0, SEEK_END);
787 if (eof < 0) {
788
789 return false;
790 }
791
792
793 ret = glfs_lseek(fd, eof, SEEK_DATA);
794#endif
795
796 return (ret < 0) && (errno == ENXIO);
797}
798
799static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
800 int bdrv_flags, Error **errp)
801{
802 BDRVGlusterState *s = bs->opaque;
803 int open_flags = 0;
804 int ret = 0;
805 BlockdevOptionsGluster *gconf = NULL;
806 QemuOpts *opts;
807 const char *filename, *logfile;
808
809 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
810 if (!qemu_opts_absorb_qdict(opts, options, errp)) {
811 ret = -EINVAL;
812 goto out;
813 }
814
815 filename = qemu_opt_get(opts, GLUSTER_OPT_FILENAME);
816
817 s->debug = qemu_opt_get_number(opts, GLUSTER_OPT_DEBUG,
818 GLUSTER_DEBUG_DEFAULT);
819 if (s->debug < 0) {
820 s->debug = 0;
821 } else if (s->debug > GLUSTER_DEBUG_MAX) {
822 s->debug = GLUSTER_DEBUG_MAX;
823 }
824
825 gconf = g_new0(BlockdevOptionsGluster, 1);
826 gconf->debug = s->debug;
827 gconf->has_debug = true;
828
829 logfile = qemu_opt_get(opts, GLUSTER_OPT_LOGFILE);
830 s->logfile = g_strdup(logfile ? logfile : GLUSTER_LOGFILE_DEFAULT);
831
832 gconf->logfile = g_strdup(s->logfile);
833 gconf->has_logfile = true;
834
835 s->glfs = qemu_gluster_init(gconf, filename, options, errp);
836 if (!s->glfs) {
837 ret = -errno;
838 goto out;
839 }
840
841#ifdef CONFIG_GLUSTERFS_XLATOR_OPT
842
843
844
845
846
847
848 ret = glfs_set_xlator_option(s->glfs, "*-write-behind",
849 "resync-failed-syncs-after-fsync",
850 "on");
851 if (ret < 0) {
852 error_setg_errno(errp, errno, "Unable to set xlator key/value pair");
853 ret = -errno;
854 goto out;
855 }
856#endif
857
858 qemu_gluster_parse_flags(bdrv_flags, &open_flags);
859
860 s->fd = glfs_open(s->glfs, gconf->path, open_flags);
861 ret = s->fd ? 0 : -errno;
862
863 if (ret == -EACCES || ret == -EROFS) {
864
865
866 if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) {
867 open_flags = (open_flags & ~O_RDWR) | O_RDONLY;
868 s->fd = glfs_open(s->glfs, gconf->path, open_flags);
869 ret = s->fd ? 0 : -errno;
870 }
871 }
872
873 s->supports_seek_data = qemu_gluster_test_seek(s->fd);
874
875out:
876 qemu_opts_del(opts);
877 qapi_free_BlockdevOptionsGluster(gconf);
878 if (!ret) {
879 return ret;
880 }
881 g_free(s->logfile);
882 if (s->fd) {
883 glfs_close(s->fd);
884 }
885
886 glfs_clear_preopened(s->glfs);
887
888 return ret;
889}
890
891static void qemu_gluster_refresh_limits(BlockDriverState *bs, Error **errp)
892{
893 bs->bl.max_transfer = GLUSTER_MAX_TRANSFER;
894 bs->bl.max_pdiscard = MIN(SIZE_MAX, INT64_MAX);
895}
896
897static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
898 BlockReopenQueue *queue, Error **errp)
899{
900 int ret = 0;
901 BDRVGlusterState *s;
902 BDRVGlusterReopenState *reop_s;
903 BlockdevOptionsGluster *gconf;
904 int open_flags = 0;
905
906 assert(state != NULL);
907 assert(state->bs != NULL);
908
909 s = state->bs->opaque;
910
911 state->opaque = g_new0(BDRVGlusterReopenState, 1);
912 reop_s = state->opaque;
913
914 qemu_gluster_parse_flags(state->flags, &open_flags);
915
916 gconf = g_new0(BlockdevOptionsGluster, 1);
917 gconf->debug = s->debug;
918 gconf->has_debug = true;
919 gconf->logfile = g_strdup(s->logfile);
920 gconf->has_logfile = true;
921
922
923
924
925
926 if (state->bs->exact_filename[0] != '\0') {
927 reop_s->glfs = qemu_gluster_init(gconf, state->bs->exact_filename, NULL,
928 errp);
929 } else {
930 reop_s->glfs = qemu_gluster_init(gconf, NULL, state->options, errp);
931 }
932 if (reop_s->glfs == NULL) {
933 ret = -errno;
934 goto exit;
935 }
936
937#ifdef CONFIG_GLUSTERFS_XLATOR_OPT
938 ret = glfs_set_xlator_option(reop_s->glfs, "*-write-behind",
939 "resync-failed-syncs-after-fsync", "on");
940 if (ret < 0) {
941 error_setg_errno(errp, errno, "Unable to set xlator key/value pair");
942 ret = -errno;
943 goto exit;
944 }
945#endif
946
947 reop_s->fd = glfs_open(reop_s->glfs, gconf->path, open_flags);
948 if (reop_s->fd == NULL) {
949
950 ret = -errno;
951 goto exit;
952 }
953
954exit:
955
956 qapi_free_BlockdevOptionsGluster(gconf);
957 return ret;
958}
959
960static void qemu_gluster_reopen_commit(BDRVReopenState *state)
961{
962 BDRVGlusterReopenState *reop_s = state->opaque;
963 BDRVGlusterState *s = state->bs->opaque;
964
965
966
967 if (s->fd) {
968 glfs_close(s->fd);
969 }
970
971 glfs_clear_preopened(s->glfs);
972
973
974 s->fd = reop_s->fd;
975 s->glfs = reop_s->glfs;
976
977 g_free(state->opaque);
978 state->opaque = NULL;
979
980 return;
981}
982
983
984static void qemu_gluster_reopen_abort(BDRVReopenState *state)
985{
986 BDRVGlusterReopenState *reop_s = state->opaque;
987
988 if (reop_s == NULL) {
989 return;
990 }
991
992 if (reop_s->fd) {
993 glfs_close(reop_s->fd);
994 }
995
996 glfs_clear_preopened(reop_s->glfs);
997
998 g_free(state->opaque);
999 state->opaque = NULL;
1000
1001 return;
1002}
1003
1004#ifdef CONFIG_GLUSTERFS_ZEROFILL
1005static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs,
1006 int64_t offset,
1007 int64_t bytes,
1008 BdrvRequestFlags flags)
1009{
1010 int ret;
1011 GlusterAIOCB acb;
1012 BDRVGlusterState *s = bs->opaque;
1013
1014 acb.size = bytes;
1015 acb.ret = 0;
1016 acb.coroutine = qemu_coroutine_self();
1017 acb.aio_context = bdrv_get_aio_context(bs);
1018
1019 ret = glfs_zerofill_async(s->fd, offset, bytes, gluster_finish_aiocb, &acb);
1020 if (ret < 0) {
1021 return -errno;
1022 }
1023
1024 qemu_coroutine_yield();
1025 return acb.ret;
1026}
1027#endif
1028
1029static int qemu_gluster_do_truncate(struct glfs_fd *fd, int64_t offset,
1030 PreallocMode prealloc, Error **errp)
1031{
1032 int64_t current_length;
1033
1034 current_length = glfs_lseek(fd, 0, SEEK_END);
1035 if (current_length < 0) {
1036 error_setg_errno(errp, errno, "Failed to determine current size");
1037 return -errno;
1038 }
1039
1040 if (current_length > offset && prealloc != PREALLOC_MODE_OFF) {
1041 error_setg(errp, "Cannot use preallocation for shrinking files");
1042 return -ENOTSUP;
1043 }
1044
1045 if (current_length == offset) {
1046 return 0;
1047 }
1048
1049 switch (prealloc) {
1050#ifdef CONFIG_GLUSTERFS_FALLOCATE
1051 case PREALLOC_MODE_FALLOC:
1052 if (glfs_fallocate(fd, 0, current_length, offset - current_length)) {
1053 error_setg_errno(errp, errno, "Could not preallocate data");
1054 return -errno;
1055 }
1056 break;
1057#endif
1058#ifdef CONFIG_GLUSTERFS_ZEROFILL
1059 case PREALLOC_MODE_FULL:
1060 if (glfs_ftruncate(fd, offset)) {
1061 error_setg_errno(errp, errno, "Could not resize file");
1062 return -errno;
1063 }
1064 if (glfs_zerofill(fd, current_length, offset - current_length)) {
1065 error_setg_errno(errp, errno, "Could not zerofill the new area");
1066 return -errno;
1067 }
1068 break;
1069#endif
1070 case PREALLOC_MODE_OFF:
1071 if (glfs_ftruncate(fd, offset)) {
1072 error_setg_errno(errp, errno, "Could not resize file");
1073 return -errno;
1074 }
1075 break;
1076 default:
1077 error_setg(errp, "Unsupported preallocation mode: %s",
1078 PreallocMode_str(prealloc));
1079 return -EINVAL;
1080 }
1081
1082 return 0;
1083}
1084
1085static int qemu_gluster_co_create(BlockdevCreateOptions *options,
1086 Error **errp)
1087{
1088 BlockdevCreateOptionsGluster *opts = &options->u.gluster;
1089 struct glfs *glfs;
1090 struct glfs_fd *fd = NULL;
1091 int ret = 0;
1092
1093 assert(options->driver == BLOCKDEV_DRIVER_GLUSTER);
1094
1095 glfs = qemu_gluster_glfs_init(opts->location, errp);
1096 if (!glfs) {
1097 ret = -errno;
1098 goto out;
1099 }
1100
1101 fd = glfs_creat(glfs, opts->location->path,
1102 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR);
1103 if (!fd) {
1104 ret = -errno;
1105 goto out;
1106 }
1107
1108 ret = qemu_gluster_do_truncate(fd, opts->size, opts->preallocation, errp);
1109
1110out:
1111 if (fd) {
1112 if (glfs_close(fd) != 0 && ret == 0) {
1113 ret = -errno;
1114 }
1115 }
1116 glfs_clear_preopened(glfs);
1117 return ret;
1118}
1119
1120static int coroutine_fn qemu_gluster_co_create_opts(BlockDriver *drv,
1121 const char *filename,
1122 QemuOpts *opts,
1123 Error **errp)
1124{
1125 BlockdevCreateOptions *options;
1126 BlockdevCreateOptionsGluster *gopts;
1127 BlockdevOptionsGluster *gconf;
1128 char *tmp = NULL;
1129 Error *local_err = NULL;
1130 int ret;
1131
1132 options = g_new0(BlockdevCreateOptions, 1);
1133 options->driver = BLOCKDEV_DRIVER_GLUSTER;
1134 gopts = &options->u.gluster;
1135
1136 gconf = g_new0(BlockdevOptionsGluster, 1);
1137 gopts->location = gconf;
1138
1139 gopts->size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
1140 BDRV_SECTOR_SIZE);
1141
1142 tmp = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
1143 gopts->preallocation = qapi_enum_parse(&PreallocMode_lookup, tmp,
1144 PREALLOC_MODE_OFF, &local_err);
1145 g_free(tmp);
1146 if (local_err) {
1147 error_propagate(errp, local_err);
1148 ret = -EINVAL;
1149 goto fail;
1150 }
1151
1152 gconf->debug = qemu_opt_get_number_del(opts, GLUSTER_OPT_DEBUG,
1153 GLUSTER_DEBUG_DEFAULT);
1154 if (gconf->debug < 0) {
1155 gconf->debug = 0;
1156 } else if (gconf->debug > GLUSTER_DEBUG_MAX) {
1157 gconf->debug = GLUSTER_DEBUG_MAX;
1158 }
1159 gconf->has_debug = true;
1160
1161 gconf->logfile = qemu_opt_get_del(opts, GLUSTER_OPT_LOGFILE);
1162 if (!gconf->logfile) {
1163 gconf->logfile = g_strdup(GLUSTER_LOGFILE_DEFAULT);
1164 }
1165 gconf->has_logfile = true;
1166
1167 ret = qemu_gluster_parse(gconf, filename, NULL, errp);
1168 if (ret < 0) {
1169 goto fail;
1170 }
1171
1172 ret = qemu_gluster_co_create(options, errp);
1173 if (ret < 0) {
1174 goto fail;
1175 }
1176
1177 ret = 0;
1178fail:
1179 qapi_free_BlockdevCreateOptions(options);
1180 return ret;
1181}
1182
1183static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
1184 int64_t sector_num, int nb_sectors,
1185 QEMUIOVector *qiov, int write)
1186{
1187 int ret;
1188 GlusterAIOCB acb;
1189 BDRVGlusterState *s = bs->opaque;
1190 size_t size = nb_sectors * BDRV_SECTOR_SIZE;
1191 off_t offset = sector_num * BDRV_SECTOR_SIZE;
1192
1193 acb.size = size;
1194 acb.ret = 0;
1195 acb.coroutine = qemu_coroutine_self();
1196 acb.aio_context = bdrv_get_aio_context(bs);
1197
1198 if (write) {
1199 ret = glfs_pwritev_async(s->fd, qiov->iov, qiov->niov, offset, 0,
1200 gluster_finish_aiocb, &acb);
1201 } else {
1202 ret = glfs_preadv_async(s->fd, qiov->iov, qiov->niov, offset, 0,
1203 gluster_finish_aiocb, &acb);
1204 }
1205
1206 if (ret < 0) {
1207 return -errno;
1208 }
1209
1210 qemu_coroutine_yield();
1211 return acb.ret;
1212}
1213
1214static coroutine_fn int qemu_gluster_co_truncate(BlockDriverState *bs,
1215 int64_t offset,
1216 bool exact,
1217 PreallocMode prealloc,
1218 BdrvRequestFlags flags,
1219 Error **errp)
1220{
1221 BDRVGlusterState *s = bs->opaque;
1222 return qemu_gluster_do_truncate(s->fd, offset, prealloc, errp);
1223}
1224
1225static coroutine_fn int qemu_gluster_co_readv(BlockDriverState *bs,
1226 int64_t sector_num,
1227 int nb_sectors,
1228 QEMUIOVector *qiov)
1229{
1230 return qemu_gluster_co_rw(bs, sector_num, nb_sectors, qiov, 0);
1231}
1232
1233static coroutine_fn int qemu_gluster_co_writev(BlockDriverState *bs,
1234 int64_t sector_num,
1235 int nb_sectors,
1236 QEMUIOVector *qiov,
1237 int flags)
1238{
1239 return qemu_gluster_co_rw(bs, sector_num, nb_sectors, qiov, 1);
1240}
1241
1242static void qemu_gluster_close(BlockDriverState *bs)
1243{
1244 BDRVGlusterState *s = bs->opaque;
1245
1246 g_free(s->logfile);
1247 if (s->fd) {
1248 glfs_close(s->fd);
1249 s->fd = NULL;
1250 }
1251 glfs_clear_preopened(s->glfs);
1252}
1253
1254static coroutine_fn int qemu_gluster_co_flush_to_disk(BlockDriverState *bs)
1255{
1256 int ret;
1257 GlusterAIOCB acb;
1258 BDRVGlusterState *s = bs->opaque;
1259
1260 acb.size = 0;
1261 acb.ret = 0;
1262 acb.coroutine = qemu_coroutine_self();
1263 acb.aio_context = bdrv_get_aio_context(bs);
1264
1265 ret = glfs_fsync_async(s->fd, gluster_finish_aiocb, &acb);
1266 if (ret < 0) {
1267 ret = -errno;
1268 goto error;
1269 }
1270
1271 qemu_coroutine_yield();
1272 if (acb.ret < 0) {
1273 ret = acb.ret;
1274 goto error;
1275 }
1276
1277 return acb.ret;
1278
1279error:
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293 qemu_gluster_close(bs);
1294 bs->drv = NULL;
1295 return ret;
1296}
1297
1298#ifdef CONFIG_GLUSTERFS_DISCARD
1299static coroutine_fn int qemu_gluster_co_pdiscard(BlockDriverState *bs,
1300 int64_t offset, int64_t bytes)
1301{
1302 int ret;
1303 GlusterAIOCB acb;
1304 BDRVGlusterState *s = bs->opaque;
1305
1306 assert(bytes <= SIZE_MAX);
1307
1308 acb.size = 0;
1309 acb.ret = 0;
1310 acb.coroutine = qemu_coroutine_self();
1311 acb.aio_context = bdrv_get_aio_context(bs);
1312
1313 ret = glfs_discard_async(s->fd, offset, bytes, gluster_finish_aiocb, &acb);
1314 if (ret < 0) {
1315 return -errno;
1316 }
1317
1318 qemu_coroutine_yield();
1319 return acb.ret;
1320}
1321#endif
1322
1323static int64_t qemu_gluster_getlength(BlockDriverState *bs)
1324{
1325 BDRVGlusterState *s = bs->opaque;
1326 int64_t ret;
1327
1328 ret = glfs_lseek(s->fd, 0, SEEK_END);
1329 if (ret < 0) {
1330 return -errno;
1331 } else {
1332 return ret;
1333 }
1334}
1335
1336static int64_t qemu_gluster_allocated_file_size(BlockDriverState *bs)
1337{
1338 BDRVGlusterState *s = bs->opaque;
1339 struct stat st;
1340 int ret;
1341
1342 ret = glfs_fstat(s->fd, &st);
1343 if (ret < 0) {
1344 return -errno;
1345 } else {
1346 return st.st_blocks * 512;
1347 }
1348}
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362static int find_allocation(BlockDriverState *bs, off_t start,
1363 off_t *data, off_t *hole)
1364{
1365 BDRVGlusterState *s = bs->opaque;
1366
1367 if (!s->supports_seek_data) {
1368 goto exit;
1369 }
1370
1371#if defined SEEK_HOLE && defined SEEK_DATA
1372 off_t offs;
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385 offs = glfs_lseek(s->fd, start, SEEK_DATA);
1386 if (offs < 0) {
1387 return -errno;
1388 }
1389
1390 if (offs < start) {
1391
1392
1393
1394
1395 return -EIO;
1396 }
1397
1398 if (offs > start) {
1399
1400 *hole = start;
1401 *data = offs;
1402 return 0;
1403 }
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424 offs = glfs_lseek(s->fd, start, SEEK_HOLE);
1425 if (offs < 0) {
1426 return -errno;
1427 }
1428
1429 if (offs < start) {
1430
1431
1432
1433
1434 return -EIO;
1435 }
1436
1437 if (offs > start) {
1438
1439
1440
1441
1442
1443
1444 *data = start;
1445 *hole = offs;
1446 return 0;
1447 }
1448
1449
1450 return -EBUSY;
1451#endif
1452
1453exit:
1454 return -ENOTSUP;
1455}
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs,
1472 bool want_zero,
1473 int64_t offset,
1474 int64_t bytes,
1475 int64_t *pnum,
1476 int64_t *map,
1477 BlockDriverState **file)
1478{
1479 BDRVGlusterState *s = bs->opaque;
1480 off_t data = 0, hole = 0;
1481 int ret = -EINVAL;
1482
1483 assert(QEMU_IS_ALIGNED(offset | bytes, bs->bl.request_alignment));
1484
1485 if (!s->fd) {
1486 return ret;
1487 }
1488
1489 if (!want_zero) {
1490 *pnum = bytes;
1491 *map = offset;
1492 *file = bs;
1493 return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
1494 }
1495
1496 ret = find_allocation(bs, offset, &data, &hole);
1497 if (ret == -ENXIO) {
1498
1499 *pnum = bytes;
1500 ret = BDRV_BLOCK_ZERO;
1501 } else if (ret < 0) {
1502
1503 *pnum = bytes;
1504 ret = BDRV_BLOCK_DATA;
1505 } else if (data == offset) {
1506
1507
1508 *pnum = hole - offset;
1509
1510
1511
1512
1513
1514 if (!QEMU_IS_ALIGNED(*pnum, bs->bl.request_alignment)) {
1515 int64_t file_length = qemu_gluster_getlength(bs);
1516 if (file_length > 0) {
1517
1518 assert(hole == file_length);
1519 }
1520 *pnum = ROUND_UP(*pnum, bs->bl.request_alignment);
1521 }
1522
1523 ret = BDRV_BLOCK_DATA;
1524 } else {
1525
1526 assert(hole == offset);
1527 *pnum = data - offset;
1528 ret = BDRV_BLOCK_ZERO;
1529 }
1530
1531 *map = offset;
1532 *file = bs;
1533
1534 return ret | BDRV_BLOCK_OFFSET_VALID;
1535}
1536
1537
1538static const char *const gluster_strong_open_opts[] = {
1539 GLUSTER_OPT_VOLUME,
1540 GLUSTER_OPT_PATH,
1541 GLUSTER_OPT_TYPE,
1542 GLUSTER_OPT_SERVER_PATTERN,
1543 GLUSTER_OPT_HOST,
1544 GLUSTER_OPT_PORT,
1545 GLUSTER_OPT_TO,
1546 GLUSTER_OPT_IPV4,
1547 GLUSTER_OPT_IPV6,
1548 GLUSTER_OPT_SOCKET,
1549
1550 NULL
1551};
1552
1553static BlockDriver bdrv_gluster = {
1554 .format_name = "gluster",
1555 .protocol_name = "gluster",
1556 .instance_size = sizeof(BDRVGlusterState),
1557 .bdrv_file_open = qemu_gluster_open,
1558 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
1559 .bdrv_reopen_commit = qemu_gluster_reopen_commit,
1560 .bdrv_reopen_abort = qemu_gluster_reopen_abort,
1561 .bdrv_close = qemu_gluster_close,
1562 .bdrv_co_create = qemu_gluster_co_create,
1563 .bdrv_co_create_opts = qemu_gluster_co_create_opts,
1564 .bdrv_getlength = qemu_gluster_getlength,
1565 .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
1566 .bdrv_co_truncate = qemu_gluster_co_truncate,
1567 .bdrv_co_readv = qemu_gluster_co_readv,
1568 .bdrv_co_writev = qemu_gluster_co_writev,
1569 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
1570#ifdef CONFIG_GLUSTERFS_DISCARD
1571 .bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
1572#endif
1573#ifdef CONFIG_GLUSTERFS_ZEROFILL
1574 .bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
1575#endif
1576 .bdrv_co_block_status = qemu_gluster_co_block_status,
1577 .bdrv_refresh_limits = qemu_gluster_refresh_limits,
1578 .create_opts = &qemu_gluster_create_opts,
1579 .strong_runtime_opts = gluster_strong_open_opts,
1580};
1581
1582static BlockDriver bdrv_gluster_tcp = {
1583 .format_name = "gluster",
1584 .protocol_name = "gluster+tcp",
1585 .instance_size = sizeof(BDRVGlusterState),
1586 .bdrv_file_open = qemu_gluster_open,
1587 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
1588 .bdrv_reopen_commit = qemu_gluster_reopen_commit,
1589 .bdrv_reopen_abort = qemu_gluster_reopen_abort,
1590 .bdrv_close = qemu_gluster_close,
1591 .bdrv_co_create = qemu_gluster_co_create,
1592 .bdrv_co_create_opts = qemu_gluster_co_create_opts,
1593 .bdrv_getlength = qemu_gluster_getlength,
1594 .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
1595 .bdrv_co_truncate = qemu_gluster_co_truncate,
1596 .bdrv_co_readv = qemu_gluster_co_readv,
1597 .bdrv_co_writev = qemu_gluster_co_writev,
1598 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
1599#ifdef CONFIG_GLUSTERFS_DISCARD
1600 .bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
1601#endif
1602#ifdef CONFIG_GLUSTERFS_ZEROFILL
1603 .bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
1604#endif
1605 .bdrv_co_block_status = qemu_gluster_co_block_status,
1606 .bdrv_refresh_limits = qemu_gluster_refresh_limits,
1607 .create_opts = &qemu_gluster_create_opts,
1608 .strong_runtime_opts = gluster_strong_open_opts,
1609};
1610
1611static BlockDriver bdrv_gluster_unix = {
1612 .format_name = "gluster",
1613 .protocol_name = "gluster+unix",
1614 .instance_size = sizeof(BDRVGlusterState),
1615 .bdrv_file_open = qemu_gluster_open,
1616 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
1617 .bdrv_reopen_commit = qemu_gluster_reopen_commit,
1618 .bdrv_reopen_abort = qemu_gluster_reopen_abort,
1619 .bdrv_close = qemu_gluster_close,
1620 .bdrv_co_create = qemu_gluster_co_create,
1621 .bdrv_co_create_opts = qemu_gluster_co_create_opts,
1622 .bdrv_getlength = qemu_gluster_getlength,
1623 .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
1624 .bdrv_co_truncate = qemu_gluster_co_truncate,
1625 .bdrv_co_readv = qemu_gluster_co_readv,
1626 .bdrv_co_writev = qemu_gluster_co_writev,
1627 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
1628#ifdef CONFIG_GLUSTERFS_DISCARD
1629 .bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
1630#endif
1631#ifdef CONFIG_GLUSTERFS_ZEROFILL
1632 .bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
1633#endif
1634 .bdrv_co_block_status = qemu_gluster_co_block_status,
1635 .bdrv_refresh_limits = qemu_gluster_refresh_limits,
1636 .create_opts = &qemu_gluster_create_opts,
1637 .strong_runtime_opts = gluster_strong_open_opts,
1638};
1639
1640
1641
1642
1643
1644
1645
1646static BlockDriver bdrv_gluster_rdma = {
1647 .format_name = "gluster",
1648 .protocol_name = "gluster+rdma",
1649 .instance_size = sizeof(BDRVGlusterState),
1650 .bdrv_file_open = qemu_gluster_open,
1651 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
1652 .bdrv_reopen_commit = qemu_gluster_reopen_commit,
1653 .bdrv_reopen_abort = qemu_gluster_reopen_abort,
1654 .bdrv_close = qemu_gluster_close,
1655 .bdrv_co_create = qemu_gluster_co_create,
1656 .bdrv_co_create_opts = qemu_gluster_co_create_opts,
1657 .bdrv_getlength = qemu_gluster_getlength,
1658 .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
1659 .bdrv_co_truncate = qemu_gluster_co_truncate,
1660 .bdrv_co_readv = qemu_gluster_co_readv,
1661 .bdrv_co_writev = qemu_gluster_co_writev,
1662 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
1663#ifdef CONFIG_GLUSTERFS_DISCARD
1664 .bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
1665#endif
1666#ifdef CONFIG_GLUSTERFS_ZEROFILL
1667 .bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
1668#endif
1669 .bdrv_co_block_status = qemu_gluster_co_block_status,
1670 .bdrv_refresh_limits = qemu_gluster_refresh_limits,
1671 .create_opts = &qemu_gluster_create_opts,
1672 .strong_runtime_opts = gluster_strong_open_opts,
1673};
1674
1675static void bdrv_gluster_init(void)
1676{
1677 bdrv_register(&bdrv_gluster_rdma);
1678 bdrv_register(&bdrv_gluster_unix);
1679 bdrv_register(&bdrv_gluster_tcp);
1680 bdrv_register(&bdrv_gluster);
1681}
1682
1683block_init(bdrv_gluster_init);
1684