Message ID | 1f4eeed1d066c6cbb8d05ffa9585f6e87b34aac6.1609167865.git.lukasstraub2@web.de |
---|---|
State | New |
Headers | show |
Series | Introduce 'yank' oob qmp command to recover from hanging qemu | expand |
On Mon, Dec 28, 2020 at 7:08 PM Lukas Straub <lukasstraub2@web.de> wrote: > Register a yank function to shutdown the socket on yank. > > Signed-off-by: Lukas Straub <lukasstraub2@web.de> > Acked-by: Stefan Hajnoczi <stefanha@redhat.com> > Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- > chardev/char-socket.c | 34 ++++++++++++++++++++++++++++++++++ > 1 file changed, 34 insertions(+) > > diff --git a/chardev/char-socket.c b/chardev/char-socket.c > index 213a4c8dd0..8a707d766c 100644 > --- a/chardev/char-socket.c > +++ b/chardev/char-socket.c > @@ -34,6 +34,7 @@ > #include "qapi/error.h" > #include "qapi/clone-visitor.h" > #include "qapi/qapi-visit-sockets.h" > +#include "qemu/yank.h" > > #include "chardev/char-io.h" > #include "qom/object.h" > @@ -70,6 +71,7 @@ struct SocketChardev { > size_t read_msgfds_num; > int *write_msgfds; > size_t write_msgfds_num; > + bool registered_yank; > > SocketAddress *addr; > bool is_listen; > @@ -415,6 +417,12 @@ static void tcp_chr_free_connection(Chardev *chr) > > tcp_set_msgfds(chr, NULL, 0); > remove_fd_in_watch(chr); > + if (s->state == TCP_CHARDEV_STATE_CONNECTING > + || s->state == TCP_CHARDEV_STATE_CONNECTED) { > + yank_unregister_function(CHARDEV_YANK_INSTANCE(chr->label), > + yank_generic_iochannel, > + QIO_CHANNEL(s->sioc)); > + } > object_unref(OBJECT(s->sioc)); > s->sioc = NULL; > object_unref(OBJECT(s->ioc)); > @@ -932,6 +940,9 @@ static int tcp_chr_add_client(Chardev *chr, int fd) > } > tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING); > tcp_chr_set_client_ioc_name(chr, sioc); > + yank_register_function(CHARDEV_YANK_INSTANCE(chr->label), > + yank_generic_iochannel, > + QIO_CHANNEL(sioc)); > ret = tcp_chr_new_client(chr, sioc); > object_unref(OBJECT(sioc)); > return ret; > @@ -946,6 +957,9 @@ static void tcp_chr_accept(QIONetListener *listener, > > tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING); > tcp_chr_set_client_ioc_name(chr, cioc); > + yank_register_function(CHARDEV_YANK_INSTANCE(chr->label), > + yank_generic_iochannel, > + QIO_CHANNEL(cioc)); > tcp_chr_new_client(chr, cioc); > } > > @@ -961,6 +975,9 @@ static int tcp_chr_connect_client_sync(Chardev *chr, > Error **errp) > object_unref(OBJECT(sioc)); > return -1; > } > + yank_register_function(CHARDEV_YANK_INSTANCE(chr->label), > + yank_generic_iochannel, > + QIO_CHANNEL(sioc)); > tcp_chr_new_client(chr, sioc); > object_unref(OBJECT(sioc)); > return 0; > @@ -976,6 +993,9 @@ static void tcp_chr_accept_server_sync(Chardev *chr) > tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING); > sioc = qio_net_listener_wait_client(s->listener); > tcp_chr_set_client_ioc_name(chr, sioc); > + yank_register_function(CHARDEV_YANK_INSTANCE(chr->label), > + yank_generic_iochannel, > + QIO_CHANNEL(sioc)); > tcp_chr_new_client(chr, sioc); > object_unref(OBJECT(sioc)); > } > @@ -1086,6 +1106,9 @@ static void char_socket_finalize(Object *obj) > object_unref(OBJECT(s->tls_creds)); > } > g_free(s->tls_authz); > + if (s->registered_yank) { > + yank_unregister_instance(CHARDEV_YANK_INSTANCE(chr->label)); > + } > > qemu_chr_be_event(chr, CHR_EVENT_CLOSED); > } > @@ -1101,6 +1124,9 @@ static void qemu_chr_socket_connected(QIOTask *task, > void *opaque) > > if (qio_task_propagate_error(task, &err)) { > tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED); > + yank_unregister_function(CHARDEV_YANK_INSTANCE(chr->label), > + yank_generic_iochannel, > + QIO_CHANNEL(sioc)); > check_report_connect_error(chr, err); > goto cleanup; > } > @@ -1134,6 +1160,9 @@ static void tcp_chr_connect_client_async(Chardev > *chr) > tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING); > sioc = qio_channel_socket_new(); > tcp_chr_set_client_ioc_name(chr, sioc); > + yank_register_function(CHARDEV_YANK_INSTANCE(chr->label), > + yank_generic_iochannel, > + QIO_CHANNEL(sioc)); > /* > * Normally code would use the qio_channel_socket_connect_async > * method which uses a QIOTask + qio_task_set_error internally > @@ -1376,6 +1405,11 @@ static void qmp_chardev_open_socket(Chardev *chr, > qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS); > } > > + if (!yank_register_instance(CHARDEV_YANK_INSTANCE(chr->label), errp)) > { > + return; > + } > + s->registered_yank = true; > + > /* be isn't opened until we get a connection */ > *be_opened = false; > > -- > 2.29.2 > >
diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 213a4c8dd0..8a707d766c 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -34,6 +34,7 @@ #include "qapi/error.h" #include "qapi/clone-visitor.h" #include "qapi/qapi-visit-sockets.h" +#include "qemu/yank.h" #include "chardev/char-io.h" #include "qom/object.h" @@ -70,6 +71,7 @@ struct SocketChardev { size_t read_msgfds_num; int *write_msgfds; size_t write_msgfds_num; + bool registered_yank; SocketAddress *addr; bool is_listen; @@ -415,6 +417,12 @@ static void tcp_chr_free_connection(Chardev *chr) tcp_set_msgfds(chr, NULL, 0); remove_fd_in_watch(chr); + if (s->state == TCP_CHARDEV_STATE_CONNECTING + || s->state == TCP_CHARDEV_STATE_CONNECTED) { + yank_unregister_function(CHARDEV_YANK_INSTANCE(chr->label), + yank_generic_iochannel, + QIO_CHANNEL(s->sioc)); + } object_unref(OBJECT(s->sioc)); s->sioc = NULL; object_unref(OBJECT(s->ioc)); @@ -932,6 +940,9 @@ static int tcp_chr_add_client(Chardev *chr, int fd) } tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING); tcp_chr_set_client_ioc_name(chr, sioc); + yank_register_function(CHARDEV_YANK_INSTANCE(chr->label), + yank_generic_iochannel, + QIO_CHANNEL(sioc)); ret = tcp_chr_new_client(chr, sioc); object_unref(OBJECT(sioc)); return ret; @@ -946,6 +957,9 @@ static void tcp_chr_accept(QIONetListener *listener, tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING); tcp_chr_set_client_ioc_name(chr, cioc); + yank_register_function(CHARDEV_YANK_INSTANCE(chr->label), + yank_generic_iochannel, + QIO_CHANNEL(cioc)); tcp_chr_new_client(chr, cioc); } @@ -961,6 +975,9 @@ static int tcp_chr_connect_client_sync(Chardev *chr, Error **errp) object_unref(OBJECT(sioc)); return -1; } + yank_register_function(CHARDEV_YANK_INSTANCE(chr->label), + yank_generic_iochannel, + QIO_CHANNEL(sioc)); tcp_chr_new_client(chr, sioc); object_unref(OBJECT(sioc)); return 0; @@ -976,6 +993,9 @@ static void tcp_chr_accept_server_sync(Chardev *chr) tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING); sioc = qio_net_listener_wait_client(s->listener); tcp_chr_set_client_ioc_name(chr, sioc); + yank_register_function(CHARDEV_YANK_INSTANCE(chr->label), + yank_generic_iochannel, + QIO_CHANNEL(sioc)); tcp_chr_new_client(chr, sioc); object_unref(OBJECT(sioc)); } @@ -1086,6 +1106,9 @@ static void char_socket_finalize(Object *obj) object_unref(OBJECT(s->tls_creds)); } g_free(s->tls_authz); + if (s->registered_yank) { + yank_unregister_instance(CHARDEV_YANK_INSTANCE(chr->label)); + } qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } @@ -1101,6 +1124,9 @@ static void qemu_chr_socket_connected(QIOTask *task, void *opaque) if (qio_task_propagate_error(task, &err)) { tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED); + yank_unregister_function(CHARDEV_YANK_INSTANCE(chr->label), + yank_generic_iochannel, + QIO_CHANNEL(sioc)); check_report_connect_error(chr, err); goto cleanup; } @@ -1134,6 +1160,9 @@ static void tcp_chr_connect_client_async(Chardev *chr) tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING); sioc = qio_channel_socket_new(); tcp_chr_set_client_ioc_name(chr, sioc); + yank_register_function(CHARDEV_YANK_INSTANCE(chr->label), + yank_generic_iochannel, + QIO_CHANNEL(sioc)); /* * Normally code would use the qio_channel_socket_connect_async * method which uses a QIOTask + qio_task_set_error internally @@ -1376,6 +1405,11 @@ static void qmp_chardev_open_socket(Chardev *chr, qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS); } + if (!yank_register_instance(CHARDEV_YANK_INSTANCE(chr->label), errp)) { + return; + } + s->registered_yank = true; + /* be isn't opened until we get a connection */ *be_opened = false;