aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--blockdev-nbd.c24
-rw-r--r--include/block/nbd.h1
-rw-r--r--nbd/server.c13
-rw-r--r--qapi/block.json41
4 files changed, 79 insertions, 0 deletions
diff --git a/blockdev-nbd.c b/blockdev-nbd.c
index 104789e521..a9f79c6778 100644
--- a/blockdev-nbd.c
+++ b/blockdev-nbd.c
@@ -189,6 +189,30 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name,
nbd_export_put(exp);
}
+void qmp_nbd_server_remove(const char *name,
+ bool has_mode, NbdServerRemoveMode mode,
+ Error **errp)
+{
+ NBDExport *exp;
+
+ if (!nbd_server) {
+ error_setg(errp, "NBD server not running");
+ return;
+ }
+
+ exp = nbd_export_find(name);
+ if (exp == NULL) {
+ error_setg(errp, "Export '%s' is not found", name);
+ return;
+ }
+
+ if (!has_mode) {
+ mode = NBD_SERVER_REMOVE_MODE_SAFE;
+ }
+
+ nbd_export_remove(exp, mode, errp);
+}
+
void qmp_nbd_server_stop(Error **errp)
{
nbd_export_close_all();
diff --git a/include/block/nbd.h b/include/block/nbd.h
index 978e443366..ee74ec391a 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -261,6 +261,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size,
bool writethrough, BlockBackend *on_eject_blk,
Error **errp);
void nbd_export_close(NBDExport *exp);
+void nbd_export_remove(NBDExport *exp, NbdServerRemoveMode mode, Error **errp);
void nbd_export_get(NBDExport *exp);
void nbd_export_put(NBDExport *exp);
diff --git a/nbd/server.c b/nbd/server.c
index 6caa8d17be..112e3f69df 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -1177,6 +1177,19 @@ void nbd_export_close(NBDExport *exp)
nbd_export_put(exp);
}
+void nbd_export_remove(NBDExport *exp, NbdServerRemoveMode mode, Error **errp)
+{
+ if (mode == NBD_SERVER_REMOVE_MODE_HARD || QTAILQ_EMPTY(&exp->clients)) {
+ nbd_export_close(exp);
+ return;
+ }
+
+ assert(mode == NBD_SERVER_REMOVE_MODE_SAFE);
+
+ error_setg(errp, "export '%s' still in use", exp->name);
+ error_append_hint(errp, "Use mode='hard' to force client disconnect\n");
+}
+
void nbd_export_get(NBDExport *exp)
{
assert(exp->refcount > 0);
diff --git a/qapi/block.json b/qapi/block.json
index 353e3a45bd..c694524002 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -228,6 +228,47 @@
'data': {'device': 'str', '*name': 'str', '*writable': 'bool'} }
##
+# @NbdServerRemoveMode:
+#
+# Mode for removing an NBD export.
+#
+# @safe: Remove export if there are no existing connections, fail otherwise.
+#
+# @hard: Drop all connections immediately and remove export.
+#
+# Potential additional modes to be added in the future:
+#
+# hide: Just hide export from new clients, leave existing connections as is.
+# Remove export after all clients are disconnected.
+#
+# soft: Hide export from new clients, answer with ESHUTDOWN for all further
+# requests from existing clients.
+#
+# Since: 2.12
+##
+{'enum': 'NbdServerRemoveMode', 'data': ['safe', 'hard']}
+
+##
+# @nbd-server-remove:
+#
+# Remove NBD export by name.
+#
+# @name: Export name.
+#
+# @mode: Mode of command operation. See @NbdServerRemoveMode description.
+# Default is 'safe'.
+#
+# Returns: error if
+# - the server is not running
+# - export is not found
+# - mode is 'safe' and there are existing connections
+#
+# Since: 2.12
+##
+{ 'command': 'nbd-server-remove',
+ 'data': {'name': 'str', '*mode': 'NbdServerRemoveMode'} }
+
+##
# @nbd-server-stop:
#
# Stop QEMU's embedded NBD server, and unregister all devices previously