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 gconf->server = g_new0(SocketAddressList, 1);
363 gconf->server->value = gsconf = g_new0(SocketAddress, 1);
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 *curr = NULL;
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 qemu_opts_absorb_qdict(opts, options, &local_err);
527 if (local_err) {
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
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 qemu_opts_absorb_qdict(opts, backing_options, &local_err);
559 if (local_err) {
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 qemu_opts_absorb_qdict(opts, backing_options, &local_err);
590 if (local_err) {
591 goto out;
592 }
593
594 ptr = qemu_opt_get(opts, GLUSTER_OPT_HOST);
595 if (!ptr) {
596 error_setg(&local_err, QERR_MISSING_PARAMETER,
597 GLUSTER_OPT_HOST);
598 error_append_hint(&local_err, GERR_INDEX_HINT, i);
599 goto out;
600 }
601 gsconf->u.inet.host = g_strdup(ptr);
602 ptr = qemu_opt_get(opts, GLUSTER_OPT_PORT);
603 if (!ptr) {
604 error_setg(&local_err, QERR_MISSING_PARAMETER,
605 GLUSTER_OPT_PORT);
606 error_append_hint(&local_err, GERR_INDEX_HINT, i);
607 goto out;
608 }
609 gsconf->u.inet.port = g_strdup(ptr);
610
611
612
613
614 ptr = qemu_opt_get(opts, GLUSTER_OPT_TO);
615 if (ptr) {
616 gsconf->u.inet.has_to = true;
617 }
618 ptr = qemu_opt_get(opts, GLUSTER_OPT_IPV4);
619 if (ptr) {
620 gsconf->u.inet.has_ipv4 = true;
621 }
622 ptr = qemu_opt_get(opts, GLUSTER_OPT_IPV6);
623 if (ptr) {
624 gsconf->u.inet.has_ipv6 = true;
625 }
626 if (gsconf->u.inet.has_to) {
627 error_setg(&local_err, "Parameter 'to' not supported");
628 goto out;
629 }
630 if (gsconf->u.inet.has_ipv4 || gsconf->u.inet.has_ipv6) {
631 error_setg(&local_err, "Parameters 'ipv4/ipv6' not supported");
632 goto out;
633 }
634 qemu_opts_del(opts);
635 } else {
636
637 opts = qemu_opts_create(&runtime_unix_opts, NULL, 0, &error_abort);
638 qemu_opts_absorb_qdict(opts, backing_options, &local_err);
639 if (local_err) {
640 goto out;
641 }
642
643 ptr = qemu_opt_get(opts, GLUSTER_OPT_PATH);
644 if (!ptr) {
645 ptr = qemu_opt_get(opts, GLUSTER_OPT_SOCKET);
646 } else if (qemu_opt_get(opts, GLUSTER_OPT_SOCKET)) {
647 error_setg(&local_err,
648 "Conflicting parameters 'path' and 'socket'");
649 error_append_hint(&local_err, GERR_INDEX_HINT, i);
650 goto out;
651 }
652 if (!ptr) {
653 error_setg(&local_err, QERR_MISSING_PARAMETER,
654 GLUSTER_OPT_PATH);
655 error_append_hint(&local_err, GERR_INDEX_HINT, i);
656 goto out;
657 }
658 gsconf->u.q_unix.path = g_strdup(ptr);
659 qemu_opts_del(opts);
660 }
661
662 if (gconf->server == NULL) {
663 gconf->server = g_new0(SocketAddressList, 1);
664 gconf->server->value = gsconf;
665 curr = gconf->server;
666 } else {
667 curr->next = g_new0(SocketAddressList, 1);
668 curr->next->value = gsconf;
669 curr = curr->next;
670 }
671 gsconf = NULL;
672
673 qobject_unref(backing_options);
674 backing_options = NULL;
675 g_free(str);
676 str = NULL;
677 }
678
679 return 0;
680
681out:
682 error_propagate(errp, local_err);
683 qapi_free_SocketAddress(gsconf);
684 qemu_opts_del(opts);
685 g_free(str);
686 qobject_unref(backing_options);
687 errno = EINVAL;
688 return -errno;
689}
690
691
692
693static int qemu_gluster_parse(BlockdevOptionsGluster *gconf,
694 const char *filename,
695 QDict *options, Error **errp)
696{
697 int ret;
698 if (filename) {
699 ret = qemu_gluster_parse_uri(gconf, filename);
700 if (ret < 0) {
701 error_setg(errp, "invalid URI %s", filename);
702 error_append_hint(errp, "Usage: file=gluster[+transport]://"
703 "[host[:port]]volume/path[?socket=...]"
704 "[,file.debug=N]"
705 "[,file.logfile=/path/filename.log]\n");
706 return ret;
707 }
708 } else {
709 ret = qemu_gluster_parse_json(gconf, options, errp);
710 if (ret < 0) {
711 error_append_hint(errp, "Usage: "
712 "-drive driver=qcow2,file.driver=gluster,"
713 "file.volume=testvol,file.path=/path/a.qcow2"
714 "[,file.debug=9]"
715 "[,file.logfile=/path/filename.log],"
716 "file.server.0.type=inet,"
717 "file.server.0.host=1.2.3.4,"
718 "file.server.0.port=24007,"
719 "file.server.1.transport=unix,"
720 "file.server.1.path=/var/run/glusterd.socket ..."
721 "\n");
722 return ret;
723 }
724 }
725
726 return 0;
727}
728
729static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
730 const char *filename,
731 QDict *options, Error **errp)
732{
733 int ret;
734
735 ret = qemu_gluster_parse(gconf, filename, options, errp);
736 if (ret < 0) {
737 errno = -ret;
738 return NULL;
739 }
740
741 return qemu_gluster_glfs_init(gconf, errp);
742}
743
744
745
746
747static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret,
748#ifdef CONFIG_GLUSTERFS_IOCB_HAS_STAT
749 struct glfs_stat *pre, struct glfs_stat *post,
750#endif
751 void *arg)
752{
753 GlusterAIOCB *acb = (GlusterAIOCB *)arg;
754
755 if (!ret || ret == acb->size) {
756 acb->ret = 0;
757 } else if (ret < 0) {
758 acb->ret = -errno;
759 } else {
760 acb->ret = -EIO;
761 }
762
763 aio_co_schedule(acb->aio_context, acb->coroutine);
764}
765
766static void qemu_gluster_parse_flags(int bdrv_flags, int *open_flags)
767{
768 assert(open_flags != NULL);
769
770 *open_flags |= O_BINARY;
771
772 if (bdrv_flags & BDRV_O_RDWR) {
773 *open_flags |= O_RDWR;
774 } else {
775 *open_flags |= O_RDONLY;
776 }
777
778 if ((bdrv_flags & BDRV_O_NOCACHE)) {
779 *open_flags |= O_DIRECT;
780 }
781}
782
783
784
785
786
787
788
789
790static bool qemu_gluster_test_seek(struct glfs_fd *fd)
791{
792 off_t ret = 0;
793
794#if defined SEEK_HOLE && defined SEEK_DATA
795 off_t eof;
796
797 eof = glfs_lseek(fd, 0, SEEK_END);
798 if (eof < 0) {
799
800 return false;
801 }
802
803
804 ret = glfs_lseek(fd, eof, SEEK_DATA);
805#endif
806
807 return (ret < 0) && (errno == ENXIO);
808}
809
810static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
811 int bdrv_flags, Error **errp)
812{
813 BDRVGlusterState *s = bs->opaque;
814 int open_flags = 0;
815 int ret = 0;
816 BlockdevOptionsGluster *gconf = NULL;
817 QemuOpts *opts;
818 Error *local_err = NULL;
819 const char *filename, *logfile;
820
821 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
822 qemu_opts_absorb_qdict(opts, options, &local_err);
823 if (local_err) {
824 error_propagate(errp, local_err);
825 ret = -EINVAL;
826 goto out;
827 }
828
829 filename = qemu_opt_get(opts, GLUSTER_OPT_FILENAME);
830
831 s->debug = qemu_opt_get_number(opts, GLUSTER_OPT_DEBUG,
832 GLUSTER_DEBUG_DEFAULT);
833 if (s->debug < 0) {
834 s->debug = 0;
835 } else if (s->debug > GLUSTER_DEBUG_MAX) {
836 s->debug = GLUSTER_DEBUG_MAX;
837 }
838
839 gconf = g_new0(BlockdevOptionsGluster, 1);
840 gconf->debug = s->debug;
841 gconf->has_debug = true;
842
843 logfile = qemu_opt_get(opts, GLUSTER_OPT_LOGFILE);
844 s->logfile = g_strdup(logfile ? logfile : GLUSTER_LOGFILE_DEFAULT);
845
846 gconf->logfile = g_strdup(s->logfile);
847 gconf->has_logfile = true;
848
849 s->glfs = qemu_gluster_init(gconf, filename, options, errp);
850 if (!s->glfs) {
851 ret = -errno;
852 goto out;
853 }
854
855#ifdef CONFIG_GLUSTERFS_XLATOR_OPT
856
857
858
859
860
861
862 ret = glfs_set_xlator_option(s->glfs, "*-write-behind",
863 "resync-failed-syncs-after-fsync",
864 "on");
865 if (ret < 0) {
866 error_setg_errno(errp, errno, "Unable to set xlator key/value pair");
867 ret = -errno;
868 goto out;
869 }
870#endif
871
872 qemu_gluster_parse_flags(bdrv_flags, &open_flags);
873
874 s->fd = glfs_open(s->glfs, gconf->path, open_flags);
875 ret = s->fd ? 0 : -errno;
876
877 if (ret == -EACCES || ret == -EROFS) {
878
879
880 if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) {
881 open_flags = (open_flags & ~O_RDWR) | O_RDONLY;
882 s->fd = glfs_open(s->glfs, gconf->path, open_flags);
883 ret = s->fd ? 0 : -errno;
884 }
885 }
886
887 s->supports_seek_data = qemu_gluster_test_seek(s->fd);
888
889out:
890 qemu_opts_del(opts);
891 qapi_free_BlockdevOptionsGluster(gconf);
892 if (!ret) {
893 return ret;
894 }
895 g_free(s->logfile);
896 if (s->fd) {
897 glfs_close(s->fd);
898 }
899
900 glfs_clear_preopened(s->glfs);
901
902 return ret;
903}
904
905static void qemu_gluster_refresh_limits(BlockDriverState *bs, Error **errp)
906{
907 bs->bl.max_transfer = GLUSTER_MAX_TRANSFER;
908}
909
910static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
911 BlockReopenQueue *queue, Error **errp)
912{
913 int ret = 0;
914 BDRVGlusterState *s;
915 BDRVGlusterReopenState *reop_s;
916 BlockdevOptionsGluster *gconf;
917 int open_flags = 0;
918
919 assert(state != NULL);
920 assert(state->bs != NULL);
921
922 s = state->bs->opaque;
923
924 state->opaque = g_new0(BDRVGlusterReopenState, 1);
925 reop_s = state->opaque;
926
927 qemu_gluster_parse_flags(state->flags, &open_flags);
928
929 gconf = g_new0(BlockdevOptionsGluster, 1);
930 gconf->debug = s->debug;
931 gconf->has_debug = true;
932 gconf->logfile = g_strdup(s->logfile);
933 gconf->has_logfile = true;
934
935
936
937
938
939 if (state->bs->exact_filename[0] != '\0') {
940 reop_s->glfs = qemu_gluster_init(gconf, state->bs->exact_filename, NULL,
941 errp);
942 } else {
943 reop_s->glfs = qemu_gluster_init(gconf, NULL, state->options, errp);
944 }
945 if (reop_s->glfs == NULL) {
946 ret = -errno;
947 goto exit;
948 }
949
950#ifdef CONFIG_GLUSTERFS_XLATOR_OPT
951 ret = glfs_set_xlator_option(reop_s->glfs, "*-write-behind",
952 "resync-failed-syncs-after-fsync", "on");
953 if (ret < 0) {
954 error_setg_errno(errp, errno, "Unable to set xlator key/value pair");
955 ret = -errno;
956 goto exit;
957 }
958#endif
959
960 reop_s->fd = glfs_open(reop_s->glfs, gconf->path, open_flags);
961 if (reop_s->fd == NULL) {
962
963 ret = -errno;
964 goto exit;
965 }
966
967exit:
968
969 qapi_free_BlockdevOptionsGluster(gconf);
970 return ret;
971}
972
973static void qemu_gluster_reopen_commit(BDRVReopenState *state)
974{
975 BDRVGlusterReopenState *reop_s = state->opaque;
976 BDRVGlusterState *s = state->bs->opaque;
977
978
979
980 if (s->fd) {
981 glfs_close(s->fd);
982 }
983
984 glfs_clear_preopened(s->glfs);
985
986
987 s->fd = reop_s->fd;
988 s->glfs = reop_s->glfs;
989
990 g_free(state->opaque);
991 state->opaque = NULL;
992
993 return;
994}
995
996
997static void qemu_gluster_reopen_abort(BDRVReopenState *state)
998{
999 BDRVGlusterReopenState *reop_s = state->opaque;
1000
1001 if (reop_s == NULL) {
1002 return;
1003 }
1004
1005 if (reop_s->fd) {
1006 glfs_close(reop_s->fd);
1007 }
1008
1009 glfs_clear_preopened(reop_s->glfs);
1010
1011 g_free(state->opaque);
1012 state->opaque = NULL;
1013
1014 return;
1015}
1016
1017#ifdef CONFIG_GLUSTERFS_ZEROFILL
1018static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs,
1019 int64_t offset,
1020 int size,
1021 BdrvRequestFlags flags)
1022{
1023 int ret;
1024 GlusterAIOCB acb;
1025 BDRVGlusterState *s = bs->opaque;
1026
1027 acb.size = size;
1028 acb.ret = 0;
1029 acb.coroutine = qemu_coroutine_self();
1030 acb.aio_context = bdrv_get_aio_context(bs);
1031
1032 ret = glfs_zerofill_async(s->fd, offset, size, gluster_finish_aiocb, &acb);
1033 if (ret < 0) {
1034 return -errno;
1035 }
1036
1037 qemu_coroutine_yield();
1038 return acb.ret;
1039}
1040#endif
1041
1042static int qemu_gluster_do_truncate(struct glfs_fd *fd, int64_t offset,
1043 PreallocMode prealloc, Error **errp)
1044{
1045 int64_t current_length;
1046
1047 current_length = glfs_lseek(fd, 0, SEEK_END);
1048 if (current_length < 0) {
1049 error_setg_errno(errp, errno, "Failed to determine current size");
1050 return -errno;
1051 }
1052
1053 if (current_length > offset && prealloc != PREALLOC_MODE_OFF) {
1054 error_setg(errp, "Cannot use preallocation for shrinking files");
1055 return -ENOTSUP;
1056 }
1057
1058 if (current_length == offset) {
1059 return 0;
1060 }
1061
1062 switch (prealloc) {
1063#ifdef CONFIG_GLUSTERFS_FALLOCATE
1064 case PREALLOC_MODE_FALLOC:
1065 if (glfs_fallocate(fd, 0, current_length, offset - current_length)) {
1066 error_setg_errno(errp, errno, "Could not preallocate data");
1067 return -errno;
1068 }
1069 break;
1070#endif
1071#ifdef CONFIG_GLUSTERFS_ZEROFILL
1072 case PREALLOC_MODE_FULL:
1073 if (glfs_ftruncate(fd, offset)) {
1074 error_setg_errno(errp, errno, "Could not resize file");
1075 return -errno;
1076 }
1077 if (glfs_zerofill(fd, current_length, offset - current_length)) {
1078 error_setg_errno(errp, errno, "Could not zerofill the new area");
1079 return -errno;
1080 }
1081 break;
1082#endif
1083 case PREALLOC_MODE_OFF:
1084 if (glfs_ftruncate(fd, offset)) {
1085 error_setg_errno(errp, errno, "Could not resize file");
1086 return -errno;
1087 }
1088 break;
1089 default:
1090 error_setg(errp, "Unsupported preallocation mode: %s",
1091 PreallocMode_str(prealloc));
1092 return -EINVAL;
1093 }
1094
1095 return 0;
1096}
1097
1098static int qemu_gluster_co_create(BlockdevCreateOptions *options,
1099 Error **errp)
1100{
1101 BlockdevCreateOptionsGluster *opts = &options->u.gluster;
1102 struct glfs *glfs;
1103 struct glfs_fd *fd = NULL;
1104 int ret = 0;
1105
1106 assert(options->driver == BLOCKDEV_DRIVER_GLUSTER);
1107
1108 glfs = qemu_gluster_glfs_init(opts->location, errp);
1109 if (!glfs) {
1110 ret = -errno;
1111 goto out;
1112 }
1113
1114 fd = glfs_creat(glfs, opts->location->path,
1115 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR);
1116 if (!fd) {
1117 ret = -errno;
1118 goto out;
1119 }
1120
1121 ret = qemu_gluster_do_truncate(fd, opts->size, opts->preallocation, errp);
1122
1123out:
1124 if (fd) {
1125 if (glfs_close(fd) != 0 && ret == 0) {
1126 ret = -errno;
1127 }
1128 }
1129 glfs_clear_preopened(glfs);
1130 return ret;
1131}
1132
1133static int coroutine_fn qemu_gluster_co_create_opts(const char *filename,
1134 QemuOpts *opts,
1135 Error **errp)
1136{
1137 BlockdevCreateOptions *options;
1138 BlockdevCreateOptionsGluster *gopts;
1139 BlockdevOptionsGluster *gconf;
1140 char *tmp = NULL;
1141 Error *local_err = NULL;
1142 int ret;
1143
1144 options = g_new0(BlockdevCreateOptions, 1);
1145 options->driver = BLOCKDEV_DRIVER_GLUSTER;
1146 gopts = &options->u.gluster;
1147
1148 gconf = g_new0(BlockdevOptionsGluster, 1);
1149 gopts->location = gconf;
1150
1151 gopts->size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
1152 BDRV_SECTOR_SIZE);
1153
1154 tmp = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
1155 gopts->preallocation = qapi_enum_parse(&PreallocMode_lookup, tmp,
1156 PREALLOC_MODE_OFF, &local_err);
1157 g_free(tmp);
1158 if (local_err) {
1159 error_propagate(errp, local_err);
1160 ret = -EINVAL;
1161 goto fail;
1162 }
1163
1164 gconf->debug = qemu_opt_get_number_del(opts, GLUSTER_OPT_DEBUG,
1165 GLUSTER_DEBUG_DEFAULT);
1166 if (gconf->debug < 0) {
1167 gconf->debug = 0;
1168 } else if (gconf->debug > GLUSTER_DEBUG_MAX) {
1169 gconf->debug = GLUSTER_DEBUG_MAX;
1170 }
1171 gconf->has_debug = true;
1172
1173 gconf->logfile = qemu_opt_get_del(opts, GLUSTER_OPT_LOGFILE);
1174 if (!gconf->logfile) {
1175 gconf->logfile = g_strdup(GLUSTER_LOGFILE_DEFAULT);
1176 }
1177 gconf->has_logfile = true;
1178
1179 ret = qemu_gluster_parse(gconf, filename, NULL, errp);
1180 if (ret < 0) {
1181 goto fail;
1182 }
1183
1184 ret = qemu_gluster_co_create(options, errp);
1185 if (ret < 0) {
1186 goto fail;
1187 }
1188
1189 ret = 0;
1190fail:
1191 qapi_free_BlockdevCreateOptions(options);
1192 return ret;
1193}
1194
1195static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
1196 int64_t sector_num, int nb_sectors,
1197 QEMUIOVector *qiov, int write)
1198{
1199 int ret;
1200 GlusterAIOCB acb;
1201 BDRVGlusterState *s = bs->opaque;
1202 size_t size = nb_sectors * BDRV_SECTOR_SIZE;
1203 off_t offset = sector_num * BDRV_SECTOR_SIZE;
1204
1205 acb.size = size;
1206 acb.ret = 0;
1207 acb.coroutine = qemu_coroutine_self();
1208 acb.aio_context = bdrv_get_aio_context(bs);
1209
1210 if (write) {
1211 ret = glfs_pwritev_async(s->fd, qiov->iov, qiov->niov, offset, 0,
1212 gluster_finish_aiocb, &acb);
1213 } else {
1214 ret = glfs_preadv_async(s->fd, qiov->iov, qiov->niov, offset, 0,
1215 gluster_finish_aiocb, &acb);
1216 }
1217
1218 if (ret < 0) {
1219 return -errno;
1220 }
1221
1222 qemu_coroutine_yield();
1223 return acb.ret;
1224}
1225
1226static coroutine_fn int qemu_gluster_co_truncate(BlockDriverState *bs,
1227 int64_t offset,
1228 PreallocMode prealloc,
1229 Error **errp)
1230{
1231 BDRVGlusterState *s = bs->opaque;
1232 return qemu_gluster_do_truncate(s->fd, offset, prealloc, errp);
1233}
1234
1235static coroutine_fn int qemu_gluster_co_readv(BlockDriverState *bs,
1236 int64_t sector_num,
1237 int nb_sectors,
1238 QEMUIOVector *qiov)
1239{
1240 return qemu_gluster_co_rw(bs, sector_num, nb_sectors, qiov, 0);
1241}
1242
1243static coroutine_fn int qemu_gluster_co_writev(BlockDriverState *bs,
1244 int64_t sector_num,
1245 int nb_sectors,
1246 QEMUIOVector *qiov,
1247 int flags)
1248{
1249 assert(!flags);
1250 return qemu_gluster_co_rw(bs, sector_num, nb_sectors, qiov, 1);
1251}
1252
1253static void qemu_gluster_close(BlockDriverState *bs)
1254{
1255 BDRVGlusterState *s = bs->opaque;
1256
1257 g_free(s->logfile);
1258 if (s->fd) {
1259 glfs_close(s->fd);
1260 s->fd = NULL;
1261 }
1262 glfs_clear_preopened(s->glfs);
1263}
1264
1265static coroutine_fn int qemu_gluster_co_flush_to_disk(BlockDriverState *bs)
1266{
1267 int ret;
1268 GlusterAIOCB acb;
1269 BDRVGlusterState *s = bs->opaque;
1270
1271 acb.size = 0;
1272 acb.ret = 0;
1273 acb.coroutine = qemu_coroutine_self();
1274 acb.aio_context = bdrv_get_aio_context(bs);
1275
1276 ret = glfs_fsync_async(s->fd, gluster_finish_aiocb, &acb);
1277 if (ret < 0) {
1278 ret = -errno;
1279 goto error;
1280 }
1281
1282 qemu_coroutine_yield();
1283 if (acb.ret < 0) {
1284 ret = acb.ret;
1285 goto error;
1286 }
1287
1288 return acb.ret;
1289
1290error:
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304 qemu_gluster_close(bs);
1305 bs->drv = NULL;
1306 return ret;
1307}
1308
1309#ifdef CONFIG_GLUSTERFS_DISCARD
1310static coroutine_fn int qemu_gluster_co_pdiscard(BlockDriverState *bs,
1311 int64_t offset, int size)
1312{
1313 int ret;
1314 GlusterAIOCB acb;
1315 BDRVGlusterState *s = bs->opaque;
1316
1317 acb.size = 0;
1318 acb.ret = 0;
1319 acb.coroutine = qemu_coroutine_self();
1320 acb.aio_context = bdrv_get_aio_context(bs);
1321
1322 ret = glfs_discard_async(s->fd, offset, size, gluster_finish_aiocb, &acb);
1323 if (ret < 0) {
1324 return -errno;
1325 }
1326
1327 qemu_coroutine_yield();
1328 return acb.ret;
1329}
1330#endif
1331
1332static int64_t qemu_gluster_getlength(BlockDriverState *bs)
1333{
1334 BDRVGlusterState *s = bs->opaque;
1335 int64_t ret;
1336
1337 ret = glfs_lseek(s->fd, 0, SEEK_END);
1338 if (ret < 0) {
1339 return -errno;
1340 } else {
1341 return ret;
1342 }
1343}
1344
1345static int64_t qemu_gluster_allocated_file_size(BlockDriverState *bs)
1346{
1347 BDRVGlusterState *s = bs->opaque;
1348 struct stat st;
1349 int ret;
1350
1351 ret = glfs_fstat(s->fd, &st);
1352 if (ret < 0) {
1353 return -errno;
1354 } else {
1355 return st.st_blocks * 512;
1356 }
1357}
1358
1359static int qemu_gluster_has_zero_init(BlockDriverState *bs)
1360{
1361
1362 return 0;
1363}
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377static int find_allocation(BlockDriverState *bs, off_t start,
1378 off_t *data, off_t *hole)
1379{
1380 BDRVGlusterState *s = bs->opaque;
1381
1382 if (!s->supports_seek_data) {
1383 goto exit;
1384 }
1385
1386#if defined SEEK_HOLE && defined SEEK_DATA
1387 off_t offs;
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400 offs = glfs_lseek(s->fd, start, SEEK_DATA);
1401 if (offs < 0) {
1402 return -errno;
1403 }
1404
1405 if (offs < start) {
1406
1407
1408
1409
1410 return -EIO;
1411 }
1412
1413 if (offs > start) {
1414
1415 *hole = start;
1416 *data = offs;
1417 return 0;
1418 }
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439 offs = glfs_lseek(s->fd, start, SEEK_HOLE);
1440 if (offs < 0) {
1441 return -errno;
1442 }
1443
1444 if (offs < start) {
1445
1446
1447
1448
1449 return -EIO;
1450 }
1451
1452 if (offs > start) {
1453
1454
1455
1456
1457
1458
1459 *data = start;
1460 *hole = offs;
1461 return 0;
1462 }
1463
1464
1465 return -EBUSY;
1466#endif
1467
1468exit:
1469 return -ENOTSUP;
1470}
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs,
1486 bool want_zero,
1487 int64_t offset,
1488 int64_t bytes,
1489 int64_t *pnum,
1490 int64_t *map,
1491 BlockDriverState **file)
1492{
1493 BDRVGlusterState *s = bs->opaque;
1494 off_t data = 0, hole = 0;
1495 int ret = -EINVAL;
1496
1497 if (!s->fd) {
1498 return ret;
1499 }
1500
1501 if (!want_zero) {
1502 *pnum = bytes;
1503 *map = offset;
1504 *file = bs;
1505 return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
1506 }
1507
1508 ret = find_allocation(bs, offset, &data, &hole);
1509 if (ret == -ENXIO) {
1510
1511 *pnum = bytes;
1512 ret = BDRV_BLOCK_ZERO;
1513 } else if (ret < 0) {
1514
1515 *pnum = bytes;
1516 ret = BDRV_BLOCK_DATA;
1517 } else if (data == offset) {
1518
1519
1520 *pnum = MIN(bytes, hole - offset);
1521 ret = BDRV_BLOCK_DATA;
1522 } else {
1523
1524 assert(hole == offset);
1525 *pnum = MIN(bytes, data - offset);
1526 ret = BDRV_BLOCK_ZERO;
1527 }
1528
1529 *map = offset;
1530 *file = bs;
1531
1532 return ret | BDRV_BLOCK_OFFSET_VALID;
1533}
1534
1535
1536static const char *const gluster_strong_open_opts[] = {
1537 GLUSTER_OPT_VOLUME,
1538 GLUSTER_OPT_PATH,
1539 GLUSTER_OPT_TYPE,
1540 GLUSTER_OPT_SERVER_PATTERN,
1541 GLUSTER_OPT_HOST,
1542 GLUSTER_OPT_PORT,
1543 GLUSTER_OPT_TO,
1544 GLUSTER_OPT_IPV4,
1545 GLUSTER_OPT_IPV6,
1546 GLUSTER_OPT_SOCKET,
1547
1548 NULL
1549};
1550
1551static BlockDriver bdrv_gluster = {
1552 .format_name = "gluster",
1553 .protocol_name = "gluster",
1554 .instance_size = sizeof(BDRVGlusterState),
1555 .bdrv_needs_filename = false,
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_getlength = qemu_gluster_getlength,
1564 .bdrv_get_allocated_file_size = qemu_gluster_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 .bdrv_has_zero_init = qemu_gluster_has_zero_init,
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_needs_filename = false,
1587 .bdrv_file_open = qemu_gluster_open,
1588 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
1589 .bdrv_reopen_commit = qemu_gluster_reopen_commit,
1590 .bdrv_reopen_abort = qemu_gluster_reopen_abort,
1591 .bdrv_close = qemu_gluster_close,
1592 .bdrv_co_create = qemu_gluster_co_create,
1593 .bdrv_co_create_opts = qemu_gluster_co_create_opts,
1594 .bdrv_getlength = qemu_gluster_getlength,
1595 .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
1596 .bdrv_co_truncate = qemu_gluster_co_truncate,
1597 .bdrv_co_readv = qemu_gluster_co_readv,
1598 .bdrv_co_writev = qemu_gluster_co_writev,
1599 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
1600 .bdrv_has_zero_init = qemu_gluster_has_zero_init,
1601#ifdef CONFIG_GLUSTERFS_DISCARD
1602 .bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
1603#endif
1604#ifdef CONFIG_GLUSTERFS_ZEROFILL
1605 .bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
1606#endif
1607 .bdrv_co_block_status = qemu_gluster_co_block_status,
1608 .bdrv_refresh_limits = qemu_gluster_refresh_limits,
1609 .create_opts = &qemu_gluster_create_opts,
1610 .strong_runtime_opts = gluster_strong_open_opts,
1611};
1612
1613static BlockDriver bdrv_gluster_unix = {
1614 .format_name = "gluster",
1615 .protocol_name = "gluster+unix",
1616 .instance_size = sizeof(BDRVGlusterState),
1617 .bdrv_needs_filename = true,
1618 .bdrv_file_open = qemu_gluster_open,
1619 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
1620 .bdrv_reopen_commit = qemu_gluster_reopen_commit,
1621 .bdrv_reopen_abort = qemu_gluster_reopen_abort,
1622 .bdrv_close = qemu_gluster_close,
1623 .bdrv_co_create = qemu_gluster_co_create,
1624 .bdrv_co_create_opts = qemu_gluster_co_create_opts,
1625 .bdrv_getlength = qemu_gluster_getlength,
1626 .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
1627 .bdrv_co_truncate = qemu_gluster_co_truncate,
1628 .bdrv_co_readv = qemu_gluster_co_readv,
1629 .bdrv_co_writev = qemu_gluster_co_writev,
1630 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
1631 .bdrv_has_zero_init = qemu_gluster_has_zero_init,
1632#ifdef CONFIG_GLUSTERFS_DISCARD
1633 .bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
1634#endif
1635#ifdef CONFIG_GLUSTERFS_ZEROFILL
1636 .bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
1637#endif
1638 .bdrv_co_block_status = qemu_gluster_co_block_status,
1639 .bdrv_refresh_limits = qemu_gluster_refresh_limits,
1640 .create_opts = &qemu_gluster_create_opts,
1641 .strong_runtime_opts = gluster_strong_open_opts,
1642};
1643
1644
1645
1646
1647
1648
1649
1650static BlockDriver bdrv_gluster_rdma = {
1651 .format_name = "gluster",
1652 .protocol_name = "gluster+rdma",
1653 .instance_size = sizeof(BDRVGlusterState),
1654 .bdrv_needs_filename = true,
1655 .bdrv_file_open = qemu_gluster_open,
1656 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
1657 .bdrv_reopen_commit = qemu_gluster_reopen_commit,
1658 .bdrv_reopen_abort = qemu_gluster_reopen_abort,
1659 .bdrv_close = qemu_gluster_close,
1660 .bdrv_co_create = qemu_gluster_co_create,
1661 .bdrv_co_create_opts = qemu_gluster_co_create_opts,
1662 .bdrv_getlength = qemu_gluster_getlength,
1663 .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
1664 .bdrv_co_truncate = qemu_gluster_co_truncate,
1665 .bdrv_co_readv = qemu_gluster_co_readv,
1666 .bdrv_co_writev = qemu_gluster_co_writev,
1667 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
1668 .bdrv_has_zero_init = qemu_gluster_has_zero_init,
1669#ifdef CONFIG_GLUSTERFS_DISCARD
1670 .bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
1671#endif
1672#ifdef CONFIG_GLUSTERFS_ZEROFILL
1673 .bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
1674#endif
1675 .bdrv_co_block_status = qemu_gluster_co_block_status,
1676 .bdrv_refresh_limits = qemu_gluster_refresh_limits,
1677 .create_opts = &qemu_gluster_create_opts,
1678 .strong_runtime_opts = gluster_strong_open_opts,
1679};
1680
1681static void bdrv_gluster_init(void)
1682{
1683 bdrv_register(&bdrv_gluster_rdma);
1684 bdrv_register(&bdrv_gluster_unix);
1685 bdrv_register(&bdrv_gluster_tcp);
1686 bdrv_register(&bdrv_gluster);
1687}
1688
1689block_init(bdrv_gluster_init);
1690