| /* | 
 |  * 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 = (const 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 = object_get_container(PR_MANAGER_PATH); | 
 |  | 
 |     object_child_foreach(container, query_one_pr_manager, &prev); | 
 |     return head; | 
 | } | 
 |  | 
 | type_init(pr_manager_register_types); |