Add patch to fix pty lockup v72+dfsg-3
authorJan Luebbe <jluebbe@debian.org>
Thu, 20 Nov 2008 15:52:05 +0000 (16:52 +0100)
committerJan Luebbe <jluebbe@debian.org>
Thu, 20 Nov 2008 15:55:31 +0000 (16:55 +0100)
debian/changelog
debian/patches/from-debian-qemu/62_fix-ptyblocking.patch [new file with mode: 0644]
debian/patches/series

index fa49a00..5ef6f32 100644 (file)
@@ -1,3 +1,11 @@
+kvm (72+dfsg-3) unstable; urgency=medium
+
+  * Apply patch from qemu (62_fix-ptyblocking.patch) which fixes a lockup
+    when using a pty as serial console, which caused problems for libvirt
+    users. Thanks to Peter Palfrader and Riku Voipio (closes: #494831)
+
+ -- Jan Lübbe <jluebbe@debian.org>  Thu, 20 Nov 2008 16:41:26 +0100
+
 kvm (72+dfsg-2) unstable; urgency=medium
 
   * Merge changes from NMU, thanks to Thomas Viehmann
diff --git a/debian/patches/from-debian-qemu/62_fix-ptyblocking.patch b/debian/patches/from-debian-qemu/62_fix-ptyblocking.patch
new file mode 100644 (file)
index 0000000..1fbc713
--- /dev/null
@@ -0,0 +1,169 @@
+--- qemu/vl.c  2008/07/23 15:19:59     4927
++++ qemu/vl.c  2008/07/28 18:55:32     4956
+@@ -2464,21 +2464,162 @@
+ #endif
+ #if defined(__linux__) || defined(__sun__)
++
++typedef struct {
++    int fd;
++    int connected;
++    int polling;
++    int read_bytes;
++    QEMUTimer *timer;
++} PtyCharDriver;
++
++static void pty_chr_update_read_handler(CharDriverState *chr);
++static void pty_chr_state(CharDriverState *chr, int connected);
++
++static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
++{
++    PtyCharDriver *s = chr->opaque;
++
++    if (!s->connected) {
++        /* guest sends data, check for (re-)connect */
++        pty_chr_update_read_handler(chr);
++        return 0;
++    }
++    return unix_write(s->fd, buf, len);
++}
++
++static int pty_chr_read_poll(void *opaque)
++{
++    CharDriverState *chr = opaque;
++    PtyCharDriver *s = chr->opaque;
++
++    s->read_bytes = qemu_chr_can_read(chr);
++    return s->read_bytes;
++}
++
++static void pty_chr_read(void *opaque)
++{
++    CharDriverState *chr = opaque;
++    PtyCharDriver *s = chr->opaque;
++    int size, len;
++    uint8_t buf[1024];
++
++    len = sizeof(buf);
++    if (len > s->read_bytes)
++        len = s->read_bytes;
++    if (len == 0)
++        return;
++    size = read(s->fd, buf, len);
++    if ((size == -1 && errno == EIO) ||
++        (size == 0)) {
++        pty_chr_state(chr, 0);
++        return;
++    }
++    if (size > 0) {
++        pty_chr_state(chr, 1);
++        qemu_chr_read(chr, buf, size);
++    }
++}
++
++static void pty_chr_update_read_handler(CharDriverState *chr)
++{
++    PtyCharDriver *s = chr->opaque;
++
++    qemu_set_fd_handler2(s->fd, pty_chr_read_poll,
++                         pty_chr_read, NULL, chr);
++    s->polling = 1;
++    /*
++     * Short timeout here: just need wait long enougth that qemu makes
++     * it through the poll loop once.  When reconnected we want a
++     * short timeout so we notice it almost instantly.  Otherwise
++     * read() gives us -EIO instantly, making pty_chr_state() reset the
++     * timeout to the normal (much longer) poll interval before the
++     * timer triggers.
++     */
++    qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 10);
++}
++
++static void pty_chr_state(CharDriverState *chr, int connected)
++{
++    PtyCharDriver *s = chr->opaque;
++
++    if (!connected) {
++        qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
++        s->connected = 0;
++        s->polling = 0;
++        /* (re-)connect poll interval for idle guests: once per second.
++         * We check more frequently in case the guests sends data to
++         * the virtual device linked to our pty. */
++        qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000);
++    } else {
++        if (!s->connected)
++            qemu_chr_reset(chr);
++        s->connected = 1;
++    }
++}
++
++void pty_chr_timer(void *opaque)
++{
++    struct CharDriverState *chr = opaque;
++    PtyCharDriver *s = chr->opaque;
++
++    if (s->connected)
++        return;
++    if (s->polling) {
++        /* If we arrive here without polling being cleared due
++         * read returning -EIO, then we are (re-)connected */
++        pty_chr_state(chr, 1);
++        return;
++    }
++
++    /* Next poll ... */
++    pty_chr_update_read_handler(chr);
++}
++
++static void pty_chr_close(struct CharDriverState *chr)
++{
++    PtyCharDriver *s = chr->opaque;
++
++    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
++    close(s->fd);
++    qemu_free(s);
++}
++
+ static CharDriverState *qemu_chr_open_pty(void)
+ {
++    CharDriverState *chr;
++    PtyCharDriver *s;
+     struct termios tty;
+-    int master_fd, slave_fd;
++    int slave_fd;
+-    if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) < 0) {
++    chr = qemu_mallocz(sizeof(CharDriverState));
++    if (!chr)
++        return NULL;
++    s = qemu_mallocz(sizeof(PtyCharDriver));
++    if (!s) {
++        qemu_free(chr);
++        return NULL;
++    }
++
++    if (openpty(&s->fd, &slave_fd, NULL, NULL, NULL) < 0) {
+         return NULL;
+     }
+     /* Set raw attributes on the pty. */
+     cfmakeraw(&tty);
+     tcsetattr(slave_fd, TCSAFLUSH, &tty);
++    close(slave_fd);
++
++    fprintf(stderr, "char device redirected to %s\n", ptsname(s->fd));
+-    fprintf(stderr, "char device redirected to %s\n", ptsname(master_fd));
+-    return qemu_chr_open_fd(master_fd, master_fd);
++    chr->opaque = s;
++    chr->chr_write = pty_chr_write;
++    chr->chr_update_read_handler = pty_chr_update_read_handler;
++    chr->chr_close = pty_chr_close;
++
++    s->timer = qemu_new_timer(rt_clock, pty_chr_timer, chr);
++
++    return chr;
+ }
+ static void tty_serial_init(int fd, int speed,
index 057cae9..2cf341c 100644 (file)
@@ -5,6 +5,7 @@
 06_no_system_linux_kvm_h.patch -p0
 from-debian-qemu/22_net_tuntap_stall.patch -p0
 from-debian-qemu/62_linux_boot_nasm.patch -p0
+from-debian-qemu/62_fix-ptyblocking.patch -p0
 07_change_qemu_docdir.patch
 CVE-2008-0928.patch
 SECURITY_CVE-2007-1321+1322+1366+2893.patch