Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 1 | /* |
| 2 | * QEMU Block driver for Veritas HyperScale (VxHS) |
| 3 | * |
| 4 | * Copyright (c) 2017 Veritas Technologies LLC. |
| 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 | |
| 11 | #include "qemu/osdep.h" |
| 12 | #include <qnio/qnio_api.h> |
| 13 | #include <sys/param.h> |
| 14 | #include "block/block_int.h" |
Max Reitz | 609f45e | 2018-06-14 21:14:28 +0200 | [diff] [blame] | 15 | #include "block/qdict.h" |
Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 16 | #include "qapi/qmp/qerror.h" |
| 17 | #include "qapi/qmp/qdict.h" |
| 18 | #include "qapi/qmp/qstring.h" |
| 19 | #include "trace.h" |
Markus Armbruster | 0b8fa32 | 2019-05-23 16:35:07 +0200 | [diff] [blame] | 20 | #include "qemu/module.h" |
Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 21 | #include "qemu/uri.h" |
| 22 | #include "qapi/error.h" |
| 23 | #include "qemu/uuid.h" |
| 24 | #include "crypto/tlscredsx509.h" |
| 25 | |
| 26 | #define VXHS_OPT_FILENAME "filename" |
| 27 | #define VXHS_OPT_VDISK_ID "vdisk-id" |
| 28 | #define VXHS_OPT_SERVER "server" |
| 29 | #define VXHS_OPT_HOST "host" |
| 30 | #define VXHS_OPT_PORT "port" |
| 31 | |
| 32 | /* Only accessed under QEMU global mutex */ |
| 33 | static uint32_t vxhs_ref; |
| 34 | |
| 35 | typedef enum { |
| 36 | VDISK_AIO_READ, |
| 37 | VDISK_AIO_WRITE, |
| 38 | } VDISKAIOCmd; |
| 39 | |
| 40 | /* |
| 41 | * HyperScale AIO callbacks structure |
| 42 | */ |
| 43 | typedef struct VXHSAIOCB { |
| 44 | BlockAIOCB common; |
| 45 | int err; |
| 46 | } VXHSAIOCB; |
| 47 | |
| 48 | typedef struct VXHSvDiskHostsInfo { |
| 49 | void *dev_handle; /* Device handle */ |
| 50 | char *host; /* Host name or IP */ |
| 51 | int port; /* Host's port number */ |
| 52 | } VXHSvDiskHostsInfo; |
| 53 | |
| 54 | /* |
| 55 | * Structure per vDisk maintained for state |
| 56 | */ |
| 57 | typedef struct BDRVVXHSState { |
| 58 | VXHSvDiskHostsInfo vdisk_hostinfo; /* Per host info */ |
| 59 | char *vdisk_guid; |
| 60 | char *tlscredsid; /* tlscredsid */ |
| 61 | } BDRVVXHSState; |
| 62 | |
| 63 | static void vxhs_complete_aio_bh(void *opaque) |
| 64 | { |
| 65 | VXHSAIOCB *acb = opaque; |
| 66 | BlockCompletionFunc *cb = acb->common.cb; |
| 67 | void *cb_opaque = acb->common.opaque; |
| 68 | int ret = 0; |
| 69 | |
| 70 | if (acb->err != 0) { |
| 71 | trace_vxhs_complete_aio(acb, acb->err); |
| 72 | ret = (-EIO); |
| 73 | } |
| 74 | |
| 75 | qemu_aio_unref(acb); |
| 76 | cb(cb_opaque, ret); |
| 77 | } |
| 78 | |
| 79 | /* |
| 80 | * Called from a libqnio thread |
| 81 | */ |
| 82 | static void vxhs_iio_callback(void *ctx, uint32_t opcode, uint32_t error) |
| 83 | { |
| 84 | VXHSAIOCB *acb = NULL; |
| 85 | |
| 86 | switch (opcode) { |
| 87 | case IRP_READ_REQUEST: |
| 88 | case IRP_WRITE_REQUEST: |
| 89 | |
| 90 | /* |
| 91 | * ctx is VXHSAIOCB* |
| 92 | * ctx is NULL if error is QNIOERROR_CHANNEL_HUP |
| 93 | */ |
| 94 | if (ctx) { |
| 95 | acb = ctx; |
| 96 | } else { |
| 97 | trace_vxhs_iio_callback(error); |
| 98 | goto out; |
| 99 | } |
| 100 | |
| 101 | if (error) { |
| 102 | if (!acb->err) { |
| 103 | acb->err = error; |
| 104 | } |
| 105 | trace_vxhs_iio_callback(error); |
| 106 | } |
| 107 | |
| 108 | aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs), |
| 109 | vxhs_complete_aio_bh, acb); |
| 110 | break; |
| 111 | |
| 112 | default: |
| 113 | if (error == QNIOERROR_HUP) { |
| 114 | /* |
| 115 | * Channel failed, spontaneous notification, |
| 116 | * not in response to I/O |
| 117 | */ |
| 118 | trace_vxhs_iio_callback_chnfail(error, errno); |
| 119 | } else { |
| 120 | trace_vxhs_iio_callback_unknwn(opcode, error); |
| 121 | } |
| 122 | break; |
| 123 | } |
| 124 | out: |
| 125 | return; |
| 126 | } |
| 127 | |
| 128 | static QemuOptsList runtime_opts = { |
| 129 | .name = "vxhs", |
| 130 | .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), |
| 131 | .desc = { |
| 132 | { |
| 133 | .name = VXHS_OPT_FILENAME, |
| 134 | .type = QEMU_OPT_STRING, |
| 135 | .help = "URI to the Veritas HyperScale image", |
| 136 | }, |
| 137 | { |
| 138 | .name = VXHS_OPT_VDISK_ID, |
| 139 | .type = QEMU_OPT_STRING, |
| 140 | .help = "UUID of the VxHS vdisk", |
| 141 | }, |
| 142 | { |
| 143 | .name = "tls-creds", |
| 144 | .type = QEMU_OPT_STRING, |
| 145 | .help = "ID of the TLS/SSL credentials to use", |
| 146 | }, |
| 147 | { /* end of list */ } |
| 148 | }, |
| 149 | }; |
| 150 | |
| 151 | static QemuOptsList runtime_tcp_opts = { |
| 152 | .name = "vxhs_tcp", |
| 153 | .head = QTAILQ_HEAD_INITIALIZER(runtime_tcp_opts.head), |
| 154 | .desc = { |
| 155 | { |
| 156 | .name = VXHS_OPT_HOST, |
| 157 | .type = QEMU_OPT_STRING, |
| 158 | .help = "host address (ipv4 addresses)", |
| 159 | }, |
| 160 | { |
| 161 | .name = VXHS_OPT_PORT, |
| 162 | .type = QEMU_OPT_NUMBER, |
| 163 | .help = "port number on which VxHSD is listening (default 9999)", |
| 164 | .def_value_str = "9999" |
| 165 | }, |
| 166 | { /* end of list */ } |
| 167 | }, |
| 168 | }; |
| 169 | |
| 170 | /* |
| 171 | * Parse incoming URI and populate *options with the host |
| 172 | * and device information |
| 173 | */ |
| 174 | static int vxhs_parse_uri(const char *filename, QDict *options) |
| 175 | { |
| 176 | URI *uri = NULL; |
| 177 | char *port; |
| 178 | int ret = 0; |
| 179 | |
| 180 | trace_vxhs_parse_uri_filename(filename); |
| 181 | uri = uri_parse(filename); |
| 182 | if (!uri || !uri->server || !uri->path) { |
| 183 | uri_free(uri); |
| 184 | return -EINVAL; |
| 185 | } |
| 186 | |
Eric Blake | 46f5ac2 | 2017-04-27 16:58:17 -0500 | [diff] [blame] | 187 | qdict_put_str(options, VXHS_OPT_SERVER ".host", uri->server); |
Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 188 | |
| 189 | if (uri->port) { |
| 190 | port = g_strdup_printf("%d", uri->port); |
Eric Blake | 46f5ac2 | 2017-04-27 16:58:17 -0500 | [diff] [blame] | 191 | qdict_put_str(options, VXHS_OPT_SERVER ".port", port); |
Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 192 | g_free(port); |
| 193 | } |
| 194 | |
Eric Blake | 46f5ac2 | 2017-04-27 16:58:17 -0500 | [diff] [blame] | 195 | qdict_put_str(options, "vdisk-id", uri->path); |
Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 196 | |
| 197 | trace_vxhs_parse_uri_hostinfo(uri->server, uri->port); |
| 198 | uri_free(uri); |
| 199 | |
| 200 | return ret; |
| 201 | } |
| 202 | |
| 203 | static void vxhs_parse_filename(const char *filename, QDict *options, |
| 204 | Error **errp) |
| 205 | { |
| 206 | if (qdict_haskey(options, "vdisk-id") || qdict_haskey(options, "server")) { |
| 207 | error_setg(errp, "vdisk-id/server and a file name may not be specified " |
| 208 | "at the same time"); |
| 209 | return; |
| 210 | } |
| 211 | |
| 212 | if (strstr(filename, "://")) { |
| 213 | int ret = vxhs_parse_uri(filename, options); |
| 214 | if (ret < 0) { |
| 215 | error_setg(errp, "Invalid URI. URI should be of the form " |
| 216 | " vxhs://<host_ip>:<port>/<vdisk-id>"); |
| 217 | } |
| 218 | } |
| 219 | } |
| 220 | |
Eric Blake | 918889b | 2018-04-24 14:25:05 -0500 | [diff] [blame] | 221 | static void vxhs_refresh_limits(BlockDriverState *bs, Error **errp) |
| 222 | { |
| 223 | /* XXX Does VXHS support AIO on less than 512-byte alignment? */ |
| 224 | bs->bl.request_alignment = 512; |
| 225 | } |
| 226 | |
Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 227 | static int vxhs_init_and_ref(void) |
| 228 | { |
| 229 | if (vxhs_ref++ == 0) { |
| 230 | if (iio_init(QNIO_VERSION, vxhs_iio_callback)) { |
| 231 | return -ENODEV; |
| 232 | } |
| 233 | } |
| 234 | return 0; |
| 235 | } |
| 236 | |
| 237 | static void vxhs_unref(void) |
| 238 | { |
| 239 | if (--vxhs_ref == 0) { |
| 240 | iio_fini(); |
| 241 | } |
| 242 | } |
| 243 | |
| 244 | static void vxhs_get_tls_creds(const char *id, char **cacert, |
| 245 | char **key, char **cert, Error **errp) |
| 246 | { |
| 247 | Object *obj; |
| 248 | QCryptoTLSCreds *creds; |
| 249 | QCryptoTLSCredsX509 *creds_x509; |
| 250 | |
| 251 | obj = object_resolve_path_component( |
| 252 | object_get_objects_root(), id); |
| 253 | |
| 254 | if (!obj) { |
| 255 | error_setg(errp, "No TLS credentials with id '%s'", |
| 256 | id); |
| 257 | return; |
| 258 | } |
| 259 | |
| 260 | creds_x509 = (QCryptoTLSCredsX509 *) |
| 261 | object_dynamic_cast(obj, TYPE_QCRYPTO_TLS_CREDS_X509); |
| 262 | |
| 263 | if (!creds_x509) { |
| 264 | error_setg(errp, "Object with id '%s' is not TLS credentials", |
| 265 | id); |
| 266 | return; |
| 267 | } |
| 268 | |
| 269 | creds = &creds_x509->parent_obj; |
| 270 | |
| 271 | if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) { |
| 272 | error_setg(errp, |
| 273 | "Expecting TLS credentials with a client endpoint"); |
| 274 | return; |
| 275 | } |
| 276 | |
| 277 | /* |
| 278 | * Get the cacert, client_cert and client_key file names. |
| 279 | */ |
| 280 | if (!creds->dir) { |
| 281 | error_setg(errp, "TLS object missing 'dir' property value"); |
| 282 | return; |
| 283 | } |
| 284 | |
| 285 | *cacert = g_strdup_printf("%s/%s", creds->dir, |
| 286 | QCRYPTO_TLS_CREDS_X509_CA_CERT); |
| 287 | *cert = g_strdup_printf("%s/%s", creds->dir, |
| 288 | QCRYPTO_TLS_CREDS_X509_CLIENT_CERT); |
| 289 | *key = g_strdup_printf("%s/%s", creds->dir, |
| 290 | QCRYPTO_TLS_CREDS_X509_CLIENT_KEY); |
| 291 | } |
| 292 | |
| 293 | static int vxhs_open(BlockDriverState *bs, QDict *options, |
| 294 | int bdrv_flags, Error **errp) |
| 295 | { |
| 296 | BDRVVXHSState *s = bs->opaque; |
| 297 | void *dev_handlep; |
| 298 | QDict *backing_options = NULL; |
| 299 | QemuOpts *opts = NULL; |
| 300 | QemuOpts *tcp_opts = NULL; |
| 301 | char *of_vsa_addr = NULL; |
| 302 | Error *local_err = NULL; |
| 303 | const char *vdisk_id_opt; |
| 304 | const char *server_host_opt; |
| 305 | int ret = 0; |
| 306 | char *cacert = NULL; |
| 307 | char *client_key = NULL; |
| 308 | char *client_cert = NULL; |
| 309 | |
| 310 | ret = vxhs_init_and_ref(); |
| 311 | if (ret < 0) { |
| 312 | ret = -EINVAL; |
| 313 | goto out; |
| 314 | } |
| 315 | |
| 316 | /* Create opts info from runtime_opts and runtime_tcp_opts list */ |
| 317 | opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); |
| 318 | tcp_opts = qemu_opts_create(&runtime_tcp_opts, NULL, 0, &error_abort); |
| 319 | |
| 320 | qemu_opts_absorb_qdict(opts, options, &local_err); |
| 321 | if (local_err) { |
| 322 | ret = -EINVAL; |
| 323 | goto out; |
| 324 | } |
| 325 | |
| 326 | /* vdisk-id is the disk UUID */ |
| 327 | vdisk_id_opt = qemu_opt_get(opts, VXHS_OPT_VDISK_ID); |
| 328 | if (!vdisk_id_opt) { |
| 329 | error_setg(&local_err, QERR_MISSING_PARAMETER, VXHS_OPT_VDISK_ID); |
| 330 | ret = -EINVAL; |
| 331 | goto out; |
| 332 | } |
| 333 | |
| 334 | /* vdisk-id may contain a leading '/' */ |
| 335 | if (strlen(vdisk_id_opt) > UUID_FMT_LEN + 1) { |
| 336 | error_setg(&local_err, "vdisk-id cannot be more than %d characters", |
| 337 | UUID_FMT_LEN); |
| 338 | ret = -EINVAL; |
| 339 | goto out; |
| 340 | } |
| 341 | |
| 342 | s->vdisk_guid = g_strdup(vdisk_id_opt); |
| 343 | trace_vxhs_open_vdiskid(vdisk_id_opt); |
| 344 | |
| 345 | /* get the 'server.' arguments */ |
| 346 | qdict_extract_subqdict(options, &backing_options, VXHS_OPT_SERVER"."); |
| 347 | |
| 348 | qemu_opts_absorb_qdict(tcp_opts, backing_options, &local_err); |
| 349 | if (local_err != NULL) { |
| 350 | ret = -EINVAL; |
| 351 | goto out; |
| 352 | } |
| 353 | |
| 354 | server_host_opt = qemu_opt_get(tcp_opts, VXHS_OPT_HOST); |
| 355 | if (!server_host_opt) { |
| 356 | error_setg(&local_err, QERR_MISSING_PARAMETER, |
| 357 | VXHS_OPT_SERVER"."VXHS_OPT_HOST); |
| 358 | ret = -EINVAL; |
| 359 | goto out; |
| 360 | } |
| 361 | |
| 362 | if (strlen(server_host_opt) > MAXHOSTNAMELEN) { |
| 363 | error_setg(&local_err, "server.host cannot be more than %d characters", |
| 364 | MAXHOSTNAMELEN); |
| 365 | ret = -EINVAL; |
| 366 | goto out; |
| 367 | } |
| 368 | |
| 369 | /* check if we got tls-creds via the --object argument */ |
| 370 | s->tlscredsid = g_strdup(qemu_opt_get(opts, "tls-creds")); |
| 371 | if (s->tlscredsid) { |
| 372 | vxhs_get_tls_creds(s->tlscredsid, &cacert, &client_key, |
| 373 | &client_cert, &local_err); |
| 374 | if (local_err != NULL) { |
| 375 | ret = -EINVAL; |
| 376 | goto out; |
| 377 | } |
| 378 | trace_vxhs_get_creds(cacert, client_key, client_cert); |
| 379 | } |
| 380 | |
| 381 | s->vdisk_hostinfo.host = g_strdup(server_host_opt); |
| 382 | s->vdisk_hostinfo.port = g_ascii_strtoll(qemu_opt_get(tcp_opts, |
| 383 | VXHS_OPT_PORT), |
| 384 | NULL, 0); |
| 385 | |
| 386 | trace_vxhs_open_hostinfo(s->vdisk_hostinfo.host, |
| 387 | s->vdisk_hostinfo.port); |
| 388 | |
| 389 | of_vsa_addr = g_strdup_printf("of://%s:%d", |
| 390 | s->vdisk_hostinfo.host, |
| 391 | s->vdisk_hostinfo.port); |
| 392 | |
| 393 | /* |
| 394 | * Open qnio channel to storage agent if not opened before |
| 395 | */ |
| 396 | dev_handlep = iio_open(of_vsa_addr, s->vdisk_guid, 0, |
| 397 | cacert, client_key, client_cert); |
| 398 | if (dev_handlep == NULL) { |
| 399 | trace_vxhs_open_iio_open(of_vsa_addr); |
| 400 | ret = -ENODEV; |
| 401 | goto out; |
| 402 | } |
| 403 | s->vdisk_hostinfo.dev_handle = dev_handlep; |
| 404 | |
| 405 | out: |
| 406 | g_free(of_vsa_addr); |
Marc-André Lureau | cb3e7f0 | 2018-04-19 17:01:43 +0200 | [diff] [blame] | 407 | qobject_unref(backing_options); |
Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 408 | qemu_opts_del(tcp_opts); |
| 409 | qemu_opts_del(opts); |
| 410 | g_free(cacert); |
| 411 | g_free(client_key); |
| 412 | g_free(client_cert); |
| 413 | |
| 414 | if (ret < 0) { |
| 415 | vxhs_unref(); |
| 416 | error_propagate(errp, local_err); |
| 417 | g_free(s->vdisk_hostinfo.host); |
| 418 | g_free(s->vdisk_guid); |
| 419 | g_free(s->tlscredsid); |
| 420 | s->vdisk_guid = NULL; |
| 421 | } |
| 422 | |
| 423 | return ret; |
| 424 | } |
| 425 | |
| 426 | static const AIOCBInfo vxhs_aiocb_info = { |
| 427 | .aiocb_size = sizeof(VXHSAIOCB) |
| 428 | }; |
| 429 | |
| 430 | /* |
| 431 | * This allocates QEMU-VXHS callback for each IO |
| 432 | * and is passed to QNIO. When QNIO completes the work, |
| 433 | * it will be passed back through the callback. |
| 434 | */ |
Eric Blake | 918889b | 2018-04-24 14:25:05 -0500 | [diff] [blame] | 435 | static BlockAIOCB *vxhs_aio_rw(BlockDriverState *bs, uint64_t offset, |
| 436 | QEMUIOVector *qiov, uint64_t size, |
Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 437 | BlockCompletionFunc *cb, void *opaque, |
| 438 | VDISKAIOCmd iodir) |
| 439 | { |
| 440 | VXHSAIOCB *acb = NULL; |
| 441 | BDRVVXHSState *s = bs->opaque; |
Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 442 | int iio_flags = 0; |
| 443 | int ret = 0; |
| 444 | void *dev_handle = s->vdisk_hostinfo.dev_handle; |
| 445 | |
Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 446 | acb = qemu_aio_get(&vxhs_aiocb_info, bs, cb, opaque); |
| 447 | |
| 448 | /* |
| 449 | * Initialize VXHSAIOCB. |
| 450 | */ |
| 451 | acb->err = 0; |
| 452 | |
| 453 | iio_flags = IIO_FLAG_ASYNC; |
| 454 | |
| 455 | switch (iodir) { |
| 456 | case VDISK_AIO_WRITE: |
| 457 | ret = iio_writev(dev_handle, acb, qiov->iov, qiov->niov, |
Eric Blake | 918889b | 2018-04-24 14:25:05 -0500 | [diff] [blame] | 458 | offset, size, iio_flags); |
Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 459 | break; |
| 460 | case VDISK_AIO_READ: |
| 461 | ret = iio_readv(dev_handle, acb, qiov->iov, qiov->niov, |
Eric Blake | 918889b | 2018-04-24 14:25:05 -0500 | [diff] [blame] | 462 | offset, size, iio_flags); |
Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 463 | break; |
| 464 | default: |
| 465 | trace_vxhs_aio_rw_invalid(iodir); |
| 466 | goto errout; |
| 467 | } |
| 468 | |
| 469 | if (ret != 0) { |
| 470 | trace_vxhs_aio_rw_ioerr(s->vdisk_guid, iodir, size, offset, |
| 471 | acb, ret, errno); |
| 472 | goto errout; |
| 473 | } |
| 474 | return &acb->common; |
| 475 | |
| 476 | errout: |
| 477 | qemu_aio_unref(acb); |
| 478 | return NULL; |
| 479 | } |
| 480 | |
Eric Blake | 918889b | 2018-04-24 14:25:05 -0500 | [diff] [blame] | 481 | static BlockAIOCB *vxhs_aio_preadv(BlockDriverState *bs, |
| 482 | uint64_t offset, uint64_t bytes, |
| 483 | QEMUIOVector *qiov, int flags, |
Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 484 | BlockCompletionFunc *cb, void *opaque) |
| 485 | { |
Eric Blake | 918889b | 2018-04-24 14:25:05 -0500 | [diff] [blame] | 486 | return vxhs_aio_rw(bs, offset, qiov, bytes, cb, opaque, VDISK_AIO_READ); |
Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 487 | } |
| 488 | |
Eric Blake | 918889b | 2018-04-24 14:25:05 -0500 | [diff] [blame] | 489 | static BlockAIOCB *vxhs_aio_pwritev(BlockDriverState *bs, |
| 490 | uint64_t offset, uint64_t bytes, |
| 491 | QEMUIOVector *qiov, int flags, |
| 492 | BlockCompletionFunc *cb, void *opaque) |
Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 493 | { |
Eric Blake | 918889b | 2018-04-24 14:25:05 -0500 | [diff] [blame] | 494 | return vxhs_aio_rw(bs, offset, qiov, bytes, cb, opaque, VDISK_AIO_WRITE); |
Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 495 | } |
| 496 | |
| 497 | static void vxhs_close(BlockDriverState *bs) |
| 498 | { |
| 499 | BDRVVXHSState *s = bs->opaque; |
| 500 | |
| 501 | trace_vxhs_close(s->vdisk_guid); |
| 502 | |
| 503 | g_free(s->vdisk_guid); |
| 504 | s->vdisk_guid = NULL; |
| 505 | |
| 506 | /* |
| 507 | * Close vDisk device |
| 508 | */ |
| 509 | if (s->vdisk_hostinfo.dev_handle) { |
| 510 | iio_close(s->vdisk_hostinfo.dev_handle); |
| 511 | s->vdisk_hostinfo.dev_handle = NULL; |
| 512 | } |
| 513 | |
| 514 | vxhs_unref(); |
| 515 | |
| 516 | /* |
| 517 | * Free the dynamically allocated host string etc |
| 518 | */ |
| 519 | g_free(s->vdisk_hostinfo.host); |
| 520 | g_free(s->tlscredsid); |
| 521 | s->tlscredsid = NULL; |
| 522 | s->vdisk_hostinfo.host = NULL; |
| 523 | s->vdisk_hostinfo.port = 0; |
| 524 | } |
| 525 | |
| 526 | static int64_t vxhs_get_vdisk_stat(BDRVVXHSState *s) |
| 527 | { |
| 528 | int64_t vdisk_size = -1; |
| 529 | int ret = 0; |
| 530 | void *dev_handle = s->vdisk_hostinfo.dev_handle; |
| 531 | |
| 532 | ret = iio_ioctl(dev_handle, IOR_VDISK_STAT, &vdisk_size, 0); |
| 533 | if (ret < 0) { |
| 534 | trace_vxhs_get_vdisk_stat_err(s->vdisk_guid, ret, errno); |
| 535 | return -EIO; |
| 536 | } |
| 537 | |
| 538 | trace_vxhs_get_vdisk_stat(s->vdisk_guid, vdisk_size); |
| 539 | return vdisk_size; |
| 540 | } |
| 541 | |
| 542 | /* |
| 543 | * Returns the size of vDisk in bytes. This is required |
| 544 | * by QEMU block upper block layer so that it is visible |
| 545 | * to guest. |
| 546 | */ |
| 547 | static int64_t vxhs_getlength(BlockDriverState *bs) |
| 548 | { |
| 549 | BDRVVXHSState *s = bs->opaque; |
| 550 | int64_t vdisk_size; |
| 551 | |
| 552 | vdisk_size = vxhs_get_vdisk_stat(s); |
| 553 | if (vdisk_size < 0) { |
| 554 | return -EIO; |
| 555 | } |
| 556 | |
| 557 | return vdisk_size; |
| 558 | } |
| 559 | |
Max Reitz | 2654267 | 2019-02-01 20:29:25 +0100 | [diff] [blame] | 560 | static const char *const vxhs_strong_runtime_opts[] = { |
| 561 | VXHS_OPT_VDISK_ID, |
| 562 | "tls-creds", |
| 563 | VXHS_OPT_HOST, |
| 564 | VXHS_OPT_PORT, |
| 565 | VXHS_OPT_SERVER".", |
| 566 | |
| 567 | NULL |
| 568 | }; |
| 569 | |
Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 570 | static BlockDriver bdrv_vxhs = { |
| 571 | .format_name = "vxhs", |
| 572 | .protocol_name = "vxhs", |
| 573 | .instance_size = sizeof(BDRVVXHSState), |
| 574 | .bdrv_file_open = vxhs_open, |
| 575 | .bdrv_parse_filename = vxhs_parse_filename, |
Eric Blake | 918889b | 2018-04-24 14:25:05 -0500 | [diff] [blame] | 576 | .bdrv_refresh_limits = vxhs_refresh_limits, |
Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 577 | .bdrv_close = vxhs_close, |
| 578 | .bdrv_getlength = vxhs_getlength, |
Eric Blake | 918889b | 2018-04-24 14:25:05 -0500 | [diff] [blame] | 579 | .bdrv_aio_preadv = vxhs_aio_preadv, |
| 580 | .bdrv_aio_pwritev = vxhs_aio_pwritev, |
Max Reitz | 2654267 | 2019-02-01 20:29:25 +0100 | [diff] [blame] | 581 | .strong_runtime_opts = vxhs_strong_runtime_opts, |
Ashish Mittal | da92c3f | 2017-04-03 20:48:08 -0700 | [diff] [blame] | 582 | }; |
| 583 | |
| 584 | static void bdrv_vxhs_init(void) |
| 585 | { |
| 586 | bdrv_register(&bdrv_vxhs); |
| 587 | } |
| 588 | |
| 589 | block_init(bdrv_vxhs_init); |