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