|  | /* | 
|  | * Persistent reservation manager abstract class | 
|  | * | 
|  | * Copyright (c) 2017 Red Hat, Inc. | 
|  | * | 
|  | * Author: Paolo Bonzini <pbonzini@redhat.com> | 
|  | * | 
|  | * This code is licensed under the LGPL. | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include "qemu/osdep.h" | 
|  | #include <scsi/sg.h> | 
|  |  | 
|  | #include "qapi/error.h" | 
|  | #include "block/aio.h" | 
|  | #include "block/thread-pool.h" | 
|  | #include "scsi/pr-manager.h" | 
|  | #include "trace.h" | 
|  | #include "qapi/qapi-types-block.h" | 
|  | #include "qemu/module.h" | 
|  | #include "qapi/qapi-commands-block.h" | 
|  |  | 
|  | #define PR_MANAGER_PATH     "/objects" | 
|  |  | 
|  | typedef struct PRManagerData { | 
|  | PRManager *pr_mgr; | 
|  | struct sg_io_hdr *hdr; | 
|  | int fd; | 
|  | } PRManagerData; | 
|  |  | 
|  | static int pr_manager_worker(void *opaque) | 
|  | { | 
|  | PRManagerData *data = opaque; | 
|  | PRManager *pr_mgr = data->pr_mgr; | 
|  | PRManagerClass *pr_mgr_class = | 
|  | PR_MANAGER_GET_CLASS(pr_mgr); | 
|  | struct sg_io_hdr *hdr = data->hdr; | 
|  | int fd = data->fd; | 
|  | int r; | 
|  |  | 
|  | trace_pr_manager_run(fd, hdr->cmdp[0], hdr->cmdp[1]); | 
|  |  | 
|  | /* The reference was taken in pr_manager_execute.  */ | 
|  | r = pr_mgr_class->run(pr_mgr, fd, hdr); | 
|  | object_unref(OBJECT(pr_mgr)); | 
|  | return r; | 
|  | } | 
|  |  | 
|  |  | 
|  | int coroutine_fn pr_manager_execute(PRManager *pr_mgr, AioContext *ctx, int fd, | 
|  | struct sg_io_hdr *hdr) | 
|  | { | 
|  | PRManagerData data = { | 
|  | .pr_mgr = pr_mgr, | 
|  | .fd     = fd, | 
|  | .hdr    = hdr, | 
|  | }; | 
|  |  | 
|  | trace_pr_manager_execute(fd, hdr->cmdp[0], hdr->cmdp[1]); | 
|  |  | 
|  | /* The matching object_unref is in pr_manager_worker.  */ | 
|  | object_ref(OBJECT(pr_mgr)); | 
|  | return thread_pool_submit_co(pr_manager_worker, &data); | 
|  | } | 
|  |  | 
|  | bool pr_manager_is_connected(PRManager *pr_mgr) | 
|  | { | 
|  | PRManagerClass *pr_mgr_class = | 
|  | PR_MANAGER_GET_CLASS(pr_mgr); | 
|  |  | 
|  | return !pr_mgr_class->is_connected || pr_mgr_class->is_connected(pr_mgr); | 
|  | } | 
|  |  | 
|  | static const TypeInfo pr_manager_info = { | 
|  | .parent = TYPE_OBJECT, | 
|  | .name = TYPE_PR_MANAGER, | 
|  | .class_size = sizeof(PRManagerClass), | 
|  | .abstract = true, | 
|  | .interfaces = (InterfaceInfo[]) { | 
|  | { TYPE_USER_CREATABLE }, | 
|  | { } | 
|  | } | 
|  | }; | 
|  |  | 
|  | PRManager *pr_manager_lookup(const char *id, Error **errp) | 
|  | { | 
|  | Object *obj; | 
|  | PRManager *pr_mgr; | 
|  |  | 
|  | obj = object_resolve_path_component(object_get_objects_root(), id); | 
|  | if (!obj) { | 
|  | error_setg(errp, "No persistent reservation manager with id '%s'", id); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | pr_mgr = (PRManager *) | 
|  | object_dynamic_cast(obj, | 
|  | TYPE_PR_MANAGER); | 
|  | if (!pr_mgr) { | 
|  | error_setg(errp, | 
|  | "Object with id '%s' is not a persistent reservation manager", | 
|  | id); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | return pr_mgr; | 
|  | } | 
|  |  | 
|  | static void | 
|  | pr_manager_register_types(void) | 
|  | { | 
|  | type_register_static(&pr_manager_info); | 
|  | } | 
|  |  | 
|  | static int query_one_pr_manager(Object *object, void *opaque) | 
|  | { | 
|  | PRManagerInfoList ***tail = opaque; | 
|  | PRManagerInfo *info; | 
|  | PRManager *pr_mgr; | 
|  |  | 
|  | pr_mgr = (PRManager *)object_dynamic_cast(object, TYPE_PR_MANAGER); | 
|  | if (!pr_mgr) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | info = g_new0(PRManagerInfo, 1); | 
|  | info->id = g_strdup(object_get_canonical_path_component(object)); | 
|  | info->connected = pr_manager_is_connected(pr_mgr); | 
|  | QAPI_LIST_APPEND(*tail, info); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | PRManagerInfoList *qmp_query_pr_managers(Error **errp) | 
|  | { | 
|  | PRManagerInfoList *head = NULL; | 
|  | PRManagerInfoList **prev = &head; | 
|  | Object *container = container_get(object_get_root(), PR_MANAGER_PATH); | 
|  |  | 
|  | object_child_foreach(container, query_one_pr_manager, &prev); | 
|  | return head; | 
|  | } | 
|  |  | 
|  | type_init(pr_manager_register_types); |