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