1019d6b8fSAnthony Liguori /* 2019d6b8fSAnthony Liguori * QEMU Block driver for NBD 3019d6b8fSAnthony Liguori * 4019d6b8fSAnthony Liguori * Copyright (C) 2008 Bull S.A.S. 5019d6b8fSAnthony Liguori * Author: Laurent Vivier <Laurent.Vivier@bull.net> 6019d6b8fSAnthony Liguori * 7019d6b8fSAnthony Liguori * Some parts: 8019d6b8fSAnthony Liguori * Copyright (C) 2007 Anthony Liguori <anthony@codemonkey.ws> 9019d6b8fSAnthony Liguori * 10019d6b8fSAnthony Liguori * Permission is hereby granted, free of charge, to any person obtaining a copy 11019d6b8fSAnthony Liguori * of this software and associated documentation files (the "Software"), to deal 12019d6b8fSAnthony Liguori * in the Software without restriction, including without limitation the rights 13019d6b8fSAnthony Liguori * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14019d6b8fSAnthony Liguori * copies of the Software, and to permit persons to whom the Software is 15019d6b8fSAnthony Liguori * furnished to do so, subject to the following conditions: 16019d6b8fSAnthony Liguori * 17019d6b8fSAnthony Liguori * The above copyright notice and this permission notice shall be included in 18019d6b8fSAnthony Liguori * all copies or substantial portions of the Software. 19019d6b8fSAnthony Liguori * 20019d6b8fSAnthony Liguori * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21019d6b8fSAnthony Liguori * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22019d6b8fSAnthony Liguori * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23019d6b8fSAnthony Liguori * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24019d6b8fSAnthony Liguori * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25019d6b8fSAnthony Liguori * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26019d6b8fSAnthony Liguori * THE SOFTWARE. 27019d6b8fSAnthony Liguori */ 28019d6b8fSAnthony Liguori 2980c71a24SPeter Maydell #include "qemu/osdep.h" 302302c1caSMarc-André Lureau #include "block/nbd-client.h" 31da34e65cSMarkus Armbruster #include "qapi/error.h" 321de7afc9SPaolo Bonzini #include "qemu/uri.h" 33737e150eSPaolo Bonzini #include "block/block_int.h" 341de7afc9SPaolo Bonzini #include "qemu/module.h" 352019d68bSMax Reitz #include "qapi/qmp/qdict.h" 36f53a1febSKevin Wolf #include "qapi/qmp/qjson.h" 37f53a1febSKevin Wolf #include "qapi/qmp/qint.h" 382019d68bSMax Reitz #include "qapi/qmp/qstring.h" 39f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 40019d6b8fSAnthony Liguori 411d45f8b5SLaurent Vivier #define EN_OPTSTR ":exportname=" 421d45f8b5SLaurent Vivier 43019d6b8fSAnthony Liguori typedef struct BDRVNBDState { 442302c1caSMarc-André Lureau NbdClientSession client; 4503504d05SMax Reitz 4603504d05SMax Reitz /* For nbd_refresh_filename() */ 4703504d05SMax Reitz char *path, *host, *port, *export, *tlscredsid; 48019d6b8fSAnthony Liguori } BDRVNBDState; 49019d6b8fSAnthony Liguori 50f53a1febSKevin Wolf static int nbd_parse_uri(const char *filename, QDict *options) 511d7d2a9dSPaolo Bonzini { 521d7d2a9dSPaolo Bonzini URI *uri; 531d7d2a9dSPaolo Bonzini const char *p; 541d7d2a9dSPaolo Bonzini QueryParams *qp = NULL; 551d7d2a9dSPaolo Bonzini int ret = 0; 56f53a1febSKevin Wolf bool is_unix; 571d7d2a9dSPaolo Bonzini 581d7d2a9dSPaolo Bonzini uri = uri_parse(filename); 591d7d2a9dSPaolo Bonzini if (!uri) { 601d7d2a9dSPaolo Bonzini return -EINVAL; 611d7d2a9dSPaolo Bonzini } 621d7d2a9dSPaolo Bonzini 631d7d2a9dSPaolo Bonzini /* transport */ 641d7d2a9dSPaolo Bonzini if (!strcmp(uri->scheme, "nbd")) { 65f53a1febSKevin Wolf is_unix = false; 661d7d2a9dSPaolo Bonzini } else if (!strcmp(uri->scheme, "nbd+tcp")) { 67f53a1febSKevin Wolf is_unix = false; 681d7d2a9dSPaolo Bonzini } else if (!strcmp(uri->scheme, "nbd+unix")) { 69f53a1febSKevin Wolf is_unix = true; 701d7d2a9dSPaolo Bonzini } else { 711d7d2a9dSPaolo Bonzini ret = -EINVAL; 721d7d2a9dSPaolo Bonzini goto out; 731d7d2a9dSPaolo Bonzini } 741d7d2a9dSPaolo Bonzini 751d7d2a9dSPaolo Bonzini p = uri->path ? uri->path : "/"; 761d7d2a9dSPaolo Bonzini p += strspn(p, "/"); 771d7d2a9dSPaolo Bonzini if (p[0]) { 78f53a1febSKevin Wolf qdict_put(options, "export", qstring_from_str(p)); 791d7d2a9dSPaolo Bonzini } 801d7d2a9dSPaolo Bonzini 811d7d2a9dSPaolo Bonzini qp = query_params_parse(uri->query); 82f53a1febSKevin Wolf if (qp->n > 1 || (is_unix && !qp->n) || (!is_unix && qp->n)) { 831d7d2a9dSPaolo Bonzini ret = -EINVAL; 841d7d2a9dSPaolo Bonzini goto out; 851d7d2a9dSPaolo Bonzini } 861d7d2a9dSPaolo Bonzini 87f53a1febSKevin Wolf if (is_unix) { 881d7d2a9dSPaolo Bonzini /* nbd+unix:///export?socket=path */ 891d7d2a9dSPaolo Bonzini if (uri->server || uri->port || strcmp(qp->p[0].name, "socket")) { 901d7d2a9dSPaolo Bonzini ret = -EINVAL; 911d7d2a9dSPaolo Bonzini goto out; 921d7d2a9dSPaolo Bonzini } 93f53a1febSKevin Wolf qdict_put(options, "path", qstring_from_str(qp->p[0].value)); 941d7d2a9dSPaolo Bonzini } else { 9523307908SJán Tomko QString *host; 96bebbf7faSKevin Wolf /* nbd[+tcp]://host[:port]/export */ 971d7d2a9dSPaolo Bonzini if (!uri->server) { 981d7d2a9dSPaolo Bonzini ret = -EINVAL; 991d7d2a9dSPaolo Bonzini goto out; 1001d7d2a9dSPaolo Bonzini } 101f17c90beSKevin Wolf 10223307908SJán Tomko /* strip braces from literal IPv6 address */ 10323307908SJán Tomko if (uri->server[0] == '[') { 10423307908SJán Tomko host = qstring_from_substr(uri->server, 1, 10523307908SJán Tomko strlen(uri->server) - 2); 10623307908SJán Tomko } else { 10723307908SJán Tomko host = qstring_from_str(uri->server); 10823307908SJán Tomko } 10923307908SJán Tomko 11023307908SJán Tomko qdict_put(options, "host", host); 111bebbf7faSKevin Wolf if (uri->port) { 112bebbf7faSKevin Wolf char* port_str = g_strdup_printf("%d", uri->port); 113f53a1febSKevin Wolf qdict_put(options, "port", qstring_from_str(port_str)); 114f53a1febSKevin Wolf g_free(port_str); 1151d7d2a9dSPaolo Bonzini } 116bebbf7faSKevin Wolf } 1171d7d2a9dSPaolo Bonzini 1181d7d2a9dSPaolo Bonzini out: 1191d7d2a9dSPaolo Bonzini if (qp) { 1201d7d2a9dSPaolo Bonzini query_params_free(qp); 1211d7d2a9dSPaolo Bonzini } 1221d7d2a9dSPaolo Bonzini uri_free(uri); 1231d7d2a9dSPaolo Bonzini return ret; 1241d7d2a9dSPaolo Bonzini } 1251d7d2a9dSPaolo Bonzini 1266963a30dSKevin Wolf static void nbd_parse_filename(const char *filename, QDict *options, 1276963a30dSKevin Wolf Error **errp) 128019d6b8fSAnthony Liguori { 1291d45f8b5SLaurent Vivier char *file; 13033897dc7SNick Thomas char *export_name; 13133897dc7SNick Thomas const char *host_spec; 132019d6b8fSAnthony Liguori const char *unixpath; 133019d6b8fSAnthony Liguori 134681e7ad0SKevin Wolf if (qdict_haskey(options, "host") 135681e7ad0SKevin Wolf || qdict_haskey(options, "port") 136681e7ad0SKevin Wolf || qdict_haskey(options, "path")) 137681e7ad0SKevin Wolf { 138681e7ad0SKevin Wolf error_setg(errp, "host/port/path and a file name may not be specified " 139681e7ad0SKevin Wolf "at the same time"); 140681e7ad0SKevin Wolf return; 141681e7ad0SKevin Wolf } 142681e7ad0SKevin Wolf 1431d7d2a9dSPaolo Bonzini if (strstr(filename, "://")) { 1446963a30dSKevin Wolf int ret = nbd_parse_uri(filename, options); 1456963a30dSKevin Wolf if (ret < 0) { 1466963a30dSKevin Wolf error_setg(errp, "No valid URL specified"); 1476963a30dSKevin Wolf } 1486963a30dSKevin Wolf return; 1491d7d2a9dSPaolo Bonzini } 1501d7d2a9dSPaolo Bonzini 1517267c094SAnthony Liguori file = g_strdup(filename); 1521d45f8b5SLaurent Vivier 15333897dc7SNick Thomas export_name = strstr(file, EN_OPTSTR); 15433897dc7SNick Thomas if (export_name) { 15533897dc7SNick Thomas if (export_name[strlen(EN_OPTSTR)] == 0) { 1561d45f8b5SLaurent Vivier goto out; 1571d45f8b5SLaurent Vivier } 15833897dc7SNick Thomas export_name[0] = 0; /* truncate 'file' */ 15933897dc7SNick Thomas export_name += strlen(EN_OPTSTR); 160f53a1febSKevin Wolf 161f53a1febSKevin Wolf qdict_put(options, "export", qstring_from_str(export_name)); 1621d45f8b5SLaurent Vivier } 1631d45f8b5SLaurent Vivier 16433897dc7SNick Thomas /* extract the host_spec - fail if it's not nbd:... */ 16533897dc7SNick Thomas if (!strstart(file, "nbd:", &host_spec)) { 1666963a30dSKevin Wolf error_setg(errp, "File name string for NBD must start with 'nbd:'"); 1671d45f8b5SLaurent Vivier goto out; 1681d45f8b5SLaurent Vivier } 169019d6b8fSAnthony Liguori 170f53a1febSKevin Wolf if (!*host_spec) { 171f53a1febSKevin Wolf goto out; 172f53a1febSKevin Wolf } 173f53a1febSKevin Wolf 17433897dc7SNick Thomas /* are we a UNIX or TCP socket? */ 17533897dc7SNick Thomas if (strstart(host_spec, "unix:", &unixpath)) { 176f53a1febSKevin Wolf qdict_put(options, "path", qstring_from_str(unixpath)); 177019d6b8fSAnthony Liguori } else { 178f53a1febSKevin Wolf InetSocketAddress *addr = NULL; 179f53a1febSKevin Wolf 1806963a30dSKevin Wolf addr = inet_parse(host_spec, errp); 18192de9012SMarkus Armbruster if (!addr) { 182f17c90beSKevin Wolf goto out; 183f17c90beSKevin Wolf } 184f53a1febSKevin Wolf 185f53a1febSKevin Wolf qdict_put(options, "host", qstring_from_str(addr->host)); 186f53a1febSKevin Wolf qdict_put(options, "port", qstring_from_str(addr->port)); 187f53a1febSKevin Wolf qapi_free_InetSocketAddress(addr); 1881d45f8b5SLaurent Vivier } 1891d45f8b5SLaurent Vivier 1901d45f8b5SLaurent Vivier out: 1917267c094SAnthony Liguori g_free(file); 19233897dc7SNick Thomas } 193f53a1febSKevin Wolf 19403504d05SMax Reitz static SocketAddress *nbd_config(BDRVNBDState *s, QemuOpts *opts, Error **errp) 195f53a1febSKevin Wolf { 1967a5ed437SDaniel P. Berrange SocketAddress *saddr; 197f53a1febSKevin Wolf 19803504d05SMax Reitz s->path = g_strdup(qemu_opt_get(opts, "path")); 19903504d05SMax Reitz s->host = g_strdup(qemu_opt_get(opts, "host")); 20003504d05SMax Reitz 20103504d05SMax Reitz if (!s->path == !s->host) { 20203504d05SMax Reitz if (s->path) { 20377e8b9caSPaolo Bonzini error_setg(errp, "path and host may not be used at the same time."); 204f53a1febSKevin Wolf } else { 20577e8b9caSPaolo Bonzini error_setg(errp, "one of path and host must be specified."); 206a69d9af4SPaolo Bonzini } 2077a5ed437SDaniel P. Berrange return NULL; 208019d6b8fSAnthony Liguori } 209019d6b8fSAnthony Liguori 2107a5ed437SDaniel P. Berrange saddr = g_new0(SocketAddress, 1); 211f53a1febSKevin Wolf 21203504d05SMax Reitz if (s->path) { 2130399293eSEric Blake UnixSocketAddress *q_unix; 2146a8f9661SEric Blake saddr->type = SOCKET_ADDRESS_KIND_UNIX; 21532bafa8fSEric Blake q_unix = saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1); 21603504d05SMax Reitz q_unix->path = g_strdup(s->path); 2177a5ed437SDaniel P. Berrange } else { 2180399293eSEric Blake InetSocketAddress *inet; 21903504d05SMax Reitz 22003504d05SMax Reitz s->port = g_strdup(qemu_opt_get(opts, "port")); 22103504d05SMax Reitz 2226a8f9661SEric Blake saddr->type = SOCKET_ADDRESS_KIND_INET; 22332bafa8fSEric Blake inet = saddr->u.inet.data = g_new0(InetSocketAddress, 1); 22403504d05SMax Reitz inet->host = g_strdup(s->host); 22503504d05SMax Reitz inet->port = g_strdup(s->port); 2267ccc44fdSMax Reitz if (!inet->port) { 2270399293eSEric Blake inet->port = g_strdup_printf("%d", NBD_DEFAULT_PORT); 2287a5ed437SDaniel P. Berrange } 229f53a1febSKevin Wolf } 230f53a1febSKevin Wolf 2316a8f9661SEric Blake s->client.is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX; 232bebbf7faSKevin Wolf 23303504d05SMax Reitz s->export = g_strdup(qemu_opt_get(opts, "export")); 2347a5ed437SDaniel P. Berrange 2357a5ed437SDaniel P. Berrange return saddr; 236f53a1febSKevin Wolf } 237f53a1febSKevin Wolf 238f53a829bSMax Reitz NbdClientSession *nbd_get_client_session(BlockDriverState *bs) 239f53a829bSMax Reitz { 240f53a829bSMax Reitz BDRVNBDState *s = bs->opaque; 241f53a829bSMax Reitz return &s->client; 242f53a829bSMax Reitz } 243f53a829bSMax Reitz 244064097d9SDaniel P. Berrange static QIOChannelSocket *nbd_establish_connection(SocketAddress *saddr, 2457a5ed437SDaniel P. Berrange Error **errp) 24633897dc7SNick Thomas { 247064097d9SDaniel P. Berrange QIOChannelSocket *sioc; 248064097d9SDaniel P. Berrange Error *local_err = NULL; 24933897dc7SNick Thomas 250064097d9SDaniel P. Berrange sioc = qio_channel_socket_new(); 251*0d73f725SDaniel P. Berrange qio_channel_set_name(QIO_CHANNEL(sioc), "nbd-client"); 25233897dc7SNick Thomas 253064097d9SDaniel P. Berrange qio_channel_socket_connect_sync(sioc, 254064097d9SDaniel P. Berrange saddr, 255064097d9SDaniel P. Berrange &local_err); 256064097d9SDaniel P. Berrange if (local_err) { 257064097d9SDaniel P. Berrange error_propagate(errp, local_err); 258064097d9SDaniel P. Berrange return NULL; 25933897dc7SNick Thomas } 26033897dc7SNick Thomas 261064097d9SDaniel P. Berrange qio_channel_set_delay(QIO_CHANNEL(sioc), false); 2627a5ed437SDaniel P. Berrange 263064097d9SDaniel P. Berrange return sioc; 26433897dc7SNick Thomas } 26533897dc7SNick Thomas 26675822a12SDaniel P. Berrange 26775822a12SDaniel P. Berrange static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp) 26875822a12SDaniel P. Berrange { 26975822a12SDaniel P. Berrange Object *obj; 27075822a12SDaniel P. Berrange QCryptoTLSCreds *creds; 27175822a12SDaniel P. Berrange 27275822a12SDaniel P. Berrange obj = object_resolve_path_component( 27375822a12SDaniel P. Berrange object_get_objects_root(), id); 27475822a12SDaniel P. Berrange if (!obj) { 27575822a12SDaniel P. Berrange error_setg(errp, "No TLS credentials with id '%s'", 27675822a12SDaniel P. Berrange id); 27775822a12SDaniel P. Berrange return NULL; 27875822a12SDaniel P. Berrange } 27975822a12SDaniel P. Berrange creds = (QCryptoTLSCreds *) 28075822a12SDaniel P. Berrange object_dynamic_cast(obj, TYPE_QCRYPTO_TLS_CREDS); 28175822a12SDaniel P. Berrange if (!creds) { 28275822a12SDaniel P. Berrange error_setg(errp, "Object with id '%s' is not TLS credentials", 28375822a12SDaniel P. Berrange id); 28475822a12SDaniel P. Berrange return NULL; 28575822a12SDaniel P. Berrange } 28675822a12SDaniel P. Berrange 28775822a12SDaniel P. Berrange if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) { 28875822a12SDaniel P. Berrange error_setg(errp, 28975822a12SDaniel P. Berrange "Expecting TLS credentials with a client endpoint"); 29075822a12SDaniel P. Berrange return NULL; 29175822a12SDaniel P. Berrange } 29275822a12SDaniel P. Berrange object_ref(obj); 29375822a12SDaniel P. Berrange return creds; 29475822a12SDaniel P. Berrange } 29575822a12SDaniel P. Berrange 29675822a12SDaniel P. Berrange 2977ccc44fdSMax Reitz static QemuOptsList nbd_runtime_opts = { 2987ccc44fdSMax Reitz .name = "nbd", 2997ccc44fdSMax Reitz .head = QTAILQ_HEAD_INITIALIZER(nbd_runtime_opts.head), 3007ccc44fdSMax Reitz .desc = { 3017ccc44fdSMax Reitz { 3027ccc44fdSMax Reitz .name = "host", 3037ccc44fdSMax Reitz .type = QEMU_OPT_STRING, 3047ccc44fdSMax Reitz .help = "TCP host to connect to", 3057ccc44fdSMax Reitz }, 3067ccc44fdSMax Reitz { 3077ccc44fdSMax Reitz .name = "port", 3087ccc44fdSMax Reitz .type = QEMU_OPT_STRING, 3097ccc44fdSMax Reitz .help = "TCP port to connect to", 3107ccc44fdSMax Reitz }, 3117ccc44fdSMax Reitz { 3127ccc44fdSMax Reitz .name = "path", 3137ccc44fdSMax Reitz .type = QEMU_OPT_STRING, 3147ccc44fdSMax Reitz .help = "Unix socket path to connect to", 3157ccc44fdSMax Reitz }, 3167ccc44fdSMax Reitz { 3177ccc44fdSMax Reitz .name = "export", 3187ccc44fdSMax Reitz .type = QEMU_OPT_STRING, 3197ccc44fdSMax Reitz .help = "Name of the NBD export to open", 3207ccc44fdSMax Reitz }, 3217ccc44fdSMax Reitz { 3227ccc44fdSMax Reitz .name = "tls-creds", 3237ccc44fdSMax Reitz .type = QEMU_OPT_STRING, 3247ccc44fdSMax Reitz .help = "ID of the TLS credentials to use", 3257ccc44fdSMax Reitz }, 3267ccc44fdSMax Reitz }, 3277ccc44fdSMax Reitz }; 3287ccc44fdSMax Reitz 329015a1036SMax Reitz static int nbd_open(BlockDriverState *bs, QDict *options, int flags, 330015a1036SMax Reitz Error **errp) 33133897dc7SNick Thomas { 33233897dc7SNick Thomas BDRVNBDState *s = bs->opaque; 3337ccc44fdSMax Reitz QemuOpts *opts = NULL; 3347ccc44fdSMax Reitz Error *local_err = NULL; 33575822a12SDaniel P. Berrange QIOChannelSocket *sioc = NULL; 3367ccc44fdSMax Reitz SocketAddress *saddr = NULL; 33775822a12SDaniel P. Berrange QCryptoTLSCreds *tlscreds = NULL; 33875822a12SDaniel P. Berrange const char *hostname = NULL; 33975822a12SDaniel P. Berrange int ret = -EINVAL; 340ae255e52SPaolo Bonzini 3417ccc44fdSMax Reitz opts = qemu_opts_create(&nbd_runtime_opts, NULL, 0, &error_abort); 3427ccc44fdSMax Reitz qemu_opts_absorb_qdict(opts, options, &local_err); 3437ccc44fdSMax Reitz if (local_err) { 3447ccc44fdSMax Reitz error_propagate(errp, local_err); 3457ccc44fdSMax Reitz goto error; 3467ccc44fdSMax Reitz } 3477ccc44fdSMax Reitz 34833897dc7SNick Thomas /* Pop the config into our state object. Exit if invalid. */ 34903504d05SMax Reitz saddr = nbd_config(s, opts, errp); 3507a5ed437SDaniel P. Berrange if (!saddr) { 35175822a12SDaniel P. Berrange goto error; 35275822a12SDaniel P. Berrange } 35375822a12SDaniel P. Berrange 35403504d05SMax Reitz s->tlscredsid = g_strdup(qemu_opt_get(opts, "tls-creds")); 35503504d05SMax Reitz if (s->tlscredsid) { 35603504d05SMax Reitz tlscreds = nbd_get_tls_creds(s->tlscredsid, errp); 35775822a12SDaniel P. Berrange if (!tlscreds) { 35875822a12SDaniel P. Berrange goto error; 35975822a12SDaniel P. Berrange } 36075822a12SDaniel P. Berrange 36175822a12SDaniel P. Berrange if (saddr->type != SOCKET_ADDRESS_KIND_INET) { 36275822a12SDaniel P. Berrange error_setg(errp, "TLS only supported over IP sockets"); 36375822a12SDaniel P. Berrange goto error; 36475822a12SDaniel P. Berrange } 36532bafa8fSEric Blake hostname = saddr->u.inet.data->host; 36633897dc7SNick Thomas } 36733897dc7SNick Thomas 36833897dc7SNick Thomas /* establish TCP connection, return error if it fails 36933897dc7SNick Thomas * TODO: Configurable retry-until-timeout behaviour. 37033897dc7SNick Thomas */ 371064097d9SDaniel P. Berrange sioc = nbd_establish_connection(saddr, errp); 372064097d9SDaniel P. Berrange if (!sioc) { 37375822a12SDaniel P. Berrange ret = -ECONNREFUSED; 37475822a12SDaniel P. Berrange goto error; 37533897dc7SNick Thomas } 37633897dc7SNick Thomas 3772302c1caSMarc-André Lureau /* NBD handshake */ 37803504d05SMax Reitz ret = nbd_client_init(bs, sioc, s->export, 37975822a12SDaniel P. Berrange tlscreds, hostname, errp); 38075822a12SDaniel P. Berrange error: 38175822a12SDaniel P. Berrange if (sioc) { 382064097d9SDaniel P. Berrange object_unref(OBJECT(sioc)); 38375822a12SDaniel P. Berrange } 38475822a12SDaniel P. Berrange if (tlscreds) { 38575822a12SDaniel P. Berrange object_unref(OBJECT(tlscreds)); 38675822a12SDaniel P. Berrange } 38703504d05SMax Reitz if (ret < 0) { 38803504d05SMax Reitz g_free(s->path); 38903504d05SMax Reitz g_free(s->host); 39003504d05SMax Reitz g_free(s->port); 39103504d05SMax Reitz g_free(s->export); 39203504d05SMax Reitz g_free(s->tlscredsid); 39303504d05SMax Reitz } 39475822a12SDaniel P. Berrange qapi_free_SocketAddress(saddr); 3957ccc44fdSMax Reitz qemu_opts_del(opts); 39675822a12SDaniel P. Berrange return ret; 397ae255e52SPaolo Bonzini } 398d9b09f13SPaolo Bonzini 3991486d04aSPaolo Bonzini static int nbd_co_flush(BlockDriverState *bs) 4001486d04aSPaolo Bonzini { 401f53a829bSMax Reitz return nbd_client_co_flush(bs); 4021486d04aSPaolo Bonzini } 4031486d04aSPaolo Bonzini 404fa21e6faSDenis V. Lunev static void nbd_refresh_limits(BlockDriverState *bs, Error **errp) 405fa21e6faSDenis V. Lunev { 406b9f7855aSEric Blake bs->bl.max_pdiscard = NBD_MAX_BUFFER_SIZE; 4075def6b80SEric Blake bs->bl.max_transfer = NBD_MAX_BUFFER_SIZE; 408fa21e6faSDenis V. Lunev } 409fa21e6faSDenis V. Lunev 410019d6b8fSAnthony Liguori static void nbd_close(BlockDriverState *bs) 411019d6b8fSAnthony Liguori { 41203504d05SMax Reitz BDRVNBDState *s = bs->opaque; 41303504d05SMax Reitz 414f53a829bSMax Reitz nbd_client_close(bs); 41503504d05SMax Reitz 41603504d05SMax Reitz g_free(s->path); 41703504d05SMax Reitz g_free(s->host); 41803504d05SMax Reitz g_free(s->port); 41903504d05SMax Reitz g_free(s->export); 42003504d05SMax Reitz g_free(s->tlscredsid); 421019d6b8fSAnthony Liguori } 422019d6b8fSAnthony Liguori 423019d6b8fSAnthony Liguori static int64_t nbd_getlength(BlockDriverState *bs) 424019d6b8fSAnthony Liguori { 425019d6b8fSAnthony Liguori BDRVNBDState *s = bs->opaque; 426019d6b8fSAnthony Liguori 4272302c1caSMarc-André Lureau return s->client.size; 428019d6b8fSAnthony Liguori } 429019d6b8fSAnthony Liguori 43069447cd8SStefan Hajnoczi static void nbd_detach_aio_context(BlockDriverState *bs) 43169447cd8SStefan Hajnoczi { 432f53a829bSMax Reitz nbd_client_detach_aio_context(bs); 43369447cd8SStefan Hajnoczi } 43469447cd8SStefan Hajnoczi 43569447cd8SStefan Hajnoczi static void nbd_attach_aio_context(BlockDriverState *bs, 43669447cd8SStefan Hajnoczi AioContext *new_context) 43769447cd8SStefan Hajnoczi { 438f53a829bSMax Reitz nbd_client_attach_aio_context(bs, new_context); 43969447cd8SStefan Hajnoczi } 44069447cd8SStefan Hajnoczi 4414cdd01d3SKevin Wolf static void nbd_refresh_filename(BlockDriverState *bs, QDict *options) 4422019d68bSMax Reitz { 44303504d05SMax Reitz BDRVNBDState *s = bs->opaque; 4442019d68bSMax Reitz QDict *opts = qdict_new(); 4452019d68bSMax Reitz 4462019d68bSMax Reitz qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("nbd"))); 4472019d68bSMax Reitz 44803504d05SMax Reitz if (s->path && s->export) { 449ec0de768SMax Reitz snprintf(bs->exact_filename, sizeof(bs->exact_filename), 45003504d05SMax Reitz "nbd+unix:///%s?socket=%s", s->export, s->path); 45103504d05SMax Reitz } else if (s->path && !s->export) { 452ec0de768SMax Reitz snprintf(bs->exact_filename, sizeof(bs->exact_filename), 45303504d05SMax Reitz "nbd+unix://?socket=%s", s->path); 45403504d05SMax Reitz } else if (!s->path && s->export && s->port) { 455ec0de768SMax Reitz snprintf(bs->exact_filename, sizeof(bs->exact_filename), 45603504d05SMax Reitz "nbd://%s:%s/%s", s->host, s->port, s->export); 45703504d05SMax Reitz } else if (!s->path && s->export && !s->port) { 458ec0de768SMax Reitz snprintf(bs->exact_filename, sizeof(bs->exact_filename), 45903504d05SMax Reitz "nbd://%s/%s", s->host, s->export); 46003504d05SMax Reitz } else if (!s->path && !s->export && s->port) { 461ec0de768SMax Reitz snprintf(bs->exact_filename, sizeof(bs->exact_filename), 46203504d05SMax Reitz "nbd://%s:%s", s->host, s->port); 46303504d05SMax Reitz } else if (!s->path && !s->export && !s->port) { 464ec0de768SMax Reitz snprintf(bs->exact_filename, sizeof(bs->exact_filename), 46503504d05SMax Reitz "nbd://%s", s->host); 466ec0de768SMax Reitz } 467ec0de768SMax Reitz 46803504d05SMax Reitz if (s->path) { 46903504d05SMax Reitz qdict_put_obj(opts, "path", QOBJECT(qstring_from_str(s->path))); 47003504d05SMax Reitz } else if (s->port) { 47103504d05SMax Reitz qdict_put_obj(opts, "host", QOBJECT(qstring_from_str(s->host))); 47203504d05SMax Reitz qdict_put_obj(opts, "port", QOBJECT(qstring_from_str(s->port))); 4732019d68bSMax Reitz } else { 47403504d05SMax Reitz qdict_put_obj(opts, "host", QOBJECT(qstring_from_str(s->host))); 475ec0de768SMax Reitz } 47603504d05SMax Reitz if (s->export) { 47703504d05SMax Reitz qdict_put_obj(opts, "export", QOBJECT(qstring_from_str(s->export))); 4782019d68bSMax Reitz } 47903504d05SMax Reitz if (s->tlscredsid) { 48003504d05SMax Reitz qdict_put_obj(opts, "tls-creds", 48103504d05SMax Reitz QOBJECT(qstring_from_str(s->tlscredsid))); 48275822a12SDaniel P. Berrange } 4832019d68bSMax Reitz 4842019d68bSMax Reitz bs->full_open_options = opts; 4852019d68bSMax Reitz } 4862019d68bSMax Reitz 487019d6b8fSAnthony Liguori static BlockDriver bdrv_nbd = { 488019d6b8fSAnthony Liguori .format_name = "nbd", 4891d7d2a9dSPaolo Bonzini .protocol_name = "nbd", 490019d6b8fSAnthony Liguori .instance_size = sizeof(BDRVNBDState), 4916963a30dSKevin Wolf .bdrv_parse_filename = nbd_parse_filename, 49266f82ceeSKevin Wolf .bdrv_file_open = nbd_open, 49370c4fb26SEric Blake .bdrv_co_preadv = nbd_client_co_preadv, 49470c4fb26SEric Blake .bdrv_co_pwritev = nbd_client_co_pwritev, 495019d6b8fSAnthony Liguori .bdrv_close = nbd_close, 4961486d04aSPaolo Bonzini .bdrv_co_flush_to_os = nbd_co_flush, 497447e57c3SEric Blake .bdrv_co_pdiscard = nbd_client_co_pdiscard, 498fa21e6faSDenis V. Lunev .bdrv_refresh_limits = nbd_refresh_limits, 499019d6b8fSAnthony Liguori .bdrv_getlength = nbd_getlength, 50069447cd8SStefan Hajnoczi .bdrv_detach_aio_context = nbd_detach_aio_context, 50169447cd8SStefan Hajnoczi .bdrv_attach_aio_context = nbd_attach_aio_context, 5022019d68bSMax Reitz .bdrv_refresh_filename = nbd_refresh_filename, 5031d7d2a9dSPaolo Bonzini }; 5041d7d2a9dSPaolo Bonzini 5051d7d2a9dSPaolo Bonzini static BlockDriver bdrv_nbd_tcp = { 5061d7d2a9dSPaolo Bonzini .format_name = "nbd", 5071d7d2a9dSPaolo Bonzini .protocol_name = "nbd+tcp", 5081d7d2a9dSPaolo Bonzini .instance_size = sizeof(BDRVNBDState), 5096963a30dSKevin Wolf .bdrv_parse_filename = nbd_parse_filename, 5101d7d2a9dSPaolo Bonzini .bdrv_file_open = nbd_open, 51170c4fb26SEric Blake .bdrv_co_preadv = nbd_client_co_preadv, 51270c4fb26SEric Blake .bdrv_co_pwritev = nbd_client_co_pwritev, 5131d7d2a9dSPaolo Bonzini .bdrv_close = nbd_close, 5141d7d2a9dSPaolo Bonzini .bdrv_co_flush_to_os = nbd_co_flush, 515447e57c3SEric Blake .bdrv_co_pdiscard = nbd_client_co_pdiscard, 516fa21e6faSDenis V. Lunev .bdrv_refresh_limits = nbd_refresh_limits, 5171d7d2a9dSPaolo Bonzini .bdrv_getlength = nbd_getlength, 51869447cd8SStefan Hajnoczi .bdrv_detach_aio_context = nbd_detach_aio_context, 51969447cd8SStefan Hajnoczi .bdrv_attach_aio_context = nbd_attach_aio_context, 5202019d68bSMax Reitz .bdrv_refresh_filename = nbd_refresh_filename, 5211d7d2a9dSPaolo Bonzini }; 5221d7d2a9dSPaolo Bonzini 5231d7d2a9dSPaolo Bonzini static BlockDriver bdrv_nbd_unix = { 5241d7d2a9dSPaolo Bonzini .format_name = "nbd", 5251d7d2a9dSPaolo Bonzini .protocol_name = "nbd+unix", 5261d7d2a9dSPaolo Bonzini .instance_size = sizeof(BDRVNBDState), 5276963a30dSKevin Wolf .bdrv_parse_filename = nbd_parse_filename, 5281d7d2a9dSPaolo Bonzini .bdrv_file_open = nbd_open, 52970c4fb26SEric Blake .bdrv_co_preadv = nbd_client_co_preadv, 53070c4fb26SEric Blake .bdrv_co_pwritev = nbd_client_co_pwritev, 5311d7d2a9dSPaolo Bonzini .bdrv_close = nbd_close, 5321d7d2a9dSPaolo Bonzini .bdrv_co_flush_to_os = nbd_co_flush, 533447e57c3SEric Blake .bdrv_co_pdiscard = nbd_client_co_pdiscard, 534fa21e6faSDenis V. Lunev .bdrv_refresh_limits = nbd_refresh_limits, 5351d7d2a9dSPaolo Bonzini .bdrv_getlength = nbd_getlength, 53669447cd8SStefan Hajnoczi .bdrv_detach_aio_context = nbd_detach_aio_context, 53769447cd8SStefan Hajnoczi .bdrv_attach_aio_context = nbd_attach_aio_context, 5382019d68bSMax Reitz .bdrv_refresh_filename = nbd_refresh_filename, 539019d6b8fSAnthony Liguori }; 540019d6b8fSAnthony Liguori 541019d6b8fSAnthony Liguori static void bdrv_nbd_init(void) 542019d6b8fSAnthony Liguori { 543019d6b8fSAnthony Liguori bdrv_register(&bdrv_nbd); 5441d7d2a9dSPaolo Bonzini bdrv_register(&bdrv_nbd_tcp); 5451d7d2a9dSPaolo Bonzini bdrv_register(&bdrv_nbd_unix); 546019d6b8fSAnthony Liguori } 547019d6b8fSAnthony Liguori 548019d6b8fSAnthony Liguori block_init(bdrv_nbd_init); 549