mirror of
https://github.com/qemu/qemu.git
synced 2026-07-08 17:46:10 +00:00
While most objects can perform all their cleanup in the finalizer method, there can be interactions with other resources / subsystems / threads which require that some cleanup be performed on an user creatable object before unparenting it and entering finalization. The current 'can_be_deleted' method runs in the deletion path and is intended to be used to block deletion. While it could be used to perform cleanup tasks, its name suggests it should be free of side-effects. Generalize this by renaming it to 'prepare_delete', explicitly allowing for cleanup to be provided. Existing users of 'can_be_deleted' are re-written, which provides them with more detailed/tailored error messages. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> Message-ID: <20260706135824.2623960-2-berrange@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
663 lines
20 KiB
C
663 lines
20 KiB
C
/*
|
|
* QEMU Crypto Device Implementation
|
|
*
|
|
* Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
|
|
*
|
|
* Authors:
|
|
* Gonglei <arei.gonglei@huawei.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "system/cryptodev.h"
|
|
#include "system/stats.h"
|
|
#include "qapi/error.h"
|
|
#include "qapi/qapi-commands-cryptodev.h"
|
|
#include "qapi/qapi-types-stats.h"
|
|
#include "qapi/visitor.h"
|
|
#include "qemu/config-file.h"
|
|
#include "qemu/error-report.h"
|
|
#include "qemu/main-loop.h"
|
|
#include "qom/object_interfaces.h"
|
|
#include "hw/virtio/virtio-crypto.h"
|
|
|
|
#define SYM_ENCRYPT_OPS_STR "sym-encrypt-ops"
|
|
#define SYM_DECRYPT_OPS_STR "sym-decrypt-ops"
|
|
#define SYM_ENCRYPT_BYTES_STR "sym-encrypt-bytes"
|
|
#define SYM_DECRYPT_BYTES_STR "sym-decrypt-bytes"
|
|
|
|
#define ASYM_ENCRYPT_OPS_STR "asym-encrypt-ops"
|
|
#define ASYM_DECRYPT_OPS_STR "asym-decrypt-ops"
|
|
#define ASYM_SIGN_OPS_STR "asym-sign-ops"
|
|
#define ASYM_VERIFY_OPS_STR "asym-verify-ops"
|
|
#define ASYM_ENCRYPT_BYTES_STR "asym-encrypt-bytes"
|
|
#define ASYM_DECRYPT_BYTES_STR "asym-decrypt-bytes"
|
|
#define ASYM_SIGN_BYTES_STR "asym-sign-bytes"
|
|
#define ASYM_VERIFY_BYTES_STR "asym-verify-bytes"
|
|
|
|
typedef struct StatsArgs {
|
|
union StatsResultsType {
|
|
StatsResultList **stats;
|
|
StatsSchemaList **schema;
|
|
} result;
|
|
strList *names;
|
|
Error **errp;
|
|
} StatsArgs;
|
|
|
|
static QTAILQ_HEAD(, CryptoDevBackendClient) crypto_clients;
|
|
|
|
static int qmp_query_cryptodev_foreach(Object *obj, void *data)
|
|
{
|
|
CryptoDevBackend *backend;
|
|
QCryptodevInfoList **infolist = data;
|
|
uint32_t services, i;
|
|
|
|
if (!object_dynamic_cast(obj, TYPE_CRYPTODEV_BACKEND)) {
|
|
return 0;
|
|
}
|
|
|
|
QCryptodevInfo *info = g_new0(QCryptodevInfo, 1);
|
|
info->id = g_strdup(object_get_canonical_path_component(obj));
|
|
|
|
backend = CRYPTODEV_BACKEND(obj);
|
|
services = backend->conf.crypto_services;
|
|
for (i = 0; i < QCRYPTODEV_BACKEND_SERVICE_TYPE__MAX; i++) {
|
|
if (services & (1 << i)) {
|
|
QAPI_LIST_PREPEND(info->service, i);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < backend->conf.peers.queues; i++) {
|
|
CryptoDevBackendClient *cc = backend->conf.peers.ccs[i];
|
|
QCryptodevBackendClient *client = g_new0(QCryptodevBackendClient, 1);
|
|
|
|
client->queue = cc->queue_index;
|
|
client->type = cc->type;
|
|
QAPI_LIST_PREPEND(info->client, client);
|
|
}
|
|
|
|
QAPI_LIST_PREPEND(*infolist, info);
|
|
|
|
return 0;
|
|
}
|
|
|
|
QCryptodevInfoList *qmp_query_cryptodev(Error **errp)
|
|
{
|
|
QCryptodevInfoList *list = NULL;
|
|
Object *objs = object_get_container("objects");
|
|
|
|
object_child_foreach(objs, qmp_query_cryptodev_foreach, &list);
|
|
|
|
return list;
|
|
}
|
|
|
|
CryptoDevBackendClient *cryptodev_backend_new_client(void)
|
|
{
|
|
CryptoDevBackendClient *cc;
|
|
|
|
cc = g_new0(CryptoDevBackendClient, 1);
|
|
QTAILQ_INSERT_TAIL(&crypto_clients, cc, next);
|
|
|
|
return cc;
|
|
}
|
|
|
|
void cryptodev_backend_free_client(
|
|
CryptoDevBackendClient *cc)
|
|
{
|
|
QTAILQ_REMOVE(&crypto_clients, cc, next);
|
|
g_free(cc->info_str);
|
|
g_free(cc);
|
|
}
|
|
|
|
void cryptodev_backend_cleanup(
|
|
CryptoDevBackend *backend,
|
|
Error **errp)
|
|
{
|
|
CryptoDevBackendClass *bc =
|
|
CRYPTODEV_BACKEND_GET_CLASS(backend);
|
|
|
|
if (bc->cleanup) {
|
|
bc->cleanup(backend, errp);
|
|
}
|
|
|
|
g_free(backend->sym_stat);
|
|
g_free(backend->asym_stat);
|
|
}
|
|
|
|
int cryptodev_backend_create_session(
|
|
CryptoDevBackend *backend,
|
|
CryptoDevBackendSessionInfo *sess_info,
|
|
uint32_t queue_index,
|
|
CryptoDevCompletionFunc cb,
|
|
void *opaque)
|
|
{
|
|
CryptoDevBackendClass *bc =
|
|
CRYPTODEV_BACKEND_GET_CLASS(backend);
|
|
|
|
if (bc->create_session) {
|
|
return bc->create_session(backend, sess_info, queue_index, cb, opaque);
|
|
}
|
|
return -VIRTIO_CRYPTO_NOTSUPP;
|
|
}
|
|
|
|
int cryptodev_backend_close_session(
|
|
CryptoDevBackend *backend,
|
|
uint64_t session_id,
|
|
uint32_t queue_index,
|
|
CryptoDevCompletionFunc cb,
|
|
void *opaque)
|
|
{
|
|
CryptoDevBackendClass *bc =
|
|
CRYPTODEV_BACKEND_GET_CLASS(backend);
|
|
|
|
if (bc->close_session) {
|
|
return bc->close_session(backend, session_id, queue_index, cb, opaque);
|
|
}
|
|
return -VIRTIO_CRYPTO_NOTSUPP;
|
|
}
|
|
|
|
static int cryptodev_backend_operation(
|
|
CryptoDevBackend *backend,
|
|
CryptoDevBackendOpInfo *op_info)
|
|
{
|
|
CryptoDevBackendClass *bc =
|
|
CRYPTODEV_BACKEND_GET_CLASS(backend);
|
|
|
|
if (bc->do_op) {
|
|
return bc->do_op(backend, op_info);
|
|
}
|
|
return -VIRTIO_CRYPTO_NOTSUPP;
|
|
}
|
|
|
|
static int cryptodev_backend_account(CryptoDevBackend *backend,
|
|
CryptoDevBackendOpInfo *op_info)
|
|
{
|
|
enum QCryptodevBackendAlgoType algtype = op_info->algtype;
|
|
int len;
|
|
|
|
if (algtype == QCRYPTODEV_BACKEND_ALGO_TYPE_ASYM) {
|
|
CryptoDevBackendAsymOpInfo *asym_op_info = op_info->u.asym_op_info;
|
|
len = asym_op_info->src_len;
|
|
|
|
if (unlikely(!backend->asym_stat)) {
|
|
error_report("cryptodev: Unexpected asym operation");
|
|
return -VIRTIO_CRYPTO_NOTSUPP;
|
|
}
|
|
switch (op_info->op_code) {
|
|
case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
|
|
CryptodevAsymStatIncEncrypt(backend, len);
|
|
break;
|
|
case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
|
|
CryptodevAsymStatIncDecrypt(backend, len);
|
|
break;
|
|
case VIRTIO_CRYPTO_AKCIPHER_SIGN:
|
|
CryptodevAsymStatIncSign(backend, len);
|
|
break;
|
|
case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
|
|
CryptodevAsymStatIncVerify(backend, len);
|
|
break;
|
|
default:
|
|
return -VIRTIO_CRYPTO_NOTSUPP;
|
|
}
|
|
} else if (algtype == QCRYPTODEV_BACKEND_ALGO_TYPE_SYM) {
|
|
CryptoDevBackendSymOpInfo *sym_op_info = op_info->u.sym_op_info;
|
|
len = sym_op_info->src_len;
|
|
|
|
if (unlikely(!backend->sym_stat)) {
|
|
error_report("cryptodev: Unexpected sym operation");
|
|
return -VIRTIO_CRYPTO_NOTSUPP;
|
|
}
|
|
switch (op_info->op_code) {
|
|
case VIRTIO_CRYPTO_CIPHER_ENCRYPT:
|
|
CryptodevSymStatIncEncrypt(backend, len);
|
|
break;
|
|
case VIRTIO_CRYPTO_CIPHER_DECRYPT:
|
|
CryptodevSymStatIncDecrypt(backend, len);
|
|
break;
|
|
default:
|
|
return -VIRTIO_CRYPTO_NOTSUPP;
|
|
}
|
|
} else {
|
|
error_report("Unsupported cryptodev alg type: %" PRIu32 "", algtype);
|
|
return -VIRTIO_CRYPTO_NOTSUPP;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static void cryptodev_backend_throttle_timer_cb(void *opaque)
|
|
{
|
|
CryptoDevBackend *backend = (CryptoDevBackend *)opaque;
|
|
CryptoDevBackendOpInfo *op_info, *tmpop;
|
|
int ret;
|
|
|
|
QTAILQ_FOREACH_SAFE(op_info, &backend->opinfos, next, tmpop) {
|
|
QTAILQ_REMOVE(&backend->opinfos, op_info, next);
|
|
ret = cryptodev_backend_account(backend, op_info);
|
|
if (ret < 0) {
|
|
op_info->cb(op_info->opaque, ret);
|
|
continue;
|
|
}
|
|
|
|
throttle_account(&backend->ts, THROTTLE_WRITE, ret);
|
|
cryptodev_backend_operation(backend, op_info);
|
|
if (throttle_enabled(&backend->tc) &&
|
|
throttle_schedule_timer(&backend->ts, &backend->tt,
|
|
THROTTLE_WRITE)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int cryptodev_backend_crypto_operation(
|
|
CryptoDevBackend *backend,
|
|
CryptoDevBackendOpInfo *op_info)
|
|
{
|
|
int ret;
|
|
|
|
if (!throttle_enabled(&backend->tc)) {
|
|
goto do_account;
|
|
}
|
|
|
|
if (throttle_schedule_timer(&backend->ts, &backend->tt, THROTTLE_WRITE) ||
|
|
!QTAILQ_EMPTY(&backend->opinfos)) {
|
|
QTAILQ_INSERT_TAIL(&backend->opinfos, op_info, next);
|
|
return 0;
|
|
}
|
|
|
|
do_account:
|
|
ret = cryptodev_backend_account(backend, op_info);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
throttle_account(&backend->ts, THROTTLE_WRITE, ret);
|
|
|
|
return cryptodev_backend_operation(backend, op_info);
|
|
}
|
|
|
|
static void
|
|
cryptodev_backend_get_queues(Object *obj, Visitor *v, const char *name,
|
|
void *opaque, Error **errp)
|
|
{
|
|
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
|
uint32_t value = backend->conf.peers.queues;
|
|
|
|
visit_type_uint32(v, name, &value, errp);
|
|
}
|
|
|
|
static void
|
|
cryptodev_backend_set_queues(Object *obj, Visitor *v, const char *name,
|
|
void *opaque, Error **errp)
|
|
{
|
|
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
|
uint32_t value;
|
|
|
|
if (!visit_type_uint32(v, name, &value, errp)) {
|
|
return;
|
|
}
|
|
if (!value) {
|
|
error_setg(errp, "Property '%s.%s' doesn't take value '%" PRIu32 "'",
|
|
object_get_typename(obj), name, value);
|
|
return;
|
|
}
|
|
backend->conf.peers.queues = value;
|
|
}
|
|
|
|
static void cryptodev_backend_set_throttle(CryptoDevBackend *backend, int field,
|
|
uint64_t value, Error **errp)
|
|
{
|
|
uint64_t orig = backend->tc.buckets[field].avg;
|
|
bool enabled = throttle_enabled(&backend->tc);
|
|
|
|
if (orig == value) {
|
|
return;
|
|
}
|
|
|
|
backend->tc.buckets[field].avg = value;
|
|
if (!throttle_enabled(&backend->tc)) {
|
|
throttle_timers_destroy(&backend->tt);
|
|
cryptodev_backend_throttle_timer_cb(backend); /* drain opinfos */
|
|
return;
|
|
}
|
|
|
|
if (!throttle_is_valid(&backend->tc, errp)) {
|
|
backend->tc.buckets[field].avg = orig; /* revert change */
|
|
return;
|
|
}
|
|
|
|
if (!enabled) {
|
|
throttle_init(&backend->ts);
|
|
throttle_timers_init(&backend->tt, qemu_get_aio_context(),
|
|
QEMU_CLOCK_REALTIME, NULL,
|
|
cryptodev_backend_throttle_timer_cb, backend);
|
|
}
|
|
|
|
throttle_config(&backend->ts, QEMU_CLOCK_REALTIME, &backend->tc);
|
|
}
|
|
|
|
static void cryptodev_backend_get_bps(Object *obj, Visitor *v,
|
|
const char *name, void *opaque,
|
|
Error **errp)
|
|
{
|
|
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
|
uint64_t value = backend->tc.buckets[THROTTLE_BPS_TOTAL].avg;
|
|
|
|
visit_type_uint64(v, name, &value, errp);
|
|
}
|
|
|
|
static void cryptodev_backend_set_bps(Object *obj, Visitor *v, const char *name,
|
|
void *opaque, Error **errp)
|
|
{
|
|
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
|
uint64_t value;
|
|
|
|
if (!visit_type_uint64(v, name, &value, errp)) {
|
|
return;
|
|
}
|
|
|
|
cryptodev_backend_set_throttle(backend, THROTTLE_BPS_TOTAL, value, errp);
|
|
}
|
|
|
|
static void cryptodev_backend_get_ops(Object *obj, Visitor *v, const char *name,
|
|
void *opaque, Error **errp)
|
|
{
|
|
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
|
uint64_t value = backend->tc.buckets[THROTTLE_OPS_TOTAL].avg;
|
|
|
|
visit_type_uint64(v, name, &value, errp);
|
|
}
|
|
|
|
static void cryptodev_backend_set_ops(Object *obj, Visitor *v,
|
|
const char *name, void *opaque,
|
|
Error **errp)
|
|
{
|
|
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
|
uint64_t value;
|
|
|
|
if (!visit_type_uint64(v, name, &value, errp)) {
|
|
return;
|
|
}
|
|
|
|
cryptodev_backend_set_throttle(backend, THROTTLE_OPS_TOTAL, value, errp);
|
|
}
|
|
|
|
static void
|
|
cryptodev_backend_complete(UserCreatable *uc, Error **errp)
|
|
{
|
|
ERRP_GUARD();
|
|
CryptoDevBackend *backend = CRYPTODEV_BACKEND(uc);
|
|
CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_GET_CLASS(uc);
|
|
uint32_t services;
|
|
uint64_t value;
|
|
|
|
QTAILQ_INIT(&backend->opinfos);
|
|
value = backend->tc.buckets[THROTTLE_OPS_TOTAL].avg;
|
|
cryptodev_backend_set_throttle(backend, THROTTLE_OPS_TOTAL, value, errp);
|
|
if (*errp) {
|
|
return;
|
|
}
|
|
value = backend->tc.buckets[THROTTLE_BPS_TOTAL].avg;
|
|
cryptodev_backend_set_throttle(backend, THROTTLE_BPS_TOTAL, value, errp);
|
|
if (*errp) {
|
|
return;
|
|
}
|
|
|
|
if (bc->init) {
|
|
bc->init(backend, errp);
|
|
if (*errp) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
services = backend->conf.crypto_services;
|
|
if (services & (1 << QCRYPTODEV_BACKEND_SERVICE_TYPE_CIPHER)) {
|
|
backend->sym_stat = g_new0(CryptodevBackendSymStat, 1);
|
|
}
|
|
|
|
if (services & (1 << QCRYPTODEV_BACKEND_SERVICE_TYPE_AKCIPHER)) {
|
|
backend->asym_stat = g_new0(CryptodevBackendAsymStat, 1);
|
|
}
|
|
}
|
|
|
|
void cryptodev_backend_set_used(CryptoDevBackend *backend, bool used)
|
|
{
|
|
backend->is_used = used;
|
|
}
|
|
|
|
bool cryptodev_backend_is_used(CryptoDevBackend *backend)
|
|
{
|
|
return backend->is_used;
|
|
}
|
|
|
|
void cryptodev_backend_set_ready(CryptoDevBackend *backend, bool ready)
|
|
{
|
|
backend->ready = ready;
|
|
}
|
|
|
|
bool cryptodev_backend_is_ready(CryptoDevBackend *backend)
|
|
{
|
|
return backend->ready;
|
|
}
|
|
|
|
static bool
|
|
cryptodev_backend_prepare_delete(UserCreatable *uc, Error **errp)
|
|
{
|
|
if (cryptodev_backend_is_used(CRYPTODEV_BACKEND(uc))) {
|
|
error_setg(errp,
|
|
"Cannot delete cryptodev backend '%s' that is in use",
|
|
object_get_canonical_path_component(OBJECT(uc)));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static void cryptodev_backend_instance_init(Object *obj)
|
|
{
|
|
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
|
|
|
/* Initialize devices' queues property to 1 */
|
|
object_property_set_int(obj, "queues", 1, NULL);
|
|
|
|
throttle_config_init(&backend->tc);
|
|
}
|
|
|
|
static void cryptodev_backend_finalize(Object *obj)
|
|
{
|
|
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
|
|
|
cryptodev_backend_cleanup(backend, NULL);
|
|
if (throttle_enabled(&backend->tc)) {
|
|
throttle_timers_destroy(&backend->tt);
|
|
}
|
|
}
|
|
|
|
static StatsList *cryptodev_backend_stats_add(const char *name, int64_t *val,
|
|
StatsList *stats_list)
|
|
{
|
|
Stats *stats = g_new0(Stats, 1);
|
|
|
|
stats->name = g_strdup(name);
|
|
stats->value = g_new0(StatsValue, 1);
|
|
stats->value->type = QTYPE_QNUM;
|
|
stats->value->u.scalar = *val;
|
|
|
|
QAPI_LIST_PREPEND(stats_list, stats);
|
|
return stats_list;
|
|
}
|
|
|
|
static int cryptodev_backend_stats_query(Object *obj, void *data)
|
|
{
|
|
StatsArgs *stats_args = data;
|
|
StatsResultList **stats_results = stats_args->result.stats;
|
|
StatsList *stats_list = NULL;
|
|
StatsResult *entry;
|
|
CryptoDevBackend *backend;
|
|
CryptodevBackendSymStat *sym_stat;
|
|
CryptodevBackendAsymStat *asym_stat;
|
|
|
|
if (!object_dynamic_cast(obj, TYPE_CRYPTODEV_BACKEND)) {
|
|
return 0;
|
|
}
|
|
|
|
backend = CRYPTODEV_BACKEND(obj);
|
|
sym_stat = backend->sym_stat;
|
|
if (sym_stat) {
|
|
stats_list = cryptodev_backend_stats_add(SYM_ENCRYPT_OPS_STR,
|
|
&sym_stat->encrypt_ops, stats_list);
|
|
stats_list = cryptodev_backend_stats_add(SYM_DECRYPT_OPS_STR,
|
|
&sym_stat->decrypt_ops, stats_list);
|
|
stats_list = cryptodev_backend_stats_add(SYM_ENCRYPT_BYTES_STR,
|
|
&sym_stat->encrypt_bytes, stats_list);
|
|
stats_list = cryptodev_backend_stats_add(SYM_DECRYPT_BYTES_STR,
|
|
&sym_stat->decrypt_bytes, stats_list);
|
|
}
|
|
|
|
asym_stat = backend->asym_stat;
|
|
if (asym_stat) {
|
|
stats_list = cryptodev_backend_stats_add(ASYM_ENCRYPT_OPS_STR,
|
|
&asym_stat->encrypt_ops, stats_list);
|
|
stats_list = cryptodev_backend_stats_add(ASYM_DECRYPT_OPS_STR,
|
|
&asym_stat->decrypt_ops, stats_list);
|
|
stats_list = cryptodev_backend_stats_add(ASYM_SIGN_OPS_STR,
|
|
&asym_stat->sign_ops, stats_list);
|
|
stats_list = cryptodev_backend_stats_add(ASYM_VERIFY_OPS_STR,
|
|
&asym_stat->verify_ops, stats_list);
|
|
stats_list = cryptodev_backend_stats_add(ASYM_ENCRYPT_BYTES_STR,
|
|
&asym_stat->encrypt_bytes, stats_list);
|
|
stats_list = cryptodev_backend_stats_add(ASYM_DECRYPT_BYTES_STR,
|
|
&asym_stat->decrypt_bytes, stats_list);
|
|
stats_list = cryptodev_backend_stats_add(ASYM_SIGN_BYTES_STR,
|
|
&asym_stat->sign_bytes, stats_list);
|
|
stats_list = cryptodev_backend_stats_add(ASYM_VERIFY_BYTES_STR,
|
|
&asym_stat->verify_bytes, stats_list);
|
|
}
|
|
|
|
entry = g_new0(StatsResult, 1);
|
|
entry->provider = STATS_PROVIDER_CRYPTODEV;
|
|
entry->qom_path = object_get_canonical_path(obj);
|
|
entry->stats = stats_list;
|
|
QAPI_LIST_PREPEND(*stats_results, entry);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void cryptodev_backend_stats_cb(StatsResultList **result,
|
|
StatsTarget target,
|
|
strList *names, strList *targets,
|
|
Error **errp)
|
|
{
|
|
switch (target) {
|
|
case STATS_TARGET_CRYPTODEV:
|
|
{
|
|
Object *objs = object_get_container("objects");
|
|
StatsArgs stats_args;
|
|
stats_args.result.stats = result;
|
|
stats_args.names = names;
|
|
stats_args.errp = errp;
|
|
|
|
object_child_foreach(objs, cryptodev_backend_stats_query, &stats_args);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static StatsSchemaValueList *cryptodev_backend_schemas_add(const char *name,
|
|
StatsSchemaValueList *list)
|
|
{
|
|
StatsSchemaValueList *schema_entry = g_new0(StatsSchemaValueList, 1);
|
|
|
|
schema_entry->value = g_new0(StatsSchemaValue, 1);
|
|
schema_entry->value->type = STATS_TYPE_CUMULATIVE;
|
|
schema_entry->value->name = g_strdup(name);
|
|
schema_entry->next = list;
|
|
|
|
return schema_entry;
|
|
}
|
|
|
|
static void cryptodev_backend_schemas_cb(StatsSchemaList **result,
|
|
Error **errp)
|
|
{
|
|
StatsSchemaValueList *stats_list = NULL;
|
|
const char *sym_stats[] = { SYM_ENCRYPT_OPS_STR, SYM_DECRYPT_OPS_STR,
|
|
SYM_ENCRYPT_BYTES_STR, SYM_DECRYPT_BYTES_STR };
|
|
const char *asym_stats[] = { ASYM_ENCRYPT_OPS_STR, ASYM_DECRYPT_OPS_STR,
|
|
ASYM_SIGN_OPS_STR, ASYM_VERIFY_OPS_STR,
|
|
ASYM_ENCRYPT_BYTES_STR, ASYM_DECRYPT_BYTES_STR,
|
|
ASYM_SIGN_BYTES_STR, ASYM_VERIFY_BYTES_STR };
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(sym_stats); i++) {
|
|
stats_list = cryptodev_backend_schemas_add(sym_stats[i], stats_list);
|
|
}
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(asym_stats); i++) {
|
|
stats_list = cryptodev_backend_schemas_add(asym_stats[i], stats_list);
|
|
}
|
|
|
|
add_stats_schema(result, STATS_PROVIDER_CRYPTODEV, STATS_TARGET_CRYPTODEV,
|
|
stats_list);
|
|
}
|
|
|
|
static void
|
|
cryptodev_backend_class_init(ObjectClass *oc, const void *data)
|
|
{
|
|
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
|
|
|
ucc->complete = cryptodev_backend_complete;
|
|
ucc->prepare_delete = cryptodev_backend_prepare_delete;
|
|
|
|
QTAILQ_INIT(&crypto_clients);
|
|
object_class_property_add(oc, "queues", "uint32",
|
|
cryptodev_backend_get_queues,
|
|
cryptodev_backend_set_queues,
|
|
NULL, NULL);
|
|
object_class_property_add(oc, "throttle-bps", "uint64",
|
|
cryptodev_backend_get_bps,
|
|
cryptodev_backend_set_bps,
|
|
NULL, NULL);
|
|
object_class_property_add(oc, "throttle-ops", "uint64",
|
|
cryptodev_backend_get_ops,
|
|
cryptodev_backend_set_ops,
|
|
NULL, NULL);
|
|
|
|
add_stats_callbacks(STATS_PROVIDER_CRYPTODEV, cryptodev_backend_stats_cb,
|
|
cryptodev_backend_schemas_cb);
|
|
}
|
|
|
|
static const TypeInfo cryptodev_backend_info = {
|
|
.name = TYPE_CRYPTODEV_BACKEND,
|
|
.parent = TYPE_OBJECT,
|
|
.instance_size = sizeof(CryptoDevBackend),
|
|
.instance_init = cryptodev_backend_instance_init,
|
|
.instance_finalize = cryptodev_backend_finalize,
|
|
.class_size = sizeof(CryptoDevBackendClass),
|
|
.class_init = cryptodev_backend_class_init,
|
|
.interfaces = (const InterfaceInfo[]) {
|
|
{ TYPE_USER_CREATABLE },
|
|
{ }
|
|
}
|
|
};
|
|
|
|
static void
|
|
cryptodev_backend_register_types(void)
|
|
{
|
|
type_register_static(&cryptodev_backend_info);
|
|
}
|
|
|
|
type_init(cryptodev_backend_register_types);
|