]> xenbits.xen.org Git - xenclient/ioemu-pq.git/commitdiff
fix race in async cdrom code
authorJames Mckenzie <jamesmck@taoand.cam.xci-test.com>
Fri, 11 Dec 2009 18:00:42 +0000 (18:00 +0000)
committerJames Mckenzie <jamesmck@taoand.cam.xci-test.com>
Fri, 11 Dec 2009 18:00:42 +0000 (18:00 +0000)
master/series
master/tidy-muticies-in-ata-pt [new file with mode: 0644]

index 9b12de06d5ec822d14b94e5daf71fef43027bc7e..90ecb79d984732a3571cdb36d77d78ea9b7fd0ef 100644 (file)
@@ -32,3 +32,4 @@ dont-carp-about-a-missing-battery
 vga-clear-hw-fb-on-resize
 hide-msi-capability-for-igfx
 vga-edid
+tidy-muticies-in-ata-pt
diff --git a/master/tidy-muticies-in-ata-pt b/master/tidy-muticies-in-ata-pt
new file mode 100644 (file)
index 0000000..c41dcfe
--- /dev/null
@@ -0,0 +1,621 @@
+diff --git a/hw/atapi-pt.c b/hw/atapi-pt.c
+index 2d26983..7f59aca 100644
+--- a/hw/atapi-pt.c
++++ b/hw/atapi-pt.c
+@@ -7,6 +7,8 @@
+ #include <pthread.h>
+ #include <sys/ioctl.h>
+ #include <unistd.h>
++#include <sys/types.h>
++#include <sys/socket.h>
+ #include "xen.h"
+ /* Even when defined debugging is only enabled if /etc/debugcdrom exists */
+@@ -395,6 +397,8 @@ static const struct {
+ static int we_have_lock = 0;
++static void ide_atapi_pt_ejected(void);
++
+ static int get_lock_fd(void) 
+ {
+     static int lock_fd=-1;
+@@ -773,6 +777,9 @@ static uint32_t ide_atapi_pt_get_data_size(int size_select, uint8_t command, uin
+ static void ide_atapi_pt_set_error(IDEState *s, int sense_key, int asc, int ascq, int error)
+ {
++    static uint32_t  serial=0;
++
++    DEBUG_PRINTF("ide_atapi_pt_set_error serial 0x%x\n",xerial++);
+     memset(&s->atapi_pt.sense, 0, 18);
+     s->atapi_pt.sense.sense_key  = sense_key;
+     s->atapi_pt.sense.asc        = asc;
+@@ -807,16 +814,11 @@ static void ide_atapi_pt_error(IDEState *s)
+  * send our command.
+  * This is the BSG SG_IO v4 implementation.
+  */
+-static void *ide_atapi_pt_sgio_worker_thread(void *arg)
++static int ide_atapi_pt_do_dispatch(volatile IDEState *s)
+ {
+-    int r;
+     struct sg_io_v4 cmd;
+     BDRVRawState *raw_state;
+-    volatile IDEState *s = (volatile IDEState *)arg;
+-
+-    for(;;) {
+-        pthread_mutex_lock(&s->atapi_pt.sgio_mutex);
+-        pthread_cond_wait(&s->atapi_pt.sgio_cv, &s->atapi_pt.sgio_mutex);
++        int r;
+         /* Send command and wait for reply, SG_IO ioctl*/
+         memset(&cmd, 0, sizeof(cmd));
+@@ -869,11 +871,215 @@ static void *ide_atapi_pt_sgio_worker_thread(void *arg)
+                                             s->atapi_pt.sense.asc,
+                                             s->atapi_pt.sense.ascq));
+         }
++      return r;
++}
++
++static int status_file_touched(const char *fn,time_t *t)
++{
++        int fd;
++      struct stat buf;
++
++      if (!t) return 0;
++
++            if(stat(IDE_ATAPI_PT_NEW_CD_FILE, &buf)) {
++                DEBUG_PRINTF("Error stating %s\n",fn);
++              return 0;
++          }
++
++      if (buf.st_ctime > *t) {
++              *t=buf.st_ctime;
++              return 1;
++      }
++
++      return 0;
++}
++
++static void touch_status_file(const char *fn,time_t *t)
++{
++        int fd;
++      struct stat buf;
++
++            fd = open(fn, O_WRONLY | O_TRUNC | O_CREAT, 0666);
++            if(fd < 0) {
++                DEBUG_PRINTF("Error touching %s\n",fn);
++            } else {
++                close(fd);
++                utime(fn, NULL);
++            }
++
++            if(stat(IDE_ATAPI_PT_NEW_CD_FILE, &buf)) {
++                DEBUG_PRINTF("Error stating %s\n",fn);
++              return;
++          }
++
++         if (t)
++            *t = buf.st_ctime;
++}
++  
++static void ide_atapi_pt_cmd_complete(void *arg) /* Mop up result*/
++{
++    IDEState *s = (IDEState *)arg;
++    uint8_t cmd_code = s->atapi_pt.request[0];
++    uint32_t din_desired;
++    static uint32_t serial = 0;
++
++    assert(s);
++
++
++    {
++          /* Get return code of ioctl from worker thread's fd */
++          int r;
++          recv(s->atapi_pt.sgio_dispatch_fd, &r, sizeof(int),0);
++
++          DEBUG_PRINTF("ide_atapi_pt_cmd_complete serial 0x%x - code %d\n",serial++,r);
++    }
++
++    if(s->atapi_pt.result)
++    {
++        if(s->atapi_pt.request[0] == GPCMD_TEST_UNIT_READY &&
++           s->atapi_pt.sense.sense_key == 2 && s->atapi_pt.sense.asc == 0x3A)
++            /* No media, remove exclusivity lock */
++            ide_atapi_pt_ejected();
++
++        ide_atapi_pt_error(s);
++        return;
++    }
++
++    if(s->atapi_pt.request[0] == GPCMD_GET_EVENT_STATUS_NOTIFICATION)
++    {
++
++        if(s->io_buffer[2] == 4 && s->io_buffer[4] == 2)
++        {
++            /* This is a "new media" message, tell any other VMs */
++            DEBUG_PRINTF("[ATAPI] new media detected\n");
++
++          touch_status_file(IDE_ATAPI_PT_NEW_CD_FILE,&s->atapi_pt.new_cd_time);
++        }
++
++        if(s->io_buffer[2] == 4 && s->io_buffer[4] == 3)
++        {
++            /* This is a "media removed" message, tell any other VMs */
++            DEBUG_PRINTF("[ATAPI] media removed\n");
++
++          touch_status_file(IDE_ATAPI_PT_EJECT_CD_FILE,&s->atapi_pt.new_cd_time);
++
++            /* Remove exclusivity lock */
++            ide_atapi_pt_ejected();
++        }
++
++        if((s->io_buffer[2] == 4 && s->io_buffer[4] == 0 && s->io_buffer[5] == 2) ||
++           (s->io_buffer[4] == 0 && s->io_buffer[5] == 0 &&
++            s->io_buffer[6] == 0 && s->io_buffer[7] == 0))
++        {
++            /* This is a no activity message we can hijack if we need to */
++
++            if(status_file_touched(IDE_ATAPI_PT_NEW_CD_FILE,&s->atapi_pt.new_cd_time)) {
++                DEBUG_PRINTF("[ATAPI] new media message spotted\n");
++
++                s->io_buffer[2] = 4;
++                s->io_buffer[4] = 2;
++                s->io_buffer[5] = 2;
++                s->io_buffer[6] = 0;
++                s->io_buffer[7] = 0;
++            } else if(status_file_touched(IDE_ATAPI_PT_EJECT_CD_FILE,&s->atapi_pt.eject_time)) 
++            {
++                /* There's been an eject message that we haven't seen yet */
++                DEBUG_PRINTF("[ATAPI] media removed message spotted\n");
++
++                s->io_buffer[2] = 4;
++                s->io_buffer[4] = 3;
++                s->io_buffer[5] = 1;
++                s->io_buffer[6] = 0;
++                s->io_buffer[7] = 0;
++            }
++        }
++    }
++
++    if(s->atapi_pt.din_xfer_len == 0)
++    {
++        // Nothing else to do
++        ide_atapi_cmd_ok(s);
++        return;
++    }
++
++    din_desired = ide_atapi_pt_get_data_size(ide_atapi_pt_size_din, cmd_code, s->io_buffer);
++
++    /* din_xfer_len is the size of the buffer provided for the din data,
++     * din_desired in the size of the data the LU tried to send to us. Either one
++     * may be bigger. */
++
++    if(s->atapi_pt.request[0] == GPCMD_READ_BUFFER)
++    {
++        switch(s->atapi_pt.request[1] & 7)
++        {
++        case 0: // data with header, as specified in atapi_data_sizes table
++            break;
++
++        case 2: // data only
++            din_desired = s->atapi_pt.din_xfer_len;
++            break;
++
++        case 3: // header only
++            din_desired = 4;
++            break;
++
++        case 1: // vendor specific
++        default:
++            DEBUG_PRINTF("\e[3;31mIllegal read buffer mode %d\e[m\n",
++                         s->io_buffer[1] & 7);
++            ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
++                                   ASC_INV_FIELD_IN_CMD_PACKET, 0, 0x70);
++            return;
++        }
++    }
++
++    if(din_desired == (__u32)-1)
++        din_desired = s->atapi_pt.din_xfer_len;
++
++    DEBUG_PRINTF("Read %d bytes of data (buffer size %d)\n",
++                 din_desired, s->atapi_pt.din_xfer_len);
++
++    if(s->atapi_pt.din_xfer_len >= 0x80 && din_desired >= 0x80)
++        DEBUG_HEXDUMP(s->io_buffer, 0x80);
++    else if(s->atapi_pt.din_xfer_len < din_desired)
++        DEBUG_HEXDUMP(s->io_buffer, s->atapi_pt.din_xfer_len);
++    else
++        DEBUG_HEXDUMP(s->io_buffer, din_desired);
++
++    ide_atapi_cmd_reply(s, din_desired, s->atapi_pt.din_xfer_len);
++} 
++
++
++static void *ide_atapi_pt_sgio_worker_thread(void *arg)
++{
++    int r;
++    fd_set rfds;
++    sigset_t set;
++    static uint32_t serial=0;
++    volatile IDEState *s = (volatile IDEState *)arg;
+-        /* Unlock _before_ signalling parent */
+-        pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
+-        write(s->atapi_pt.sgio_wfd, &r, sizeof(int));
++    if (sigfillset(&set)) { DEBUG_PRINTF("sigfillset\n"); return NULL; }
++    if (pthread_sigmask(SIG_BLOCK, &set, NULL)) { DEBUG_PRINTF("sigprocmask"); return NULL; }
++
++    FD_ZERO(&rfds);
++
++    for(;;) {
++      struct timeval zero={0};
++        recv(s->atapi_pt.sgio_worker_fd,&r,sizeof(int),0);
++
++      FD_SET(s->atapi_pt.sgio_worker_fd,&rfds);
++      
++      while (select(s->atapi_pt.sgio_worker_fd+1,&rfds,NULL,NULL,&zero)==1) {
++              recv(s->atapi_pt.sgio_worker_fd,&r,sizeof(int),MSG_DONTWAIT);
++      }
++
++      DEBUG_PRINTF("ide_atapi_pt_sgio_worker_thread: in serial 0x%x\n",serial++);
++      r=ide_atapi_pt_do_dispatch(s);
++      DEBUG_PRINTF("ide_atapi_pt_sgio_worker_thread: out serial 0x%x response %d\n",serial-1,r);
++
++        write(s->atapi_pt.sgio_worker_fd, &r, sizeof(int));
+     }
++return NULL;
+ }
+@@ -884,49 +1090,45 @@ static int ide_atapi_pt_aio_flush(void *unused)
+     return 0;
+ }
+-static void ide_atapi_pt_cmd_complete(void *arg);
+ static void ide_atapi_pt_setup_sgio_thread(IDEState *s)
+ {
+     int fds[2];
+-    if(pipe(fds) < 0) {
+-        DEBUG_PRINTF("atapi-pt failed to create pipe: %m\n");
++    if(socketpair(PF_UNIX,SOCK_DGRAM,0,fds) < 0) {
++        DEBUG_PRINTF("atapi-pt failed to create socketpair: %m\n");
+         exit(1);
+     }
+-    s->atapi_pt.sgio_rfd = fds[0];
+-    s->atapi_pt.sgio_wfd = fds[1];
+-
+-    pthread_mutex_init(&s->atapi_pt.sgio_mutex, NULL);
+-    pthread_cond_init (&s->atapi_pt.sgio_cv, NULL);
++    s->atapi_pt.sgio_dispatch_fd = fds[0];
++    s->atapi_pt.sgio_worker_fd = fds[1];
+     if (pthread_create(&s->atapi_pt.sgio_thread, NULL, ide_atapi_pt_sgio_worker_thread, (void *)s))
+     {
+        DEBUG_PRINTF("Create CD-ROM worker thread failed\n");
+        exit(1);
+     }
+-    qemu_aio_set_fd_handler(s->atapi_pt.sgio_rfd, ide_atapi_pt_cmd_complete, NULL, ide_atapi_pt_aio_flush, (void *)s);
++    qemu_aio_set_fd_handler(s->atapi_pt.sgio_dispatch_fd, ide_atapi_pt_cmd_complete, NULL, ide_atapi_pt_aio_flush, (void *)s);
+ }
+-/* Call with ide_atapi_sgio_mutex held */
+ static void ide_atapi_pt_do_sg_io(IDEState *s)
+ {
++    static uint32_t serial=0;
++    int r='K';
++      DEBUG_PRINTF("ide_atapi_pt_do_sg_io 0x%x\n",serial++);
++
+     /* Poke worker thread to send command using SG_IO ioctl */
+-    pthread_cond_signal(&s->atapi_pt.sgio_cv);
+-    pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
++    send(s->atapi_pt.sgio_dispatch_fd,&r,sizeof(int),MSG_NOSIGNAL);
+ }
+  
+ /* Functions to fetch dout data from where-ever it comes from */
+-/* Call with ide_atapi_sgio_mutex held */
+ static void ide_atapi_pt_dout_fetch_pio_done(IDEState *s)
+ {
+     ide_transfer_stop(s);
+     ide_atapi_pt_do_sg_io(s);
+ }
+-/* Call with ide_atapi_sgio_mutex held */
+ static void ide_atapi_pt_dout_fetch_dma_done(void *opaque, int ret)
+ {
+     BMDMAState *bm = opaque;
+@@ -935,7 +1137,6 @@ static void ide_atapi_pt_dout_fetch_dma_done(void *opaque, int ret)
+     if (ret < 0) {
+         ide_atapi_io_error(s, ret);
+-        pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
+         return;
+     }
+@@ -943,7 +1144,6 @@ static void ide_atapi_pt_dout_fetch_dma_done(void *opaque, int ret)
+     ide_atapi_pt_do_sg_io(s);
+ }
+-/* Call with ide_atapi_sgio_mutex held */
+ static void ide_atapi_pt_wcmd(IDEState *s)
+ {
+     if (s->atapi_dma)
+@@ -1107,11 +1307,6 @@ static void ide_atapi_pt_cmd(IDEState *s)
+     uint8_t cmd_code;
+     FILE *fp;
+-    if(pthread_mutex_trylock(&s->atapi_pt.sgio_mutex)) {
+-        DEBUG_PRINTF("ide_atapi_pt_cmd() called with existing request processing - ignored!\n");
+-        return;
+-    }
+-
+     memcpy(s->atapi_pt.request, s->io_buffer, ATAPI_PACKET_SIZE);
+     cmd_code = s->atapi_pt.request[0];
+     s->atapi_pt.timeout = 15000;
+@@ -1148,8 +1343,8 @@ static void ide_atapi_pt_cmd(IDEState *s)
+         DEBUG_HEXDUMP(s->io_buffer, actual_size);
+         ide_atapi_cmd_reply(s, size, max_size);
+-        pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
+-        return;
++      return;
++
+     }
+     s->atapi_pt.dout_xfer_len = ide_atapi_pt_get_data_size(ide_atapi_pt_size_dout,
+@@ -1178,8 +1373,8 @@ static void ide_atapi_pt_cmd(IDEState *s)
+             memcpy(s->io_buffer, inquiry_data, 96);
+             memset(&s->atapi_pt.sense, 0, sizeof(sense));
+             ide_atapi_cmd_reply(s, 96, s->atapi_pt.din_xfer_len);
+-            pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
+-            return;
++      return;
++
+         }
+         if(cmd_code == GPCMD_MODE_SENSE_10)
+@@ -1192,8 +1387,7 @@ static void ide_atapi_pt_cmd(IDEState *s)
+         DEBUG_PRINTF("Blocking command due to exclusivity lock\n");
+         memcpy(&s->atapi_pt.sense, sense, sizeof(sense));
+         ide_atapi_pt_set_error(s, sense[2], sense[12], sense[13], 0x70);
+-        pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
+-        return;
++      return;
+     }
+     /* Claim exclusive use if we're doing any kind of writing */
+@@ -1210,8 +1404,7 @@ static void ide_atapi_pt_cmd(IDEState *s)
+           // FIXME XXX - make this throw an error
+             memcpy(&s->atapi_pt.sense, sense, 18);
+             ide_atapi_pt_set_error(s, sense[2], sense[12], sense[13], 0x70);
+-            pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
+-          return;
++              return;
+ #endif
+         }
+     }
+@@ -1225,8 +1418,8 @@ static void ide_atapi_pt_cmd(IDEState *s)
+     case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
+         // we don't allow locking, to prevent a VM from hogging the drive
+         ide_atapi_cmd_ok(s);
+-        pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
+-        return;
++      return;
++
+     case GPCMD_FLUSH_CACHE: // bigger timeout while flushing write cache
+         s->atapi_pt.timeout = 1000 * 60;
+@@ -1256,8 +1449,7 @@ static void ide_atapi_pt_cmd(IDEState *s)
+                          s->io_buffer[1] & 7);
+             ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
+                                    ASC_INV_FIELD_IN_CMD_PACKET, 0, 0x70);
+-            pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
+-            return;
++      return;
+         }
+         break;
+@@ -1328,8 +1520,8 @@ static void ide_atapi_pt_cmd(IDEState *s)
+                          s->io_buffer[10]);
+             ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
+                                    ASC_INV_FIELD_IN_CMD_PACKET, 0, 0x70);
+-            pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
+-            return;
++      return;
++
+         }
+         s->atapi_pt.din_xfer_len += 8;  // 8 bytes of header
+@@ -1352,8 +1544,7 @@ static void ide_atapi_pt_cmd(IDEState *s)
+         DEBUG_HEXDUMP(s->atapi_pt.request, ATAPI_PACKET_SIZE);
+         ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
+                                ASC_ILLEGAL_OPCODE, 0, 0x70);
+-        pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
+-        return;
++      return;
+     }
+     if(s->atapi_pt.dout_xfer_len > 0)
+@@ -1364,162 +1555,6 @@ static void ide_atapi_pt_cmd(IDEState *s)
+     }
+     ide_atapi_pt_do_sg_io(s);
+-}
+-
+-static void ide_atapi_pt_cmd_complete(void *arg)
+-{
+-    IDEState *s = (IDEState *)arg;
+-    int r;
+-    uint8_t cmd_code = s->atapi_pt.request[0];
+-    uint32_t din_desired;
+-
+-    assert(s);
+-
+-    /* Get return code of ioctl from worker thread's fd */
+-    read(s->atapi_pt.sgio_rfd, &r, sizeof(int));
+-
+-    if(s->atapi_pt.result)
+-    {
+-        if(s->atapi_pt.request[0] == GPCMD_TEST_UNIT_READY &&
+-           s->atapi_pt.sense.sense_key == 2 && s->atapi_pt.sense.asc == 0x3A)
+-            /* No media, remove exclusivity lock */
+-            ide_atapi_pt_ejected();
+-
+-        ide_atapi_pt_error(s);
+-        return;
+-    }
+-
+-    if(s->atapi_pt.request[0] == GPCMD_GET_EVENT_STATUS_NOTIFICATION)
+-    {
+-        struct stat file_stat;
+-        int fd;
+-
+-        if(s->io_buffer[2] == 4 && s->io_buffer[4] == 2)
+-        {
+-            /* This is a "new media" message, tell any other VMs */
+-            DEBUG_PRINTF("[ATAPI] new media detected\n");
+-
+-            fd = open(IDE_ATAPI_PT_NEW_CD_FILE, O_WRONLY | O_TRUNC | O_CREAT, 0666);
+-            if(fd < 0) {
+-                DEBUG_PRINTF("Error touching new CD file\n");
+-            } else {
+-                close(fd);
+-                utime(IDE_ATAPI_PT_NEW_CD_FILE, NULL);
+-            }
+-
+-            if(stat(IDE_ATAPI_PT_NEW_CD_FILE, &file_stat) != 0)
+-                DEBUG_PRINTF("Error writing to new CD file\n");
+-            else
+-                s->atapi_pt.new_cd_time = file_stat.st_ctime;
+-        }
+-
+-        if(s->io_buffer[2] == 4 && s->io_buffer[4] == 3)
+-        {
+-            /* This is a "media removed" message, tell any other VMs */
+-            DEBUG_PRINTF("[ATAPI] media removed\n");
+-
+-            fd = open(IDE_ATAPI_PT_EJECT_CD_FILE, O_WRONLY | O_TRUNC | O_CREAT, 0666);
+-            if(fd < 0) {
+-                DEBUG_PRINTF("Error touching eject CD file\n");
+-            } else {
+-                close(fd);
+-                utime(IDE_ATAPI_PT_EJECT_CD_FILE, NULL);
+-            }
+-
+-            if(stat(IDE_ATAPI_PT_EJECT_CD_FILE, &file_stat) != 0)
+-                DEBUG_PRINTF("Error writing to eject CD file\n");
+-            else
+-                s->atapi_pt.eject_time = file_stat.st_ctime;
+-
+-            /* Remove exclusivity lock */
+-            ide_atapi_pt_ejected();
+-        }
+-
+-        if((s->io_buffer[2] == 4 && s->io_buffer[4] == 0 && s->io_buffer[5] == 2) ||
+-           (s->io_buffer[4] == 0 && s->io_buffer[5] == 0 &&
+-            s->io_buffer[6] == 0 && s->io_buffer[7] == 0))
+-        {
+-            /* This is a no activity message we can hijack if we need to */
+-
+-            if(stat(IDE_ATAPI_PT_NEW_CD_FILE, &file_stat) == 0 &&
+-               s->atapi_pt.new_cd_time < file_stat.st_ctime)
+-            {
+-                /* There's been a new media message that we haven't seen yet */
+-                s->atapi_pt.new_cd_time = file_stat.st_ctime;
+-                DEBUG_PRINTF("[ATAPI] new media message spotted\n");
+-
+-                s->io_buffer[2] = 4;
+-                s->io_buffer[4] = 2;
+-                s->io_buffer[5] = 2;
+-                s->io_buffer[6] = 0;
+-                s->io_buffer[7] = 0;
+-            }
+-            else if(stat(IDE_ATAPI_PT_EJECT_CD_FILE, &file_stat) == 0 &&
+-               s->atapi_pt.eject_time < file_stat.st_ctime)
+-            {
+-                /* There's been an eject message that we haven't seen yet */
+-                DEBUG_PRINTF("[ATAPI] media removed message spotted\n");
+-                s->atapi_pt.eject_time = file_stat.st_ctime;
+-
+-                s->io_buffer[2] = 4;
+-                s->io_buffer[4] = 3;
+-                s->io_buffer[5] = 1;
+-                s->io_buffer[6] = 0;
+-                s->io_buffer[7] = 0;
+-            }
+-        }
+-    }
+-
+-    if(s->atapi_pt.din_xfer_len == 0)
+-    {
+-        // Nothing else to do
+-        ide_atapi_cmd_ok(s);
+-        return;
+-    }
+-
+-    din_desired = ide_atapi_pt_get_data_size(ide_atapi_pt_size_din, cmd_code, s->io_buffer);
+-
+-    /* din_xfer_len is the size of the buffer provided for the din data,
+-     * din_desired in the size of the data the LU tried to send to us. Either one
+-     * may be bigger. */
+-
+-    if(s->atapi_pt.request[0] == GPCMD_READ_BUFFER)
+-    {
+-        switch(s->atapi_pt.request[1] & 7)
+-        {
+-        case 0: // data with header, as specified in atapi_data_sizes table
+-            break;
+-
+-        case 2: // data only
+-            din_desired = s->atapi_pt.din_xfer_len;
+-            break;
+-        case 3: // header only
+-            din_desired = 4;
+-            break;
+-
+-        case 1: // vendor specific
+-        default:
+-            DEBUG_PRINTF("\e[3;31mIllegal read buffer mode %d\e[m\n",
+-                         s->io_buffer[1] & 7);
+-            ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
+-                                   ASC_INV_FIELD_IN_CMD_PACKET, 0, 0x70);
+-            return;
+-        }
+-    }
+-
+-    if(din_desired == (__u32)-1)
+-        din_desired = s->atapi_pt.din_xfer_len;
+-
+-    DEBUG_PRINTF("Read %d bytes of data (buffer size %d)\n",
+-                 din_desired, s->atapi_pt.din_xfer_len);
+-
+-    if(s->atapi_pt.din_xfer_len >= 0x80 && din_desired >= 0x80)
+-        DEBUG_HEXDUMP(s->io_buffer, 0x80);
+-    else if(s->atapi_pt.din_xfer_len < din_desired)
+-        DEBUG_HEXDUMP(s->io_buffer, s->atapi_pt.din_xfer_len);
+-    else
+-        DEBUG_HEXDUMP(s->io_buffer, din_desired);
+-
+-    ide_atapi_cmd_reply(s, din_desired, s->atapi_pt.din_xfer_len);
+ }
++
+diff --git a/hw/ide.c b/hw/ide.c
+index 37d0996..8a8c856 100644
+--- a/hw/ide.c
++++ b/hw/ide.c
+@@ -437,8 +437,8 @@ typedef struct ATAPIPassThroughState
+     pthread_t            sgio_thread;
+     pthread_mutex_t      sgio_mutex;
+     pthread_cond_t       sgio_cv;
+-    int                  sgio_rfd;
+-    int                  sgio_wfd;
++    int                  sgio_worker_fd;
++    int                  sgio_dispatch_fd;
+ } ATAPIPassThroughState;
+ #endif /* __linux__ */