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}
895
896static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
897 BlockReopenQueue *queue, Error **errp)
898{
899 int ret = 0;
900 BDRVGlusterState *s;
901 BDRVGlusterReopenState *reop_s;
902 BlockdevOptionsGluster *gconf;
903 int open_flags = 0;
904
905 assert(state != NULL);
906 assert(state->bs != NULL);
907
908 s = state->bs->opaque;
909
910 state->opaque = g_new0(BDRVGlusterReopenState, 1);
911 reop_s = state->opaque;
912
913 qemu_gluster_parse_flags(state->flags, &open_flags);
914
915 gconf = g_new0(BlockdevOptionsGluster, 1);
916 gconf->debug = s->debug;
917 gconf->has_debug = true;
918 gconf->logfile = g_strdup(s->logfile);
919 gconf->has_logfile = true;
920
921
922
923
924
925 if (state->bs->exact_filename[0] != '\0') {
926 reop_s->glfs = qemu_gluster_init(gconf, state->bs->exact_filename, NULL,
927 errp);
928 } else {
929 reop_s->glfs = qemu_gluster_init(gconf, NULL, state->options, errp);
930 }
931 if (reop_s->glfs == NULL) {
932 ret = -errno;
933 goto exit;
934 }
935
936#ifdef CONFIG_GLUSTERFS_XLATOR_OPT
937 ret = glfs_set_xlator_option(reop_s->glfs, "*-write-behind",
938 "resync-failed-syncs-after-fsync", "on");
939 if (ret < 0) {
940 error_setg_errno(errp, errno, "Unable to set xlator key/value pair");
941 ret = -errno;
942 goto exit;
943 }
944#endif
945
946 reop_s->fd = glfs_open(reop_s->glfs, gconf->path, open_flags);
947 if (reop_s->fd == NULL) {
948
949 ret = -errno;
950 goto exit;
951 }
952
953exit:
954
955 qapi_free_BlockdevOptionsGluster(gconf);
956 return ret;
957}
958
959static void qemu_gluster_reopen_commit(BDRVReopenState *state)
960{
961 BDRVGlusterReopenState *reop_s = state->opaque;
962 BDRVGlusterState *s = state->bs->opaque;
963
964
965
966 if (s->fd) {
967 glfs_close(s->fd);
968 }
969
970 glfs_clear_preopened(s->glfs);
971
972
973 s->fd = reop_s->fd;
974 s->glfs = reop_s->glfs;
975
976 g_free(state->opaque);
977 state->opaque = NULL;
978
979 return;
980}
981
982
983static void qemu_gluster_reopen_abort(BDRVReopenState *state)
984{
985 BDRVGlusterReopenState *reop_s = state->opaque;
986
987 if (reop_s == NULL) {
988 return;
989 }
990
991 if (reop_s->fd) {
992 glfs_close(reop_s->fd);
993 }
994
995 glfs_clear_preopened(reop_s->glfs);
996
997 g_free(state->opaque);
998 state->opaque = NULL;
999
1000 return;
1001}
1002
1003#ifdef CONFIG_GLUSTERFS_ZEROFILL
1004static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs,
1005 int64_t offset,
1006 int size,
1007 BdrvRequestFlags flags)
1008{
1009 int ret;
1010 GlusterAIOCB acb;
1011 BDRVGlusterState *s = bs->opaque;
1012
1013 acb.size = size;
1014 acb.ret = 0;
1015 acb.coroutine = qemu_coroutine_self();
1016 acb.aio_context = bdrv_get_aio_context(bs);
1017
1018 ret = glfs_zerofill_async(s->fd, offset, size, gluster_finish_aiocb, &acb);
1019 if (ret < 0) {
1020 return -errno;
1021 }
1022
1023 qemu_coroutine_yield();
1024 return acb.ret;
1025}
1026#endif
1027
1028static int qemu_gluster_do_truncate(struct glfs_fd *fd, int64_t offset,
1029 PreallocMode prealloc, Error **errp)
1030{
1031 int64_t current_length;
1032
1033 current_length = glfs_lseek(fd, 0, SEEK_END);
1034 if (current_length < 0) {
1035 error_setg_errno(errp, errno, "Failed to determine current size");
1036 return -errno;
1037 }
1038
1039 if (current_length > offset && prealloc != PREALLOC_MODE_OFF) {
1040 error_setg(errp, "Cannot use preallocation for shrinking files");
1041 return -ENOTSUP;
1042 }
1043
1044 if (current_length == offset) {
1045 return 0;
1046 }
1047
1048 switch (prealloc) {
1049#ifdef CONFIG_GLUSTERFS_FALLOCATE
1050 case PREALLOC_MODE_FALLOC:
1051 if (glfs_fallocate(fd, 0, current_length, offset - current_length)) {
1052 error_setg_errno(errp, errno, "Could not preallocate data");
1053 return -errno;
1054 }
1055 break;
1056#endif
1057#ifdef CONFIG_GLUSTERFS_ZEROFILL
1058 case PREALLOC_MODE_FULL:
1059 if (glfs_ftruncate(fd, offset)) {
1060 error_setg_errno(errp, errno, "Could not resize file");
1061 return -errno;
1062 }
1063 if (glfs_zerofill(fd, current_length, offset - current_length)) {
1064 error_setg_errno(errp, errno, "Could not zerofill the new area");
1065 return -errno;
1066 }
1067 break;
1068#endif
1069 case PREALLOC_MODE_OFF:
1070 if (glfs_ftruncate(fd, offset)) {
1071 error_setg_errno(errp, errno, "Could not resize file");
1072 return -errno;
1073 }
1074 break;
1075 default:
1076 error_setg(errp, "Unsupported preallocation mode: %s",
1077 PreallocMode_str(prealloc));
1078 return -EINVAL;
1079 }
1080
1081 return 0;
1082}
1083
1084static int qemu_gluster_co_create(BlockdevCreateOptions *options,
1085 Error **errp)
1086{
1087 BlockdevCreateOptionsGluster *opts = &options->u.gluster;
1088 struct glfs *glfs;
1089 struct glfs_fd *fd = NULL;
1090 int ret = 0;
1091
1092 assert(options->driver == BLOCKDEV_DRIVER_GLUSTER);
1093
1094 glfs = qemu_gluster_glfs_init(opts->location, errp);
1095 if (!glfs) {
1096 ret = -errno;
1097 goto out;
1098 }
1099
1100 fd = glfs_creat(glfs, opts->location->path,
1101 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR);
1102 if (!fd) {
1103 ret = -errno;
1104 goto out;
1105 }
1106
1107 ret = qemu_gluster_do_truncate(fd, opts->size, opts->preallocation, errp);
1108
1109out:
1110 if (fd) {
1111 if (glfs_close(fd) != 0 && ret == 0) {
1112 ret = -errno;
1113 }
1114 }
1115 glfs_clear_preopened(glfs);
1116 return ret;
1117}
1118
1119static int coroutine_fn qemu_gluster_co_create_opts(BlockDriver *drv,
1120 const char *filename,
1121 QemuOpts *opts,
1122 Error **errp)
1123{
1124 BlockdevCreateOptions *options;
1125 BlockdevCreateOptionsGluster *gopts;
1126 BlockdevOptionsGluster *gconf;
1127 char *tmp = NULL;
1128 Error *local_err = NULL;
1129 int ret;
1130
1131 options = g_new0(BlockdevCreateOptions, 1);
1132 options->driver = BLOCKDEV_DRIVER_GLUSTER;
1133 gopts = &options->u.gluster;
1134
1135 gconf = g_new0(BlockdevOptionsGluster, 1);
1136 gopts->location = gconf;
1137
1138 gopts->size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
1139 BDRV_SECTOR_SIZE);
1140
1141 tmp = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
1142 gopts->preallocation = qapi_enum_parse(&PreallocMode_lookup, tmp,
1143 PREALLOC_MODE_OFF, &local_err);
1144 g_free(tmp);
1145 if (local_err) {
1146 error_propagate(errp, local_err);
1147 ret = -EINVAL;
1148 goto fail;
1149 }
1150
1151 gconf->debug = qemu_opt_get_number_del(opts, GLUSTER_OPT_DEBUG,
1152 GLUSTER_DEBUG_DEFAULT);
1153 if (gconf->debug < 0) {
1154 gconf->debug = 0;
1155 } else if (gconf->debug > GLUSTER_DEBUG_MAX) {
1156 gconf->debug = GLUSTER_DEBUG_MAX;
1157 }
1158 gconf->has_debug = true;
1159
1160 gconf->logfile = qemu_opt_get_del(opts, GLUSTER_OPT_LOGFILE);
1161 if (!gconf->logfile) {
1162 gconf->logfile = g_strdup(GLUSTER_LOGFILE_DEFAULT);
1163 }
1164 gconf->has_logfile = true;
1165
1166 ret = qemu_gluster_parse(gconf, filename, NULL, errp);
1167 if (ret < 0) {
1168 goto fail;
1169 }
1170
1171 ret = qemu_gluster_co_create(options, errp);
1172 if (ret < 0) {
1173 goto fail;
1174 }
1175
1176 ret = 0;
1177fail:
1178 qapi_free_BlockdevCreateOptions(options);
1179 return ret;
1180}
1181
1182static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
1183 int64_t sector_num, int nb_sectors,
1184 QEMUIOVector *qiov, int write)
1185{
1186 int ret;
1187 GlusterAIOCB acb;
1188 BDRVGlusterState *s = bs->opaque;
1189 size_t size = nb_sectors * BDRV_SECTOR_SIZE;
1190 off_t offset = sector_num * BDRV_SECTOR_SIZE;
1191
1192 acb.size = size;
1193 acb.ret = 0;
1194 acb.coroutine = qemu_coroutine_self();
1195 acb.aio_context = bdrv_get_aio_context(bs);
1196
1197 if (write) {
1198 ret = glfs_pwritev_async(s->fd, qiov->iov, qiov->niov, offset, 0,
1199 gluster_finish_aiocb, &acb);
1200 } else {
1201 ret = glfs_preadv_async(s->fd, qiov->iov, qiov->niov, offset, 0,
1202 gluster_finish_aiocb, &acb);
1203 }
1204
1205 if (ret < 0) {
1206 return -errno;
1207 }
1208
1209 qemu_coroutine_yield();
1210 return acb.ret;
1211}
1212
1213static coroutine_fn int qemu_gluster_co_truncate(BlockDriverState *bs,
1214 int64_t offset,
1215 bool exact,
1216 PreallocMode prealloc,
1217 BdrvRequestFlags flags,
1218 Error **errp)
1219{
1220 BDRVGlusterState *s = bs->opaque;
1221 return qemu_gluster_do_truncate(s->fd, offset, prealloc, errp);
1222}
1223
1224static coroutine_fn int qemu_gluster_co_readv(BlockDriverState *bs,
1225 int64_t sector_num,
1226 int nb_sectors,
1227 QEMUIOVector *qiov)
1228{
1229 return qemu_gluster_co_rw(bs, sector_num, nb_sectors, qiov, 0);
1230}
1231
1232static coroutine_fn int qemu_gluster_co_writev(BlockDriverState *bs,
1233 int64_t sector_num,
1234 int nb_sectors,
1235 QEMUIOVector *qiov,
1236 int flags)
1237{
1238 assert(!flags);
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, int size)
1301{
1302 int ret;
1303 GlusterAIOCB acb;
1304 BDRVGlusterState *s = bs->opaque;
1305
1306 acb.size = 0;
1307 acb.ret = 0;
1308 acb.coroutine = qemu_coroutine_self();
1309 acb.aio_context = bdrv_get_aio_context(bs);
1310
1311 ret = glfs_discard_async(s->fd, offset, size, gluster_finish_aiocb, &acb);
1312 if (ret < 0) {
1313 return -errno;
1314 }
1315
1316 qemu_coroutine_yield();
1317 return acb.ret;
1318}
1319#endif
1320
1321static int64_t qemu_gluster_getlength(BlockDriverState *bs)
1322{
1323 BDRVGlusterState *s = bs->opaque;
1324 int64_t ret;
1325
1326 ret = glfs_lseek(s->fd, 0, SEEK_END);
1327 if (ret < 0) {
1328 return -errno;
1329 } else {
1330 return ret;
1331 }
1332}
1333
1334static int64_t qemu_gluster_allocated_file_size(BlockDriverState *bs)
1335{
1336 BDRVGlusterState *s = bs->opaque;
1337 struct stat st;
1338 int ret;
1339
1340 ret = glfs_fstat(s->fd, &st);
1341 if (ret < 0) {
1342 return -errno;
1343 } else {
1344 return st.st_blocks * 512;
1345 }
1346}
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360static int find_allocation(BlockDriverState *bs, off_t start,
1361 off_t *data, off_t *hole)
1362{
1363 BDRVGlusterState *s = bs->opaque;
1364
1365 if (!s->supports_seek_data) {
1366 goto exit;
1367 }
1368
1369#if defined SEEK_HOLE && defined SEEK_DATA
1370 off_t offs;
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383 offs = glfs_lseek(s->fd, start, SEEK_DATA);
1384 if (offs < 0) {
1385 return -errno;
1386 }
1387
1388 if (offs < start) {
1389
1390
1391
1392
1393 return -EIO;
1394 }
1395
1396 if (offs > start) {
1397
1398 *hole = start;
1399 *data = offs;
1400 return 0;
1401 }
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422 offs = glfs_lseek(s->fd, start, SEEK_HOLE);
1423 if (offs < 0) {
1424 return -errno;
1425 }
1426
1427 if (offs < start) {
1428
1429
1430
1431
1432 return -EIO;
1433 }
1434
1435 if (offs > start) {
1436
1437
1438
1439
1440
1441
1442 *data = start;
1443 *hole = offs;
1444 return 0;
1445 }
1446
1447
1448 return -EBUSY;
1449#endif
1450
1451exit:
1452 return -ENOTSUP;
1453}
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs,
1469 bool want_zero,
1470 int64_t offset,
1471 int64_t bytes,
1472 int64_t *pnum,
1473 int64_t *map,
1474 BlockDriverState **file)
1475{
1476 BDRVGlusterState *s = bs->opaque;
1477 off_t data = 0, hole = 0;
1478 int ret = -EINVAL;
1479
1480 if (!s->fd) {
1481 return ret;
1482 }
1483
1484 if (!want_zero) {
1485 *pnum = bytes;
1486 *map = offset;
1487 *file = bs;
1488 return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
1489 }
1490
1491 ret = find_allocation(bs, offset, &data, &hole);
1492 if (ret == -ENXIO) {
1493
1494 *pnum = bytes;
1495 ret = BDRV_BLOCK_ZERO;
1496 } else if (ret < 0) {
1497
1498 *pnum = bytes;
1499 ret = BDRV_BLOCK_DATA;
1500 } else if (data == offset) {
1501
1502
1503 *pnum = MIN(bytes, hole - offset);
1504 ret = BDRV_BLOCK_DATA;
1505 } else {
1506
1507 assert(hole == offset);
1508 *pnum = MIN(bytes, data - offset);
1509 ret = BDRV_BLOCK_ZERO;
1510 }
1511
1512 *map = offset;
1513 *file = bs;
1514
1515 return ret | BDRV_BLOCK_OFFSET_VALID;
1516}
1517
1518
1519static const char *const gluster_strong_open_opts[] = {
1520 GLUSTER_OPT_VOLUME,
1521 GLUSTER_OPT_PATH,
1522 GLUSTER_OPT_TYPE,
1523 GLUSTER_OPT_SERVER_PATTERN,
1524 GLUSTER_OPT_HOST,
1525 GLUSTER_OPT_PORT,
1526 GLUSTER_OPT_TO,
1527 GLUSTER_OPT_IPV4,
1528 GLUSTER_OPT_IPV6,
1529 GLUSTER_OPT_SOCKET,
1530
1531 NULL
1532};
1533
1534static BlockDriver bdrv_gluster = {
1535 .format_name = "gluster",
1536 .protocol_name = "gluster",
1537 .instance_size = sizeof(BDRVGlusterState),
1538 .bdrv_needs_filename = false,
1539 .bdrv_file_open = qemu_gluster_open,
1540 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
1541 .bdrv_reopen_commit = qemu_gluster_reopen_commit,
1542 .bdrv_reopen_abort = qemu_gluster_reopen_abort,
1543 .bdrv_close = qemu_gluster_close,
1544 .bdrv_co_create = qemu_gluster_co_create,
1545 .bdrv_co_create_opts = qemu_gluster_co_create_opts,
1546 .bdrv_getlength = qemu_gluster_getlength,
1547 .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
1548 .bdrv_co_truncate = qemu_gluster_co_truncate,
1549 .bdrv_co_readv = qemu_gluster_co_readv,
1550 .bdrv_co_writev = qemu_gluster_co_writev,
1551 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
1552#ifdef CONFIG_GLUSTERFS_DISCARD
1553 .bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
1554#endif
1555#ifdef CONFIG_GLUSTERFS_ZEROFILL
1556 .bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
1557#endif
1558 .bdrv_co_block_status = qemu_gluster_co_block_status,
1559 .bdrv_refresh_limits = qemu_gluster_refresh_limits,
1560 .create_opts = &qemu_gluster_create_opts,
1561 .strong_runtime_opts = gluster_strong_open_opts,
1562};
1563
1564static BlockDriver bdrv_gluster_tcp = {
1565 .format_name = "gluster",
1566 .protocol_name = "gluster+tcp",
1567 .instance_size = sizeof(BDRVGlusterState),
1568 .bdrv_needs_filename = false,
1569 .bdrv_file_open = qemu_gluster_open,
1570 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
1571 .bdrv_reopen_commit = qemu_gluster_reopen_commit,
1572 .bdrv_reopen_abort = qemu_gluster_reopen_abort,
1573 .bdrv_close = qemu_gluster_close,
1574 .bdrv_co_create = qemu_gluster_co_create,
1575 .bdrv_co_create_opts = qemu_gluster_co_create_opts,
1576 .bdrv_getlength = qemu_gluster_getlength,
1577 .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
1578 .bdrv_co_truncate = qemu_gluster_co_truncate,
1579 .bdrv_co_readv = qemu_gluster_co_readv,
1580 .bdrv_co_writev = qemu_gluster_co_writev,
1581 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
1582#ifdef CONFIG_GLUSTERFS_DISCARD
1583 .bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
1584#endif
1585#ifdef CONFIG_GLUSTERFS_ZEROFILL
1586 .bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
1587#endif
1588 .bdrv_co_block_status = qemu_gluster_co_block_status,
1589 .bdrv_refresh_limits = qemu_gluster_refresh_limits,
1590 .create_opts = &qemu_gluster_create_opts,
1591 .strong_runtime_opts = gluster_strong_open_opts,
1592};
1593
1594static BlockDriver bdrv_gluster_unix = {
1595 .format_name = "gluster",
1596 .protocol_name = "gluster+unix",
1597 .instance_size = sizeof(BDRVGlusterState),
1598 .bdrv_needs_filename = true,
1599 .bdrv_file_open = qemu_gluster_open,
1600 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
1601 .bdrv_reopen_commit = qemu_gluster_reopen_commit,
1602 .bdrv_reopen_abort = qemu_gluster_reopen_abort,
1603 .bdrv_close = qemu_gluster_close,
1604 .bdrv_co_create = qemu_gluster_co_create,
1605 .bdrv_co_create_opts = qemu_gluster_co_create_opts,
1606 .bdrv_getlength = qemu_gluster_getlength,
1607 .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
1608 .bdrv_co_truncate = qemu_gluster_co_truncate,
1609 .bdrv_co_readv = qemu_gluster_co_readv,
1610 .bdrv_co_writev = qemu_gluster_co_writev,
1611 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
1612#ifdef CONFIG_GLUSTERFS_DISCARD
1613 .bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
1614#endif
1615#ifdef CONFIG_GLUSTERFS_ZEROFILL
1616 .bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
1617#endif
1618 .bdrv_co_block_status = qemu_gluster_co_block_status,
1619 .bdrv_refresh_limits = qemu_gluster_refresh_limits,
1620 .create_opts = &qemu_gluster_create_opts,
1621 .strong_runtime_opts = gluster_strong_open_opts,
1622};
1623
1624
1625
1626
1627
1628
1629
1630static BlockDriver bdrv_gluster_rdma = {
1631 .format_name = "gluster",
1632 .protocol_name = "gluster+rdma",
1633 .instance_size = sizeof(BDRVGlusterState),
1634 .bdrv_needs_filename = true,
1635 .bdrv_file_open = qemu_gluster_open,
1636 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
1637 .bdrv_reopen_commit = qemu_gluster_reopen_commit,
1638 .bdrv_reopen_abort = qemu_gluster_reopen_abort,
1639 .bdrv_close = qemu_gluster_close,
1640 .bdrv_co_create = qemu_gluster_co_create,
1641 .bdrv_co_create_opts = qemu_gluster_co_create_opts,
1642 .bdrv_getlength = qemu_gluster_getlength,
1643 .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
1644 .bdrv_co_truncate = qemu_gluster_co_truncate,
1645 .bdrv_co_readv = qemu_gluster_co_readv,
1646 .bdrv_co_writev = qemu_gluster_co_writev,
1647 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
1648#ifdef CONFIG_GLUSTERFS_DISCARD
1649 .bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
1650#endif
1651#ifdef CONFIG_GLUSTERFS_ZEROFILL
1652 .bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
1653#endif
1654 .bdrv_co_block_status = qemu_gluster_co_block_status,
1655 .bdrv_refresh_limits = qemu_gluster_refresh_limits,
1656 .create_opts = &qemu_gluster_create_opts,
1657 .strong_runtime_opts = gluster_strong_open_opts,
1658};
1659
1660static void bdrv_gluster_init(void)
1661{
1662 bdrv_register(&bdrv_gluster_rdma);
1663 bdrv_register(&bdrv_gluster_unix);
1664 bdrv_register(&bdrv_gluster_tcp);
1665 bdrv_register(&bdrv_gluster);
1666}
1667
1668block_init(bdrv_gluster_init);
1669