blob: 1eb3a8c398eb29450dd65f216744bec36b0b5ddc [file] [log] [blame]
Bharata B Rao8d6d89c2012-09-27 19:30:32 +05301/*
2 * GlusterFS backend for QEMU
3 *
4 * Copyright (C) 2012 Bharata B Rao <bharata@linux.vnet.ibm.com>
5 *
Bharata B Rao85c09bc2014-01-29 19:59:55 +05306 * 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.
Bharata B Rao8d6d89c2012-09-27 19:30:32 +05308 *
Bharata B Rao8d6d89c2012-09-27 19:30:32 +05309 */
10#include <glusterfs/api/glfs.h>
Paolo Bonzini737e1502012-12-17 18:19:44 +010011#include "block/block_int.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010012#include "qemu/uri.h"
Bharata B Rao8d6d89c2012-09-27 19:30:32 +053013
14typedef struct GlusterAIOCB {
Bharata B Rao8d6d89c2012-09-27 19:30:32 +053015 int64_t size;
16 int ret;
Bharata B Rao8d6d89c2012-09-27 19:30:32 +053017 QEMUBH *bh;
Bharata B Rao15744b02013-12-21 14:51:24 +053018 Coroutine *coroutine;
Stefan Hajnoczi6ee50af2014-05-08 16:34:41 +020019 AioContext *aio_context;
Bharata B Rao8d6d89c2012-09-27 19:30:32 +053020} GlusterAIOCB;
21
22typedef struct BDRVGlusterState {
23 struct glfs *glfs;
Bharata B Rao8d6d89c2012-09-27 19:30:32 +053024 struct glfs_fd *fd;
Bharata B Rao8d6d89c2012-09-27 19:30:32 +053025} BDRVGlusterState;
26
Bharata B Rao8d6d89c2012-09-27 19:30:32 +053027typedef struct GlusterConf {
28 char *server;
29 int port;
30 char *volname;
31 char *image;
32 char *transport;
33} GlusterConf;
34
35static void qemu_gluster_gconf_free(GlusterConf *gconf)
36{
Jeff Cody1b37b342014-02-17 11:11:11 -050037 if (gconf) {
38 g_free(gconf->server);
39 g_free(gconf->volname);
40 g_free(gconf->image);
41 g_free(gconf->transport);
42 g_free(gconf);
43 }
Bharata B Rao8d6d89c2012-09-27 19:30:32 +053044}
45
46static int parse_volume_options(GlusterConf *gconf, char *path)
47{
48 char *p, *q;
49
50 if (!path) {
51 return -EINVAL;
52 }
53
54 /* volume */
55 p = q = path + strspn(path, "/");
56 p += strcspn(p, "/");
57 if (*p == '\0') {
58 return -EINVAL;
59 }
60 gconf->volname = g_strndup(q, p - q);
61
62 /* image */
63 p += strspn(p, "/");
64 if (*p == '\0') {
65 return -EINVAL;
66 }
67 gconf->image = g_strdup(p);
68 return 0;
69}
70
71/*
72 * file=gluster[+transport]://[server[:port]]/volname/image[?socket=...]
73 *
74 * 'gluster' is the protocol.
75 *
76 * 'transport' specifies the transport type used to connect to gluster
77 * management daemon (glusterd). Valid transport types are
78 * tcp, unix and rdma. If a transport type isn't specified, then tcp
79 * type is assumed.
80 *
81 * 'server' specifies the server where the volume file specification for
82 * the given volume resides. This can be either hostname, ipv4 address
83 * or ipv6 address. ipv6 address needs to be within square brackets [ ].
Deepak Kathayatdc6fb732014-03-24 16:30:17 +080084 * If transport type is 'unix', then 'server' field should not be specified.
Bharata B Rao8d6d89c2012-09-27 19:30:32 +053085 * The 'socket' field needs to be populated with the path to unix domain
86 * socket.
87 *
88 * 'port' is the port number on which glusterd is listening. This is optional
89 * and if not specified, QEMU will send 0 which will make gluster to use the
90 * default port. If the transport type is unix, then 'port' should not be
91 * specified.
92 *
93 * 'volname' is the name of the gluster volume which contains the VM image.
94 *
95 * 'image' is the path to the actual VM image that resides on gluster volume.
96 *
97 * Examples:
98 *
99 * file=gluster://1.2.3.4/testvol/a.img
100 * file=gluster+tcp://1.2.3.4/testvol/a.img
101 * file=gluster+tcp://1.2.3.4:24007/testvol/dir/a.img
102 * file=gluster+tcp://[1:2:3:4:5:6:7:8]/testvol/dir/a.img
103 * file=gluster+tcp://[1:2:3:4:5:6:7:8]:24007/testvol/dir/a.img
104 * file=gluster+tcp://server.domain.com:24007/testvol/dir/a.img
105 * file=gluster+unix:///testvol/dir/a.img?socket=/tmp/glusterd.socket
106 * file=gluster+rdma://1.2.3.4:24007/testvol/a.img
107 */
108static int qemu_gluster_parseuri(GlusterConf *gconf, const char *filename)
109{
110 URI *uri;
111 QueryParams *qp = NULL;
112 bool is_unix = false;
113 int ret = 0;
114
115 uri = uri_parse(filename);
116 if (!uri) {
117 return -EINVAL;
118 }
119
120 /* transport */
Paolo Bonzini24897a72014-02-17 14:43:54 +0100121 if (!uri->scheme || !strcmp(uri->scheme, "gluster")) {
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530122 gconf->transport = g_strdup("tcp");
123 } else if (!strcmp(uri->scheme, "gluster+tcp")) {
124 gconf->transport = g_strdup("tcp");
125 } else if (!strcmp(uri->scheme, "gluster+unix")) {
126 gconf->transport = g_strdup("unix");
127 is_unix = true;
128 } else if (!strcmp(uri->scheme, "gluster+rdma")) {
129 gconf->transport = g_strdup("rdma");
130 } else {
131 ret = -EINVAL;
132 goto out;
133 }
134
135 ret = parse_volume_options(gconf, uri->path);
136 if (ret < 0) {
137 goto out;
138 }
139
140 qp = query_params_parse(uri->query);
141 if (qp->n > 1 || (is_unix && !qp->n) || (!is_unix && qp->n)) {
142 ret = -EINVAL;
143 goto out;
144 }
145
146 if (is_unix) {
147 if (uri->server || uri->port) {
148 ret = -EINVAL;
149 goto out;
150 }
151 if (strcmp(qp->p[0].name, "socket")) {
152 ret = -EINVAL;
153 goto out;
154 }
155 gconf->server = g_strdup(qp->p[0].value);
156 } else {
Paolo Bonzini24897a72014-02-17 14:43:54 +0100157 gconf->server = g_strdup(uri->server ? uri->server : "localhost");
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530158 gconf->port = uri->port;
159 }
160
161out:
162 if (qp) {
163 query_params_free(qp);
164 }
165 uri_free(uri);
166 return ret;
167}
168
Paolo Bonzinia7451cb2014-02-17 14:43:55 +0100169static struct glfs *qemu_gluster_init(GlusterConf *gconf, const char *filename,
170 Error **errp)
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530171{
172 struct glfs *glfs = NULL;
173 int ret;
174 int old_errno;
175
176 ret = qemu_gluster_parseuri(gconf, filename);
177 if (ret < 0) {
Paolo Bonzinia7451cb2014-02-17 14:43:55 +0100178 error_setg(errp, "Usage: file=gluster[+transport]://[server[:port]]/"
179 "volname/image[?socket=...]");
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530180 errno = -ret;
181 goto out;
182 }
183
184 glfs = glfs_new(gconf->volname);
185 if (!glfs) {
186 goto out;
187 }
188
189 ret = glfs_set_volfile_server(glfs, gconf->transport, gconf->server,
190 gconf->port);
191 if (ret < 0) {
192 goto out;
193 }
194
195 /*
196 * TODO: Use GF_LOG_ERROR instead of hard code value of 4 here when
197 * GlusterFS makes GF_LOG_* macros available to libgfapi users.
198 */
199 ret = glfs_set_logging(glfs, "-", 4);
200 if (ret < 0) {
201 goto out;
202 }
203
204 ret = glfs_init(glfs);
205 if (ret) {
Paolo Bonzinia7451cb2014-02-17 14:43:55 +0100206 error_setg_errno(errp, errno,
207 "Gluster connection failed for server=%s port=%d "
208 "volume=%s image=%s transport=%s", gconf->server,
209 gconf->port, gconf->volname, gconf->image,
210 gconf->transport);
Peter Krempa45571172014-05-09 12:08:10 +0200211
212 /* glfs_init sometimes doesn't set errno although docs suggest that */
213 if (errno == 0)
214 errno = EINVAL;
215
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530216 goto out;
217 }
218 return glfs;
219
220out:
221 if (glfs) {
222 old_errno = errno;
223 glfs_fini(glfs);
224 errno = old_errno;
225 }
226 return NULL;
227}
228
Bharata B Rao15744b02013-12-21 14:51:24 +0530229static void qemu_gluster_complete_aio(void *opaque)
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530230{
Bharata B Rao15744b02013-12-21 14:51:24 +0530231 GlusterAIOCB *acb = (GlusterAIOCB *)opaque;
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530232
Bharata B Rao15744b02013-12-21 14:51:24 +0530233 qemu_bh_delete(acb->bh);
234 acb->bh = NULL;
235 qemu_coroutine_enter(acb->coroutine, NULL);
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530236}
237
Bharata B Rao7c815372013-12-21 14:51:25 +0530238/*
239 * AIO callback routine called from GlusterFS thread.
240 */
241static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg)
242{
243 GlusterAIOCB *acb = (GlusterAIOCB *)arg;
244
245 if (!ret || ret == acb->size) {
246 acb->ret = 0; /* Success */
247 } else if (ret < 0) {
248 acb->ret = ret; /* Read/Write failed */
249 } else {
250 acb->ret = -EIO; /* Partial read/write - fail it */
251 }
252
Stefan Hajnoczi6ee50af2014-05-08 16:34:41 +0200253 acb->bh = aio_bh_new(acb->aio_context, qemu_gluster_complete_aio, acb);
Bharata B Rao7c815372013-12-21 14:51:25 +0530254 qemu_bh_schedule(acb->bh);
255}
256
Kevin Wolfb4894772013-04-12 17:50:16 +0200257/* TODO Convert to fine grained options */
258static QemuOptsList runtime_opts = {
259 .name = "gluster",
260 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
261 .desc = {
262 {
263 .name = "filename",
264 .type = QEMU_OPT_STRING,
265 .help = "URL to the gluster image",
266 },
267 { /* end of list */ }
268 },
269};
270
Jeff Cody1b37b342014-02-17 11:11:11 -0500271static void qemu_gluster_parse_flags(int bdrv_flags, int *open_flags)
272{
273 assert(open_flags != NULL);
274
275 *open_flags |= O_BINARY;
276
277 if (bdrv_flags & BDRV_O_RDWR) {
278 *open_flags |= O_RDWR;
279 } else {
280 *open_flags |= O_RDONLY;
281 }
282
283 if ((bdrv_flags & BDRV_O_NOCACHE)) {
284 *open_flags |= O_DIRECT;
285 }
286}
287
Kevin Wolf56d1b4d2013-04-12 20:02:37 +0200288static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
Max Reitz015a1032013-09-05 14:22:29 +0200289 int bdrv_flags, Error **errp)
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530290{
291 BDRVGlusterState *s = bs->opaque;
Jeff Cody1b37b342014-02-17 11:11:11 -0500292 int open_flags = 0;
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530293 int ret = 0;
Markus Armbruster5839e532014-08-19 10:31:08 +0200294 GlusterConf *gconf = g_new0(GlusterConf, 1);
Kevin Wolfb4894772013-04-12 17:50:16 +0200295 QemuOpts *opts;
296 Error *local_err = NULL;
297 const char *filename;
298
Peter Crosthwaite87ea75d2014-01-01 18:49:17 -0800299 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
Kevin Wolfb4894772013-04-12 17:50:16 +0200300 qemu_opts_absorb_qdict(opts, options, &local_err);
Markus Armbruster84d18f02014-01-30 15:07:28 +0100301 if (local_err) {
Paolo Bonzinia7451cb2014-02-17 14:43:55 +0100302 error_propagate(errp, local_err);
Kevin Wolfb4894772013-04-12 17:50:16 +0200303 ret = -EINVAL;
304 goto out;
305 }
306
307 filename = qemu_opt_get(opts, "filename");
308
Paolo Bonzinia7451cb2014-02-17 14:43:55 +0100309 s->glfs = qemu_gluster_init(gconf, filename, errp);
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530310 if (!s->glfs) {
311 ret = -errno;
312 goto out;
313 }
314
Jeff Cody1b37b342014-02-17 11:11:11 -0500315 qemu_gluster_parse_flags(bdrv_flags, &open_flags);
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530316
317 s->fd = glfs_open(s->glfs, gconf->image, open_flags);
318 if (!s->fd) {
319 ret = -errno;
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530320 }
321
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530322out:
Kevin Wolfb4894772013-04-12 17:50:16 +0200323 qemu_opts_del(opts);
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530324 qemu_gluster_gconf_free(gconf);
325 if (!ret) {
326 return ret;
327 }
328 if (s->fd) {
329 glfs_close(s->fd);
330 }
331 if (s->glfs) {
332 glfs_fini(s->glfs);
333 }
334 return ret;
335}
336
Jeff Codyadccfbc2014-02-17 11:11:12 -0500337typedef struct BDRVGlusterReopenState {
338 struct glfs *glfs;
339 struct glfs_fd *fd;
340} BDRVGlusterReopenState;
341
342
343static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
344 BlockReopenQueue *queue, Error **errp)
345{
346 int ret = 0;
347 BDRVGlusterReopenState *reop_s;
348 GlusterConf *gconf = NULL;
349 int open_flags = 0;
350
351 assert(state != NULL);
352 assert(state->bs != NULL);
353
Markus Armbruster5839e532014-08-19 10:31:08 +0200354 state->opaque = g_new0(BDRVGlusterReopenState, 1);
Jeff Codyadccfbc2014-02-17 11:11:12 -0500355 reop_s = state->opaque;
356
357 qemu_gluster_parse_flags(state->flags, &open_flags);
358
Markus Armbruster5839e532014-08-19 10:31:08 +0200359 gconf = g_new0(GlusterConf, 1);
Jeff Codyadccfbc2014-02-17 11:11:12 -0500360
Andreas Färberf55ea622014-03-04 21:00:28 +0100361 reop_s->glfs = qemu_gluster_init(gconf, state->bs->filename, errp);
Jeff Codyadccfbc2014-02-17 11:11:12 -0500362 if (reop_s->glfs == NULL) {
363 ret = -errno;
364 goto exit;
365 }
366
367 reop_s->fd = glfs_open(reop_s->glfs, gconf->image, open_flags);
368 if (reop_s->fd == NULL) {
369 /* reops->glfs will be cleaned up in _abort */
370 ret = -errno;
371 goto exit;
372 }
373
374exit:
375 /* state->opaque will be freed in either the _abort or _commit */
376 qemu_gluster_gconf_free(gconf);
377 return ret;
378}
379
380static void qemu_gluster_reopen_commit(BDRVReopenState *state)
381{
382 BDRVGlusterReopenState *reop_s = state->opaque;
383 BDRVGlusterState *s = state->bs->opaque;
384
385
386 /* close the old */
387 if (s->fd) {
388 glfs_close(s->fd);
389 }
390 if (s->glfs) {
391 glfs_fini(s->glfs);
392 }
393
394 /* use the newly opened image / connection */
395 s->fd = reop_s->fd;
396 s->glfs = reop_s->glfs;
397
398 g_free(state->opaque);
399 state->opaque = NULL;
400
401 return;
402}
403
404
405static void qemu_gluster_reopen_abort(BDRVReopenState *state)
406{
407 BDRVGlusterReopenState *reop_s = state->opaque;
408
409 if (reop_s == NULL) {
410 return;
411 }
412
413 if (reop_s->fd) {
414 glfs_close(reop_s->fd);
415 }
416
417 if (reop_s->glfs) {
418 glfs_fini(reop_s->glfs);
419 }
420
421 g_free(state->opaque);
422 state->opaque = NULL;
423
424 return;
425}
426
Bharata B Rao7c815372013-12-21 14:51:25 +0530427#ifdef CONFIG_GLUSTERFS_ZEROFILL
428static coroutine_fn int qemu_gluster_co_write_zeroes(BlockDriverState *bs,
429 int64_t sector_num, int nb_sectors, BdrvRequestFlags flags)
430{
431 int ret;
432 GlusterAIOCB *acb = g_slice_new(GlusterAIOCB);
433 BDRVGlusterState *s = bs->opaque;
434 off_t size = nb_sectors * BDRV_SECTOR_SIZE;
435 off_t offset = sector_num * BDRV_SECTOR_SIZE;
436
437 acb->size = size;
438 acb->ret = 0;
439 acb->coroutine = qemu_coroutine_self();
Stefan Hajnoczi6ee50af2014-05-08 16:34:41 +0200440 acb->aio_context = bdrv_get_aio_context(bs);
Bharata B Rao7c815372013-12-21 14:51:25 +0530441
442 ret = glfs_zerofill_async(s->fd, offset, size, &gluster_finish_aiocb, acb);
443 if (ret < 0) {
444 ret = -errno;
445 goto out;
446 }
447
448 qemu_coroutine_yield();
449 ret = acb->ret;
450
451out:
452 g_slice_free(GlusterAIOCB, acb);
453 return ret;
454}
Bharata B Raocf7f6162013-12-21 14:51:26 +0530455
456static inline bool gluster_supports_zerofill(void)
457{
458 return 1;
459}
460
461static inline int qemu_gluster_zerofill(struct glfs_fd *fd, int64_t offset,
462 int64_t size)
463{
464 return glfs_zerofill(fd, offset, size);
465}
466
467#else
468static inline bool gluster_supports_zerofill(void)
469{
470 return 0;
471}
472
473static inline int qemu_gluster_zerofill(struct glfs_fd *fd, int64_t offset,
474 int64_t size)
475{
476 return 0;
477}
Bharata B Rao7c815372013-12-21 14:51:25 +0530478#endif
479
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530480static int qemu_gluster_create(const char *filename,
Chunyan Liu90c772d2014-06-05 17:20:54 +0800481 QemuOpts *opts, Error **errp)
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530482{
483 struct glfs *glfs;
484 struct glfs_fd *fd;
485 int ret = 0;
Bharata B Raocf7f6162013-12-21 14:51:26 +0530486 int prealloc = 0;
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530487 int64_t total_size = 0;
Chunyan Liu90c772d2014-06-05 17:20:54 +0800488 char *tmp = NULL;
Markus Armbruster5839e532014-08-19 10:31:08 +0200489 GlusterConf *gconf = g_new0(GlusterConf, 1);
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530490
Paolo Bonzinia7451cb2014-02-17 14:43:55 +0100491 glfs = qemu_gluster_init(gconf, filename, errp);
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530492 if (!glfs) {
Peter Krempa45571172014-05-09 12:08:10 +0200493 ret = -errno;
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530494 goto out;
495 }
496
Hu Tao180e9522014-09-10 17:05:46 +0800497 total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
498 BDRV_SECTOR_SIZE);
Chunyan Liu90c772d2014-06-05 17:20:54 +0800499
500 tmp = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
501 if (!tmp || !strcmp(tmp, "off")) {
502 prealloc = 0;
503 } else if (!strcmp(tmp, "full") &&
504 gluster_supports_zerofill()) {
505 prealloc = 1;
506 } else {
507 error_setg(errp, "Invalid preallocation mode: '%s'"
508 " or GlusterFS doesn't support zerofill API",
509 tmp);
510 ret = -EINVAL;
511 goto out;
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530512 }
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 {
Hu Tao180e9522014-09-10 17:05:46 +0800519 if (!glfs_ftruncate(fd, total_size)) {
520 if (prealloc && qemu_gluster_zerofill(fd, 0, total_size)) {
Bharata B Raocf7f6162013-12-21 14:51:26 +0530521 ret = -errno;
522 }
523 } else {
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530524 ret = -errno;
525 }
Bharata B Raocf7f6162013-12-21 14:51:26 +0530526
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530527 if (glfs_close(fd) != 0) {
528 ret = -errno;
529 }
530 }
531out:
Chunyan Liu90c772d2014-06-05 17:20:54 +0800532 g_free(tmp);
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530533 qemu_gluster_gconf_free(gconf);
534 if (glfs) {
535 glfs_fini(glfs);
536 }
537 return ret;
538}
539
Bharata B Rao15744b02013-12-21 14:51:24 +0530540static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
541 int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, int write)
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530542{
543 int ret;
Bharata B Rao15744b02013-12-21 14:51:24 +0530544 GlusterAIOCB *acb = g_slice_new(GlusterAIOCB);
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530545 BDRVGlusterState *s = bs->opaque;
Bharata B Rao15744b02013-12-21 14:51:24 +0530546 size_t size = nb_sectors * BDRV_SECTOR_SIZE;
547 off_t offset = sector_num * BDRV_SECTOR_SIZE;
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530548
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530549 acb->size = size;
550 acb->ret = 0;
Bharata B Rao15744b02013-12-21 14:51:24 +0530551 acb->coroutine = qemu_coroutine_self();
Stefan Hajnoczi6ee50af2014-05-08 16:34:41 +0200552 acb->aio_context = bdrv_get_aio_context(bs);
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530553
554 if (write) {
555 ret = glfs_pwritev_async(s->fd, qiov->iov, qiov->niov, offset, 0,
556 &gluster_finish_aiocb, acb);
557 } else {
558 ret = glfs_preadv_async(s->fd, qiov->iov, qiov->niov, offset, 0,
559 &gluster_finish_aiocb, acb);
560 }
561
562 if (ret < 0) {
Bharata B Rao15744b02013-12-21 14:51:24 +0530563 ret = -errno;
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530564 goto out;
565 }
Bharata B Rao15744b02013-12-21 14:51:24 +0530566
567 qemu_coroutine_yield();
568 ret = acb->ret;
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530569
570out:
Bharata B Rao15744b02013-12-21 14:51:24 +0530571 g_slice_free(GlusterAIOCB, acb);
572 return ret;
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530573}
574
Paolo Bonzini42ec24e2013-07-19 19:51:33 +0530575static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset)
576{
577 int ret;
578 BDRVGlusterState *s = bs->opaque;
579
580 ret = glfs_ftruncate(s->fd, offset);
581 if (ret < 0) {
582 return -errno;
583 }
584
585 return 0;
586}
587
Bharata B Rao15744b02013-12-21 14:51:24 +0530588static coroutine_fn int qemu_gluster_co_readv(BlockDriverState *bs,
589 int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530590{
Bharata B Rao15744b02013-12-21 14:51:24 +0530591 return qemu_gluster_co_rw(bs, sector_num, nb_sectors, qiov, 0);
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530592}
593
Bharata B Rao15744b02013-12-21 14:51:24 +0530594static coroutine_fn int qemu_gluster_co_writev(BlockDriverState *bs,
595 int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530596{
Bharata B Rao15744b02013-12-21 14:51:24 +0530597 return qemu_gluster_co_rw(bs, sector_num, nb_sectors, qiov, 1);
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530598}
599
Bharata B Rao15744b02013-12-21 14:51:24 +0530600static coroutine_fn int qemu_gluster_co_flush_to_disk(BlockDriverState *bs)
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530601{
602 int ret;
Bharata B Rao15744b02013-12-21 14:51:24 +0530603 GlusterAIOCB *acb = g_slice_new(GlusterAIOCB);
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530604 BDRVGlusterState *s = bs->opaque;
605
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530606 acb->size = 0;
607 acb->ret = 0;
Bharata B Rao15744b02013-12-21 14:51:24 +0530608 acb->coroutine = qemu_coroutine_self();
Stefan Hajnoczi6ee50af2014-05-08 16:34:41 +0200609 acb->aio_context = bdrv_get_aio_context(bs);
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530610
611 ret = glfs_fsync_async(s->fd, &gluster_finish_aiocb, acb);
612 if (ret < 0) {
Bharata B Rao15744b02013-12-21 14:51:24 +0530613 ret = -errno;
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530614 goto out;
615 }
Bharata B Rao15744b02013-12-21 14:51:24 +0530616
617 qemu_coroutine_yield();
618 ret = acb->ret;
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530619
620out:
Bharata B Rao15744b02013-12-21 14:51:24 +0530621 g_slice_free(GlusterAIOCB, acb);
622 return ret;
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530623}
624
Bharata B Rao0c14fb42013-07-16 21:47:42 +0530625#ifdef CONFIG_GLUSTERFS_DISCARD
Bharata B Rao15744b02013-12-21 14:51:24 +0530626static coroutine_fn int qemu_gluster_co_discard(BlockDriverState *bs,
627 int64_t sector_num, int nb_sectors)
Bharata B Rao0c14fb42013-07-16 21:47:42 +0530628{
629 int ret;
Bharata B Rao15744b02013-12-21 14:51:24 +0530630 GlusterAIOCB *acb = g_slice_new(GlusterAIOCB);
Bharata B Rao0c14fb42013-07-16 21:47:42 +0530631 BDRVGlusterState *s = bs->opaque;
Bharata B Rao15744b02013-12-21 14:51:24 +0530632 size_t size = nb_sectors * BDRV_SECTOR_SIZE;
633 off_t offset = sector_num * BDRV_SECTOR_SIZE;
Bharata B Rao0c14fb42013-07-16 21:47:42 +0530634
Bharata B Rao0c14fb42013-07-16 21:47:42 +0530635 acb->size = 0;
636 acb->ret = 0;
Bharata B Rao15744b02013-12-21 14:51:24 +0530637 acb->coroutine = qemu_coroutine_self();
Stefan Hajnoczi6ee50af2014-05-08 16:34:41 +0200638 acb->aio_context = bdrv_get_aio_context(bs);
Bharata B Rao0c14fb42013-07-16 21:47:42 +0530639
640 ret = glfs_discard_async(s->fd, offset, size, &gluster_finish_aiocb, acb);
641 if (ret < 0) {
Bharata B Rao15744b02013-12-21 14:51:24 +0530642 ret = -errno;
Bharata B Rao0c14fb42013-07-16 21:47:42 +0530643 goto out;
644 }
Bharata B Rao15744b02013-12-21 14:51:24 +0530645
646 qemu_coroutine_yield();
647 ret = acb->ret;
Bharata B Rao0c14fb42013-07-16 21:47:42 +0530648
649out:
Bharata B Rao15744b02013-12-21 14:51:24 +0530650 g_slice_free(GlusterAIOCB, acb);
651 return ret;
Bharata B Rao0c14fb42013-07-16 21:47:42 +0530652}
653#endif
654
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530655static int64_t qemu_gluster_getlength(BlockDriverState *bs)
656{
657 BDRVGlusterState *s = bs->opaque;
658 int64_t ret;
659
660 ret = glfs_lseek(s->fd, 0, SEEK_END);
661 if (ret < 0) {
662 return -errno;
663 } else {
664 return ret;
665 }
666}
667
668static int64_t qemu_gluster_allocated_file_size(BlockDriverState *bs)
669{
670 BDRVGlusterState *s = bs->opaque;
671 struct stat st;
672 int ret;
673
674 ret = glfs_fstat(s->fd, &st);
675 if (ret < 0) {
676 return -errno;
677 } else {
678 return st.st_blocks * 512;
679 }
680}
681
682static void qemu_gluster_close(BlockDriverState *bs)
683{
684 BDRVGlusterState *s = bs->opaque;
685
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530686 if (s->fd) {
687 glfs_close(s->fd);
688 s->fd = NULL;
689 }
690 glfs_fini(s->glfs);
691}
692
Kevin Wolf8ab6fee2013-06-26 09:41:57 +0200693static int qemu_gluster_has_zero_init(BlockDriverState *bs)
694{
695 /* GlusterFS volume could be backed by a block device */
696 return 0;
697}
698
Chunyan Liu90c772d2014-06-05 17:20:54 +0800699static QemuOptsList qemu_gluster_create_opts = {
700 .name = "qemu-gluster-create-opts",
701 .head = QTAILQ_HEAD_INITIALIZER(qemu_gluster_create_opts.head),
702 .desc = {
703 {
704 .name = BLOCK_OPT_SIZE,
705 .type = QEMU_OPT_SIZE,
706 .help = "Virtual disk size"
707 },
708 {
709 .name = BLOCK_OPT_PREALLOC,
710 .type = QEMU_OPT_STRING,
711 .help = "Preallocation mode (allowed values: off, full)"
712 },
713 { /* end of list */ }
714 }
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530715};
716
717static BlockDriver bdrv_gluster = {
718 .format_name = "gluster",
719 .protocol_name = "gluster",
720 .instance_size = sizeof(BDRVGlusterState),
Benoît Canet030be322013-09-24 17:07:04 +0200721 .bdrv_needs_filename = true,
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530722 .bdrv_file_open = qemu_gluster_open,
Jeff Codyadccfbc2014-02-17 11:11:12 -0500723 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
724 .bdrv_reopen_commit = qemu_gluster_reopen_commit,
725 .bdrv_reopen_abort = qemu_gluster_reopen_abort,
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530726 .bdrv_close = qemu_gluster_close,
Chunyan Liuc282e1f2014-06-05 17:21:11 +0800727 .bdrv_create = qemu_gluster_create,
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530728 .bdrv_getlength = qemu_gluster_getlength,
729 .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
Paolo Bonzini42ec24e2013-07-19 19:51:33 +0530730 .bdrv_truncate = qemu_gluster_truncate,
Bharata B Rao15744b02013-12-21 14:51:24 +0530731 .bdrv_co_readv = qemu_gluster_co_readv,
732 .bdrv_co_writev = qemu_gluster_co_writev,
733 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
Kevin Wolf8ab6fee2013-06-26 09:41:57 +0200734 .bdrv_has_zero_init = qemu_gluster_has_zero_init,
Bharata B Rao0c14fb42013-07-16 21:47:42 +0530735#ifdef CONFIG_GLUSTERFS_DISCARD
Bharata B Rao15744b02013-12-21 14:51:24 +0530736 .bdrv_co_discard = qemu_gluster_co_discard,
Bharata B Rao0c14fb42013-07-16 21:47:42 +0530737#endif
Bharata B Rao7c815372013-12-21 14:51:25 +0530738#ifdef CONFIG_GLUSTERFS_ZEROFILL
739 .bdrv_co_write_zeroes = qemu_gluster_co_write_zeroes,
740#endif
Chunyan Liu90c772d2014-06-05 17:20:54 +0800741 .create_opts = &qemu_gluster_create_opts,
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530742};
743
744static BlockDriver bdrv_gluster_tcp = {
745 .format_name = "gluster",
746 .protocol_name = "gluster+tcp",
747 .instance_size = sizeof(BDRVGlusterState),
Benoît Canet030be322013-09-24 17:07:04 +0200748 .bdrv_needs_filename = true,
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530749 .bdrv_file_open = qemu_gluster_open,
Jeff Codyadccfbc2014-02-17 11:11:12 -0500750 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
751 .bdrv_reopen_commit = qemu_gluster_reopen_commit,
752 .bdrv_reopen_abort = qemu_gluster_reopen_abort,
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530753 .bdrv_close = qemu_gluster_close,
Chunyan Liuc282e1f2014-06-05 17:21:11 +0800754 .bdrv_create = qemu_gluster_create,
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530755 .bdrv_getlength = qemu_gluster_getlength,
756 .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
Paolo Bonzini42ec24e2013-07-19 19:51:33 +0530757 .bdrv_truncate = qemu_gluster_truncate,
Bharata B Rao15744b02013-12-21 14:51:24 +0530758 .bdrv_co_readv = qemu_gluster_co_readv,
759 .bdrv_co_writev = qemu_gluster_co_writev,
760 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
Kevin Wolf8ab6fee2013-06-26 09:41:57 +0200761 .bdrv_has_zero_init = qemu_gluster_has_zero_init,
Bharata B Rao0c14fb42013-07-16 21:47:42 +0530762#ifdef CONFIG_GLUSTERFS_DISCARD
Bharata B Rao15744b02013-12-21 14:51:24 +0530763 .bdrv_co_discard = qemu_gluster_co_discard,
Bharata B Rao0c14fb42013-07-16 21:47:42 +0530764#endif
Bharata B Rao7c815372013-12-21 14:51:25 +0530765#ifdef CONFIG_GLUSTERFS_ZEROFILL
766 .bdrv_co_write_zeroes = qemu_gluster_co_write_zeroes,
767#endif
Chunyan Liu90c772d2014-06-05 17:20:54 +0800768 .create_opts = &qemu_gluster_create_opts,
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530769};
770
771static BlockDriver bdrv_gluster_unix = {
772 .format_name = "gluster",
773 .protocol_name = "gluster+unix",
774 .instance_size = sizeof(BDRVGlusterState),
Benoît Canet030be322013-09-24 17:07:04 +0200775 .bdrv_needs_filename = true,
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530776 .bdrv_file_open = qemu_gluster_open,
Jeff Codyadccfbc2014-02-17 11:11:12 -0500777 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
778 .bdrv_reopen_commit = qemu_gluster_reopen_commit,
779 .bdrv_reopen_abort = qemu_gluster_reopen_abort,
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530780 .bdrv_close = qemu_gluster_close,
Chunyan Liuc282e1f2014-06-05 17:21:11 +0800781 .bdrv_create = qemu_gluster_create,
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530782 .bdrv_getlength = qemu_gluster_getlength,
783 .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
Paolo Bonzini42ec24e2013-07-19 19:51:33 +0530784 .bdrv_truncate = qemu_gluster_truncate,
Bharata B Rao15744b02013-12-21 14:51:24 +0530785 .bdrv_co_readv = qemu_gluster_co_readv,
786 .bdrv_co_writev = qemu_gluster_co_writev,
787 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
Kevin Wolf8ab6fee2013-06-26 09:41:57 +0200788 .bdrv_has_zero_init = qemu_gluster_has_zero_init,
Bharata B Rao0c14fb42013-07-16 21:47:42 +0530789#ifdef CONFIG_GLUSTERFS_DISCARD
Bharata B Rao15744b02013-12-21 14:51:24 +0530790 .bdrv_co_discard = qemu_gluster_co_discard,
Bharata B Rao0c14fb42013-07-16 21:47:42 +0530791#endif
Bharata B Rao7c815372013-12-21 14:51:25 +0530792#ifdef CONFIG_GLUSTERFS_ZEROFILL
793 .bdrv_co_write_zeroes = qemu_gluster_co_write_zeroes,
794#endif
Chunyan Liu90c772d2014-06-05 17:20:54 +0800795 .create_opts = &qemu_gluster_create_opts,
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530796};
797
798static BlockDriver bdrv_gluster_rdma = {
799 .format_name = "gluster",
800 .protocol_name = "gluster+rdma",
801 .instance_size = sizeof(BDRVGlusterState),
Benoît Canet030be322013-09-24 17:07:04 +0200802 .bdrv_needs_filename = true,
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530803 .bdrv_file_open = qemu_gluster_open,
Jeff Codyadccfbc2014-02-17 11:11:12 -0500804 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
805 .bdrv_reopen_commit = qemu_gluster_reopen_commit,
806 .bdrv_reopen_abort = qemu_gluster_reopen_abort,
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530807 .bdrv_close = qemu_gluster_close,
Chunyan Liuc282e1f2014-06-05 17:21:11 +0800808 .bdrv_create = qemu_gluster_create,
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530809 .bdrv_getlength = qemu_gluster_getlength,
810 .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
Paolo Bonzini42ec24e2013-07-19 19:51:33 +0530811 .bdrv_truncate = qemu_gluster_truncate,
Bharata B Rao15744b02013-12-21 14:51:24 +0530812 .bdrv_co_readv = qemu_gluster_co_readv,
813 .bdrv_co_writev = qemu_gluster_co_writev,
814 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
Kevin Wolf8ab6fee2013-06-26 09:41:57 +0200815 .bdrv_has_zero_init = qemu_gluster_has_zero_init,
Bharata B Rao0c14fb42013-07-16 21:47:42 +0530816#ifdef CONFIG_GLUSTERFS_DISCARD
Bharata B Rao15744b02013-12-21 14:51:24 +0530817 .bdrv_co_discard = qemu_gluster_co_discard,
Bharata B Rao0c14fb42013-07-16 21:47:42 +0530818#endif
Bharata B Rao7c815372013-12-21 14:51:25 +0530819#ifdef CONFIG_GLUSTERFS_ZEROFILL
820 .bdrv_co_write_zeroes = qemu_gluster_co_write_zeroes,
821#endif
Chunyan Liu90c772d2014-06-05 17:20:54 +0800822 .create_opts = &qemu_gluster_create_opts,
Bharata B Rao8d6d89c2012-09-27 19:30:32 +0530823};
824
825static void bdrv_gluster_init(void)
826{
827 bdrv_register(&bdrv_gluster_rdma);
828 bdrv_register(&bdrv_gluster_unix);
829 bdrv_register(&bdrv_gluster_tcp);
830 bdrv_register(&bdrv_gluster);
831}
832
833block_init(bdrv_gluster_init);