diff --git a/include/scsi/pr-manager.h b/include/scsi/pr-manager.h index 71971ae34a..50a77b08fc 100644 --- a/include/scsi/pr-manager.h +++ b/include/scsi/pr-manager.h @@ -33,8 +33,10 @@ typedef struct PRManagerClass { /* */ int (*run)(PRManager *pr_mgr, int fd, struct sg_io_hdr *hdr); + bool (*is_connected)(PRManager *pr_mgr); } PRManagerClass; +bool pr_manager_is_connected(PRManager *pr_mgr); BlockAIOCB *pr_manager_execute(PRManager *pr_mgr, AioContext *ctx, int fd, struct sg_io_hdr *hdr, diff --git a/qapi/block.json b/qapi/block.json index ca807f176a..8765c29a06 100644 --- a/qapi/block.json +++ b/qapi/block.json @@ -77,6 +77,34 @@ { 'struct': 'BlockdevSnapshotInternal', 'data': { 'device': 'str', 'name': 'str' } } +## +# @PRManagerInfo: +# +# Information about a persistent reservation manager +# +# @id: the identifier of the persistent reservation manager +# +# @connected: true if the persistent reservation manager is connected to +# the underlying storage or helper +# +# Since: 3.0 +## +{ 'struct': 'PRManagerInfo', + 'data': {'id': 'str', 'connected': 'bool'} } + +## +# @query-pr-managers: +# +# Returns a list of information about each persistent reservation manager. +# +# Returns: a list of @PRManagerInfo for each persistent reservation manager +# +# Since: 3.0 +## +{ 'command': 'query-pr-managers', 'returns': ['PRManagerInfo'], + 'allow-preconfig': true } + + ## # @blockdev-snapshot-internal-sync: # diff --git a/scsi/pr-manager-helper.c b/scsi/pr-manager-helper.c index 0c0fe389b7..b11481be9e 100644 --- a/scsi/pr-manager-helper.c +++ b/scsi/pr-manager-helper.c @@ -235,6 +235,18 @@ out: return ret; } +static bool pr_manager_helper_is_connected(PRManager *p) +{ + PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(p); + bool result; + + qemu_mutex_lock(&pr_mgr->lock); + result = (pr_mgr->ioc != NULL); + qemu_mutex_unlock(&pr_mgr->lock); + + return result; +} + static void pr_manager_helper_complete(UserCreatable *uc, Error **errp) { PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(uc); @@ -284,6 +296,7 @@ static void pr_manager_helper_class_init(ObjectClass *klass, &error_abort); uc_klass->complete = pr_manager_helper_complete; prmgr_klass->run = pr_manager_helper_run; + prmgr_klass->is_connected = pr_manager_helper_is_connected; } static const TypeInfo pr_manager_helper_info = { diff --git a/scsi/pr-manager-stub.c b/scsi/pr-manager-stub.c index 632f17c7f9..738b6d7425 100644 --- a/scsi/pr-manager-stub.c +++ b/scsi/pr-manager-stub.c @@ -22,3 +22,9 @@ PRManager *pr_manager_lookup(const char *id, Error **errp) error_setg(errp, "No persistent reservation manager with id '%s'", id); return NULL; } + + +PRManagerInfoList *qmp_query_pr_managers(Error **errp) +{ + return NULL; +} diff --git a/scsi/pr-manager.c b/scsi/pr-manager.c index 87c45db5d4..2a8f300dde 100644 --- a/scsi/pr-manager.c +++ b/scsi/pr-manager.c @@ -17,6 +17,10 @@ #include "block/thread-pool.h" #include "scsi/pr-manager.h" #include "trace.h" +#include "qapi/qapi-types-block.h" +#include "qapi/qapi-commands-block.h" + +#define PR_MANAGER_PATH "/objects" typedef struct PRManagerData { PRManager *pr_mgr; @@ -64,6 +68,14 @@ BlockAIOCB *pr_manager_execute(PRManager *pr_mgr, data, complete, opaque); } +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, @@ -105,5 +117,38 @@ pr_manager_register_types(void) type_register_static(&pr_manager_info); } +static int query_one_pr_manager(Object *object, void *opaque) +{ + PRManagerInfoList ***prev = opaque; + PRManagerInfoList *elem; + PRManagerInfo *info; + PRManager *pr_mgr; + + pr_mgr = (PRManager *)object_dynamic_cast(object, TYPE_PR_MANAGER); + if (!pr_mgr) { + return 0; + } + + elem = g_new0(PRManagerInfoList, 1); + info = g_new0(PRManagerInfo, 1); + info->id = object_get_canonical_path_component(object); + info->connected = pr_manager_is_connected(pr_mgr); + elem->value = info; + elem->next = NULL; + + **prev = elem; + *prev = &elem->next; + return 0; +} + +PRManagerInfoList *qmp_query_pr_managers(Error **errp) +{ + PRManagerInfoList *head = NULL; + PRManagerInfoList **prev = &head; + Object *container = container_get(object_get_root(), PR_MANAGER_PATH); + + object_child_foreach(container, query_one_pr_manager, &prev); + return head; +} type_init(pr_manager_register_types);