+/*
+ * Convert the json formatted command line into qapi.
+*/
+static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
+ QDict *options, Error **errp)
+{
+ QemuOpts *opts;
+ SocketAddressFlat *gsconf = NULL;
+ SocketAddressFlatList *curr = NULL;
+ QDict *backing_options = NULL;
+ Error *local_err = NULL;
+ char *str = NULL;
+ const char *ptr;
+ size_t num_servers;
+ int i;
+
+ /* create opts info from runtime_json_opts list */
+ opts = qemu_opts_create(&runtime_json_opts, NULL, 0, &error_abort);
+ qemu_opts_absorb_qdict(opts, options, &local_err);
+ if (local_err) {
+ goto out;
+ }
+
+ num_servers = qdict_array_entries(options, GLUSTER_OPT_SERVER_PATTERN);
+ if (num_servers < 1) {
+ error_setg(&local_err, QERR_MISSING_PARAMETER, "server");
+ goto out;
+ }
+
+ ptr = qemu_opt_get(opts, GLUSTER_OPT_VOLUME);
+ if (!ptr) {
+ error_setg(&local_err, QERR_MISSING_PARAMETER, GLUSTER_OPT_VOLUME);
+ goto out;
+ }
+ gconf->volume = g_strdup(ptr);
+
+ ptr = qemu_opt_get(opts, GLUSTER_OPT_PATH);
+ if (!ptr) {
+ error_setg(&local_err, QERR_MISSING_PARAMETER, GLUSTER_OPT_PATH);
+ goto out;
+ }
+ gconf->path = g_strdup(ptr);
+ qemu_opts_del(opts);
+
+ for (i = 0; i < num_servers; i++) {
+ str = g_strdup_printf(GLUSTER_OPT_SERVER_PATTERN"%d.", i);
+ qdict_extract_subqdict(options, &backing_options, str);
+
+ /* create opts info from runtime_type_opts list */
+ opts = qemu_opts_create(&runtime_type_opts, NULL, 0, &error_abort);
+ qemu_opts_absorb_qdict(opts, backing_options, &local_err);
+ if (local_err) {
+ goto out;
+ }
+
+ ptr = qemu_opt_get(opts, GLUSTER_OPT_TYPE);
+ if (!ptr) {
+ error_setg(&local_err, QERR_MISSING_PARAMETER, GLUSTER_OPT_TYPE);
+ error_append_hint(&local_err, GERR_INDEX_HINT, i);
+ goto out;
+
+ }
+ gsconf = g_new0(SocketAddressFlat, 1);
+ if (!strcmp(ptr, "tcp")) {
+ ptr = "inet"; /* accept legacy "tcp" */
+ }
+ gsconf->type = qapi_enum_parse(SocketAddressFlatType_lookup, ptr,
+ SOCKET_ADDRESS_FLAT_TYPE__MAX, -1,
+ &local_err);
+ if (local_err) {
+ error_append_hint(&local_err,
+ "Parameter '%s' may be 'inet' or 'unix'\n",
+ GLUSTER_OPT_TYPE);
+ error_append_hint(&local_err, GERR_INDEX_HINT, i);
+ goto out;
+ }
+ qemu_opts_del(opts);
+
+ if (gsconf->type == SOCKET_ADDRESS_FLAT_TYPE_INET) {
+ /* create opts info from runtime_inet_opts list */
+ opts = qemu_opts_create(&runtime_inet_opts, NULL, 0, &error_abort);
+ qemu_opts_absorb_qdict(opts, backing_options, &local_err);
+ if (local_err) {
+ goto out;
+ }
+
+ ptr = qemu_opt_get(opts, GLUSTER_OPT_HOST);
+ if (!ptr) {
+ error_setg(&local_err, QERR_MISSING_PARAMETER,
+ GLUSTER_OPT_HOST);
+ error_append_hint(&local_err, GERR_INDEX_HINT, i);
+ goto out;
+ }
+ gsconf->u.inet.host = g_strdup(ptr);
+ ptr = qemu_opt_get(opts, GLUSTER_OPT_PORT);
+ if (!ptr) {
+ error_setg(&local_err, QERR_MISSING_PARAMETER,
+ GLUSTER_OPT_PORT);
+ error_append_hint(&local_err, GERR_INDEX_HINT, i);
+ goto out;
+ }
+ gsconf->u.inet.port = g_strdup(ptr);
+
+ /* defend for unsupported fields in InetSocketAddress,
+ * i.e. @ipv4, @ipv6 and @to
+ */
+ ptr = qemu_opt_get(opts, GLUSTER_OPT_TO);
+ if (ptr) {
+ gsconf->u.inet.has_to = true;
+ }
+ ptr = qemu_opt_get(opts, GLUSTER_OPT_IPV4);
+ if (ptr) {
+ gsconf->u.inet.has_ipv4 = true;
+ }
+ ptr = qemu_opt_get(opts, GLUSTER_OPT_IPV6);
+ if (ptr) {
+ gsconf->u.inet.has_ipv6 = true;
+ }
+ if (gsconf->u.inet.has_to) {
+ error_setg(&local_err, "Parameter 'to' not supported");
+ goto out;
+ }
+ if (gsconf->u.inet.has_ipv4 || gsconf->u.inet.has_ipv6) {
+ error_setg(&local_err, "Parameters 'ipv4/ipv6' not supported");
+ goto out;
+ }
+ qemu_opts_del(opts);
+ } else {
+ /* create opts info from runtime_unix_opts list */
+ opts = qemu_opts_create(&runtime_unix_opts, NULL, 0, &error_abort);
+ qemu_opts_absorb_qdict(opts, backing_options, &local_err);
+ if (local_err) {
+ goto out;
+ }
+
+ ptr = qemu_opt_get(opts, GLUSTER_OPT_SOCKET);
+ if (!ptr) {
+ error_setg(&local_err, QERR_MISSING_PARAMETER,
+ GLUSTER_OPT_SOCKET);
+ error_append_hint(&local_err, GERR_INDEX_HINT, i);
+ goto out;
+ }
+ gsconf->u.q_unix.path = g_strdup(ptr);
+ qemu_opts_del(opts);
+ }
+
+ if (gconf->server == NULL) {
+ gconf->server = g_new0(SocketAddressFlatList, 1);
+ gconf->server->value = gsconf;
+ curr = gconf->server;
+ } else {
+ curr->next = g_new0(SocketAddressFlatList, 1);
+ curr->next->value = gsconf;
+ curr = curr->next;
+ }
+ gsconf = NULL;
+
+ QDECREF(backing_options);
+ backing_options = NULL;
+ g_free(str);
+ str = NULL;
+ }
+
+ return 0;
+
+out:
+ error_propagate(errp, local_err);
+ qapi_free_SocketAddressFlat(gsconf);
+ qemu_opts_del(opts);
+ g_free(str);
+ QDECREF(backing_options);
+ errno = EINVAL;
+ return -errno;
+}
+
+static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
+ const char *filename,
+ QDict *options, Error **errp)