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-io.h"
15#include "block/block_int.h"
16#include "block/qdict.h"
17#include "qapi/error.h"
18#include "qapi/qmp/qdict.h"
19#include "qapi/qmp/qerror.h"
20#include "qemu/uri.h"
21#include "qemu/error-report.h"
22#include "qemu/module.h"
23#include "qemu/option.h"
24#include "qemu/cutils.h"
25
26#ifdef CONFIG_GLUSTERFS_FTRUNCATE_HAS_STAT
27# define glfs_ftruncate(fd, offset) glfs_ftruncate(fd, offset, NULL, NULL)
28#endif
29
30#define GLUSTER_OPT_FILENAME "filename"
31#define GLUSTER_OPT_VOLUME "volume"
32#define GLUSTER_OPT_PATH "path"
33#define GLUSTER_OPT_TYPE "type"
34#define GLUSTER_OPT_SERVER_PATTERN "server."
35#define GLUSTER_OPT_HOST "host"
36#define GLUSTER_OPT_PORT "port"
37#define GLUSTER_OPT_TO "to"
38#define GLUSTER_OPT_IPV4 "ipv4"
39#define GLUSTER_OPT_IPV6 "ipv6"
40#define GLUSTER_OPT_SOCKET "socket"
41#define GLUSTER_OPT_DEBUG "debug"
42#define GLUSTER_DEFAULT_PORT 24007
43#define GLUSTER_DEBUG_DEFAULT 4
44#define GLUSTER_DEBUG_MAX 9
45#define GLUSTER_OPT_LOGFILE "logfile"
46#define GLUSTER_LOGFILE_DEFAULT "-"
47
48
49
50
51
52#define GLUSTER_MAX_TRANSFER (512 * MiB)
53
54#define GERR_INDEX_HINT "hint: check in 'server' array index '%d'\n"
55
56typedef struct GlusterAIOCB {
57 int64_t size;
58 int ret;
59 Coroutine *coroutine;
60 AioContext *aio_context;
61} GlusterAIOCB;
62
63typedef struct BDRVGlusterState {
64 struct glfs *glfs;
65 struct glfs_fd *fd;
66 char *logfile;
67 bool supports_seek_data;
68 int debug;
69} BDRVGlusterState;
70
71typedef struct BDRVGlusterReopenState {
72 struct glfs *glfs;
73 struct glfs_fd *fd;
74} BDRVGlusterReopenState;
75
76
77typedef struct GlfsPreopened {
78 char *volume;
79 glfs_t *fs;
80 int ref;
81} GlfsPreopened;
82
83typedef struct ListElement {
84 QLIST_ENTRY(ListElement) list;
85 GlfsPreopened saved;
86} ListElement;
87
88static QLIST_HEAD(, ListElement) glfs_list;
89
90static QemuOptsList qemu_gluster_create_opts = {
91 .name = "qemu-gluster-create-opts",
92 .head = QTAILQ_HEAD_INITIALIZER(qemu_gluster_create_opts.head),
93 .desc = {
94 {
95 .name = BLOCK_OPT_SIZE,
96 .type = QEMU_OPT_SIZE,
97 .help = "Virtual disk size"
98 },
99 {
100 .name = BLOCK_OPT_PREALLOC,
101 .type = QEMU_OPT_STRING,
102 .help = "Preallocation mode (allowed values: off"
103#ifdef CONFIG_GLUSTERFS_FALLOCATE
104 ", falloc"
105#endif
106#ifdef CONFIG_GLUSTERFS_ZEROFILL
107 ", full"
108#endif
109 ")"
110 },
111 {
112 .name = GLUSTER_OPT_DEBUG,
113 .type = QEMU_OPT_NUMBER,
114 .help = "Gluster log level, valid range is 0-9",
115 },
116 {
117 .name = GLUSTER_OPT_LOGFILE,
118 .type = QEMU_OPT_STRING,
119 .help = "Logfile path of libgfapi",
120 },
121 { }
122 }
123};
124
125static QemuOptsList runtime_opts = {
126 .name = "gluster",
127 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
128 .desc = {
129 {
130 .name = GLUSTER_OPT_FILENAME,
131 .type = QEMU_OPT_STRING,
132 .help = "URL to the gluster image",
133 },
134 {
135 .name = GLUSTER_OPT_DEBUG,
136 .type = QEMU_OPT_NUMBER,
137 .help = "Gluster log level, valid range is 0-9",
138 },
139 {
140 .name = GLUSTER_OPT_LOGFILE,
141 .type = QEMU_OPT_STRING,
142 .help = "Logfile path of libgfapi",
143 },
144 { }
145 },
146};
147
148static QemuOptsList runtime_json_opts = {
149 .name = "gluster_json",
150 .head = QTAILQ_HEAD_INITIALIZER(runtime_json_opts.head),
151 .desc = {
152 {
153 .name = GLUSTER_OPT_VOLUME,
154 .type = QEMU_OPT_STRING,
155 .help = "name of gluster volume where VM image resides",
156 },
157 {
158 .name = GLUSTER_OPT_PATH,
159 .type = QEMU_OPT_STRING,
160 .help = "absolute path to image file in gluster volume",
161 },
162 {
163 .name = GLUSTER_OPT_DEBUG,
164 .type = QEMU_OPT_NUMBER,
165 .help = "Gluster log level, valid range is 0-9",
166 },
167 { }
168 },
169};
170
171static QemuOptsList runtime_type_opts = {
172 .name = "gluster_type",
173 .head = QTAILQ_HEAD_INITIALIZER(runtime_type_opts.head),
174 .desc = {
175 {
176 .name = GLUSTER_OPT_TYPE,
177 .type = QEMU_OPT_STRING,
178 .help = "inet|unix",
179 },
180 { }
181 },
182};
183
184static QemuOptsList runtime_unix_opts = {
185 .name = "gluster_unix",
186 .head = QTAILQ_HEAD_INITIALIZER(runtime_unix_opts.head),
187 .desc = {
188 {
189 .name = GLUSTER_OPT_SOCKET,
190 .type = QEMU_OPT_STRING,
191 .help = "socket file path (legacy)",
192 },
193 {
194 .name = GLUSTER_OPT_PATH,
195 .type = QEMU_OPT_STRING,
196 .help = "socket file path (QAPI)",
197 },
198 { }
199 },
200};
201
202static QemuOptsList runtime_inet_opts = {
203 .name = "gluster_inet",
204 .head = QTAILQ_HEAD_INITIALIZER(runtime_inet_opts.head),
205 .desc = {
206 {
207 .name = GLUSTER_OPT_TYPE,
208 .type = QEMU_OPT_STRING,
209 .help = "inet|unix",
210 },
211 {
212 .name = GLUSTER_OPT_HOST,
213 .type = QEMU_OPT_STRING,
214 .help = "host address (hostname/ipv4/ipv6 addresses)",
215 },
216 {
217 .name = GLUSTER_OPT_PORT,
218 .type = QEMU_OPT_STRING,
219 .help = "port number on which glusterd is listening (default 24007)",
220 },
221 {
222 .name = "to",
223 .type = QEMU_OPT_NUMBER,
224 .help = "max port number, not supported by gluster",
225 },
226 {
227 .name = "ipv4",
228 .type = QEMU_OPT_BOOL,
229 .help = "ipv4 bool value, not supported by gluster",
230 },
231 {
232 .name = "ipv6",
233 .type = QEMU_OPT_BOOL,
234 .help = "ipv6 bool value, not supported by gluster",
235 },
236 { }
237 },
238};
239
240static void glfs_set_preopened(const char *volume, glfs_t *fs)
241{
242 ListElement *entry = NULL;
243
244 entry = g_new(ListElement, 1);
245
246 entry->saved.volume = g_strdup(volume);
247
248 entry->saved.fs = fs;
249 entry->saved.ref = 1;
250
251 QLIST_INSERT_HEAD(&glfs_list, entry, list);
252}
253
254static glfs_t *glfs_find_preopened(const char *volume)
255{
256 ListElement *entry = NULL;
257
258 QLIST_FOREACH(entry, &glfs_list, list) {
259 if (strcmp(entry->saved.volume, volume) == 0) {
260 entry->saved.ref++;
261 return entry->saved.fs;
262 }
263 }
264
265 return NULL;
266}
267
268static void glfs_clear_preopened(glfs_t *fs)
269{
270 ListElement *entry = NULL;
271 ListElement *next;
272
273 if (fs == NULL) {
274 return;
275 }
276
277 QLIST_FOREACH_SAFE(entry, &glfs_list, list, next) {
278 if (entry->saved.fs == fs) {
279 if (--entry->saved.ref) {
280 return;
281 }
282
283 QLIST_REMOVE(entry, list);
284
285 glfs_fini(entry->saved.fs);
286 g_free(entry->saved.volume);
287 g_free(entry);
288 }
289 }
290}
291
292static int parse_volume_options(BlockdevOptionsGluster *gconf, char *path)
293{
294 char *p, *q;
295
296 if (!path) {
297 return -EINVAL;
298 }
299
300
301 p = q = path + strspn(path, "/");
302 p += strcspn(p, "/");
303 if (*p == '\0') {
304 return -EINVAL;
305 }
306 gconf->volume = g_strndup(q, p - q);
307
308
309 p += strspn(p, "/");
310 if (*p == '\0') {
311 return -EINVAL;
312 }
313 gconf->path = g_strdup(p);
314 return 0;
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
348
349static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf,
350 const char *filename)
351{
352 SocketAddress *gsconf;
353 URI *uri;
354 QueryParams *qp = NULL;
355 bool is_unix = false;
356 int ret = 0;
357
358 uri = uri_parse(filename);
359 if (!uri) {
360 return -EINVAL;
361 }
362
363 gsconf = g_new0(SocketAddress, 1);
364 QAPI_LIST_PREPEND(gconf->server, gsconf);
365
366
367 if (!uri->scheme || !strcmp(uri->scheme, "gluster")) {
368 gsconf->type = SOCKET_ADDRESS_TYPE_INET;
369 } else if (!strcmp(uri->scheme, "gluster+tcp")) {
370 gsconf->type = SOCKET_ADDRESS_TYPE_INET;
371 } else if (!strcmp(uri->scheme, "gluster+unix")) {
372 gsconf->type = SOCKET_ADDRESS_TYPE_UNIX;
373 is_unix = true;
374 } else if (!strcmp(uri->scheme, "gluster+rdma")) {
375 gsconf->type = SOCKET_ADDRESS_TYPE_INET;
376 warn_report("rdma feature is not supported, falling back to tcp");
377 } else {
378 ret = -EINVAL;
379 goto out;
380 }
381
382 ret = parse_volume_options(gconf, uri->path);
383 if (ret < 0) {
384 goto out;
385 }
386
387 qp = query_params_parse(uri->query);
388 if (qp->n > 1 || (is_unix && !qp->n) || (!is_unix && qp->n)) {
389 ret = -EINVAL;
390 goto out;
391 }
392
393 if (is_unix) {
394 if (uri->server || uri->port) {
395 ret = -EINVAL;
396 goto out;
397 }
398 if (strcmp(qp->p[0].name, "socket")) {
399 ret = -EINVAL;
400 goto out;
401 }
402 gsconf->u.q_unix.path = g_strdup(qp->p[0].value);
403 } else {
404 gsconf->u.inet.host = g_strdup(uri->server ? uri->server : "localhost");
405 if (uri->port) {
406 gsconf->u.inet.port = g_strdup_printf("%d", uri->port);
407 } else {
408 gsconf->u.inet.port = g_strdup_printf("%d", GLUSTER_DEFAULT_PORT);
409 }
410 }
411
412out:
413 if (qp) {
414 query_params_free(qp);
415 }
416 uri_free(uri);
417 return ret;
418}
419
420static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
421 Error **errp)
422{
423 struct glfs *glfs;
424 int ret;
425 int old_errno;
426 SocketAddressList *server;
427 unsigned long long port;
428
429 glfs = glfs_find_preopened(gconf->volume);
430 if (glfs) {
431 return glfs;
432 }
433
434 glfs = glfs_new(gconf->volume);
435 if (!glfs) {
436 goto out;
437 }
438
439 glfs_set_preopened(gconf->volume, glfs);
440
441 for (server = gconf->server; server; server = server->next) {
442 switch (server->value->type) {
443 case SOCKET_ADDRESS_TYPE_UNIX:
444 ret = glfs_set_volfile_server(glfs, "unix",
445 server->value->u.q_unix.path, 0);
446 break;
447 case SOCKET_ADDRESS_TYPE_INET:
448 if (parse_uint_full(server->value->u.inet.port, &port, 10) < 0 ||
449 port > 65535) {
450 error_setg(errp, "'%s' is not a valid port number",
451 server->value->u.inet.port);
452 errno = EINVAL;
453 goto out;
454 }
455 ret = glfs_set_volfile_server(glfs, "tcp",
456 server->value->u.inet.host,
457 (int)port);
458 break;
459 case SOCKET_ADDRESS_TYPE_VSOCK:
460 case SOCKET_ADDRESS_TYPE_FD:
461 default:
462 abort();
463 }
464
465 if (ret < 0) {
466 goto out;
467 }
468 }
469
470 ret = glfs_set_logging(glfs, gconf->logfile, gconf->debug);
471 if (ret < 0) {
472 goto out;
473 }
474
475 ret = glfs_init(glfs);
476 if (ret) {
477 error_setg(errp, "Gluster connection for volume %s, path %s failed"
478 " to connect", gconf->volume, gconf->path);
479 for (server = gconf->server; server; server = server->next) {
480 if (server->value->type == SOCKET_ADDRESS_TYPE_UNIX) {
481 error_append_hint(errp, "hint: failed on socket %s ",
482 server->value->u.q_unix.path);
483 } else {
484 error_append_hint(errp, "hint: failed on host %s and port %s ",
485 server->value->u.inet.host,
486 server->value->u.inet.port);
487 }
488 }
489
490 error_append_hint(errp, "Please refer to gluster logs for more info\n");
491
492
493 if (errno == 0) {
494 errno = EINVAL;
495 }
496
497 goto out;
498 }
499 return glfs;
500
501out:
502 if (glfs) {
503 old_errno = errno;
504 glfs_clear_preopened(glfs);
505 errno = old_errno;
506 }
507 return NULL;
508}
509
510
511
512
513static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
514 QDict *options, Error **errp)
515{
516 QemuOpts *opts;
517 SocketAddress *gsconf = NULL;
518 SocketAddressList **tail;
519 QDict *backing_options = NULL;
520 Error *local_err = NULL;
521 char *str = NULL;
522 const char *ptr;
523 int i, type, num_servers;
524
525
526 opts = qemu_opts_create(&runtime_json_opts, NULL, 0, &error_abort);
527 if (!qemu_opts_absorb_qdict(opts, options, errp)) {
528 goto out;
529 }
530
531 num_servers = qdict_array_entries(options, GLUSTER_OPT_SERVER_PATTERN);
532 if (num_servers < 1) {
533 error_setg(&local_err, QERR_MISSING_PARAMETER, "server");
534 goto out;
535 }
536
537 ptr = qemu_opt_get(opts, GLUSTER_OPT_VOLUME);
538 if (!ptr) {
539 error_setg(&local_err, QERR_MISSING_PARAMETER, GLUSTER_OPT_VOLUME);
540 goto out;
541 }
542 gconf->volume = g_strdup(ptr);
543
544 ptr = qemu_opt_get(opts, GLUSTER_OPT_PATH);
545 if (!ptr) {
546 error_setg(&local_err, QERR_MISSING_PARAMETER, GLUSTER_OPT_PATH);
547 goto out;
548 }
549 gconf->path = g_strdup(ptr);
550 qemu_opts_del(opts);
551 tail = &gconf->server;
552
553 for (i = 0; i < num_servers; i++) {
554 str = g_strdup_printf(GLUSTER_OPT_SERVER_PATTERN"%d.", i);
555 qdict_extract_subqdict(options, &backing_options, str);
556
557
558 opts = qemu_opts_create(&runtime_type_opts, NULL, 0, &error_abort);
559 if (!qemu_opts_absorb_qdict(opts, backing_options, errp)) {
560 goto out;
561 }
562
563 ptr = qemu_opt_get(opts, GLUSTER_OPT_TYPE);
564 if (!ptr) {
565 error_setg(&local_err, QERR_MISSING_PARAMETER, GLUSTER_OPT_TYPE);
566 error_append_hint(&local_err, GERR_INDEX_HINT, i);
567 goto out;
568
569 }
570 gsconf = g_new0(SocketAddress, 1);
571 if (!strcmp(ptr, "tcp")) {
572 ptr = "inet";
573 }
574 type = qapi_enum_parse(&SocketAddressType_lookup, ptr, -1, NULL);
575 if (type != SOCKET_ADDRESS_TYPE_INET
576 && type != SOCKET_ADDRESS_TYPE_UNIX) {
577 error_setg(&local_err,
578 "Parameter '%s' may be 'inet' or 'unix'",
579 GLUSTER_OPT_TYPE);
580 error_append_hint(&local_err, GERR_INDEX_HINT, i);
581 goto out;
582 }
583 gsconf->type = type;
584 qemu_opts_del(opts);
585
586 if (gsconf->type == SOCKET_ADDRESS_TYPE_INET) {
587
588 opts = qemu_opts_create(&runtime_inet_opts, NULL, 0, &error_abort);
589 if (!qemu_opts_absorb_qdict(opts, backing_options, errp)) {
590 goto out;
591 }
592
593 ptr = qemu_opt_get(opts, GLUSTER_OPT_HOST);
594 if (!ptr) {
595 error_setg(&local_err, QERR_MISSING_PARAMETER,
596 GLUSTER_OPT_HOST);
597 error_append_hint(&local_err, GERR_INDEX_HINT, i);
598 goto out;
599 }
600 gsconf->u.inet.host = g_strdup(ptr);
601 ptr = qemu_opt_get(opts, GLUSTER_OPT_PORT);
602 if (!ptr) {
603 error_setg(&local_err, QERR_MISSING_PARAMETER,
604 GLUSTER_OPT_PORT);
605 error_append_hint(&local_err, GERR_INDEX_HINT, i);
606 goto out;
607 }
608 gsconf->u.inet.port = g_strdup(ptr);
609
610
611
612
613 ptr = qemu_opt_get(opts, GLUSTER_OPT_TO);
614 if (ptr) {
615 gsconf->u.inet.has_to = true;
616 }
617 ptr = qemu_opt_get(opts, GLUSTER_OPT_IPV4);
618 if (ptr) {
619 gsconf->u.inet.has_ipv4 = true;
620 }
621 ptr = qemu_opt_get(opts, GLUSTER_OPT_IPV6);
622 if (ptr) {
623 gsconf->u.inet.has_ipv6 = true;
624 }
625 if (gsconf->u.inet.has_to) {
626 error_setg(&local_err, "Parameter 'to' not supported");
627 goto out;
628 }
629 if (gsconf->u.inet.has_ipv4 || gsconf->u.inet.has_ipv6) {
630 error_setg(&local_err, "Parameters 'ipv4/ipv6' not supported");
631 goto out;
632 }
633 qemu_opts_del(opts);
634 } else {
635
636 opts = qemu_opts_create(&runtime_unix_opts, NULL, 0, &error_abort);
637 if (!qemu_opts_absorb_qdict(opts, backing_options, errp)) {
638 goto out;
639 }
640
641 ptr = qemu_opt_get(opts, GLUSTER_OPT_PATH);
642 if (!ptr) {
643 ptr = qemu_opt_get(opts, GLUSTER_OPT_SOCKET);
644 } else if (qemu_opt_get(opts, GLUSTER_OPT_SOCKET)) {
645 error_setg(&local_err,
646 "Conflicting parameters 'path' and 'socket'");
647 error_append_hint(&local_err, GERR_INDEX_HINT, i);
648 goto out;
649 }
650 if (!ptr) {
651 error_setg(&local_err, QERR_MISSING_PARAMETER,
652 GLUSTER_OPT_PATH);
653 error_append_hint(&local_err, GERR_INDEX_HINT, i);
654 goto out;
655 }
656 gsconf->u.q_unix.path = g_strdup(ptr);
657 qemu_opts_del(opts);
658 }
659
660 QAPI_LIST_APPEND(tail, gsconf);
661 gsconf = NULL;
662
663 qobject_unref(backing_options);
664 backing_options = NULL;
665 g_free(str);
666 str = NULL;
667 }
668
669 return 0;
670
671out:
672 error_propagate(errp, local_err);
673 qapi_free_SocketAddress(gsconf);
674 qemu_opts_del(opts);
675 g_free(str);
676 qobject_unref(backing_options);
677 errno = EINVAL;
678 return -errno;
679}
680
681
682
683static int qemu_gluster_parse(BlockdevOptionsGluster *gconf,
684 const char *filename,
685 QDict *options, Error **errp)
686{
687 int ret;
688 if (filename) {
689 ret = qemu_gluster_parse_uri(gconf, filename);
690 if (ret < 0) {
691 error_setg(errp, "invalid URI %s", filename);
692 error_append_hint(errp, "Usage: file=gluster[+transport]://"
693 "[host[:port]]volume/path[?socket=...]"
694 "[,file.debug=N]"
695 "[,file.logfile=/path/filename.log]\n");
696 return ret;
697 }
698 } else {
699 ret = qemu_gluster_parse_json(gconf, options, errp);
700 if (ret < 0) {
701 error_append_hint(errp, "Usage: "
702 "-drive driver=qcow2,file.driver=gluster,"
703 "file.volume=testvol,file.path=/path/a.qcow2"
704 "[,file.debug=9]"
705 "[,file.logfile=/path/filename.log],"
706 "file.server.0.type=inet,"
707 "file.server.0.host=1.2.3.4,"
708 "file.server.0.port=24007,"
709 "file.server.1.transport=unix,"
710 "file.server.1.path=/var/run/glusterd.socket ..."
711 "\n");
712 return ret;
713 }
714 }
715
716 return 0;
717}
718
719static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
720 const char *filename,
721 QDict *options, Error **errp)
722{
723 int ret;
724
725 ret = qemu_gluster_parse(gconf, filename, options, errp);
726 if (ret < 0) {
727 errno = -ret;
728 return NULL;
729 }
730
731 return qemu_gluster_glfs_init(gconf, errp);
732}
733
734
735
736
737static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret,
738#ifdef CONFIG_GLUSTERFS_IOCB_HAS_STAT
739 struct glfs_stat *pre, struct glfs_stat *post,
740#endif
741 void *arg)
742{
743 GlusterAIOCB *acb = (GlusterAIOCB *)arg;
744
745 if (!ret || ret == acb->size) {
746 acb->ret = 0;
747 } else if (ret < 0) {
748 acb->ret = -errno;
749 } else {
750 acb->ret = -EIO;
751 }
752
753 aio_co_schedule(acb->aio_context, acb->coroutine);
754}
755
756static void qemu_gluster_parse_flags(int bdrv_flags, int *open_flags)
757{
758 assert(open_flags != NULL);
759
760 *open_flags |= O_BINARY;
761
762 if (bdrv_flags & BDRV_O_RDWR) {
763 *open_flags |= O_RDWR;
764 } else {
765 *open_flags |= O_RDONLY;
766 }
767
768 if ((bdrv_flags & BDRV_O_NOCACHE)) {
769 *open_flags |= O_DIRECT;
770 }
771}
772
773
774
775
776
777
778
779
780static bool qemu_gluster_test_seek(struct glfs_fd *fd)
781{
782 off_t ret = 0;
783
784#if defined SEEK_HOLE && defined SEEK_DATA
785 off_t eof;
786
787 eof = glfs_lseek(fd, 0, SEEK_END);
788 if (eof < 0) {
789
790 return false;
791 }
792
793
794 ret = glfs_lseek(fd, eof, SEEK_DATA);
795#endif
796
797 return (ret < 0) && (errno == ENXIO);
798}
799
800static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
801 int bdrv_flags, Error **errp)
802{
803 BDRVGlusterState *s = bs->opaque;
804 int open_flags = 0;
805 int ret = 0;
806 BlockdevOptionsGluster *gconf = NULL;
807 QemuOpts *opts;
808 const char *filename, *logfile;
809
810 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
811 if (!qemu_opts_absorb_qdict(opts, options, errp)) {
812 ret = -EINVAL;
813 goto out;
814 }
815
816 filename = qemu_opt_get(opts, GLUSTER_OPT_FILENAME);
817
818 s->debug = qemu_opt_get_number(opts, GLUSTER_OPT_DEBUG,
819 GLUSTER_DEBUG_DEFAULT);
820 if (s->debug < 0) {
821 s->debug = 0;
822 } else if (s->debug > GLUSTER_DEBUG_MAX) {
823 s->debug = GLUSTER_DEBUG_MAX;
824 }
825
826 gconf = g_new0(BlockdevOptionsGluster, 1);
827 gconf->debug = s->debug;
828 gconf->has_debug = true;
829
830 logfile = qemu_opt_get(opts, GLUSTER_OPT_LOGFILE);
831 s->logfile = g_strdup(logfile ? logfile : GLUSTER_LOGFILE_DEFAULT);
832
833 gconf->logfile = g_strdup(s->logfile);
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
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 int64_t bytes,
1007 BdrvRequestFlags flags)
1008{
1009 int ret;
1010 GlusterAIOCB acb;
1011 BDRVGlusterState *s = bs->opaque;
1012
1013 acb.size = bytes;
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, bytes, 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
1165 ret = qemu_gluster_parse(gconf, filename, NULL, errp);
1166 if (ret < 0) {
1167 goto fail;
1168 }
1169
1170 ret = qemu_gluster_co_create(options, errp);
1171 if (ret < 0) {
1172 goto fail;
1173 }
1174
1175 ret = 0;
1176fail:
1177 qapi_free_BlockdevCreateOptions(options);
1178 return ret;
1179}
1180
1181static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
1182 int64_t sector_num, int nb_sectors,
1183 QEMUIOVector *qiov, int write)
1184{
1185 int ret;
1186 GlusterAIOCB acb;
1187 BDRVGlusterState *s = bs->opaque;
1188 size_t size = nb_sectors * BDRV_SECTOR_SIZE;
1189 off_t offset = sector_num * BDRV_SECTOR_SIZE;
1190
1191 acb.size = size;
1192 acb.ret = 0;
1193 acb.coroutine = qemu_coroutine_self();
1194 acb.aio_context = bdrv_get_aio_context(bs);
1195
1196 if (write) {
1197 ret = glfs_pwritev_async(s->fd, qiov->iov, qiov->niov, offset, 0,
1198 gluster_finish_aiocb, &acb);
1199 } else {
1200 ret = glfs_preadv_async(s->fd, qiov->iov, qiov->niov, offset, 0,
1201 gluster_finish_aiocb, &acb);
1202 }
1203
1204 if (ret < 0) {
1205 return -errno;
1206 }
1207
1208 qemu_coroutine_yield();
1209 return acb.ret;
1210}
1211
1212static coroutine_fn int qemu_gluster_co_truncate(BlockDriverState *bs,
1213 int64_t offset,
1214 bool exact,
1215 PreallocMode prealloc,
1216 BdrvRequestFlags flags,
1217 Error **errp)
1218{
1219 BDRVGlusterState *s = bs->opaque;
1220 return qemu_gluster_do_truncate(s->fd, offset, prealloc, errp);
1221}
1222
1223static coroutine_fn int qemu_gluster_co_readv(BlockDriverState *bs,
1224 int64_t sector_num,
1225 int nb_sectors,
1226 QEMUIOVector *qiov)
1227{
1228 return qemu_gluster_co_rw(bs, sector_num, nb_sectors, qiov, 0);
1229}
1230
1231static coroutine_fn int qemu_gluster_co_writev(BlockDriverState *bs,
1232 int64_t sector_num,
1233 int nb_sectors,
1234 QEMUIOVector *qiov,
1235 int flags)
1236{
1237 return qemu_gluster_co_rw(bs, sector_num, nb_sectors, qiov, 1);
1238}
1239
1240static void qemu_gluster_close(BlockDriverState *bs)
1241{
1242 BDRVGlusterState *s = bs->opaque;
1243
1244 g_free(s->logfile);
1245 if (s->fd) {
1246 glfs_close(s->fd);
1247 s->fd = NULL;
1248 }
1249 glfs_clear_preopened(s->glfs);
1250}
1251
1252static coroutine_fn int qemu_gluster_co_flush_to_disk(BlockDriverState *bs)
1253{
1254 int ret;
1255 GlusterAIOCB acb;
1256 BDRVGlusterState *s = bs->opaque;
1257
1258 acb.size = 0;
1259 acb.ret = 0;
1260 acb.coroutine = qemu_coroutine_self();
1261 acb.aio_context = bdrv_get_aio_context(bs);
1262
1263 ret = glfs_fsync_async(s->fd, gluster_finish_aiocb, &acb);
1264 if (ret < 0) {
1265 ret = -errno;
1266 goto error;
1267 }
1268
1269 qemu_coroutine_yield();
1270 if (acb.ret < 0) {
1271 ret = acb.ret;
1272 goto error;
1273 }
1274
1275 return acb.ret;
1276
1277error:
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291 qemu_gluster_close(bs);
1292 bs->drv = NULL;
1293 return ret;
1294}
1295
1296#ifdef CONFIG_GLUSTERFS_DISCARD
1297static coroutine_fn int qemu_gluster_co_pdiscard(BlockDriverState *bs,
1298 int64_t offset, int64_t bytes)
1299{
1300 int ret;
1301 GlusterAIOCB acb;
1302 BDRVGlusterState *s = bs->opaque;
1303
1304 assert(bytes <= SIZE_MAX);
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, bytes, 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 coroutine_fn qemu_gluster_co_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 coroutine_fn
1335qemu_gluster_co_get_allocated_file_size(BlockDriverState *bs)
1336{
1337 BDRVGlusterState *s = bs->opaque;
1338 struct stat st;
1339 int ret;
1340
1341 ret = glfs_fstat(s->fd, &st);
1342 if (ret < 0) {
1343 return -errno;
1344 } else {
1345 return st.st_blocks * 512;
1346 }
1347}
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361static int find_allocation(BlockDriverState *bs, off_t start,
1362 off_t *data, off_t *hole)
1363{
1364 BDRVGlusterState *s = bs->opaque;
1365
1366 if (!s->supports_seek_data) {
1367 goto exit;
1368 }
1369
1370#if defined SEEK_HOLE && defined SEEK_DATA
1371 off_t offs;
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384 offs = glfs_lseek(s->fd, start, SEEK_DATA);
1385 if (offs < 0) {
1386 return -errno;
1387 }
1388
1389 if (offs < start) {
1390
1391
1392
1393
1394 return -EIO;
1395 }
1396
1397 if (offs > start) {
1398
1399 *hole = start;
1400 *data = offs;
1401 return 0;
1402 }
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423 offs = glfs_lseek(s->fd, start, SEEK_HOLE);
1424 if (offs < 0) {
1425 return -errno;
1426 }
1427
1428 if (offs < start) {
1429
1430
1431
1432
1433 return -EIO;
1434 }
1435
1436 if (offs > start) {
1437
1438
1439
1440
1441
1442
1443 *data = start;
1444 *hole = offs;
1445 return 0;
1446 }
1447
1448
1449 return -EBUSY;
1450#endif
1451
1452exit:
1453 return -ENOTSUP;
1454}
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs,
1471 bool want_zero,
1472 int64_t offset,
1473 int64_t bytes,
1474 int64_t *pnum,
1475 int64_t *map,
1476 BlockDriverState **file)
1477{
1478 BDRVGlusterState *s = bs->opaque;
1479 off_t data = 0, hole = 0;
1480 int ret = -EINVAL;
1481
1482 assert(QEMU_IS_ALIGNED(offset | bytes, bs->bl.request_alignment));
1483
1484 if (!s->fd) {
1485 return ret;
1486 }
1487
1488 if (!want_zero) {
1489 *pnum = bytes;
1490 *map = offset;
1491 *file = bs;
1492 return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
1493 }
1494
1495 ret = find_allocation(bs, offset, &data, &hole);
1496 if (ret == -ENXIO) {
1497
1498 *pnum = bytes;
1499 ret = BDRV_BLOCK_ZERO;
1500 } else if (ret < 0) {
1501
1502 *pnum = bytes;
1503 ret = BDRV_BLOCK_DATA;
1504 } else if (data == offset) {
1505
1506
1507 *pnum = hole - offset;
1508
1509
1510
1511
1512
1513 if (!QEMU_IS_ALIGNED(*pnum, bs->bl.request_alignment)) {
1514 int64_t file_length = qemu_gluster_co_getlength(bs);
1515 if (file_length > 0) {
1516
1517 assert(hole == file_length);
1518 }
1519 *pnum = ROUND_UP(*pnum, bs->bl.request_alignment);
1520 }
1521
1522 ret = BDRV_BLOCK_DATA;
1523 } else {
1524
1525 assert(hole == offset);
1526 *pnum = data - offset;
1527 ret = BDRV_BLOCK_ZERO;
1528 }
1529
1530 *map = offset;
1531 *file = bs;
1532
1533 return ret | BDRV_BLOCK_OFFSET_VALID;
1534}
1535
1536
1537static const char *const gluster_strong_open_opts[] = {
1538 GLUSTER_OPT_VOLUME,
1539 GLUSTER_OPT_PATH,
1540 GLUSTER_OPT_TYPE,
1541 GLUSTER_OPT_SERVER_PATTERN,
1542 GLUSTER_OPT_HOST,
1543 GLUSTER_OPT_PORT,
1544 GLUSTER_OPT_TO,
1545 GLUSTER_OPT_IPV4,
1546 GLUSTER_OPT_IPV6,
1547 GLUSTER_OPT_SOCKET,
1548
1549 NULL
1550};
1551
1552static BlockDriver bdrv_gluster = {
1553 .format_name = "gluster",
1554 .protocol_name = "gluster",
1555 .instance_size = sizeof(BDRVGlusterState),
1556 .bdrv_file_open = qemu_gluster_open,
1557 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
1558 .bdrv_reopen_commit = qemu_gluster_reopen_commit,
1559 .bdrv_reopen_abort = qemu_gluster_reopen_abort,
1560 .bdrv_close = qemu_gluster_close,
1561 .bdrv_co_create = qemu_gluster_co_create,
1562 .bdrv_co_create_opts = qemu_gluster_co_create_opts,
1563 .bdrv_co_getlength = qemu_gluster_co_getlength,
1564 .bdrv_co_get_allocated_file_size = qemu_gluster_co_get_allocated_file_size,
1565 .bdrv_co_truncate = qemu_gluster_co_truncate,
1566 .bdrv_co_readv = qemu_gluster_co_readv,
1567 .bdrv_co_writev = qemu_gluster_co_writev,
1568 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
1569#ifdef CONFIG_GLUSTERFS_DISCARD
1570 .bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
1571#endif
1572#ifdef CONFIG_GLUSTERFS_ZEROFILL
1573 .bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
1574#endif
1575 .bdrv_co_block_status = qemu_gluster_co_block_status,
1576 .bdrv_refresh_limits = qemu_gluster_refresh_limits,
1577 .create_opts = &qemu_gluster_create_opts,
1578 .strong_runtime_opts = gluster_strong_open_opts,
1579};
1580
1581static BlockDriver bdrv_gluster_tcp = {
1582 .format_name = "gluster",
1583 .protocol_name = "gluster+tcp",
1584 .instance_size = sizeof(BDRVGlusterState),
1585 .bdrv_file_open = qemu_gluster_open,
1586 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
1587 .bdrv_reopen_commit = qemu_gluster_reopen_commit,
1588 .bdrv_reopen_abort = qemu_gluster_reopen_abort,
1589 .bdrv_close = qemu_gluster_close,
1590 .bdrv_co_create = qemu_gluster_co_create,
1591 .bdrv_co_create_opts = qemu_gluster_co_create_opts,
1592 .bdrv_co_getlength = qemu_gluster_co_getlength,
1593 .bdrv_co_get_allocated_file_size = qemu_gluster_co_get_allocated_file_size,
1594 .bdrv_co_truncate = qemu_gluster_co_truncate,
1595 .bdrv_co_readv = qemu_gluster_co_readv,
1596 .bdrv_co_writev = qemu_gluster_co_writev,
1597 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
1598#ifdef CONFIG_GLUSTERFS_DISCARD
1599 .bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
1600#endif
1601#ifdef CONFIG_GLUSTERFS_ZEROFILL
1602 .bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
1603#endif
1604 .bdrv_co_block_status = qemu_gluster_co_block_status,
1605 .bdrv_refresh_limits = qemu_gluster_refresh_limits,
1606 .create_opts = &qemu_gluster_create_opts,
1607 .strong_runtime_opts = gluster_strong_open_opts,
1608};
1609
1610static BlockDriver bdrv_gluster_unix = {
1611 .format_name = "gluster",
1612 .protocol_name = "gluster+unix",
1613 .instance_size = sizeof(BDRVGlusterState),
1614 .bdrv_file_open = qemu_gluster_open,
1615 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
1616 .bdrv_reopen_commit = qemu_gluster_reopen_commit,
1617 .bdrv_reopen_abort = qemu_gluster_reopen_abort,
1618 .bdrv_close = qemu_gluster_close,
1619 .bdrv_co_create = qemu_gluster_co_create,
1620 .bdrv_co_create_opts = qemu_gluster_co_create_opts,
1621 .bdrv_co_getlength = qemu_gluster_co_getlength,
1622 .bdrv_co_get_allocated_file_size = qemu_gluster_co_get_allocated_file_size,
1623 .bdrv_co_truncate = qemu_gluster_co_truncate,
1624 .bdrv_co_readv = qemu_gluster_co_readv,
1625 .bdrv_co_writev = qemu_gluster_co_writev,
1626 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
1627#ifdef CONFIG_GLUSTERFS_DISCARD
1628 .bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
1629#endif
1630#ifdef CONFIG_GLUSTERFS_ZEROFILL
1631 .bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
1632#endif
1633 .bdrv_co_block_status = qemu_gluster_co_block_status,
1634 .bdrv_refresh_limits = qemu_gluster_refresh_limits,
1635 .create_opts = &qemu_gluster_create_opts,
1636 .strong_runtime_opts = gluster_strong_open_opts,
1637};
1638
1639
1640
1641
1642
1643
1644
1645static BlockDriver bdrv_gluster_rdma = {
1646 .format_name = "gluster",
1647 .protocol_name = "gluster+rdma",
1648 .instance_size = sizeof(BDRVGlusterState),
1649 .bdrv_file_open = qemu_gluster_open,
1650 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
1651 .bdrv_reopen_commit = qemu_gluster_reopen_commit,
1652 .bdrv_reopen_abort = qemu_gluster_reopen_abort,
1653 .bdrv_close = qemu_gluster_close,
1654 .bdrv_co_create = qemu_gluster_co_create,
1655 .bdrv_co_create_opts = qemu_gluster_co_create_opts,
1656 .bdrv_co_getlength = qemu_gluster_co_getlength,
1657 .bdrv_co_get_allocated_file_size = qemu_gluster_co_get_allocated_file_size,
1658 .bdrv_co_truncate = qemu_gluster_co_truncate,
1659 .bdrv_co_readv = qemu_gluster_co_readv,
1660 .bdrv_co_writev = qemu_gluster_co_writev,
1661 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
1662#ifdef CONFIG_GLUSTERFS_DISCARD
1663 .bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
1664#endif
1665#ifdef CONFIG_GLUSTERFS_ZEROFILL
1666 .bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
1667#endif
1668 .bdrv_co_block_status = qemu_gluster_co_block_status,
1669 .bdrv_refresh_limits = qemu_gluster_refresh_limits,
1670 .create_opts = &qemu_gluster_create_opts,
1671 .strong_runtime_opts = gluster_strong_open_opts,
1672};
1673
1674static void bdrv_gluster_init(void)
1675{
1676 bdrv_register(&bdrv_gluster_rdma);
1677 bdrv_register(&bdrv_gluster_unix);
1678 bdrv_register(&bdrv_gluster_tcp);
1679 bdrv_register(&bdrv_gluster);
1680}
1681
1682block_init(bdrv_gluster_init);
1683