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