]> xenbits.xen.org Git - xenclient/ioemu-pq.git/commitdiff
Make qemu use separate thread for async ATAPI passthrough
authorThomas Horsten <thomas.horsten@citrix.com>
Wed, 16 Sep 2009 17:31:03 +0000 (18:31 +0100)
committerThomas Horsten <thomas.horsten@citrix.com>
Wed, 16 Sep 2009 17:31:03 +0000 (18:31 +0100)
master/atapi-async-fix.patch [new file with mode: 0644]
master/series

diff --git a/master/atapi-async-fix.patch b/master/atapi-async-fix.patch
new file mode 100644 (file)
index 0000000..bbca52d
--- /dev/null
@@ -0,0 +1,265 @@
+diff --git a/hw/atapi-pt.c b/hw/atapi-pt.c
+index 92f2934..c2a24ec 100644
+--- a/hw/atapi-pt.c
++++ b/hw/atapi-pt.c
+@@ -1,19 +1,25 @@
++#include <scsi/sg.h>
+ #include <utime.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>
++#include <pthread.h>
++#include <sys/ioctl.h>
+ #undef DEBUG_IDE_ATAPI_PT
+ #define MSF_TO_FRAMES(M, S, F) (((M) * CD_SECS + (S)) * CD_FRAMES + (F))
++static int log_fd=-1;
+ #ifdef DEBUG_IDE_ATAPI_PT
+-# define DEBUG_PRINTF(Args...) printf(Args)
++# define DEBUG_PRINTF(Args...) do { char buf[1024]; int len; if (log_fd==-1) log_fd=open("/tmp/cdrom.log",O_WRONLY | O_CREAT | O_APPEND,0666);  len=sprintf(buf,Args); write(log_fd,buf,len); } while (1==0)
++//#undef fprintf
++//# define DEBUG_PRINTF(Args...) fprintf(stderr, Args)
+ # define CHECK_SAME_VALUE(Val1, Val2)                                   \
+     do {                                                                \
+-        if ((Val1) != (Val2))                                           \
+-            printf("[\e[1;32m!VALUE\e[m] %s:%d, %s=%d %s=%d\n",         \
+-                   __PRETTY_FUNCTION__, __LINE__, #Val1, (Val1),        \
+-                   #Val2, (Val2));                                      \
++    if ((Val1) != (Val2))                                           \
++      printf("[\e[1;32m!VALUE\e[m] %s:%d, %s=%d %s=%d\n",         \
++          __PRETTY_FUNCTION__, __LINE__, #Val1, (Val1),        \
++             #Val2, (Val2));                                      \
+     } while (0)
+ #else
+ # define DEBUG_PRINTF(Args...)
+@@ -676,14 +682,58 @@ static void ide_atapi_pt_error(IDEState *s)
+     ide_set_irq(s);
+ }
+-static void ide_atapi_pt_do_sg_io(IDEState *s)
++static void *ide_atapi_pt_sgio_worker_thread(void *arg)
+ {
+-    struct sg_io_v4 *cmd = &s->atapi_pt.cmd;
+-    BDRVRawState *raw_state = s->bs->opaque;
+     int r;
+-    uint8_t cmd_code = s->atapi_pt.request[0];
+-    uint32_t din_desired;
++    volatile struct sg_io_v4 *cmd;
++    BDRVRawState *raw_state;
++    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);
++
++      /* Send command and wait for reply, SG_IO ioctl*/
++      cmd = &s->atapi_pt.cmd;
++      raw_state = s->bs->opaque;
++      r = ioctl(raw_state->fd, 0x2285, cmd);
++
++      /* Unlock _before_ signalling parent */
++      pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
++      write(s->atapi_pt.sgio_wfd, &r, sizeof(int));
++    }
++}
++
++static int ide_atapi_pt_aio_flush(void *unused)
++{
++    return 0;
++}
++
++static void ide_atapi_pt_do_sg_io_complete(void *unused);
++
++static void ide_atapi_pt_setup_sgio_thread(IDEState *s)
++{
++    int fds[2];
++
++    DEBUG_PRINTF("%s\n", __FUNCTION__);
++    if (pipe(fds) < 0) {
++      fprintf(stderr, "atapi-pt failed to create pipe: %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);
++    pthread_create(&s->atapi_pt.sgio_thread, NULL, ide_atapi_pt_sgio_worker_thread, (void *)s);
++    qemu_aio_set_fd_handler(s->atapi_pt.sgio_rfd, ide_atapi_pt_do_sg_io_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, int timeout)
++{
++    DEBUG_PRINTF("%s\n", __FUNCTION__);
++    struct sg_io_v4 *cmd = &s->atapi_pt.cmd;
+     assert(cmd->din_xfer_len != (__u32)-1);
+     s->atapi_pt.sense.error_code = 0;
+@@ -691,9 +741,27 @@ static void ide_atapi_pt_do_sg_io(IDEState *s)
+     s->atapi_pt.sense.asc = 0;
+     s->atapi_pt.sense.ascq = 0;
++    cmd->timeout = timeout ? timeout : 15000;
+-    /* Send command and wait for reply, SG_IO ioctl*/
+-    r = ioctl(raw_state->fd, 0x2285, cmd);
++    /* 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);
++}
++
++static void ide_atapi_pt_do_sg_io_complete(void *arg)
++{
++    IDEState *s = (IDEState *)arg;
++    struct sg_io_v4 *cmd = &s->atapi_pt.cmd;
++    BDRVRawState *raw_state = s->bs->opaque;
++    int r;
++    uint8_t cmd_code = s->atapi_pt.request[0];
++    uint32_t din_desired;
++
++    DEBUG_PRINTF("%s\n", __FUNCTION__);
++    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.request[0] == GPCMD_GET_EVENT_STATUS_NOTIFICATION)
+     {
+@@ -836,12 +904,14 @@ static void ide_atapi_pt_do_sg_io(IDEState *s)
+     ide_atapi_cmd_reply(s, din_desired, cmd->din_xfer_len);
+ }
++/* 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);
++    ide_atapi_pt_do_sg_io(s, 0);
+ }
++/* Call with ide_atapi_sgio_mutex held */
+ static void ide_atapi_pt_dout_fetch_dma_done(void *opaque, int ret)
+ {
+     BMDMAState *bm = opaque;
+@@ -850,13 +920,15 @@ 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;
+     }
+     i = dma_buf_rw(bm, 0);
+-    ide_atapi_pt_do_sg_io(s);
++    ide_atapi_pt_do_sg_io(s, 0);
+ }
++/* Call with ide_atapi_sgio_mutex held */
+ static void ide_atapi_pt_wcmd(IDEState *s)
+ {
+     if (s->atapi_dma)
+@@ -1005,11 +1077,20 @@ static int ide_atapi_pt_read_cd_block_size(const uint8_t *io_buffer)
+     return block_size;
+ }
++
+ static void ide_atapi_pt_cmd(IDEState *s)
+ {
++    int timeout;
+     struct sg_io_v4 *cmd = &s->atapi_pt.cmd;
+     uint8_t cmd_code;
++
++    DEBUG_PRINTF("%s (before mutex)\n", __FUNCTION__);
++    if (pthread_mutex_trylock(&s->atapi_pt.sgio_mutex)) {
++        fprintf(stderr, "ide_atapi_pt_cmd() called with existing request processing - ignored!\n");
++        return;
++    }
++
+     memset(cmd, 0, sizeof(*cmd));
+     memcpy(s->atapi_pt.request, s->io_buffer, ATAPI_PACKET_SIZE);
+     cmd_code = s->atapi_pt.request[0];
+@@ -1021,6 +1102,7 @@ static void ide_atapi_pt_cmd(IDEState *s)
+     cmd->response         = (__u64)&s->atapi_pt.sense;
+     cmd->max_response_len = sizeof(s->atapi_pt.sense);
+     cmd->timeout          = 15000; // 15 seconds
++    timeout = 0;
+     s->status |= BUSY_STAT;
+@@ -1054,14 +1136,15 @@ static void ide_atapi_pt_cmd(IDEState *s)
+             ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
+                                    ASC_INV_FIELD_IN_CMD_PACKET, 0x70);
++      pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
+         return;
+     case GPCMD_BLANK: // bigger timeout while blanking
+-        cmd->timeout = 1000 * 60 * 80; // 80 mins
++        timeout = 1000 * 60 * 80; // 80 mins
+         break;
+     case GPCMD_CLOSE_TRACK:
+-        cmd->timeout = 1000 * 60 * 5; // 5 mins
++        timeout = 1000 * 60 * 5; // 5 mins
+         break;
+     case GPCMD_WRITE_BUFFER:
+@@ -1072,6 +1155,7 @@ static void ide_atapi_pt_cmd(IDEState *s)
+                          s->io_buffer[1] & 7);
+             ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
+                                    ASC_ILLEGAL_OPCODE, 0x70);
++          pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
+             return;
+         }
+@@ -1091,6 +1175,7 @@ static void ide_atapi_pt_cmd(IDEState *s)
+         int size = 8 + s->atapi_pt.sense.add_sense_len;
+         memcpy(s->io_buffer, &s->atapi_pt.sense, sizeof (s->atapi_pt.sense));
+         ide_atapi_cmd_reply(s, size, max_size);
++      pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
+         return;
+     }
+@@ -1152,6 +1237,7 @@ static void ide_atapi_pt_cmd(IDEState *s)
+                          s->io_buffer[10]);
+             ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
+                                    ASC_ILLEGAL_OPCODE, 0x70);
++          pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
+             return;
+         }
+         break;
+@@ -1169,5 +1255,5 @@ static void ide_atapi_pt_cmd(IDEState *s)
+         return;
+     }
+-    ide_atapi_pt_do_sg_io(s);
++    ide_atapi_pt_do_sg_io(s, timeout);
+ }
+diff --git a/hw/ide.c b/hw/ide.c
+index 6c1d60a..2b58728 100644
+--- a/hw/ide.c
++++ b/hw/ide.c
+@@ -435,6 +435,12 @@ typedef struct ATAPIPassThroughState
+     time_t               new_cd_time;
+     time_t               eject_time;
++
++    pthread_t            sgio_thread;
++    pthread_mutex_t      sgio_mutex;
++    pthread_cond_t       sgio_cv;
++    int                  sgio_rfd;
++    int                  sgio_wfd;
+ } ATAPIPassThroughState;
+ #endif /* __linux__ */
+@@ -3220,6 +3226,7 @@ static void ide_init2(IDEState *ide_state,
+             }
+ #ifdef __linux__
+             else if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM_PT) {
++              ide_atapi_pt_setup_sgio_thread(s);
+                 //              BDRVRawState *raw_state = s->bs->opaque;
+                 s->is_cdrom = 1;
+                 s->atapi_cmd = ide_atapi_pt_cmd;
index 9a556512b6272509ba14c8aa3cafca81b45fd827..27b3be7c6ce5aaa56ba28d498d22ed170f8de18c 100644 (file)
@@ -30,3 +30,4 @@ new-input-code
 atapi-pass-through
 pv_driver_throttling_disabled
 move-iso-cdrom
+atapi-async-fix.patch