mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-03 15:53:54 -06:00

This adds a function to shut down all block exports, and another one to shut down the block exports of a single type. The latter is used for now when stopping the NBD server. As soon as we implement support for multiple NBD servers, we'll need a per-server list of exports and it will be replaced by a function using that. As a side effect, the BlockExport layer has a list tracking all existing exports now. closed_exports loses its only user and can go away. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com> Message-Id: <20200924152717.287415-18-kwolf@redhat.com> Acked-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
169 lines
4 KiB
C
169 lines
4 KiB
C
/*
|
|
* Common block export infrastructure
|
|
*
|
|
* Copyright (c) 2012, 2020 Red Hat, Inc.
|
|
*
|
|
* Authors:
|
|
* Paolo Bonzini <pbonzini@redhat.com>
|
|
* Kevin Wolf <kwolf@redhat.com>
|
|
*
|
|
* This work is licensed under the terms of the GNU GPL, version 2 or
|
|
* later. See the COPYING file in the top-level directory.
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
|
|
#include "block/block.h"
|
|
#include "sysemu/block-backend.h"
|
|
#include "block/export.h"
|
|
#include "block/nbd.h"
|
|
#include "qapi/error.h"
|
|
#include "qapi/qapi-commands-block-export.h"
|
|
|
|
static const BlockExportDriver *blk_exp_drivers[] = {
|
|
&blk_exp_nbd,
|
|
};
|
|
|
|
/* Only accessed from the main thread */
|
|
static QLIST_HEAD(, BlockExport) block_exports =
|
|
QLIST_HEAD_INITIALIZER(block_exports);
|
|
|
|
static const BlockExportDriver *blk_exp_find_driver(BlockExportType type)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(blk_exp_drivers); i++) {
|
|
if (blk_exp_drivers[i]->type == type) {
|
|
return blk_exp_drivers[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
|
|
{
|
|
const BlockExportDriver *drv;
|
|
BlockExport *exp;
|
|
int ret;
|
|
|
|
drv = blk_exp_find_driver(export->type);
|
|
if (!drv) {
|
|
error_setg(errp, "No driver found for the requested export type");
|
|
return NULL;
|
|
}
|
|
|
|
assert(drv->instance_size >= sizeof(BlockExport));
|
|
exp = g_malloc0(drv->instance_size);
|
|
*exp = (BlockExport) {
|
|
.drv = drv,
|
|
.refcount = 1,
|
|
};
|
|
|
|
ret = drv->create(exp, export, errp);
|
|
if (ret < 0) {
|
|
g_free(exp);
|
|
return NULL;
|
|
}
|
|
|
|
QLIST_INSERT_HEAD(&block_exports, exp, next);
|
|
return exp;
|
|
}
|
|
|
|
/* Callers must hold exp->ctx lock */
|
|
void blk_exp_ref(BlockExport *exp)
|
|
{
|
|
assert(exp->refcount > 0);
|
|
exp->refcount++;
|
|
}
|
|
|
|
/* Runs in the main thread */
|
|
static void blk_exp_delete_bh(void *opaque)
|
|
{
|
|
BlockExport *exp = opaque;
|
|
AioContext *aio_context = exp->ctx;
|
|
|
|
aio_context_acquire(aio_context);
|
|
|
|
assert(exp->refcount == 0);
|
|
QLIST_REMOVE(exp, next);
|
|
exp->drv->delete(exp);
|
|
g_free(exp);
|
|
|
|
aio_context_release(aio_context);
|
|
}
|
|
|
|
/* Callers must hold exp->ctx lock */
|
|
void blk_exp_unref(BlockExport *exp)
|
|
{
|
|
assert(exp->refcount > 0);
|
|
if (--exp->refcount == 0) {
|
|
/* Touch the block_exports list only in the main thread */
|
|
aio_bh_schedule_oneshot(qemu_get_aio_context(), blk_exp_delete_bh,
|
|
exp);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Drops the user reference to the export and requests that all client
|
|
* connections and other internally held references start to shut down. When
|
|
* the function returns, there may still be active references while the export
|
|
* is in the process of shutting down.
|
|
*
|
|
* Acquires exp->ctx internally. Callers must *not* hold the lock.
|
|
*/
|
|
void blk_exp_request_shutdown(BlockExport *exp)
|
|
{
|
|
AioContext *aio_context = exp->ctx;
|
|
|
|
aio_context_acquire(aio_context);
|
|
exp->drv->request_shutdown(exp);
|
|
aio_context_release(aio_context);
|
|
}
|
|
|
|
/*
|
|
* Returns whether a block export of the given type exists.
|
|
* type == BLOCK_EXPORT_TYPE__MAX checks for an export of any type.
|
|
*/
|
|
static bool blk_exp_has_type(BlockExportType type)
|
|
{
|
|
BlockExport *exp;
|
|
|
|
if (type == BLOCK_EXPORT_TYPE__MAX) {
|
|
return !QLIST_EMPTY(&block_exports);
|
|
}
|
|
|
|
QLIST_FOREACH(exp, &block_exports, next) {
|
|
if (exp->drv->type == type) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/* type == BLOCK_EXPORT_TYPE__MAX for all types */
|
|
void blk_exp_close_all_type(BlockExportType type)
|
|
{
|
|
BlockExport *exp, *next;
|
|
|
|
assert(in_aio_context_home_thread(qemu_get_aio_context()));
|
|
|
|
QLIST_FOREACH_SAFE(exp, &block_exports, next, next) {
|
|
if (type != BLOCK_EXPORT_TYPE__MAX && exp->drv->type != type) {
|
|
continue;
|
|
}
|
|
blk_exp_request_shutdown(exp);
|
|
}
|
|
|
|
AIO_WAIT_WHILE(NULL, blk_exp_has_type(type));
|
|
}
|
|
|
|
void blk_exp_close_all(void)
|
|
{
|
|
blk_exp_close_all_type(BLOCK_EXPORT_TYPE__MAX);
|
|
}
|
|
|
|
void qmp_block_export_add(BlockExportOptions *export, Error **errp)
|
|
{
|
|
blk_exp_add(export, errp);
|
|
}
|