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 g_free(data); 43 trace_pr_manager_run(fd, hdr->cmdp[0], hdr->cmdp[1]); 44 45 /* The reference was taken in pr_manager_execute. */ 46 r = pr_mgr_class->run(pr_mgr, fd, hdr); 47 object_unref(OBJECT(pr_mgr)); 48 return r; 49 } 50 51 52 int coroutine_fn pr_manager_execute(PRManager *pr_mgr, AioContext *ctx, int fd, 53 struct sg_io_hdr *hdr) 54 { 55 ThreadPool *pool = aio_get_thread_pool(ctx); 56 PRManagerData data = { 57 .pr_mgr = pr_mgr, 58 .fd = fd, 59 .hdr = hdr, 60 }; 61 62 trace_pr_manager_execute(fd, hdr->cmdp[0], hdr->cmdp[1]); 63 64 /* The matching object_unref is in pr_manager_worker. */ 65 object_ref(OBJECT(pr_mgr)); 66 return thread_pool_submit_co(pool, pr_manager_worker, &data); 67 } 68 69 bool pr_manager_is_connected(PRManager *pr_mgr) 70 { 71 PRManagerClass *pr_mgr_class = 72 PR_MANAGER_GET_CLASS(pr_mgr); 73 74 return !pr_mgr_class->is_connected || pr_mgr_class->is_connected(pr_mgr); 75 } 76 77 static const TypeInfo pr_manager_info = { 78 .parent = TYPE_OBJECT, 79 .name = TYPE_PR_MANAGER, 80 .class_size = sizeof(PRManagerClass), 81 .abstract = true, 82 .interfaces = (InterfaceInfo[]) { 83 { TYPE_USER_CREATABLE }, 84 { } 85 } 86 }; 87 88 PRManager *pr_manager_lookup(const char *id, Error **errp) 89 { 90 Object *obj; 91 PRManager *pr_mgr; 92 93 obj = object_resolve_path_component(object_get_objects_root(), id); 94 if (!obj) { 95 error_setg(errp, "No persistent reservation manager with id '%s'", id); 96 return NULL; 97 } 98 99 pr_mgr = (PRManager *) 100 object_dynamic_cast(obj, 101 TYPE_PR_MANAGER); 102 if (!pr_mgr) { 103 error_setg(errp, 104 "Object with id '%s' is not a persistent reservation manager", 105 id); 106 return NULL; 107 } 108 109 return pr_mgr; 110 } 111 112 static void 113 pr_manager_register_types(void) 114 { 115 type_register_static(&pr_manager_info); 116 } 117 118 static int query_one_pr_manager(Object *object, void *opaque) 119 { 120 PRManagerInfoList ***prev = opaque; 121 PRManagerInfoList *elem; 122 PRManagerInfo *info; 123 PRManager *pr_mgr; 124 125 pr_mgr = (PRManager *)object_dynamic_cast(object, TYPE_PR_MANAGER); 126 if (!pr_mgr) { 127 return 0; 128 } 129 130 elem = g_new0(PRManagerInfoList, 1); 131 info = g_new0(PRManagerInfo, 1); 132 info->id = object_get_canonical_path_component(object); 133 info->connected = pr_manager_is_connected(pr_mgr); 134 elem->value = info; 135 elem->next = NULL; 136 137 **prev = elem; 138 *prev = &elem->next; 139 return 0; 140 } 141 142 PRManagerInfoList *qmp_query_pr_managers(Error **errp) 143 { 144 PRManagerInfoList *head = NULL; 145 PRManagerInfoList **prev = &head; 146 Object *container = container_get(object_get_root(), PR_MANAGER_PATH); 147 148 object_child_foreach(container, query_one_pr_manager, &prev); 149 return head; 150 } 151 152 type_init(pr_manager_register_types); 153