xref: /openbmc/qemu/block/gluster.c (revision 35d08458)
1 /*
2  * GlusterFS backend for QEMU
3  *
4  * Copyright (C) 2012 Bharata B Rao <bharata@linux.vnet.ibm.com>
5  *
6  * This work is licensed under the terms of the GNU GPL, version 2 or later.
7  * See the COPYING file in the top-level directory.
8  *
9  */
10 #include <glusterfs/api/glfs.h>
11 #include "block/block_int.h"
12 #include "qemu/uri.h"
13 
14 typedef struct GlusterAIOCB {
15     int64_t size;
16     int ret;
17     QEMUBH *bh;
18     Coroutine *coroutine;
19 } GlusterAIOCB;
20 
21 typedef struct BDRVGlusterState {
22     struct glfs *glfs;
23     struct glfs_fd *fd;
24 } BDRVGlusterState;
25 
26 typedef struct GlusterConf {
27     char *server;
28     int port;
29     char *volname;
30     char *image;
31     char *transport;
32 } GlusterConf;
33 
34 static void qemu_gluster_gconf_free(GlusterConf *gconf)
35 {
36     if (gconf) {
37         g_free(gconf->server);
38         g_free(gconf->volname);
39         g_free(gconf->image);
40         g_free(gconf->transport);
41         g_free(gconf);
42     }
43 }
44 
45 static int parse_volume_options(GlusterConf *gconf, char *path)
46 {
47     char *p, *q;
48 
49     if (!path) {
50         return -EINVAL;
51     }
52 
53     /* volume */
54     p = q = path + strspn(path, "/");
55     p += strcspn(p, "/");
56     if (*p == '\0') {
57         return -EINVAL;
58     }
59     gconf->volname = g_strndup(q, p - q);
60 
61     /* image */
62     p += strspn(p, "/");
63     if (*p == '\0') {
64         return -EINVAL;
65     }
66     gconf->image = g_strdup(p);
67     return 0;
68 }
69 
70 /*
71  * file=gluster[+transport]://[server[:port]]/volname/image[?socket=...]
72  *
73  * 'gluster' is the protocol.
74  *
75  * 'transport' specifies the transport type used to connect to gluster
76  * management daemon (glusterd). Valid transport types are
77  * tcp, unix and rdma. If a transport type isn't specified, then tcp
78  * type is assumed.
79  *
80  * 'server' specifies the server where the volume file specification for
81  * the given volume resides. This can be either hostname, ipv4 address
82  * or ipv6 address. ipv6 address needs to be within square brackets [ ].
83  * If transport type is 'unix', then 'server' field should not be specified.
84  * The 'socket' field needs to be populated with the path to unix domain
85  * socket.
86  *
87  * 'port' is the port number on which glusterd is listening. This is optional
88  * and if not specified, QEMU will send 0 which will make gluster to use the
89  * default port. If the transport type is unix, then 'port' should not be
90  * specified.
91  *
92  * 'volname' is the name of the gluster volume which contains the VM image.
93  *
94  * 'image' is the path to the actual VM image that resides on gluster volume.
95  *
96  * Examples:
97  *
98  * file=gluster://1.2.3.4/testvol/a.img
99  * file=gluster+tcp://1.2.3.4/testvol/a.img
100  * file=gluster+tcp://1.2.3.4:24007/testvol/dir/a.img
101  * file=gluster+tcp://[1:2:3:4:5:6:7:8]/testvol/dir/a.img
102  * file=gluster+tcp://[1:2:3:4:5:6:7:8]:24007/testvol/dir/a.img
103  * file=gluster+tcp://server.domain.com:24007/testvol/dir/a.img
104  * file=gluster+unix:///testvol/dir/a.img?socket=/tmp/glusterd.socket
105  * file=gluster+rdma://1.2.3.4:24007/testvol/a.img
106  */
107 static int qemu_gluster_parseuri(GlusterConf *gconf, const char *filename)
108 {
109     URI *uri;
110     QueryParams *qp = NULL;
111     bool is_unix = false;
112     int ret = 0;
113 
114     uri = uri_parse(filename);
115     if (!uri) {
116         return -EINVAL;
117     }
118 
119     /* transport */
120     if (!uri->scheme || !strcmp(uri->scheme, "gluster")) {
121         gconf->transport = g_strdup("tcp");
122     } else if (!strcmp(uri->scheme, "gluster+tcp")) {
123         gconf->transport = g_strdup("tcp");
124     } else if (!strcmp(uri->scheme, "gluster+unix")) {
125         gconf->transport = g_strdup("unix");
126         is_unix = true;
127     } else if (!strcmp(uri->scheme, "gluster+rdma")) {
128         gconf->transport = g_strdup("rdma");
129     } else {
130         ret = -EINVAL;
131         goto out;
132     }
133 
134     ret = parse_volume_options(gconf, uri->path);
135     if (ret < 0) {
136         goto out;
137     }
138 
139     qp = query_params_parse(uri->query);
140     if (qp->n > 1 || (is_unix && !qp->n) || (!is_unix && qp->n)) {
141         ret = -EINVAL;
142         goto out;
143     }
144 
145     if (is_unix) {
146         if (uri->server || uri->port) {
147             ret = -EINVAL;
148             goto out;
149         }
150         if (strcmp(qp->p[0].name, "socket")) {
151             ret = -EINVAL;
152             goto out;
153         }
154         gconf->server = g_strdup(qp->p[0].value);
155     } else {
156         gconf->server = g_strdup(uri->server ? uri->server : "localhost");
157         gconf->port = uri->port;
158     }
159 
160 out:
161     if (qp) {
162         query_params_free(qp);
163     }
164     uri_free(uri);
165     return ret;
166 }
167 
168 static struct glfs *qemu_gluster_init(GlusterConf *gconf, const char *filename,
169                                       Error **errp)
170 {
171     struct glfs *glfs = NULL;
172     int ret;
173     int old_errno;
174 
175     ret = qemu_gluster_parseuri(gconf, filename);
176     if (ret < 0) {
177         error_setg(errp, "Usage: file=gluster[+transport]://[server[:port]]/"
178                    "volname/image[?socket=...]");
179         errno = -ret;
180         goto out;
181     }
182 
183     glfs = glfs_new(gconf->volname);
184     if (!glfs) {
185         goto out;
186     }
187 
188     ret = glfs_set_volfile_server(glfs, gconf->transport, gconf->server,
189             gconf->port);
190     if (ret < 0) {
191         goto out;
192     }
193 
194     /*
195      * TODO: Use GF_LOG_ERROR instead of hard code value of 4 here when
196      * GlusterFS makes GF_LOG_* macros available to libgfapi users.
197      */
198     ret = glfs_set_logging(glfs, "-", 4);
199     if (ret < 0) {
200         goto out;
201     }
202 
203     ret = glfs_init(glfs);
204     if (ret) {
205         error_setg_errno(errp, errno,
206                          "Gluster connection failed for server=%s port=%d "
207                          "volume=%s image=%s transport=%s", gconf->server,
208                          gconf->port, gconf->volname, gconf->image,
209                          gconf->transport);
210 
211         /* glfs_init sometimes doesn't set errno although docs suggest that */
212         if (errno == 0)
213             errno = EINVAL;
214 
215         goto out;
216     }
217     return glfs;
218 
219 out:
220     if (glfs) {
221         old_errno = errno;
222         glfs_fini(glfs);
223         errno = old_errno;
224     }
225     return NULL;
226 }
227 
228 static void qemu_gluster_complete_aio(void *opaque)
229 {
230     GlusterAIOCB *acb = (GlusterAIOCB *)opaque;
231 
232     qemu_bh_delete(acb->bh);
233     acb->bh = NULL;
234     qemu_coroutine_enter(acb->coroutine, NULL);
235 }
236 
237 /*
238  * AIO callback routine called from GlusterFS thread.
239  */
240 static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg)
241 {
242     GlusterAIOCB *acb = (GlusterAIOCB *)arg;
243 
244     if (!ret || ret == acb->size) {
245         acb->ret = 0; /* Success */
246     } else if (ret < 0) {
247         acb->ret = ret; /* Read/Write failed */
248     } else {
249         acb->ret = -EIO; /* Partial read/write - fail it */
250     }
251 
252     acb->bh = qemu_bh_new(qemu_gluster_complete_aio, acb);
253     qemu_bh_schedule(acb->bh);
254 }
255 
256 /* TODO Convert to fine grained options */
257 static QemuOptsList runtime_opts = {
258     .name = "gluster",
259     .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
260     .desc = {
261         {
262             .name = "filename",
263             .type = QEMU_OPT_STRING,
264             .help = "URL to the gluster image",
265         },
266         { /* end of list */ }
267     },
268 };
269 
270 static void qemu_gluster_parse_flags(int bdrv_flags, int *open_flags)
271 {
272     assert(open_flags != NULL);
273 
274     *open_flags |= O_BINARY;
275 
276     if (bdrv_flags & BDRV_O_RDWR) {
277         *open_flags |= O_RDWR;
278     } else {
279         *open_flags |= O_RDONLY;
280     }
281 
282     if ((bdrv_flags & BDRV_O_NOCACHE)) {
283         *open_flags |= O_DIRECT;
284     }
285 }
286 
287 static int qemu_gluster_open(BlockDriverState *bs,  QDict *options,
288                              int bdrv_flags, Error **errp)
289 {
290     BDRVGlusterState *s = bs->opaque;
291     int open_flags = 0;
292     int ret = 0;
293     GlusterConf *gconf = g_malloc0(sizeof(GlusterConf));
294     QemuOpts *opts;
295     Error *local_err = NULL;
296     const char *filename;
297 
298     opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
299     qemu_opts_absorb_qdict(opts, options, &local_err);
300     if (local_err) {
301         error_propagate(errp, local_err);
302         ret = -EINVAL;
303         goto out;
304     }
305 
306     filename = qemu_opt_get(opts, "filename");
307 
308     s->glfs = qemu_gluster_init(gconf, filename, errp);
309     if (!s->glfs) {
310         ret = -errno;
311         goto out;
312     }
313 
314     qemu_gluster_parse_flags(bdrv_flags, &open_flags);
315 
316     s->fd = glfs_open(s->glfs, gconf->image, open_flags);
317     if (!s->fd) {
318         ret = -errno;
319     }
320 
321 out:
322     qemu_opts_del(opts);
323     qemu_gluster_gconf_free(gconf);
324     if (!ret) {
325         return ret;
326     }
327     if (s->fd) {
328         glfs_close(s->fd);
329     }
330     if (s->glfs) {
331         glfs_fini(s->glfs);
332     }
333     return ret;
334 }
335 
336 typedef struct BDRVGlusterReopenState {
337     struct glfs *glfs;
338     struct glfs_fd *fd;
339 } BDRVGlusterReopenState;
340 
341 
342 static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
343                                        BlockReopenQueue *queue, Error **errp)
344 {
345     int ret = 0;
346     BDRVGlusterReopenState *reop_s;
347     GlusterConf *gconf = NULL;
348     int open_flags = 0;
349 
350     assert(state != NULL);
351     assert(state->bs != NULL);
352 
353     state->opaque = g_malloc0(sizeof(BDRVGlusterReopenState));
354     reop_s = state->opaque;
355 
356     qemu_gluster_parse_flags(state->flags, &open_flags);
357 
358     gconf = g_malloc0(sizeof(GlusterConf));
359 
360     reop_s->glfs = qemu_gluster_init(gconf, state->bs->filename, errp);
361     if (reop_s->glfs == NULL) {
362         ret = -errno;
363         goto exit;
364     }
365 
366     reop_s->fd = glfs_open(reop_s->glfs, gconf->image, open_flags);
367     if (reop_s->fd == NULL) {
368         /* reops->glfs will be cleaned up in _abort */
369         ret = -errno;
370         goto exit;
371     }
372 
373 exit:
374     /* state->opaque will be freed in either the _abort or _commit */
375     qemu_gluster_gconf_free(gconf);
376     return ret;
377 }
378 
379 static void qemu_gluster_reopen_commit(BDRVReopenState *state)
380 {
381     BDRVGlusterReopenState *reop_s = state->opaque;
382     BDRVGlusterState *s = state->bs->opaque;
383 
384 
385     /* close the old */
386     if (s->fd) {
387         glfs_close(s->fd);
388     }
389     if (s->glfs) {
390         glfs_fini(s->glfs);
391     }
392 
393     /* use the newly opened image / connection */
394     s->fd         = reop_s->fd;
395     s->glfs       = reop_s->glfs;
396 
397     g_free(state->opaque);
398     state->opaque = NULL;
399 
400     return;
401 }
402 
403 
404 static void qemu_gluster_reopen_abort(BDRVReopenState *state)
405 {
406     BDRVGlusterReopenState *reop_s = state->opaque;
407 
408     if (reop_s == NULL) {
409         return;
410     }
411 
412     if (reop_s->fd) {
413         glfs_close(reop_s->fd);
414     }
415 
416     if (reop_s->glfs) {
417         glfs_fini(reop_s->glfs);
418     }
419 
420     g_free(state->opaque);
421     state->opaque = NULL;
422 
423     return;
424 }
425 
426 #ifdef CONFIG_GLUSTERFS_ZEROFILL
427 static coroutine_fn int qemu_gluster_co_write_zeroes(BlockDriverState *bs,
428         int64_t sector_num, int nb_sectors, BdrvRequestFlags flags)
429 {
430     int ret;
431     GlusterAIOCB *acb = g_slice_new(GlusterAIOCB);
432     BDRVGlusterState *s = bs->opaque;
433     off_t size = nb_sectors * BDRV_SECTOR_SIZE;
434     off_t offset = sector_num * BDRV_SECTOR_SIZE;
435 
436     acb->size = size;
437     acb->ret = 0;
438     acb->coroutine = qemu_coroutine_self();
439 
440     ret = glfs_zerofill_async(s->fd, offset, size, &gluster_finish_aiocb, acb);
441     if (ret < 0) {
442         ret = -errno;
443         goto out;
444     }
445 
446     qemu_coroutine_yield();
447     ret = acb->ret;
448 
449 out:
450     g_slice_free(GlusterAIOCB, acb);
451     return ret;
452 }
453 
454 static inline bool gluster_supports_zerofill(void)
455 {
456     return 1;
457 }
458 
459 static inline int qemu_gluster_zerofill(struct glfs_fd *fd, int64_t offset,
460         int64_t size)
461 {
462     return glfs_zerofill(fd, offset, size);
463 }
464 
465 #else
466 static inline bool gluster_supports_zerofill(void)
467 {
468     return 0;
469 }
470 
471 static inline int qemu_gluster_zerofill(struct glfs_fd *fd, int64_t offset,
472         int64_t size)
473 {
474     return 0;
475 }
476 #endif
477 
478 static int qemu_gluster_create(const char *filename,
479         QEMUOptionParameter *options, Error **errp)
480 {
481     struct glfs *glfs;
482     struct glfs_fd *fd;
483     int ret = 0;
484     int prealloc = 0;
485     int64_t total_size = 0;
486     GlusterConf *gconf = g_malloc0(sizeof(GlusterConf));
487 
488     glfs = qemu_gluster_init(gconf, filename, errp);
489     if (!glfs) {
490         ret = -errno;
491         goto out;
492     }
493 
494     while (options && options->name) {
495         if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
496             total_size = options->value.n / BDRV_SECTOR_SIZE;
497         } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
498             if (!options->value.s || !strcmp(options->value.s, "off")) {
499                 prealloc = 0;
500             } else if (!strcmp(options->value.s, "full") &&
501                     gluster_supports_zerofill()) {
502                 prealloc = 1;
503             } else {
504                 error_setg(errp, "Invalid preallocation mode: '%s'"
505                     " or GlusterFS doesn't support zerofill API",
506                            options->value.s);
507                 ret = -EINVAL;
508                 goto out;
509             }
510         }
511         options++;
512     }
513 
514     fd = glfs_creat(glfs, gconf->image,
515         O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR);
516     if (!fd) {
517         ret = -errno;
518     } else {
519         if (!glfs_ftruncate(fd, total_size * BDRV_SECTOR_SIZE)) {
520             if (prealloc && qemu_gluster_zerofill(fd, 0,
521                     total_size * BDRV_SECTOR_SIZE)) {
522                 ret = -errno;
523             }
524         } else {
525             ret = -errno;
526         }
527 
528         if (glfs_close(fd) != 0) {
529             ret = -errno;
530         }
531     }
532 out:
533     qemu_gluster_gconf_free(gconf);
534     if (glfs) {
535         glfs_fini(glfs);
536     }
537     return ret;
538 }
539 
540 static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
541         int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, int write)
542 {
543     int ret;
544     GlusterAIOCB *acb = g_slice_new(GlusterAIOCB);
545     BDRVGlusterState *s = bs->opaque;
546     size_t size = nb_sectors * BDRV_SECTOR_SIZE;
547     off_t offset = sector_num * BDRV_SECTOR_SIZE;
548 
549     acb->size = size;
550     acb->ret = 0;
551     acb->coroutine = qemu_coroutine_self();
552 
553     if (write) {
554         ret = glfs_pwritev_async(s->fd, qiov->iov, qiov->niov, offset, 0,
555             &gluster_finish_aiocb, acb);
556     } else {
557         ret = glfs_preadv_async(s->fd, qiov->iov, qiov->niov, offset, 0,
558             &gluster_finish_aiocb, acb);
559     }
560 
561     if (ret < 0) {
562         ret = -errno;
563         goto out;
564     }
565 
566     qemu_coroutine_yield();
567     ret = acb->ret;
568 
569 out:
570     g_slice_free(GlusterAIOCB, acb);
571     return ret;
572 }
573 
574 static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset)
575 {
576     int ret;
577     BDRVGlusterState *s = bs->opaque;
578 
579     ret = glfs_ftruncate(s->fd, offset);
580     if (ret < 0) {
581         return -errno;
582     }
583 
584     return 0;
585 }
586 
587 static coroutine_fn int qemu_gluster_co_readv(BlockDriverState *bs,
588         int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
589 {
590     return qemu_gluster_co_rw(bs, sector_num, nb_sectors, qiov, 0);
591 }
592 
593 static coroutine_fn int qemu_gluster_co_writev(BlockDriverState *bs,
594         int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
595 {
596     return qemu_gluster_co_rw(bs, sector_num, nb_sectors, qiov, 1);
597 }
598 
599 static coroutine_fn int qemu_gluster_co_flush_to_disk(BlockDriverState *bs)
600 {
601     int ret;
602     GlusterAIOCB *acb = g_slice_new(GlusterAIOCB);
603     BDRVGlusterState *s = bs->opaque;
604 
605     acb->size = 0;
606     acb->ret = 0;
607     acb->coroutine = qemu_coroutine_self();
608 
609     ret = glfs_fsync_async(s->fd, &gluster_finish_aiocb, acb);
610     if (ret < 0) {
611         ret = -errno;
612         goto out;
613     }
614 
615     qemu_coroutine_yield();
616     ret = acb->ret;
617 
618 out:
619     g_slice_free(GlusterAIOCB, acb);
620     return ret;
621 }
622 
623 #ifdef CONFIG_GLUSTERFS_DISCARD
624 static coroutine_fn int qemu_gluster_co_discard(BlockDriverState *bs,
625         int64_t sector_num, int nb_sectors)
626 {
627     int ret;
628     GlusterAIOCB *acb = g_slice_new(GlusterAIOCB);
629     BDRVGlusterState *s = bs->opaque;
630     size_t size = nb_sectors * BDRV_SECTOR_SIZE;
631     off_t offset = sector_num * BDRV_SECTOR_SIZE;
632 
633     acb->size = 0;
634     acb->ret = 0;
635     acb->coroutine = qemu_coroutine_self();
636 
637     ret = glfs_discard_async(s->fd, offset, size, &gluster_finish_aiocb, acb);
638     if (ret < 0) {
639         ret = -errno;
640         goto out;
641     }
642 
643     qemu_coroutine_yield();
644     ret = acb->ret;
645 
646 out:
647     g_slice_free(GlusterAIOCB, acb);
648     return ret;
649 }
650 #endif
651 
652 static int64_t qemu_gluster_getlength(BlockDriverState *bs)
653 {
654     BDRVGlusterState *s = bs->opaque;
655     int64_t ret;
656 
657     ret = glfs_lseek(s->fd, 0, SEEK_END);
658     if (ret < 0) {
659         return -errno;
660     } else {
661         return ret;
662     }
663 }
664 
665 static int64_t qemu_gluster_allocated_file_size(BlockDriverState *bs)
666 {
667     BDRVGlusterState *s = bs->opaque;
668     struct stat st;
669     int ret;
670 
671     ret = glfs_fstat(s->fd, &st);
672     if (ret < 0) {
673         return -errno;
674     } else {
675         return st.st_blocks * 512;
676     }
677 }
678 
679 static void qemu_gluster_close(BlockDriverState *bs)
680 {
681     BDRVGlusterState *s = bs->opaque;
682 
683     if (s->fd) {
684         glfs_close(s->fd);
685         s->fd = NULL;
686     }
687     glfs_fini(s->glfs);
688 }
689 
690 static int qemu_gluster_has_zero_init(BlockDriverState *bs)
691 {
692     /* GlusterFS volume could be backed by a block device */
693     return 0;
694 }
695 
696 static QEMUOptionParameter qemu_gluster_create_options[] = {
697     {
698         .name = BLOCK_OPT_SIZE,
699         .type = OPT_SIZE,
700         .help = "Virtual disk size"
701     },
702     {
703         .name = BLOCK_OPT_PREALLOC,
704         .type = OPT_STRING,
705         .help = "Preallocation mode (allowed values: off, full)"
706     },
707     { NULL }
708 };
709 
710 static BlockDriver bdrv_gluster = {
711     .format_name                  = "gluster",
712     .protocol_name                = "gluster",
713     .instance_size                = sizeof(BDRVGlusterState),
714     .bdrv_needs_filename          = true,
715     .bdrv_file_open               = qemu_gluster_open,
716     .bdrv_reopen_prepare          = qemu_gluster_reopen_prepare,
717     .bdrv_reopen_commit           = qemu_gluster_reopen_commit,
718     .bdrv_reopen_abort            = qemu_gluster_reopen_abort,
719     .bdrv_close                   = qemu_gluster_close,
720     .bdrv_create                  = qemu_gluster_create,
721     .bdrv_getlength               = qemu_gluster_getlength,
722     .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
723     .bdrv_truncate                = qemu_gluster_truncate,
724     .bdrv_co_readv                = qemu_gluster_co_readv,
725     .bdrv_co_writev               = qemu_gluster_co_writev,
726     .bdrv_co_flush_to_disk        = qemu_gluster_co_flush_to_disk,
727     .bdrv_has_zero_init           = qemu_gluster_has_zero_init,
728 #ifdef CONFIG_GLUSTERFS_DISCARD
729     .bdrv_co_discard              = qemu_gluster_co_discard,
730 #endif
731 #ifdef CONFIG_GLUSTERFS_ZEROFILL
732     .bdrv_co_write_zeroes         = qemu_gluster_co_write_zeroes,
733 #endif
734     .create_options               = qemu_gluster_create_options,
735 };
736 
737 static BlockDriver bdrv_gluster_tcp = {
738     .format_name                  = "gluster",
739     .protocol_name                = "gluster+tcp",
740     .instance_size                = sizeof(BDRVGlusterState),
741     .bdrv_needs_filename          = true,
742     .bdrv_file_open               = qemu_gluster_open,
743     .bdrv_reopen_prepare          = qemu_gluster_reopen_prepare,
744     .bdrv_reopen_commit           = qemu_gluster_reopen_commit,
745     .bdrv_reopen_abort            = qemu_gluster_reopen_abort,
746     .bdrv_close                   = qemu_gluster_close,
747     .bdrv_create                  = qemu_gluster_create,
748     .bdrv_getlength               = qemu_gluster_getlength,
749     .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
750     .bdrv_truncate                = qemu_gluster_truncate,
751     .bdrv_co_readv                = qemu_gluster_co_readv,
752     .bdrv_co_writev               = qemu_gluster_co_writev,
753     .bdrv_co_flush_to_disk        = qemu_gluster_co_flush_to_disk,
754     .bdrv_has_zero_init           = qemu_gluster_has_zero_init,
755 #ifdef CONFIG_GLUSTERFS_DISCARD
756     .bdrv_co_discard              = qemu_gluster_co_discard,
757 #endif
758 #ifdef CONFIG_GLUSTERFS_ZEROFILL
759     .bdrv_co_write_zeroes         = qemu_gluster_co_write_zeroes,
760 #endif
761     .create_options               = qemu_gluster_create_options,
762 };
763 
764 static BlockDriver bdrv_gluster_unix = {
765     .format_name                  = "gluster",
766     .protocol_name                = "gluster+unix",
767     .instance_size                = sizeof(BDRVGlusterState),
768     .bdrv_needs_filename          = true,
769     .bdrv_file_open               = qemu_gluster_open,
770     .bdrv_reopen_prepare          = qemu_gluster_reopen_prepare,
771     .bdrv_reopen_commit           = qemu_gluster_reopen_commit,
772     .bdrv_reopen_abort            = qemu_gluster_reopen_abort,
773     .bdrv_close                   = qemu_gluster_close,
774     .bdrv_create                  = qemu_gluster_create,
775     .bdrv_getlength               = qemu_gluster_getlength,
776     .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
777     .bdrv_truncate                = qemu_gluster_truncate,
778     .bdrv_co_readv                = qemu_gluster_co_readv,
779     .bdrv_co_writev               = qemu_gluster_co_writev,
780     .bdrv_co_flush_to_disk        = qemu_gluster_co_flush_to_disk,
781     .bdrv_has_zero_init           = qemu_gluster_has_zero_init,
782 #ifdef CONFIG_GLUSTERFS_DISCARD
783     .bdrv_co_discard              = qemu_gluster_co_discard,
784 #endif
785 #ifdef CONFIG_GLUSTERFS_ZEROFILL
786     .bdrv_co_write_zeroes         = qemu_gluster_co_write_zeroes,
787 #endif
788     .create_options               = qemu_gluster_create_options,
789 };
790 
791 static BlockDriver bdrv_gluster_rdma = {
792     .format_name                  = "gluster",
793     .protocol_name                = "gluster+rdma",
794     .instance_size                = sizeof(BDRVGlusterState),
795     .bdrv_needs_filename          = true,
796     .bdrv_file_open               = qemu_gluster_open,
797     .bdrv_reopen_prepare          = qemu_gluster_reopen_prepare,
798     .bdrv_reopen_commit           = qemu_gluster_reopen_commit,
799     .bdrv_reopen_abort            = qemu_gluster_reopen_abort,
800     .bdrv_close                   = qemu_gluster_close,
801     .bdrv_create                  = qemu_gluster_create,
802     .bdrv_getlength               = qemu_gluster_getlength,
803     .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
804     .bdrv_truncate                = qemu_gluster_truncate,
805     .bdrv_co_readv                = qemu_gluster_co_readv,
806     .bdrv_co_writev               = qemu_gluster_co_writev,
807     .bdrv_co_flush_to_disk        = qemu_gluster_co_flush_to_disk,
808     .bdrv_has_zero_init           = qemu_gluster_has_zero_init,
809 #ifdef CONFIG_GLUSTERFS_DISCARD
810     .bdrv_co_discard              = qemu_gluster_co_discard,
811 #endif
812 #ifdef CONFIG_GLUSTERFS_ZEROFILL
813     .bdrv_co_write_zeroes         = qemu_gluster_co_write_zeroes,
814 #endif
815     .create_options               = qemu_gluster_create_options,
816 };
817 
818 static void bdrv_gluster_init(void)
819 {
820     bdrv_register(&bdrv_gluster_rdma);
821     bdrv_register(&bdrv_gluster_unix);
822     bdrv_register(&bdrv_gluster_tcp);
823     bdrv_register(&bdrv_gluster);
824 }
825 
826 block_init(bdrv_gluster_init);
827