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