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 "qemu/osdep.h" 11 #include <glusterfs/api/glfs.h> 12 #include "block/block_int.h" 13 #include "qapi/error.h" 14 #include "qapi/qmp/qerror.h" 15 #include "qemu/uri.h" 16 #include "qemu/error-report.h" 17 18 #define GLUSTER_OPT_FILENAME "filename" 19 #define GLUSTER_OPT_VOLUME "volume" 20 #define GLUSTER_OPT_PATH "path" 21 #define GLUSTER_OPT_TYPE "type" 22 #define GLUSTER_OPT_SERVER_PATTERN "server." 23 #define GLUSTER_OPT_HOST "host" 24 #define GLUSTER_OPT_PORT "port" 25 #define GLUSTER_OPT_TO "to" 26 #define GLUSTER_OPT_IPV4 "ipv4" 27 #define GLUSTER_OPT_IPV6 "ipv6" 28 #define GLUSTER_OPT_SOCKET "socket" 29 #define GLUSTER_OPT_DEBUG "debug" 30 #define GLUSTER_DEFAULT_PORT 24007 31 #define GLUSTER_DEBUG_DEFAULT 4 32 #define GLUSTER_DEBUG_MAX 9 33 #define GLUSTER_OPT_LOGFILE "logfile" 34 #define GLUSTER_LOGFILE_DEFAULT "-" /* handled in libgfapi as /dev/stderr */ 35 36 #define GERR_INDEX_HINT "hint: check in 'server' array index '%d'\n" 37 38 typedef struct GlusterAIOCB { 39 int64_t size; 40 int ret; 41 Coroutine *coroutine; 42 AioContext *aio_context; 43 } GlusterAIOCB; 44 45 typedef struct BDRVGlusterState { 46 struct glfs *glfs; 47 struct glfs_fd *fd; 48 char *logfile; 49 bool supports_seek_data; 50 int debug_level; 51 } BDRVGlusterState; 52 53 typedef struct BDRVGlusterReopenState { 54 struct glfs *glfs; 55 struct glfs_fd *fd; 56 } BDRVGlusterReopenState; 57 58 59 static QemuOptsList qemu_gluster_create_opts = { 60 .name = "qemu-gluster-create-opts", 61 .head = QTAILQ_HEAD_INITIALIZER(qemu_gluster_create_opts.head), 62 .desc = { 63 { 64 .name = BLOCK_OPT_SIZE, 65 .type = QEMU_OPT_SIZE, 66 .help = "Virtual disk size" 67 }, 68 { 69 .name = BLOCK_OPT_PREALLOC, 70 .type = QEMU_OPT_STRING, 71 .help = "Preallocation mode (allowed values: off, full)" 72 }, 73 { 74 .name = GLUSTER_OPT_DEBUG, 75 .type = QEMU_OPT_NUMBER, 76 .help = "Gluster log level, valid range is 0-9", 77 }, 78 { 79 .name = GLUSTER_OPT_LOGFILE, 80 .type = QEMU_OPT_STRING, 81 .help = "Logfile path of libgfapi", 82 }, 83 { /* end of list */ } 84 } 85 }; 86 87 static QemuOptsList runtime_opts = { 88 .name = "gluster", 89 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), 90 .desc = { 91 { 92 .name = GLUSTER_OPT_FILENAME, 93 .type = QEMU_OPT_STRING, 94 .help = "URL to the gluster image", 95 }, 96 { 97 .name = GLUSTER_OPT_DEBUG, 98 .type = QEMU_OPT_NUMBER, 99 .help = "Gluster log level, valid range is 0-9", 100 }, 101 { 102 .name = GLUSTER_OPT_LOGFILE, 103 .type = QEMU_OPT_STRING, 104 .help = "Logfile path of libgfapi", 105 }, 106 { /* end of list */ } 107 }, 108 }; 109 110 static QemuOptsList runtime_json_opts = { 111 .name = "gluster_json", 112 .head = QTAILQ_HEAD_INITIALIZER(runtime_json_opts.head), 113 .desc = { 114 { 115 .name = GLUSTER_OPT_VOLUME, 116 .type = QEMU_OPT_STRING, 117 .help = "name of gluster volume where VM image resides", 118 }, 119 { 120 .name = GLUSTER_OPT_PATH, 121 .type = QEMU_OPT_STRING, 122 .help = "absolute path to image file in gluster volume", 123 }, 124 { 125 .name = GLUSTER_OPT_DEBUG, 126 .type = QEMU_OPT_NUMBER, 127 .help = "Gluster log level, valid range is 0-9", 128 }, 129 { /* end of list */ } 130 }, 131 }; 132 133 static QemuOptsList runtime_type_opts = { 134 .name = "gluster_type", 135 .head = QTAILQ_HEAD_INITIALIZER(runtime_type_opts.head), 136 .desc = { 137 { 138 .name = GLUSTER_OPT_TYPE, 139 .type = QEMU_OPT_STRING, 140 .help = "tcp|unix", 141 }, 142 { /* end of list */ } 143 }, 144 }; 145 146 static QemuOptsList runtime_unix_opts = { 147 .name = "gluster_unix", 148 .head = QTAILQ_HEAD_INITIALIZER(runtime_unix_opts.head), 149 .desc = { 150 { 151 .name = GLUSTER_OPT_SOCKET, 152 .type = QEMU_OPT_STRING, 153 .help = "socket file path)", 154 }, 155 { /* end of list */ } 156 }, 157 }; 158 159 static QemuOptsList runtime_tcp_opts = { 160 .name = "gluster_tcp", 161 .head = QTAILQ_HEAD_INITIALIZER(runtime_tcp_opts.head), 162 .desc = { 163 { 164 .name = GLUSTER_OPT_TYPE, 165 .type = QEMU_OPT_STRING, 166 .help = "tcp|unix", 167 }, 168 { 169 .name = GLUSTER_OPT_HOST, 170 .type = QEMU_OPT_STRING, 171 .help = "host address (hostname/ipv4/ipv6 addresses)", 172 }, 173 { 174 .name = GLUSTER_OPT_PORT, 175 .type = QEMU_OPT_NUMBER, 176 .help = "port number on which glusterd is listening (default 24007)", 177 }, 178 { 179 .name = "to", 180 .type = QEMU_OPT_NUMBER, 181 .help = "max port number, not supported by gluster", 182 }, 183 { 184 .name = "ipv4", 185 .type = QEMU_OPT_BOOL, 186 .help = "ipv4 bool value, not supported by gluster", 187 }, 188 { 189 .name = "ipv6", 190 .type = QEMU_OPT_BOOL, 191 .help = "ipv6 bool value, not supported by gluster", 192 }, 193 { /* end of list */ } 194 }, 195 }; 196 197 static int parse_volume_options(BlockdevOptionsGluster *gconf, char *path) 198 { 199 char *p, *q; 200 201 if (!path) { 202 return -EINVAL; 203 } 204 205 /* volume */ 206 p = q = path + strspn(path, "/"); 207 p += strcspn(p, "/"); 208 if (*p == '\0') { 209 return -EINVAL; 210 } 211 gconf->volume = g_strndup(q, p - q); 212 213 /* path */ 214 p += strspn(p, "/"); 215 if (*p == '\0') { 216 return -EINVAL; 217 } 218 gconf->path = g_strdup(p); 219 return 0; 220 } 221 222 /* 223 * file=gluster[+transport]://[host[:port]]/volume/path[?socket=...] 224 * 225 * 'gluster' is the protocol. 226 * 227 * 'transport' specifies the transport type used to connect to gluster 228 * management daemon (glusterd). Valid transport types are 229 * tcp or unix. If a transport type isn't specified, then tcp type is assumed. 230 * 231 * 'host' specifies the host where the volume file specification for 232 * the given volume resides. This can be either hostname or ipv4 address. 233 * If transport type is 'unix', then 'host' field should not be specified. 234 * The 'socket' field needs to be populated with the path to unix domain 235 * socket. 236 * 237 * 'port' is the port number on which glusterd is listening. This is optional 238 * and if not specified, QEMU will send 0 which will make gluster to use the 239 * default port. If the transport type is unix, then 'port' should not be 240 * specified. 241 * 242 * 'volume' is the name of the gluster volume which contains the VM image. 243 * 244 * 'path' is the path to the actual VM image that resides on gluster volume. 245 * 246 * Examples: 247 * 248 * file=gluster://1.2.3.4/testvol/a.img 249 * file=gluster+tcp://1.2.3.4/testvol/a.img 250 * file=gluster+tcp://1.2.3.4:24007/testvol/dir/a.img 251 * file=gluster+tcp://host.domain.com:24007/testvol/dir/a.img 252 * file=gluster+unix:///testvol/dir/a.img?socket=/tmp/glusterd.socket 253 */ 254 static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf, 255 const char *filename) 256 { 257 GlusterServer *gsconf; 258 URI *uri; 259 QueryParams *qp = NULL; 260 bool is_unix = false; 261 int ret = 0; 262 263 uri = uri_parse(filename); 264 if (!uri) { 265 return -EINVAL; 266 } 267 268 gconf->server = g_new0(GlusterServerList, 1); 269 gconf->server->value = gsconf = g_new0(GlusterServer, 1); 270 271 /* transport */ 272 if (!uri->scheme || !strcmp(uri->scheme, "gluster")) { 273 gsconf->type = GLUSTER_TRANSPORT_TCP; 274 } else if (!strcmp(uri->scheme, "gluster+tcp")) { 275 gsconf->type = GLUSTER_TRANSPORT_TCP; 276 } else if (!strcmp(uri->scheme, "gluster+unix")) { 277 gsconf->type = GLUSTER_TRANSPORT_UNIX; 278 is_unix = true; 279 } else if (!strcmp(uri->scheme, "gluster+rdma")) { 280 gsconf->type = GLUSTER_TRANSPORT_TCP; 281 error_report("Warning: rdma feature is not supported, falling " 282 "back to tcp"); 283 } else { 284 ret = -EINVAL; 285 goto out; 286 } 287 288 ret = parse_volume_options(gconf, uri->path); 289 if (ret < 0) { 290 goto out; 291 } 292 293 qp = query_params_parse(uri->query); 294 if (qp->n > 1 || (is_unix && !qp->n) || (!is_unix && qp->n)) { 295 ret = -EINVAL; 296 goto out; 297 } 298 299 if (is_unix) { 300 if (uri->server || uri->port) { 301 ret = -EINVAL; 302 goto out; 303 } 304 if (strcmp(qp->p[0].name, "socket")) { 305 ret = -EINVAL; 306 goto out; 307 } 308 gsconf->u.q_unix.path = g_strdup(qp->p[0].value); 309 } else { 310 gsconf->u.tcp.host = g_strdup(uri->server ? uri->server : "localhost"); 311 if (uri->port) { 312 gsconf->u.tcp.port = g_strdup_printf("%d", uri->port); 313 } else { 314 gsconf->u.tcp.port = g_strdup_printf("%d", GLUSTER_DEFAULT_PORT); 315 } 316 } 317 318 out: 319 if (qp) { 320 query_params_free(qp); 321 } 322 uri_free(uri); 323 return ret; 324 } 325 326 static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf, 327 Error **errp) 328 { 329 struct glfs *glfs; 330 int ret; 331 int old_errno; 332 GlusterServerList *server; 333 334 glfs = glfs_new(gconf->volume); 335 if (!glfs) { 336 goto out; 337 } 338 339 for (server = gconf->server; server; server = server->next) { 340 if (server->value->type == GLUSTER_TRANSPORT_UNIX) { 341 ret = glfs_set_volfile_server(glfs, 342 GlusterTransport_lookup[server->value->type], 343 server->value->u.q_unix.path, 0); 344 } else { 345 ret = glfs_set_volfile_server(glfs, 346 GlusterTransport_lookup[server->value->type], 347 server->value->u.tcp.host, 348 atoi(server->value->u.tcp.port)); 349 } 350 351 if (ret < 0) { 352 goto out; 353 } 354 } 355 356 ret = glfs_set_logging(glfs, gconf->logfile, gconf->debug_level); 357 if (ret < 0) { 358 goto out; 359 } 360 361 ret = glfs_init(glfs); 362 if (ret) { 363 error_setg(errp, "Gluster connection for volume %s, path %s failed" 364 " to connect", gconf->volume, gconf->path); 365 for (server = gconf->server; server; server = server->next) { 366 if (server->value->type == GLUSTER_TRANSPORT_UNIX) { 367 error_append_hint(errp, "hint: failed on socket %s ", 368 server->value->u.q_unix.path); 369 } else { 370 error_append_hint(errp, "hint: failed on host %s and port %s ", 371 server->value->u.tcp.host, 372 server->value->u.tcp.port); 373 } 374 } 375 376 error_append_hint(errp, "Please refer to gluster logs for more info\n"); 377 378 /* glfs_init sometimes doesn't set errno although docs suggest that */ 379 if (errno == 0) { 380 errno = EINVAL; 381 } 382 383 goto out; 384 } 385 return glfs; 386 387 out: 388 if (glfs) { 389 old_errno = errno; 390 glfs_fini(glfs); 391 errno = old_errno; 392 } 393 return NULL; 394 } 395 396 static int qapi_enum_parse(const char *opt) 397 { 398 int i; 399 400 if (!opt) { 401 return GLUSTER_TRANSPORT__MAX; 402 } 403 404 for (i = 0; i < GLUSTER_TRANSPORT__MAX; i++) { 405 if (!strcmp(opt, GlusterTransport_lookup[i])) { 406 return i; 407 } 408 } 409 410 return i; 411 } 412 413 /* 414 * Convert the json formatted command line into qapi. 415 */ 416 static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf, 417 QDict *options, Error **errp) 418 { 419 QemuOpts *opts; 420 GlusterServer *gsconf; 421 GlusterServerList *curr = NULL; 422 QDict *backing_options = NULL; 423 Error *local_err = NULL; 424 char *str = NULL; 425 const char *ptr; 426 size_t num_servers; 427 int i; 428 429 /* create opts info from runtime_json_opts list */ 430 opts = qemu_opts_create(&runtime_json_opts, NULL, 0, &error_abort); 431 qemu_opts_absorb_qdict(opts, options, &local_err); 432 if (local_err) { 433 goto out; 434 } 435 436 num_servers = qdict_array_entries(options, GLUSTER_OPT_SERVER_PATTERN); 437 if (num_servers < 1) { 438 error_setg(&local_err, QERR_MISSING_PARAMETER, "server"); 439 goto out; 440 } 441 442 ptr = qemu_opt_get(opts, GLUSTER_OPT_VOLUME); 443 if (!ptr) { 444 error_setg(&local_err, QERR_MISSING_PARAMETER, GLUSTER_OPT_VOLUME); 445 goto out; 446 } 447 gconf->volume = g_strdup(ptr); 448 449 ptr = qemu_opt_get(opts, GLUSTER_OPT_PATH); 450 if (!ptr) { 451 error_setg(&local_err, QERR_MISSING_PARAMETER, GLUSTER_OPT_PATH); 452 goto out; 453 } 454 gconf->path = g_strdup(ptr); 455 qemu_opts_del(opts); 456 457 for (i = 0; i < num_servers; i++) { 458 str = g_strdup_printf(GLUSTER_OPT_SERVER_PATTERN"%d.", i); 459 qdict_extract_subqdict(options, &backing_options, str); 460 461 /* create opts info from runtime_type_opts list */ 462 opts = qemu_opts_create(&runtime_type_opts, NULL, 0, &error_abort); 463 qemu_opts_absorb_qdict(opts, backing_options, &local_err); 464 if (local_err) { 465 goto out; 466 } 467 468 ptr = qemu_opt_get(opts, GLUSTER_OPT_TYPE); 469 gsconf = g_new0(GlusterServer, 1); 470 gsconf->type = qapi_enum_parse(ptr); 471 if (!ptr) { 472 error_setg(&local_err, QERR_MISSING_PARAMETER, GLUSTER_OPT_TYPE); 473 error_append_hint(&local_err, GERR_INDEX_HINT, i); 474 goto out; 475 476 } 477 if (gsconf->type == GLUSTER_TRANSPORT__MAX) { 478 error_setg(&local_err, QERR_INVALID_PARAMETER_VALUE, 479 GLUSTER_OPT_TYPE, "tcp or unix"); 480 error_append_hint(&local_err, GERR_INDEX_HINT, i); 481 goto out; 482 } 483 qemu_opts_del(opts); 484 485 if (gsconf->type == GLUSTER_TRANSPORT_TCP) { 486 /* create opts info from runtime_tcp_opts list */ 487 opts = qemu_opts_create(&runtime_tcp_opts, NULL, 0, &error_abort); 488 qemu_opts_absorb_qdict(opts, backing_options, &local_err); 489 if (local_err) { 490 goto out; 491 } 492 493 ptr = qemu_opt_get(opts, GLUSTER_OPT_HOST); 494 if (!ptr) { 495 error_setg(&local_err, QERR_MISSING_PARAMETER, 496 GLUSTER_OPT_HOST); 497 error_append_hint(&local_err, GERR_INDEX_HINT, i); 498 goto out; 499 } 500 gsconf->u.tcp.host = g_strdup(ptr); 501 ptr = qemu_opt_get(opts, GLUSTER_OPT_PORT); 502 if (!ptr) { 503 error_setg(&local_err, QERR_MISSING_PARAMETER, 504 GLUSTER_OPT_PORT); 505 error_append_hint(&local_err, GERR_INDEX_HINT, i); 506 goto out; 507 } 508 gsconf->u.tcp.port = g_strdup(ptr); 509 510 /* defend for unsupported fields in InetSocketAddress, 511 * i.e. @ipv4, @ipv6 and @to 512 */ 513 ptr = qemu_opt_get(opts, GLUSTER_OPT_TO); 514 if (ptr) { 515 gsconf->u.tcp.has_to = true; 516 } 517 ptr = qemu_opt_get(opts, GLUSTER_OPT_IPV4); 518 if (ptr) { 519 gsconf->u.tcp.has_ipv4 = true; 520 } 521 ptr = qemu_opt_get(opts, GLUSTER_OPT_IPV6); 522 if (ptr) { 523 gsconf->u.tcp.has_ipv6 = true; 524 } 525 if (gsconf->u.tcp.has_to) { 526 error_setg(&local_err, "Parameter 'to' not supported"); 527 goto out; 528 } 529 if (gsconf->u.tcp.has_ipv4 || gsconf->u.tcp.has_ipv6) { 530 error_setg(&local_err, "Parameters 'ipv4/ipv6' not supported"); 531 goto out; 532 } 533 qemu_opts_del(opts); 534 } else { 535 /* create opts info from runtime_unix_opts list */ 536 opts = qemu_opts_create(&runtime_unix_opts, NULL, 0, &error_abort); 537 qemu_opts_absorb_qdict(opts, backing_options, &local_err); 538 if (local_err) { 539 goto out; 540 } 541 542 ptr = qemu_opt_get(opts, GLUSTER_OPT_SOCKET); 543 if (!ptr) { 544 error_setg(&local_err, QERR_MISSING_PARAMETER, 545 GLUSTER_OPT_SOCKET); 546 error_append_hint(&local_err, GERR_INDEX_HINT, i); 547 goto out; 548 } 549 gsconf->u.q_unix.path = g_strdup(ptr); 550 qemu_opts_del(opts); 551 } 552 553 if (gconf->server == NULL) { 554 gconf->server = g_new0(GlusterServerList, 1); 555 gconf->server->value = gsconf; 556 curr = gconf->server; 557 } else { 558 curr->next = g_new0(GlusterServerList, 1); 559 curr->next->value = gsconf; 560 curr = curr->next; 561 } 562 563 qdict_del(backing_options, str); 564 g_free(str); 565 str = NULL; 566 } 567 568 return 0; 569 570 out: 571 error_propagate(errp, local_err); 572 qemu_opts_del(opts); 573 if (str) { 574 qdict_del(backing_options, str); 575 g_free(str); 576 } 577 errno = EINVAL; 578 return -errno; 579 } 580 581 static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf, 582 const char *filename, 583 QDict *options, Error **errp) 584 { 585 int ret; 586 if (filename) { 587 ret = qemu_gluster_parse_uri(gconf, filename); 588 if (ret < 0) { 589 error_setg(errp, "invalid URI"); 590 error_append_hint(errp, "Usage: file=gluster[+transport]://" 591 "[host[:port]]volume/path[?socket=...]" 592 "[,file.debug=N]" 593 "[,file.logfile=/path/filename.log]\n"); 594 errno = -ret; 595 return NULL; 596 } 597 } else { 598 ret = qemu_gluster_parse_json(gconf, options, errp); 599 if (ret < 0) { 600 error_append_hint(errp, "Usage: " 601 "-drive driver=qcow2,file.driver=gluster," 602 "file.volume=testvol,file.path=/path/a.qcow2" 603 "[,file.debug=9]" 604 "[,file.logfile=/path/filename.log]," 605 "file.server.0.type=tcp," 606 "file.server.0.host=1.2.3.4," 607 "file.server.0.port=24007," 608 "file.server.1.transport=unix," 609 "file.server.1.socket=/var/run/glusterd.socket ..." 610 "\n"); 611 errno = -ret; 612 return NULL; 613 } 614 615 } 616 617 return qemu_gluster_glfs_init(gconf, errp); 618 } 619 620 static void qemu_gluster_complete_aio(void *opaque) 621 { 622 GlusterAIOCB *acb = (GlusterAIOCB *)opaque; 623 624 qemu_coroutine_enter(acb->coroutine); 625 } 626 627 /* 628 * AIO callback routine called from GlusterFS thread. 629 */ 630 static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg) 631 { 632 GlusterAIOCB *acb = (GlusterAIOCB *)arg; 633 634 if (!ret || ret == acb->size) { 635 acb->ret = 0; /* Success */ 636 } else if (ret < 0) { 637 acb->ret = -errno; /* Read/Write failed */ 638 } else { 639 acb->ret = -EIO; /* Partial read/write - fail it */ 640 } 641 642 aio_bh_schedule_oneshot(acb->aio_context, qemu_gluster_complete_aio, acb); 643 } 644 645 static void qemu_gluster_parse_flags(int bdrv_flags, int *open_flags) 646 { 647 assert(open_flags != NULL); 648 649 *open_flags |= O_BINARY; 650 651 if (bdrv_flags & BDRV_O_RDWR) { 652 *open_flags |= O_RDWR; 653 } else { 654 *open_flags |= O_RDONLY; 655 } 656 657 if ((bdrv_flags & BDRV_O_NOCACHE)) { 658 *open_flags |= O_DIRECT; 659 } 660 } 661 662 /* 663 * Do SEEK_DATA/HOLE to detect if it is functional. Older broken versions of 664 * gfapi incorrectly return the current offset when SEEK_DATA/HOLE is used. 665 * - Corrected versions return -1 and set errno to EINVAL. 666 * - Versions that support SEEK_DATA/HOLE correctly, will return -1 and set 667 * errno to ENXIO when SEEK_DATA is called with a position of EOF. 668 */ 669 static bool qemu_gluster_test_seek(struct glfs_fd *fd) 670 { 671 off_t ret, eof; 672 673 eof = glfs_lseek(fd, 0, SEEK_END); 674 if (eof < 0) { 675 /* this should never occur */ 676 return false; 677 } 678 679 /* this should always fail with ENXIO if SEEK_DATA is supported */ 680 ret = glfs_lseek(fd, eof, SEEK_DATA); 681 return (ret < 0) && (errno == ENXIO); 682 } 683 684 static int qemu_gluster_open(BlockDriverState *bs, QDict *options, 685 int bdrv_flags, Error **errp) 686 { 687 BDRVGlusterState *s = bs->opaque; 688 int open_flags = 0; 689 int ret = 0; 690 BlockdevOptionsGluster *gconf = NULL; 691 QemuOpts *opts; 692 Error *local_err = NULL; 693 const char *filename, *logfile; 694 695 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); 696 qemu_opts_absorb_qdict(opts, options, &local_err); 697 if (local_err) { 698 error_propagate(errp, local_err); 699 ret = -EINVAL; 700 goto out; 701 } 702 703 filename = qemu_opt_get(opts, GLUSTER_OPT_FILENAME); 704 705 s->debug_level = qemu_opt_get_number(opts, GLUSTER_OPT_DEBUG, 706 GLUSTER_DEBUG_DEFAULT); 707 if (s->debug_level < 0) { 708 s->debug_level = 0; 709 } else if (s->debug_level > GLUSTER_DEBUG_MAX) { 710 s->debug_level = GLUSTER_DEBUG_MAX; 711 } 712 713 gconf = g_new0(BlockdevOptionsGluster, 1); 714 gconf->debug_level = s->debug_level; 715 gconf->has_debug_level = true; 716 717 logfile = qemu_opt_get(opts, GLUSTER_OPT_LOGFILE); 718 s->logfile = g_strdup(logfile ? logfile : GLUSTER_LOGFILE_DEFAULT); 719 720 gconf->logfile = g_strdup(s->logfile); 721 gconf->has_logfile = true; 722 723 s->glfs = qemu_gluster_init(gconf, filename, options, errp); 724 if (!s->glfs) { 725 ret = -errno; 726 goto out; 727 } 728 729 #ifdef CONFIG_GLUSTERFS_XLATOR_OPT 730 /* Without this, if fsync fails for a recoverable reason (for instance, 731 * ENOSPC), gluster will dump its cache, preventing retries. This means 732 * almost certain data loss. Not all gluster versions support the 733 * 'resync-failed-syncs-after-fsync' key value, but there is no way to 734 * discover during runtime if it is supported (this api returns success for 735 * unknown key/value pairs) */ 736 ret = glfs_set_xlator_option(s->glfs, "*-write-behind", 737 "resync-failed-syncs-after-fsync", 738 "on"); 739 if (ret < 0) { 740 error_setg_errno(errp, errno, "Unable to set xlator key/value pair"); 741 ret = -errno; 742 goto out; 743 } 744 #endif 745 746 qemu_gluster_parse_flags(bdrv_flags, &open_flags); 747 748 s->fd = glfs_open(s->glfs, gconf->path, open_flags); 749 if (!s->fd) { 750 ret = -errno; 751 } 752 753 s->supports_seek_data = qemu_gluster_test_seek(s->fd); 754 755 out: 756 qemu_opts_del(opts); 757 qapi_free_BlockdevOptionsGluster(gconf); 758 if (!ret) { 759 return ret; 760 } 761 g_free(s->logfile); 762 if (s->fd) { 763 glfs_close(s->fd); 764 } 765 if (s->glfs) { 766 glfs_fini(s->glfs); 767 } 768 return ret; 769 } 770 771 static int qemu_gluster_reopen_prepare(BDRVReopenState *state, 772 BlockReopenQueue *queue, Error **errp) 773 { 774 int ret = 0; 775 BDRVGlusterState *s; 776 BDRVGlusterReopenState *reop_s; 777 BlockdevOptionsGluster *gconf; 778 int open_flags = 0; 779 780 assert(state != NULL); 781 assert(state->bs != NULL); 782 783 s = state->bs->opaque; 784 785 state->opaque = g_new0(BDRVGlusterReopenState, 1); 786 reop_s = state->opaque; 787 788 qemu_gluster_parse_flags(state->flags, &open_flags); 789 790 gconf = g_new0(BlockdevOptionsGluster, 1); 791 gconf->debug_level = s->debug_level; 792 gconf->has_debug_level = true; 793 gconf->logfile = g_strdup(s->logfile); 794 gconf->has_logfile = true; 795 reop_s->glfs = qemu_gluster_init(gconf, state->bs->filename, NULL, errp); 796 if (reop_s->glfs == NULL) { 797 ret = -errno; 798 goto exit; 799 } 800 801 #ifdef CONFIG_GLUSTERFS_XLATOR_OPT 802 ret = glfs_set_xlator_option(reop_s->glfs, "*-write-behind", 803 "resync-failed-syncs-after-fsync", "on"); 804 if (ret < 0) { 805 error_setg_errno(errp, errno, "Unable to set xlator key/value pair"); 806 ret = -errno; 807 goto exit; 808 } 809 #endif 810 811 reop_s->fd = glfs_open(reop_s->glfs, gconf->path, open_flags); 812 if (reop_s->fd == NULL) { 813 /* reops->glfs will be cleaned up in _abort */ 814 ret = -errno; 815 goto exit; 816 } 817 818 exit: 819 /* state->opaque will be freed in either the _abort or _commit */ 820 qapi_free_BlockdevOptionsGluster(gconf); 821 return ret; 822 } 823 824 static void qemu_gluster_reopen_commit(BDRVReopenState *state) 825 { 826 BDRVGlusterReopenState *reop_s = state->opaque; 827 BDRVGlusterState *s = state->bs->opaque; 828 829 830 /* close the old */ 831 if (s->fd) { 832 glfs_close(s->fd); 833 } 834 if (s->glfs) { 835 glfs_fini(s->glfs); 836 } 837 838 /* use the newly opened image / connection */ 839 s->fd = reop_s->fd; 840 s->glfs = reop_s->glfs; 841 842 g_free(state->opaque); 843 state->opaque = NULL; 844 845 return; 846 } 847 848 849 static void qemu_gluster_reopen_abort(BDRVReopenState *state) 850 { 851 BDRVGlusterReopenState *reop_s = state->opaque; 852 853 if (reop_s == NULL) { 854 return; 855 } 856 857 if (reop_s->fd) { 858 glfs_close(reop_s->fd); 859 } 860 861 if (reop_s->glfs) { 862 glfs_fini(reop_s->glfs); 863 } 864 865 g_free(state->opaque); 866 state->opaque = NULL; 867 868 return; 869 } 870 871 #ifdef CONFIG_GLUSTERFS_ZEROFILL 872 static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs, 873 int64_t offset, 874 int size, 875 BdrvRequestFlags flags) 876 { 877 int ret; 878 GlusterAIOCB acb; 879 BDRVGlusterState *s = bs->opaque; 880 881 acb.size = size; 882 acb.ret = 0; 883 acb.coroutine = qemu_coroutine_self(); 884 acb.aio_context = bdrv_get_aio_context(bs); 885 886 ret = glfs_zerofill_async(s->fd, offset, size, gluster_finish_aiocb, &acb); 887 if (ret < 0) { 888 return -errno; 889 } 890 891 qemu_coroutine_yield(); 892 return acb.ret; 893 } 894 895 static inline bool gluster_supports_zerofill(void) 896 { 897 return 1; 898 } 899 900 static inline int qemu_gluster_zerofill(struct glfs_fd *fd, int64_t offset, 901 int64_t size) 902 { 903 return glfs_zerofill(fd, offset, size); 904 } 905 906 #else 907 static inline bool gluster_supports_zerofill(void) 908 { 909 return 0; 910 } 911 912 static inline int qemu_gluster_zerofill(struct glfs_fd *fd, int64_t offset, 913 int64_t size) 914 { 915 return 0; 916 } 917 #endif 918 919 static int qemu_gluster_create(const char *filename, 920 QemuOpts *opts, Error **errp) 921 { 922 BlockdevOptionsGluster *gconf; 923 struct glfs *glfs; 924 struct glfs_fd *fd; 925 int ret = 0; 926 int prealloc = 0; 927 int64_t total_size = 0; 928 char *tmp = NULL; 929 930 gconf = g_new0(BlockdevOptionsGluster, 1); 931 gconf->debug_level = qemu_opt_get_number_del(opts, GLUSTER_OPT_DEBUG, 932 GLUSTER_DEBUG_DEFAULT); 933 if (gconf->debug_level < 0) { 934 gconf->debug_level = 0; 935 } else if (gconf->debug_level > GLUSTER_DEBUG_MAX) { 936 gconf->debug_level = GLUSTER_DEBUG_MAX; 937 } 938 gconf->has_debug_level = true; 939 940 gconf->logfile = qemu_opt_get_del(opts, GLUSTER_OPT_LOGFILE); 941 if (!gconf->logfile) { 942 gconf->logfile = g_strdup(GLUSTER_LOGFILE_DEFAULT); 943 } 944 gconf->has_logfile = true; 945 946 glfs = qemu_gluster_init(gconf, filename, NULL, errp); 947 if (!glfs) { 948 ret = -errno; 949 goto out; 950 } 951 952 total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), 953 BDRV_SECTOR_SIZE); 954 955 tmp = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); 956 if (!tmp || !strcmp(tmp, "off")) { 957 prealloc = 0; 958 } else if (!strcmp(tmp, "full") && gluster_supports_zerofill()) { 959 prealloc = 1; 960 } else { 961 error_setg(errp, "Invalid preallocation mode: '%s'" 962 " or GlusterFS doesn't support zerofill API", tmp); 963 ret = -EINVAL; 964 goto out; 965 } 966 967 fd = glfs_creat(glfs, gconf->path, 968 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR); 969 if (!fd) { 970 ret = -errno; 971 } else { 972 if (!glfs_ftruncate(fd, total_size)) { 973 if (prealloc && qemu_gluster_zerofill(fd, 0, total_size)) { 974 ret = -errno; 975 } 976 } else { 977 ret = -errno; 978 } 979 980 if (glfs_close(fd) != 0) { 981 ret = -errno; 982 } 983 } 984 out: 985 g_free(tmp); 986 qapi_free_BlockdevOptionsGluster(gconf); 987 if (glfs) { 988 glfs_fini(glfs); 989 } 990 return ret; 991 } 992 993 static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs, 994 int64_t sector_num, int nb_sectors, 995 QEMUIOVector *qiov, int write) 996 { 997 int ret; 998 GlusterAIOCB acb; 999 BDRVGlusterState *s = bs->opaque; 1000 size_t size = nb_sectors * BDRV_SECTOR_SIZE; 1001 off_t offset = sector_num * BDRV_SECTOR_SIZE; 1002 1003 acb.size = size; 1004 acb.ret = 0; 1005 acb.coroutine = qemu_coroutine_self(); 1006 acb.aio_context = bdrv_get_aio_context(bs); 1007 1008 if (write) { 1009 ret = glfs_pwritev_async(s->fd, qiov->iov, qiov->niov, offset, 0, 1010 gluster_finish_aiocb, &acb); 1011 } else { 1012 ret = glfs_preadv_async(s->fd, qiov->iov, qiov->niov, offset, 0, 1013 gluster_finish_aiocb, &acb); 1014 } 1015 1016 if (ret < 0) { 1017 return -errno; 1018 } 1019 1020 qemu_coroutine_yield(); 1021 return acb.ret; 1022 } 1023 1024 static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset) 1025 { 1026 int ret; 1027 BDRVGlusterState *s = bs->opaque; 1028 1029 ret = glfs_ftruncate(s->fd, offset); 1030 if (ret < 0) { 1031 return -errno; 1032 } 1033 1034 return 0; 1035 } 1036 1037 static coroutine_fn int qemu_gluster_co_readv(BlockDriverState *bs, 1038 int64_t sector_num, 1039 int nb_sectors, 1040 QEMUIOVector *qiov) 1041 { 1042 return qemu_gluster_co_rw(bs, sector_num, nb_sectors, qiov, 0); 1043 } 1044 1045 static coroutine_fn int qemu_gluster_co_writev(BlockDriverState *bs, 1046 int64_t sector_num, 1047 int nb_sectors, 1048 QEMUIOVector *qiov) 1049 { 1050 return qemu_gluster_co_rw(bs, sector_num, nb_sectors, qiov, 1); 1051 } 1052 1053 static void qemu_gluster_close(BlockDriverState *bs) 1054 { 1055 BDRVGlusterState *s = bs->opaque; 1056 1057 g_free(s->logfile); 1058 if (s->fd) { 1059 glfs_close(s->fd); 1060 s->fd = NULL; 1061 } 1062 glfs_fini(s->glfs); 1063 } 1064 1065 static coroutine_fn int qemu_gluster_co_flush_to_disk(BlockDriverState *bs) 1066 { 1067 int ret; 1068 GlusterAIOCB acb; 1069 BDRVGlusterState *s = bs->opaque; 1070 1071 acb.size = 0; 1072 acb.ret = 0; 1073 acb.coroutine = qemu_coroutine_self(); 1074 acb.aio_context = bdrv_get_aio_context(bs); 1075 1076 ret = glfs_fsync_async(s->fd, gluster_finish_aiocb, &acb); 1077 if (ret < 0) { 1078 ret = -errno; 1079 goto error; 1080 } 1081 1082 qemu_coroutine_yield(); 1083 if (acb.ret < 0) { 1084 ret = acb.ret; 1085 goto error; 1086 } 1087 1088 return acb.ret; 1089 1090 error: 1091 /* Some versions of Gluster (3.5.6 -> 3.5.8?) will not retain its cache 1092 * after a fsync failure, so we have no way of allowing the guest to safely 1093 * continue. Gluster versions prior to 3.5.6 don't retain the cache 1094 * either, but will invalidate the fd on error, so this is again our only 1095 * option. 1096 * 1097 * The 'resync-failed-syncs-after-fsync' xlator option for the 1098 * write-behind cache will cause later gluster versions to retain its 1099 * cache after error, so long as the fd remains open. However, we 1100 * currently have no way of knowing if this option is supported. 1101 * 1102 * TODO: Once gluster provides a way for us to determine if the option 1103 * is supported, bypass the closure and setting drv to NULL. */ 1104 qemu_gluster_close(bs); 1105 bs->drv = NULL; 1106 return ret; 1107 } 1108 1109 #ifdef CONFIG_GLUSTERFS_DISCARD 1110 static coroutine_fn int qemu_gluster_co_pdiscard(BlockDriverState *bs, 1111 int64_t offset, int size) 1112 { 1113 int ret; 1114 GlusterAIOCB acb; 1115 BDRVGlusterState *s = bs->opaque; 1116 1117 acb.size = 0; 1118 acb.ret = 0; 1119 acb.coroutine = qemu_coroutine_self(); 1120 acb.aio_context = bdrv_get_aio_context(bs); 1121 1122 ret = glfs_discard_async(s->fd, offset, size, gluster_finish_aiocb, &acb); 1123 if (ret < 0) { 1124 return -errno; 1125 } 1126 1127 qemu_coroutine_yield(); 1128 return acb.ret; 1129 } 1130 #endif 1131 1132 static int64_t qemu_gluster_getlength(BlockDriverState *bs) 1133 { 1134 BDRVGlusterState *s = bs->opaque; 1135 int64_t ret; 1136 1137 ret = glfs_lseek(s->fd, 0, SEEK_END); 1138 if (ret < 0) { 1139 return -errno; 1140 } else { 1141 return ret; 1142 } 1143 } 1144 1145 static int64_t qemu_gluster_allocated_file_size(BlockDriverState *bs) 1146 { 1147 BDRVGlusterState *s = bs->opaque; 1148 struct stat st; 1149 int ret; 1150 1151 ret = glfs_fstat(s->fd, &st); 1152 if (ret < 0) { 1153 return -errno; 1154 } else { 1155 return st.st_blocks * 512; 1156 } 1157 } 1158 1159 static int qemu_gluster_has_zero_init(BlockDriverState *bs) 1160 { 1161 /* GlusterFS volume could be backed by a block device */ 1162 return 0; 1163 } 1164 1165 /* 1166 * Find allocation range in @bs around offset @start. 1167 * May change underlying file descriptor's file offset. 1168 * If @start is not in a hole, store @start in @data, and the 1169 * beginning of the next hole in @hole, and return 0. 1170 * If @start is in a non-trailing hole, store @start in @hole and the 1171 * beginning of the next non-hole in @data, and return 0. 1172 * If @start is in a trailing hole or beyond EOF, return -ENXIO. 1173 * If we can't find out, return a negative errno other than -ENXIO. 1174 * 1175 * (Shamefully copied from raw-posix.c, only miniscule adaptions.) 1176 */ 1177 static int find_allocation(BlockDriverState *bs, off_t start, 1178 off_t *data, off_t *hole) 1179 { 1180 BDRVGlusterState *s = bs->opaque; 1181 off_t offs; 1182 1183 if (!s->supports_seek_data) { 1184 return -ENOTSUP; 1185 } 1186 1187 /* 1188 * SEEK_DATA cases: 1189 * D1. offs == start: start is in data 1190 * D2. offs > start: start is in a hole, next data at offs 1191 * D3. offs < 0, errno = ENXIO: either start is in a trailing hole 1192 * or start is beyond EOF 1193 * If the latter happens, the file has been truncated behind 1194 * our back since we opened it. All bets are off then. 1195 * Treating like a trailing hole is simplest. 1196 * D4. offs < 0, errno != ENXIO: we learned nothing 1197 */ 1198 offs = glfs_lseek(s->fd, start, SEEK_DATA); 1199 if (offs < 0) { 1200 return -errno; /* D3 or D4 */ 1201 } 1202 assert(offs >= start); 1203 1204 if (offs > start) { 1205 /* D2: in hole, next data at offs */ 1206 *hole = start; 1207 *data = offs; 1208 return 0; 1209 } 1210 1211 /* D1: in data, end not yet known */ 1212 1213 /* 1214 * SEEK_HOLE cases: 1215 * H1. offs == start: start is in a hole 1216 * If this happens here, a hole has been dug behind our back 1217 * since the previous lseek(). 1218 * H2. offs > start: either start is in data, next hole at offs, 1219 * or start is in trailing hole, EOF at offs 1220 * Linux treats trailing holes like any other hole: offs == 1221 * start. Solaris seeks to EOF instead: offs > start (blech). 1222 * If that happens here, a hole has been dug behind our back 1223 * since the previous lseek(). 1224 * H3. offs < 0, errno = ENXIO: start is beyond EOF 1225 * If this happens, the file has been truncated behind our 1226 * back since we opened it. Treat it like a trailing hole. 1227 * H4. offs < 0, errno != ENXIO: we learned nothing 1228 * Pretend we know nothing at all, i.e. "forget" about D1. 1229 */ 1230 offs = glfs_lseek(s->fd, start, SEEK_HOLE); 1231 if (offs < 0) { 1232 return -errno; /* D1 and (H3 or H4) */ 1233 } 1234 assert(offs >= start); 1235 1236 if (offs > start) { 1237 /* 1238 * D1 and H2: either in data, next hole at offs, or it was in 1239 * data but is now in a trailing hole. In the latter case, 1240 * all bets are off. Treating it as if it there was data all 1241 * the way to EOF is safe, so simply do that. 1242 */ 1243 *data = start; 1244 *hole = offs; 1245 return 0; 1246 } 1247 1248 /* D1 and H1 */ 1249 return -EBUSY; 1250 } 1251 1252 /* 1253 * Returns the allocation status of the specified sectors. 1254 * 1255 * If 'sector_num' is beyond the end of the disk image the return value is 0 1256 * and 'pnum' is set to 0. 1257 * 1258 * 'pnum' is set to the number of sectors (including and immediately following 1259 * the specified sector) that are known to be in the same 1260 * allocated/unallocated state. 1261 * 1262 * 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes 1263 * beyond the end of the disk image it will be clamped. 1264 * 1265 * (Based on raw_co_get_block_status() from raw-posix.c.) 1266 */ 1267 static int64_t coroutine_fn qemu_gluster_co_get_block_status( 1268 BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum, 1269 BlockDriverState **file) 1270 { 1271 BDRVGlusterState *s = bs->opaque; 1272 off_t start, data = 0, hole = 0; 1273 int64_t total_size; 1274 int ret = -EINVAL; 1275 1276 if (!s->fd) { 1277 return ret; 1278 } 1279 1280 start = sector_num * BDRV_SECTOR_SIZE; 1281 total_size = bdrv_getlength(bs); 1282 if (total_size < 0) { 1283 return total_size; 1284 } else if (start >= total_size) { 1285 *pnum = 0; 1286 return 0; 1287 } else if (start + nb_sectors * BDRV_SECTOR_SIZE > total_size) { 1288 nb_sectors = DIV_ROUND_UP(total_size - start, BDRV_SECTOR_SIZE); 1289 } 1290 1291 ret = find_allocation(bs, start, &data, &hole); 1292 if (ret == -ENXIO) { 1293 /* Trailing hole */ 1294 *pnum = nb_sectors; 1295 ret = BDRV_BLOCK_ZERO; 1296 } else if (ret < 0) { 1297 /* No info available, so pretend there are no holes */ 1298 *pnum = nb_sectors; 1299 ret = BDRV_BLOCK_DATA; 1300 } else if (data == start) { 1301 /* On a data extent, compute sectors to the end of the extent, 1302 * possibly including a partial sector at EOF. */ 1303 *pnum = MIN(nb_sectors, DIV_ROUND_UP(hole - start, BDRV_SECTOR_SIZE)); 1304 ret = BDRV_BLOCK_DATA; 1305 } else { 1306 /* On a hole, compute sectors to the beginning of the next extent. */ 1307 assert(hole == start); 1308 *pnum = MIN(nb_sectors, (data - start) / BDRV_SECTOR_SIZE); 1309 ret = BDRV_BLOCK_ZERO; 1310 } 1311 1312 *file = bs; 1313 1314 return ret | BDRV_BLOCK_OFFSET_VALID | start; 1315 } 1316 1317 1318 static BlockDriver bdrv_gluster = { 1319 .format_name = "gluster", 1320 .protocol_name = "gluster", 1321 .instance_size = sizeof(BDRVGlusterState), 1322 .bdrv_needs_filename = false, 1323 .bdrv_file_open = qemu_gluster_open, 1324 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare, 1325 .bdrv_reopen_commit = qemu_gluster_reopen_commit, 1326 .bdrv_reopen_abort = qemu_gluster_reopen_abort, 1327 .bdrv_close = qemu_gluster_close, 1328 .bdrv_create = qemu_gluster_create, 1329 .bdrv_getlength = qemu_gluster_getlength, 1330 .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, 1331 .bdrv_truncate = qemu_gluster_truncate, 1332 .bdrv_co_readv = qemu_gluster_co_readv, 1333 .bdrv_co_writev = qemu_gluster_co_writev, 1334 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk, 1335 .bdrv_has_zero_init = qemu_gluster_has_zero_init, 1336 #ifdef CONFIG_GLUSTERFS_DISCARD 1337 .bdrv_co_pdiscard = qemu_gluster_co_pdiscard, 1338 #endif 1339 #ifdef CONFIG_GLUSTERFS_ZEROFILL 1340 .bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes, 1341 #endif 1342 .bdrv_co_get_block_status = qemu_gluster_co_get_block_status, 1343 .create_opts = &qemu_gluster_create_opts, 1344 }; 1345 1346 static BlockDriver bdrv_gluster_tcp = { 1347 .format_name = "gluster", 1348 .protocol_name = "gluster+tcp", 1349 .instance_size = sizeof(BDRVGlusterState), 1350 .bdrv_needs_filename = false, 1351 .bdrv_file_open = qemu_gluster_open, 1352 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare, 1353 .bdrv_reopen_commit = qemu_gluster_reopen_commit, 1354 .bdrv_reopen_abort = qemu_gluster_reopen_abort, 1355 .bdrv_close = qemu_gluster_close, 1356 .bdrv_create = qemu_gluster_create, 1357 .bdrv_getlength = qemu_gluster_getlength, 1358 .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, 1359 .bdrv_truncate = qemu_gluster_truncate, 1360 .bdrv_co_readv = qemu_gluster_co_readv, 1361 .bdrv_co_writev = qemu_gluster_co_writev, 1362 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk, 1363 .bdrv_has_zero_init = qemu_gluster_has_zero_init, 1364 #ifdef CONFIG_GLUSTERFS_DISCARD 1365 .bdrv_co_pdiscard = qemu_gluster_co_pdiscard, 1366 #endif 1367 #ifdef CONFIG_GLUSTERFS_ZEROFILL 1368 .bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes, 1369 #endif 1370 .bdrv_co_get_block_status = qemu_gluster_co_get_block_status, 1371 .create_opts = &qemu_gluster_create_opts, 1372 }; 1373 1374 static BlockDriver bdrv_gluster_unix = { 1375 .format_name = "gluster", 1376 .protocol_name = "gluster+unix", 1377 .instance_size = sizeof(BDRVGlusterState), 1378 .bdrv_needs_filename = true, 1379 .bdrv_file_open = qemu_gluster_open, 1380 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare, 1381 .bdrv_reopen_commit = qemu_gluster_reopen_commit, 1382 .bdrv_reopen_abort = qemu_gluster_reopen_abort, 1383 .bdrv_close = qemu_gluster_close, 1384 .bdrv_create = qemu_gluster_create, 1385 .bdrv_getlength = qemu_gluster_getlength, 1386 .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, 1387 .bdrv_truncate = qemu_gluster_truncate, 1388 .bdrv_co_readv = qemu_gluster_co_readv, 1389 .bdrv_co_writev = qemu_gluster_co_writev, 1390 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk, 1391 .bdrv_has_zero_init = qemu_gluster_has_zero_init, 1392 #ifdef CONFIG_GLUSTERFS_DISCARD 1393 .bdrv_co_pdiscard = qemu_gluster_co_pdiscard, 1394 #endif 1395 #ifdef CONFIG_GLUSTERFS_ZEROFILL 1396 .bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes, 1397 #endif 1398 .bdrv_co_get_block_status = qemu_gluster_co_get_block_status, 1399 .create_opts = &qemu_gluster_create_opts, 1400 }; 1401 1402 /* rdma is deprecated (actually never supported for volfile fetch). 1403 * Let's maintain it for the protocol compatibility, to make sure things 1404 * won't break immediately. For now, gluster+rdma will fall back to gluster+tcp 1405 * protocol with a warning. 1406 * TODO: remove gluster+rdma interface support 1407 */ 1408 static BlockDriver bdrv_gluster_rdma = { 1409 .format_name = "gluster", 1410 .protocol_name = "gluster+rdma", 1411 .instance_size = sizeof(BDRVGlusterState), 1412 .bdrv_needs_filename = true, 1413 .bdrv_file_open = qemu_gluster_open, 1414 .bdrv_reopen_prepare = qemu_gluster_reopen_prepare, 1415 .bdrv_reopen_commit = qemu_gluster_reopen_commit, 1416 .bdrv_reopen_abort = qemu_gluster_reopen_abort, 1417 .bdrv_close = qemu_gluster_close, 1418 .bdrv_create = qemu_gluster_create, 1419 .bdrv_getlength = qemu_gluster_getlength, 1420 .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, 1421 .bdrv_truncate = qemu_gluster_truncate, 1422 .bdrv_co_readv = qemu_gluster_co_readv, 1423 .bdrv_co_writev = qemu_gluster_co_writev, 1424 .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk, 1425 .bdrv_has_zero_init = qemu_gluster_has_zero_init, 1426 #ifdef CONFIG_GLUSTERFS_DISCARD 1427 .bdrv_co_pdiscard = qemu_gluster_co_pdiscard, 1428 #endif 1429 #ifdef CONFIG_GLUSTERFS_ZEROFILL 1430 .bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes, 1431 #endif 1432 .bdrv_co_get_block_status = qemu_gluster_co_get_block_status, 1433 .create_opts = &qemu_gluster_create_opts, 1434 }; 1435 1436 static void bdrv_gluster_init(void) 1437 { 1438 bdrv_register(&bdrv_gluster_rdma); 1439 bdrv_register(&bdrv_gluster_unix); 1440 bdrv_register(&bdrv_gluster_tcp); 1441 bdrv_register(&bdrv_gluster); 1442 } 1443 1444 block_init(bdrv_gluster_init); 1445