Grab device locks when moving data through char devices in the host->guest direction.
Index: kvm-userspace.io/qemu/hw/serial.c =================================================================== --- kvm-userspace.io.orig/qemu/hw/serial.c +++ kvm-userspace.io/qemu/hw/serial.c @@ -305,18 +305,21 @@ static void serial_receive_break(SerialS static int serial_can_receive1(void *opaque) { SerialState *s = opaque; + assert_is_locked(&s->qemu_dev.lock); return serial_can_receive(s); } static void serial_receive1(void *opaque, const uint8_t *buf, int size) { SerialState *s = opaque; + assert_is_locked(&s->qemu_dev.lock); serial_receive_byte(s, buf[0]); } static void serial_event(void *opaque, int event) { SerialState *s = opaque; + assert_is_locked(&s->qemu_dev.lock); if (event == CHR_EVENT_BREAK) serial_receive_break(s); } @@ -400,6 +403,7 @@ SerialState *serial_init(int base, qemu_ register_ioport_write(dev, base, 8, 1, serial_ioport_write, s); register_ioport_read(dev, base, 8, 1, serial_ioport_read, s); s->chr = chr; + chr->qemu_dev = dev; qemu_chr_add_handlers(chr, serial_can_receive1, serial_receive1, serial_event, s); return s; Index: kvm-userspace.io/qemu/qemu-char.h =================================================================== --- kvm-userspace.io.orig/qemu/qemu-char.h +++ kvm-userspace.io/qemu/qemu-char.h @@ -44,6 +44,7 @@ struct CharDriverState { void *opaque; int focus; QEMUBH *bh; + QEMUDevice *qemu_dev; }; CharDriverState *qemu_chr_open(const char *filename); Index: kvm-userspace.io/qemu/vl.c =================================================================== --- kvm-userspace.io.orig/qemu/vl.c +++ kvm-userspace.io/qemu/vl.c @@ -1690,6 +1690,18 @@ int qemu_timedate_diff(struct tm *tm) /***********************************************************/ /* character device */ +static void qemu_chr_lock(CharDriverState *s) +{ + if (!s->qemu_dev) + hw_error("%s: no qemu_dev\n", __func__); + qemu_mutex_lock(&s->qemu_dev->lock); +} + +static void qemu_chr_unlock(CharDriverState *s) +{ + qemu_mutex_unlock(&s->qemu_dev->lock); +} + static void qemu_chr_event(CharDriverState *s, int event) { if (!s->chr_event) @@ -1715,7 +1727,12 @@ void qemu_chr_reset(CharDriverState *s) int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len) { - return s->chr_write(s, buf, len); + int ret; + + assert_is_dev_locked(s->qemu_dev); + ret = s->chr_write(s, buf, len); + + return ret; } int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg) @@ -1727,9 +1744,11 @@ int qemu_chr_ioctl(CharDriverState *s, i int qemu_chr_can_read(CharDriverState *s) { + int ret = 0; if (!s->chr_can_read) - return 0; - return s->chr_can_read(s->handler_opaque); + return ret; + ret = s->chr_can_read(s->handler_opaque); + return ret; } void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len) @@ -1755,8 +1774,10 @@ void qemu_chr_printf(CharDriverState *s, void qemu_chr_send_event(CharDriverState *s, int event) { + qemu_chr_lock(s); if (s->chr_send_event) s->chr_send_event(s, event); + qemu_chr_unlock(s); } void qemu_chr_add_handlers(CharDriverState *s, @@ -1799,8 +1820,10 @@ typedef struct { IOCanRWHandler *chr_can_read[MAX_MUX]; IOReadHandler *chr_read[MAX_MUX]; IOEventHandler *chr_event[MAX_MUX]; + QEMUDevice *devices[MAX_MUX]; void *ext_opaque[MAX_MUX]; CharDriverState *drv; + QEMUDevice qemu_dev; unsigned char buffer[MUX_BUFFER_SIZE]; int prod; int cons; @@ -1935,11 +1958,13 @@ static void mux_chr_accept_input(CharDri int m = chr->focus; MuxDriver *d = chr->opaque; - while (d->prod != d->cons && - d->chr_can_read[m] && - d->chr_can_read[m](d->ext_opaque[m])) { - d->chr_read[m](d->ext_opaque[m], - &d->buffer[d->cons++ & MUX_BUFFER_MASK], 1); + while (d->prod != d->cons) { + qemu_mutex_lock(&d->devices[m]->lock); + if (d->chr_can_read[m] && d->chr_can_read[m](d->ext_opaque[m])) { + d->chr_read[m](d->ext_opaque[m], + &d->buffer[d->cons++ & MUX_BUFFER_MASK], 1); + } + qemu_mutex_unlock(&d->devices[m]->lock); } } @@ -1950,8 +1975,13 @@ static int mux_chr_can_read(void *opaque if ((d->prod - d->cons) < MUX_BUFFER_SIZE) return 1; - if (d->chr_can_read[chr->focus]) - return d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]); + if (d->chr_can_read[chr->focus]) { + int ret; + qemu_mutex_lock(&d->devices[chr->focus]->lock); + ret = d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]); + qemu_mutex_unlock(&d->devices[chr->focus]->lock); + return ret; + } return 0; } @@ -1966,11 +1996,13 @@ static void mux_chr_read(void *opaque, c for(i = 0; i < size; i++) if (mux_proc_byte(chr, d, buf[i])) { - if (d->prod == d->cons && - d->chr_can_read[m] && - d->chr_can_read[m](d->ext_opaque[m])) - d->chr_read[m](d->ext_opaque[m], &buf[i], 1); - else + if (d->prod == d->cons) { + qemu_mutex_lock(&d->devices[m]->lock); + if (d->chr_can_read[m] && d->chr_can_read[m](d->ext_opaque[m])) { + d->chr_read[m](d->ext_opaque[m], &buf[i], 1); + } + qemu_mutex_unlock(&d->devices[m]->lock); + } else d->buffer[d->prod++ & MUX_BUFFER_MASK] = buf[i]; } } @@ -1982,9 +2014,13 @@ static void mux_chr_event(void *opaque, int i; /* Send the event to all registered listeners */ - for (i = 0; i < d->mux_cnt; i++) - if (d->chr_event[i]) + for (i = 0; i < d->mux_cnt; i++) { + if (d->chr_event[i]) { + qemu_mutex_lock(&d->devices[i]->lock); d->chr_event[i](d->ext_opaque[i], event); + qemu_mutex_unlock(&d->devices[i]->lock); + } + } } static void mux_chr_update_read_handler(CharDriverState *chr) @@ -1999,6 +2035,7 @@ static void mux_chr_update_read_handler( d->chr_can_read[d->mux_cnt] = chr->chr_can_read; d->chr_read[d->mux_cnt] = chr->chr_read; d->chr_event[d->mux_cnt] = chr->chr_event; + d->devices[d->mux_cnt] = chr->qemu_dev; /* Fix up the real driver with mux routines */ if (d->mux_cnt == 0) { qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read, @@ -2021,8 +2058,10 @@ static CharDriverState *qemu_chr_open_mu free(chr); return NULL; } + qemu_register_device(&d->qemu_dev); chr->opaque = d; + chr->qemu_dev = &d->qemu_dev; d->drv = drv; chr->focus = -1; chr->chr_write = mux_chr_write; Index: kvm-userspace.io/qemu/qemu-device.h =================================================================== --- kvm-userspace.io.orig/qemu/qemu-device.h +++ kvm-userspace.io/qemu/qemu-device.h @@ -10,6 +10,7 @@ #define qemu_mutex_lock(mutex) pthread_mutex_lock(mutex) #define qemu_mutex_unlock(mutex) pthread_mutex_unlock(mutex) #define assert_is_locked(mutex) do { } while (0) +#define assert_is_dev_locked(mutex) do { } while (0) static inline void qemu_mutex_init(qemu_mutex_t *mutex) { pthread_mutex_init(mutex, NULL); @@ -42,6 +43,16 @@ static inline void assert_is_locked(qemu } } +static inline void assert_is_dev_locked(void *dev) +{ + if (!dev) { + printf("assert failure, qemu_dev is null\n"); + print_backtrace(); + exit(0); + } + assert_is_locked((qemu_mutex_t *)dev); +} + static inline void qemu_mutex_lock(qemu_mutex_t *mutex) { if (!mutex) { -- ------------------------------------------------------------------------- This SF.net email is sponsored by the 2008 JavaOne(SM) Conference Don't miss this year's exciting event. There's still time to save $100. Use priority code J8TL2D2. http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone _______________________________________________ kvm-devel mailing list kvm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kvm-devel