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