chardev: rework filename handling

Instead of checking, did backend set the filename state or not, let's
be stateless: filename is needed rarely, so, let's just have a generic
function (with optional implementation by backends) to get it.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
[ Marc-André - fix leak in ivshmem-pci.c ]
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20260115144606.233252-10-vsementsov@yandex-team.ru>
This commit is contained in:
Vladimir Sementsov-Ogievskiy
2026-01-15 17:46:03 +03:00
committed by Marc-André Lureau
parent e43eb54dc8
commit bc339129b6
5 changed files with 42 additions and 30 deletions

View File

@@ -351,7 +351,6 @@ static bool pty_chr_open(Chardev *chr, ChardevBackend *backend, Error **errp)
return false; return false;
} }
chr->filename = g_strdup_printf("pty:%s", s->pty_name);
qemu_printf("char device redirected to %s (label %s)\n", qemu_printf("char device redirected to %s (label %s)\n",
s->pty_name, chr->label); s->pty_name, chr->label);
@@ -393,6 +392,12 @@ static char *pty_chr_get_pty_name(Chardev *chr)
return g_strdup(s->pty_name); return g_strdup(s->pty_name);
} }
static char *pty_chr_get_filename(Chardev *chr)
{
PtyChardev *s = PTY_CHARDEV(chr);
return g_strdup_printf("pty:%s", s->pty_name);
}
static void char_pty_class_init(ObjectClass *oc, const void *data) static void char_pty_class_init(ObjectClass *oc, const void *data)
{ {
ChardevClass *cc = CHARDEV_CLASS(oc); ChardevClass *cc = CHARDEV_CLASS(oc);
@@ -403,6 +408,7 @@ static void char_pty_class_init(ObjectClass *oc, const void *data)
cc->chr_update_read_handler = pty_chr_update_read_handler; cc->chr_update_read_handler = pty_chr_update_read_handler;
cc->chr_add_watch = pty_chr_add_watch; cc->chr_add_watch = pty_chr_add_watch;
cc->chr_get_pty_name = pty_chr_get_pty_name; cc->chr_get_pty_name = pty_chr_get_pty_name;
cc->chr_get_filename = pty_chr_get_filename;
} }
static const TypeInfo char_pty_type_info = { static const TypeInfo char_pty_type_info = {

View File

@@ -40,6 +40,7 @@
static gboolean socket_reconnect_timeout(gpointer opaque); static gboolean socket_reconnect_timeout(gpointer opaque);
static void tcp_chr_telnet_init(Chardev *chr); static void tcp_chr_telnet_init(Chardev *chr);
static char *qemu_chr_compute_filename(SocketChardev *s);
static void tcp_chr_change_state(SocketChardev *s, TCPChardevState state) static void tcp_chr_change_state(SocketChardev *s, TCPChardevState state)
{ {
@@ -384,8 +385,6 @@ static void tcp_chr_free_connection(Chardev *chr)
s->sioc = NULL; s->sioc = NULL;
object_unref(OBJECT(s->ioc)); object_unref(OBJECT(s->ioc));
s->ioc = NULL; s->ioc = NULL;
g_free(chr->filename);
chr->filename = NULL;
tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED); tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED);
} }
@@ -439,16 +438,17 @@ static char *qemu_chr_socket_address(SocketChardev *s, const char *prefix)
} }
} }
static void update_disconnected_filename(SocketChardev *s) static char *tcp_chr_get_filename(Chardev *chr)
{ {
Chardev *chr = CHARDEV(s); SocketChardev *s = SOCKET_CHARDEV(chr);
g_free(chr->filename); if (s->state == TCP_CHARDEV_STATE_CONNECTED) {
if (s->addr) { return qemu_chr_compute_filename(s);
chr->filename = qemu_chr_socket_address(s, "disconnected:"); } else if (s->addr) {
} else { return qemu_chr_socket_address(s, "disconnected:");
chr->filename = g_strdup("disconnected:socket");
} }
return g_strdup("disconnected:socket");
} }
/* NB may be called even if tcp_chr_connect has not been /* NB may be called even if tcp_chr_connect has not been
@@ -468,7 +468,6 @@ static void tcp_chr_disconnect_locked(Chardev *chr)
qio_net_listener_set_client_func_full(s->listener, tcp_chr_accept, qio_net_listener_set_client_func_full(s->listener, tcp_chr_accept,
chr, NULL, chr->gcontext); chr, NULL, chr->gcontext);
} }
update_disconnected_filename(s);
if (emit_close) { if (emit_close) {
qemu_chr_be_event(chr, CHR_EVENT_CLOSED); qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
} }
@@ -639,9 +638,6 @@ static void tcp_chr_connect(void *opaque)
Chardev *chr = CHARDEV(opaque); Chardev *chr = CHARDEV(opaque);
SocketChardev *s = SOCKET_CHARDEV(opaque); SocketChardev *s = SOCKET_CHARDEV(opaque);
g_free(chr->filename);
chr->filename = qemu_chr_compute_filename(s);
tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTED); tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTED);
update_ioc_handlers(s); update_ioc_handlers(s);
qemu_chr_be_event(chr, CHR_EVENT_OPENED); qemu_chr_be_event(chr, CHR_EVENT_OPENED);
@@ -1000,8 +996,8 @@ static void tcp_chr_accept_server_sync(Chardev *chr)
{ {
SocketChardev *s = SOCKET_CHARDEV(chr); SocketChardev *s = SOCKET_CHARDEV(chr);
QIOChannelSocket *sioc; QIOChannelSocket *sioc;
info_report("QEMU waiting for connection on: %s", g_autofree char *filename = qemu_chr_get_filename(chr);
chr->filename); info_report("QEMU waiting for connection on: %s", filename);
tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING); tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING);
sioc = qio_net_listener_wait_client(s->listener); sioc = qio_net_listener_wait_client(s->listener);
tcp_chr_set_client_ioc_name(chr, sioc); tcp_chr_set_client_ioc_name(chr, sioc);
@@ -1258,8 +1254,6 @@ static int qmp_chardev_open_socket_server(Chardev *chr,
s->addr = qio_net_listener_get_local_address(s->listener, 0, errp); s->addr = qio_net_listener_get_local_address(s->listener, 0, errp);
skip_listen: skip_listen:
update_disconnected_filename(s);
if (is_waitconnect) { if (is_waitconnect) {
tcp_chr_accept_server_sync(chr); tcp_chr_accept_server_sync(chr);
} else { } else {
@@ -1436,8 +1430,6 @@ static bool tcp_chr_open(Chardev *chr, ChardevBackend *backend, Error **errp)
} }
s->registered_yank = true; s->registered_yank = true;
update_disconnected_filename(s);
if (s->is_listen) { if (s->is_listen) {
if (qmp_chardev_open_socket_server(chr, is_telnet || is_tn3270, if (qmp_chardev_open_socket_server(chr, is_telnet || is_tn3270,
is_waitconnect, errp) < 0) { is_waitconnect, errp) < 0) {
@@ -1593,6 +1585,7 @@ static void char_socket_class_init(ObjectClass *oc, const void *data)
cc->chr_add_watch = tcp_chr_add_watch; cc->chr_add_watch = tcp_chr_add_watch;
cc->chr_update_read_handler = tcp_chr_update_read_handler; cc->chr_update_read_handler = tcp_chr_update_read_handler;
cc->chr_listener_cleanup = tcp_chr_listener_cleanup; cc->chr_listener_cleanup = tcp_chr_listener_cleanup;
cc->chr_get_filename = tcp_chr_get_filename;
object_class_property_add(oc, "addr", "SocketAddress", object_class_property_add(oc, "addr", "SocketAddress",
char_socket_get_addr, NULL, char_socket_get_addr, NULL,

View File

@@ -309,7 +309,6 @@ static void char_finalize(Object *obj)
if (chr->fe) { if (chr->fe) {
chr->fe->chr = NULL; chr->fe->chr = NULL;
} }
g_free(chr->filename);
g_free(chr->label); g_free(chr->label);
if (chr->logfd != -1) { if (chr->logfd != -1) {
close(chr->logfd); close(chr->logfd);
@@ -796,7 +795,7 @@ static int qmp_query_chardev_foreach(Object *obj, void *data)
ChardevInfo *value = g_malloc0(sizeof(*value)); ChardevInfo *value = g_malloc0(sizeof(*value));
value->label = g_strdup(chr->label); value->label = g_strdup(chr->label);
value->filename = g_strdup(chr->filename); value->filename = qemu_chr_get_filename(chr);
value->frontend_open = chr->fe && chr->fe->fe_is_open; value->frontend_open = chr->fe && chr->fe->fe_is_open;
QAPI_LIST_PREPEND(*list, value); QAPI_LIST_PREPEND(*list, value);
@@ -1025,10 +1024,6 @@ static Chardev *chardev_new(const char *id, const char *typename,
return NULL; return NULL;
} }
if (!chr->filename) {
chr->filename = g_strdup(typename + 8);
}
return chr; return chr;
} }
@@ -1110,6 +1105,20 @@ char *qemu_chr_get_pty_name(Chardev *chr)
return NULL; return NULL;
} }
char *qemu_chr_get_filename(Chardev *chr)
{
ChardevClass *cc = CHARDEV_GET_CLASS(chr);
const char *typename;
if (cc->chr_get_filename) {
return cc->chr_get_filename(chr);
}
typename = object_get_typename(OBJECT(chr));
assert(g_str_has_prefix(typename, "chardev-"));
return g_strdup(typename + 8);
}
ChardevReturn *qmp_chardev_change(const char *id, ChardevBackend *backend, ChardevReturn *qmp_chardev_change(const char *id, ChardevBackend *backend,
Error **errp) Error **errp)
{ {

View File

@@ -873,10 +873,11 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
host_memory_backend_set_mapped(s->hostmem, true); host_memory_backend_set_mapped(s->hostmem, true);
} else { } else {
Chardev *chr = qemu_chr_fe_get_driver(&s->server_chr); Chardev *chr = qemu_chr_fe_get_driver(&s->server_chr);
assert(chr); g_autofree char *filename = NULL;
IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n", assert(chr);
chr->filename); filename = qemu_chr_get_filename(chr);
IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n", filename);
/* we allocate enough space for 16 peers and grow as needed */ /* we allocate enough space for 16 peers and grow as needed */
resize_peers(s, 16); resize_peers(s, 16);

View File

@@ -62,7 +62,6 @@ struct Chardev {
QemuMutex chr_write_lock; QemuMutex chr_write_lock;
CharFrontend *fe; CharFrontend *fe;
char *label; char *label;
char *filename;
int logfd; int logfd;
int be_open; int be_open;
/* used to coordinate the chardev-change special-case: */ /* used to coordinate the chardev-change special-case: */
@@ -309,6 +308,9 @@ struct ChardevClass {
/* return PTY name if available */ /* return PTY name if available */
char *(*chr_get_pty_name)(Chardev *s); char *(*chr_get_pty_name)(Chardev *s);
/* get filename for reporting */
char *(*chr_get_filename)(Chardev *s);
}; };
Chardev *qemu_chardev_new(const char *id, const char *typename, Chardev *qemu_chardev_new(const char *id, const char *typename,
@@ -324,5 +326,6 @@ void suspend_mux_open(void);
void resume_mux_open(void); void resume_mux_open(void);
char *qemu_chr_get_pty_name(Chardev *chr); char *qemu_chr_get_pty_name(Chardev *chr);
char *qemu_chr_get_filename(Chardev *chr);
#endif #endif