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