1 /* 2 * Persistent reservation manager abstract class 3 * 4 * Copyright (c) 2017 Red Hat, Inc. 5 * 6 * Author: Paolo Bonzini <pbonzini@redhat.com> 7 * 8 * This code is licensed under the LGPL. 9 * 10 */ 11 12 #include "qemu/osdep.h" 13 #include <scsi/sg.h> 14 15 #include "qapi/error.h" 16 #include "block/aio.h" 17 #include "block/thread-pool.h" 18 #include "scsi/pr-manager.h" 19 #include "trace.h" 20 #include "qapi/qapi-types-block.h" 21 #include "qemu/module.h" 22 #include "qapi/qapi-commands-block.h" 23 24 #define PR_MANAGER_PATH "/objects" 25 26 typedef struct PRManagerData { 27 PRManager *pr_mgr; 28 struct sg_io_hdr *hdr; 29 int fd; 30 } PRManagerData; 31 32 static int pr_manager_worker(void *opaque) 33 { 34 PRManagerData *data = opaque; 35 PRManager *pr_mgr = data->pr_mgr; 36 PRManagerClass *pr_mgr_class = 37 PR_MANAGER_GET_CLASS(pr_mgr); 38 struct sg_io_hdr *hdr = data->hdr; 39 int fd = data->fd; 40 int r; 41 42 trace_pr_manager_run(fd, hdr->cmdp[0], hdr->cmdp[1]); 43 44 /* The reference was taken in pr_manager_execute. */ 45 r = pr_mgr_class->run(pr_mgr, fd, hdr); 46 object_unref(OBJECT(pr_mgr)); 47 return r; 48 } 49 50 51 int coroutine_fn pr_manager_execute(PRManager *pr_mgr, AioContext *ctx, int fd, 52 struct sg_io_hdr *hdr) 53 { 54 PRManagerData data = { 55 .pr_mgr = pr_mgr, 56 .fd = fd, 57 .hdr = hdr, 58 }; 59 60 trace_pr_manager_execute(fd, hdr->cmdp[0], hdr->cmdp[1]); 61 62 /* The matching object_unref is in pr_manager_worker. */ 63 object_ref(OBJECT(pr_mgr)); 64 return thread_pool_submit_co(pr_manager_worker, &data); 65 } 66 67 bool pr_manager_is_connected(PRManager *pr_mgr) 68 { 69 PRManagerClass *pr_mgr_class = 70 PR_MANAGER_GET_CLASS(pr_mgr); 71 72 return !pr_mgr_class->is_connected || pr_mgr_class->is_connected(pr_mgr); 73 } 74 75 static const TypeInfo pr_manager_info = { 76 .parent = TYPE_OBJECT, 77 .name = TYPE_PR_MANAGER, 78 .class_size = sizeof(PRManagerClass), 79 .abstract = true, 80 .interfaces = (InterfaceInfo[]) { 81 { TYPE_USER_CREATABLE }, 82 { } 83 } 84 }; 85 86 PRManager *pr_manager_lookup(const char *id, Error **errp) 87 { 88 Object *obj; 89 PRManager *pr_mgr; 90 91 obj = object_resolve_path_component(object_get_objects_root(), id); 92 if (!obj) { 93 error_setg(errp, "No persistent reservation manager with id '%s'", id); 94 return NULL; 95 } 96 97 pr_mgr = (PRManager *) 98 object_dynamic_cast(obj, 99 TYPE_PR_MANAGER); 100 if (!pr_mgr) { 101 error_setg(errp, 102 "Object with id '%s' is not a persistent reservation manager", 103 id); 104 return NULL; 105 } 106 107 return pr_mgr; 108 } 109 110 static void 111 pr_manager_register_types(void) 112 { 113 type_register_static(&pr_manager_info); 114 } 115 116 static int query_one_pr_manager(Object *object, void *opaque) 117 { 118 PRManagerInfoList ***tail = opaque; 119 PRManagerInfo *info; 120 PRManager *pr_mgr; 121 122 pr_mgr = (PRManager *)object_dynamic_cast(object, TYPE_PR_MANAGER); 123 if (!pr_mgr) { 124 return 0; 125 } 126 127 info = g_new0(PRManagerInfo, 1); 128 info->id = g_strdup(object_get_canonical_path_component(object)); 129 info->connected = pr_manager_is_connected(pr_mgr); 130 QAPI_LIST_APPEND(*tail, info); 131 return 0; 132 } 133 134 PRManagerInfoList *qmp_query_pr_managers(Error **errp) 135 { 136 PRManagerInfoList *head = NULL; 137 PRManagerInfoList **prev = &head; 138 Object *container = container_get(object_get_root(), PR_MANAGER_PATH); 139 140 object_child_foreach(container, query_one_pr_manager, &prev); 141 return head; 142 } 143 144 type_init(pr_manager_register_types); 145