aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2021-08-05 16:25:44 +0100
committerPeter Maydell <peter.maydell@linaro.org>2021-08-05 16:25:44 +0100
commit287d53398a425308629a9d8ae85595cf55d7bf14 (patch)
tree12646d8aca7f9ab87128bf32637c6b4645dd1d38
parentbccabb3a5d60182645c7749e89f21a9ff307a9eb (diff)
parenta68403b0a6843f106e381b0bbeaacb29f6d27255 (diff)
downloadqemu-287d53398a425308629a9d8ae85595cf55d7bf14.zip
qemu-287d53398a425308629a9d8ae85595cf55d7bf14.tar.gz
qemu-287d53398a425308629a9d8ae85595cf55d7bf14.tar.bz2
Merge remote-tracking branch 'remotes/marcandre/tags/chr-fix-pull-request' into staging
Chardev-related fixes Hi Here are some bug fixes worthy for 6.1. thanks # gpg: Signature made Thu 05 Aug 2021 13:52:03 BST # gpg: using RSA key 87A9BD933F87C606D276F62DDAE8E10975969CE5 # gpg: issuer "marcandre.lureau@redhat.com" # gpg: Good signature from "Marc-André Lureau <marcandre.lureau@redhat.com>" [full] # gpg: aka "Marc-André Lureau <marcandre.lureau@gmail.com>" [full] # Primary key fingerprint: 87A9 BD93 3F87 C606 D276 F62D DAE8 E109 7596 9CE5 * remotes/marcandre/tags/chr-fix-pull-request: chardev: report a simpler error about duplicated id chardev: give some context on chardev-add error chardev: fix qemu_chr_open_fd() with fd_in==fd_out chardev: fix qemu_chr_open_fd() being called with fd=-1 chardev: fix fd_chr_add_watch() when in != out chardev: mark explicitly first argument as poisoned chardev/socket: print a more correct command-line address util: fix abstract socket path copy Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--chardev/char-fd.c119
-rw-r--r--chardev/char-fe.c2
-rw-r--r--chardev/char-socket.c4
-rw-r--r--chardev/char.c20
-rw-r--r--hw/char/cadence_uart.c2
-rw-r--r--hw/char/cmsdk-apb-uart.c2
-rw-r--r--hw/char/ibex_uart.c2
-rw-r--r--hw/char/nrf51_uart.c2
-rw-r--r--hw/char/serial.c2
-rw-r--r--hw/char/virtio-console.c2
-rw-r--r--hw/usb/redirect.c2
-rw-r--r--hw/virtio/vhost-user.c2
-rw-r--r--include/chardev/char-fe.h8
-rw-r--r--monitor/monitor.c2
-rw-r--r--net/vhost-user.c4
-rw-r--r--util/qemu-sockets.c5
16 files changed, 146 insertions, 34 deletions
diff --git a/chardev/char-fd.c b/chardev/char-fd.c
index 1cd62f2..93c5691 100644
--- a/chardev/char-fd.c
+++ b/chardev/char-fd.c
@@ -28,6 +28,7 @@
#include "qemu/sockets.h"
#include "qapi/error.h"
#include "chardev/char.h"
+#include "chardev/char-fe.h"
#include "io/channel-file.h"
#include "chardev/char-fd.h"
@@ -38,6 +39,10 @@ static int fd_chr_write(Chardev *chr, const uint8_t *buf, int len)
{
FDChardev *s = FD_CHARDEV(chr);
+ if (!s->ioc_out) {
+ return -1;
+ }
+
return io_channel_send(s->ioc_out, buf, len);
}
@@ -80,10 +85,85 @@ static int fd_chr_read_poll(void *opaque)
return s->max_size;
}
+typedef struct FDSource {
+ GSource parent;
+
+ GIOCondition cond;
+} FDSource;
+
+static gboolean
+fd_source_prepare(GSource *source,
+ gint *timeout_)
+{
+ FDSource *src = (FDSource *)source;
+
+ return src->cond != 0;
+}
+
+static gboolean
+fd_source_check(GSource *source)
+{
+ FDSource *src = (FDSource *)source;
+
+ return src->cond != 0;
+}
+
+static gboolean
+fd_source_dispatch(GSource *source, GSourceFunc callback,
+ gpointer user_data)
+{
+ FDSource *src = (FDSource *)source;
+ FEWatchFunc func = (FEWatchFunc)callback;
+ gboolean ret = G_SOURCE_CONTINUE;
+
+ if (src->cond) {
+ ret = func(NULL, src->cond, user_data);
+ src->cond = 0;
+ }
+
+ return ret;
+}
+
+static GSourceFuncs fd_source_funcs = {
+ fd_source_prepare,
+ fd_source_check,
+ fd_source_dispatch,
+ NULL, NULL, NULL
+};
+
+static GSource *fd_source_new(FDChardev *chr)
+{
+ return g_source_new(&fd_source_funcs, sizeof(FDSource));
+}
+
+static gboolean child_func(GIOChannel *source,
+ GIOCondition condition,
+ gpointer data)
+{
+ FDSource *parent = data;
+
+ parent->cond |= condition;
+
+ return G_SOURCE_CONTINUE;
+}
+
static GSource *fd_chr_add_watch(Chardev *chr, GIOCondition cond)
{
FDChardev *s = FD_CHARDEV(chr);
- return qio_channel_create_watch(s->ioc_out, cond);
+ g_autoptr(GSource) source = fd_source_new(s);
+
+ if (s->ioc_out) {
+ g_autoptr(GSource) child = qio_channel_create_watch(s->ioc_out, cond & ~G_IO_IN);
+ g_source_set_callback(child, (GSourceFunc)child_func, source, NULL);
+ g_source_add_child_source(source, child);
+ }
+ if (s->ioc_in) {
+ g_autoptr(GSource) child = qio_channel_create_watch(s->ioc_in, cond & ~G_IO_OUT);
+ g_source_set_callback(child, (GSourceFunc)child_func, source, NULL);
+ g_source_add_child_source(source, child);
+ }
+
+ return g_steal_pointer(&source);
}
static void fd_chr_update_read_handler(Chardev *chr)
@@ -131,17 +211,32 @@ void qemu_chr_open_fd(Chardev *chr,
int fd_in, int fd_out)
{
FDChardev *s = FD_CHARDEV(chr);
- char *name;
-
- s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
- name = g_strdup_printf("chardev-file-in-%s", chr->label);
- qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
- g_free(name);
- s->ioc_out = QIO_CHANNEL(qio_channel_file_new_fd(fd_out));
- name = g_strdup_printf("chardev-file-out-%s", chr->label);
- qio_channel_set_name(QIO_CHANNEL(s->ioc_out), name);
- g_free(name);
- qemu_set_nonblock(fd_out);
+ g_autofree char *name = NULL;
+
+ if (fd_out >= 0) {
+ qemu_set_nonblock(fd_out);
+ }
+
+ if (fd_out == fd_in && fd_in >= 0) {
+ s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
+ name = g_strdup_printf("chardev-file-%s", chr->label);
+ qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
+ s->ioc_out = QIO_CHANNEL(object_ref(s->ioc_in));
+ return;
+ }
+
+ if (fd_in >= 0) {
+ s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
+ name = g_strdup_printf("chardev-file-in-%s", chr->label);
+ qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
+ }
+
+ if (fd_out >= 0) {
+ s->ioc_out = QIO_CHANNEL(qio_channel_file_new_fd(fd_out));
+ g_free(name);
+ name = g_strdup_printf("chardev-file-out-%s", chr->label);
+ qio_channel_set_name(QIO_CHANNEL(s->ioc_out), name);
+ }
}
static void char_fd_class_init(ObjectClass *oc, void *data)
diff --git a/chardev/char-fe.c b/chardev/char-fe.c
index 474715c..7789f7b 100644
--- a/chardev/char-fe.c
+++ b/chardev/char-fe.c
@@ -354,7 +354,7 @@ void qemu_chr_fe_set_open(CharBackend *be, int fe_open)
}
guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
- GIOFunc func, void *user_data)
+ FEWatchFunc func, void *user_data)
{
Chardev *s = be->chr;
GSource *src;
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index d0fb545..c43668c 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -468,9 +468,9 @@ static char *qemu_chr_socket_address(SocketChardev *s, const char *prefix)
#ifdef CONFIG_LINUX
if (sa->has_abstract && sa->abstract) {
- abstract = ",abstract";
+ abstract = ",abstract=on";
if (sa->has_tight && sa->tight) {
- tight = ",tight";
+ tight = ",tight=on";
}
}
#endif
diff --git a/chardev/char.c b/chardev/char.c
index d959eec..4595a8d 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -1031,27 +1031,31 @@ Chardev *qemu_chardev_new(const char *id, const char *typename,
ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
Error **errp)
{
+ ERRP_GUARD();
const ChardevClass *cc;
ChardevReturn *ret;
- Chardev *chr;
+ g_autoptr(Chardev) chr = NULL;
+
+ if (qemu_chr_find(id)) {
+ error_setg(errp, "Chardev with id '%s' already exists", id);
+ return NULL;
+ }
cc = char_get_class(ChardevBackendKind_str(backend->type), errp);
if (!cc) {
- return NULL;
+ goto err;
}
chr = chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)),
backend, NULL, false, errp);
if (!chr) {
- return NULL;
+ goto err;
}
if (!object_property_try_add_child(get_chardevs_root(), id, OBJECT(chr),
errp)) {
- object_unref(OBJECT(chr));
- return NULL;
+ goto err;
}
- object_unref(OBJECT(chr));
ret = g_new0(ChardevReturn, 1);
if (CHARDEV_IS_PTY(chr)) {
@@ -1060,6 +1064,10 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
}
return ret;
+
+err:
+ error_prepend(errp, "Failed to add chardev '%s': ", id);
+ return NULL;
}
ChardevReturn *qmp_chardev_change(const char *id, ChardevBackend *backend,
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
index ceb677b..b4b5e8a 100644
--- a/hw/char/cadence_uart.c
+++ b/hw/char/cadence_uart.c
@@ -288,7 +288,7 @@ static void uart_write_rx_fifo(void *opaque, const uint8_t *buf, int size)
uart_update_status(s);
}
-static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond,
+static gboolean cadence_uart_xmit(void *do_not_use, GIOCondition cond,
void *opaque)
{
CadenceUARTState *s = opaque;
diff --git a/hw/char/cmsdk-apb-uart.c b/hw/char/cmsdk-apb-uart.c
index ba2cbbe..f8dc89e 100644
--- a/hw/char/cmsdk-apb-uart.c
+++ b/hw/char/cmsdk-apb-uart.c
@@ -191,7 +191,7 @@ static uint64_t uart_read(void *opaque, hwaddr offset, unsigned size)
/* Try to send tx data, and arrange to be called back later if
* we can't (ie the char backend is busy/blocking).
*/
-static gboolean uart_transmit(GIOChannel *chan, GIOCondition cond, void *opaque)
+static gboolean uart_transmit(void *do_not_use, GIOCondition cond, void *opaque)
{
CMSDKAPBUART *s = CMSDK_APB_UART(opaque);
int ret;
diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
index 6b0c933..9b0a817 100644
--- a/hw/char/ibex_uart.c
+++ b/hw/char/ibex_uart.c
@@ -135,7 +135,7 @@ static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size)
ibex_uart_update_irqs(s);
}
-static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond,
+static gboolean ibex_uart_xmit(void *do_not_use, GIOCondition cond,
void *opaque)
{
IbexUartState *s = opaque;
diff --git a/hw/char/nrf51_uart.c b/hw/char/nrf51_uart.c
index 045ca5f..3c6f982 100644
--- a/hw/char/nrf51_uart.c
+++ b/hw/char/nrf51_uart.c
@@ -75,7 +75,7 @@ static uint64_t uart_read(void *opaque, hwaddr addr, unsigned int size)
return r;
}
-static gboolean uart_transmit(GIOChannel *chan, GIOCondition cond, void *opaque)
+static gboolean uart_transmit(void *do_not_use, GIOCondition cond, void *opaque)
{
NRF51UARTState *s = NRF51_UART(opaque);
int r;
diff --git a/hw/char/serial.c b/hw/char/serial.c
index bc2e322..7061aac 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -220,7 +220,7 @@ static void serial_update_msl(SerialState *s)
}
}
-static gboolean serial_watch_cb(GIOChannel *chan, GIOCondition cond,
+static gboolean serial_watch_cb(void *do_not_use, GIOCondition cond,
void *opaque)
{
SerialState *s = opaque;
diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c
index 6b132ca..dd5a02e 100644
--- a/hw/char/virtio-console.c
+++ b/hw/char/virtio-console.c
@@ -38,7 +38,7 @@ struct VirtConsole {
* Callback function that's called from chardevs when backend becomes
* writable.
*/
-static gboolean chr_write_unblocked(GIOChannel *chan, GIOCondition cond,
+static gboolean chr_write_unblocked(void *do_not_use, GIOCondition cond,
void *opaque)
{
VirtConsole *vcon = opaque;
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 1ec909a..5f0ef9c 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -270,7 +270,7 @@ static int usbredir_read(void *priv, uint8_t *data, int count)
return count;
}
-static gboolean usbredir_write_unblocked(GIOChannel *chan, GIOCondition cond,
+static gboolean usbredir_write_unblocked(void *do_not_use, GIOCondition cond,
void *opaque)
{
USBRedirDevice *dev = opaque;
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 29ea2b4..aec6cc1 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -303,7 +303,7 @@ struct vhost_user_read_cb_data {
int ret;
};
-static gboolean vhost_user_read_cb(GIOChannel *source, GIOCondition condition,
+static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition,
gpointer opaque)
{
struct vhost_user_read_cb_data *data = opaque;
diff --git a/include/chardev/char-fe.h b/include/chardev/char-fe.h
index a553843..867ef1b 100644
--- a/include/chardev/char-fe.h
+++ b/include/chardev/char-fe.h
@@ -174,6 +174,9 @@ void qemu_chr_fe_set_open(CharBackend *be, int fe_open);
void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
GCC_FMT_ATTR(2, 3);
+
+typedef gboolean (*FEWatchFunc)(void *do_not_use, GIOCondition condition, void *data);
+
/**
* qemu_chr_fe_add_watch:
* @cond: the condition to poll for
@@ -188,10 +191,13 @@ void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
* Note that you are responsible to update the front-end sources if
* you are switching the main context with qemu_chr_fe_set_handlers().
*
+ * Warning: DO NOT use the first callback argument (it may be either
+ * a GIOChannel or a QIOChannel, depending on the underlying chardev)
+ *
* Returns: the source tag
*/
guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
- GIOFunc func, void *user_data);
+ FEWatchFunc func, void *user_data);
/**
* qemu_chr_fe_write:
diff --git a/monitor/monitor.c b/monitor/monitor.c
index b90c0f4..46a171b 100644
--- a/monitor/monitor.c
+++ b/monitor/monitor.c
@@ -156,7 +156,7 @@ static inline bool monitor_is_hmp_non_interactive(const Monitor *mon)
static void monitor_flush_locked(Monitor *mon);
-static gboolean monitor_unblocked(GIOChannel *chan, GIOCondition cond,
+static gboolean monitor_unblocked(void *do_not_use, GIOCondition cond,
void *opaque)
{
Monitor *mon = opaque;
diff --git a/net/vhost-user.c b/net/vhost-user.c
index ffbd94d..6adfcd6 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -208,8 +208,8 @@ static NetClientInfo net_vhost_user_info = {
.set_vnet_le = vhost_user_set_vnet_endianness,
};
-static gboolean net_vhost_user_watch(GIOChannel *chan, GIOCondition cond,
- void *opaque)
+static gboolean net_vhost_user_watch(void *do_not_use, GIOCondition cond,
+ void *opaque)
{
NetVhostUserState *s = opaque;
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 080a240..f2f3676 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -1345,13 +1345,16 @@ socket_sockaddr_to_address_unix(struct sockaddr_storage *sa,
SocketAddress *addr;
struct sockaddr_un *su = (struct sockaddr_un *)sa;
+ assert(salen >= sizeof(su->sun_family) + 1 &&
+ salen <= sizeof(struct sockaddr_un));
+
addr = g_new0(SocketAddress, 1);
addr->type = SOCKET_ADDRESS_TYPE_UNIX;
#ifdef CONFIG_LINUX
if (!su->sun_path[0]) {
/* Linux abstract socket */
addr->u.q_unix.path = g_strndup(su->sun_path + 1,
- sizeof(su->sun_path) - 1);
+ salen - sizeof(su->sun_family) - 1);
addr->u.q_unix.has_abstract = true;
addr->u.q_unix.abstract = true;
addr->u.q_unix.has_tight = true;