Commit ceb42de899e068d10f104d570c3fb3b36ec8e8d6

Authored by aliguori
1 parent f141eafe

native preadv/pwritev support (Christoph Hellwig)

This ties up the preadv/pwritev syscalls to qemu if they are declared in
unistd.h.  This is the case currently on at least NetBSD and OpenBSD and
will hopefully soon be the case on Linux.

Thanks to Blue Swirl and Gerd Hoffmann for the configure autodetection
of preadv/pwritev.


Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7021 c046a42c-6fe2-441c-8c8c-71466251a162
@@ -1354,10 +1354,9 @@ static void bdrv_aio_bh_cb(void *opaque) @@ -1354,10 +1354,9 @@ static void bdrv_aio_bh_cb(void *opaque)
1354 { 1354 {
1355 BlockDriverAIOCBSync *acb = opaque; 1355 BlockDriverAIOCBSync *acb = opaque;
1356 1356
1357 - qemu_vfree(acb->bounce);  
1358 -  
1359 if (!acb->is_write) 1357 if (!acb->is_write)
1360 qemu_iovec_from_buffer(acb->qiov, acb->bounce, acb->qiov->size); 1358 qemu_iovec_from_buffer(acb->qiov, acb->bounce, acb->qiov->size);
  1359 + qemu_vfree(acb->bounce);
1361 acb->common.cb(acb->common.opaque, acb->ret); 1360 acb->common.cb(acb->common.opaque, acb->ret);
1362 1361
1363 qemu_aio_release(acb); 1362 qemu_aio_release(acb);
configure
@@ -1108,6 +1108,19 @@ if $cc $ARCH_CFLAGS -o $TMPE $TMPC &gt; /dev/null 2&gt; /dev/null ; then @@ -1108,6 +1108,19 @@ if $cc $ARCH_CFLAGS -o $TMPE $TMPC &gt; /dev/null 2&gt; /dev/null ; then
1108 fi 1108 fi
1109 1109
1110 ########################################## 1110 ##########################################
  1111 +# preadv probe
  1112 +cat > $TMPC <<EOF
  1113 +#include <sys/types.h>
  1114 +#include <sys/uio.h>
  1115 +#include <unistd.h>
  1116 +int main(void) { preadv; }
  1117 +EOF
  1118 +preadv=no
  1119 +if $cc $ARCH_CFLAGS -o $TMPE $TMPC > /dev/null 2> /dev/null ; then
  1120 + preadv=yes
  1121 +fi
  1122 +
  1123 +##########################################
1111 # fdt probe 1124 # fdt probe
1112 if test "$fdt" = "yes" ; then 1125 if test "$fdt" = "yes" ; then
1113 fdt=no 1126 fdt=no
@@ -1221,6 +1234,7 @@ echo &quot;AIO support $aio&quot; @@ -1221,6 +1234,7 @@ echo &quot;AIO support $aio&quot;
1221 echo "Install blobs $blobs" 1234 echo "Install blobs $blobs"
1222 echo "KVM support $kvm" 1235 echo "KVM support $kvm"
1223 echo "fdt support $fdt" 1236 echo "fdt support $fdt"
  1237 +echo "preadv support $preadv"
1224 1238
1225 if test $sdl_too_old = "yes"; then 1239 if test $sdl_too_old = "yes"; then
1226 echo "-> Your SDL version is too old - please upgrade to have SDL support" 1240 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -1522,6 +1536,9 @@ fi @@ -1522,6 +1536,9 @@ fi
1522 if test "$iovec" = "yes" ; then 1536 if test "$iovec" = "yes" ; then
1523 echo "#define HAVE_IOVEC 1" >> $config_h 1537 echo "#define HAVE_IOVEC 1" >> $config_h
1524 fi 1538 fi
  1539 +if test "$preadv" = "yes" ; then
  1540 + echo "#define HAVE_PREADV 1" >> $config_h
  1541 +fi
1525 if test "$fdt" = "yes" ; then 1542 if test "$fdt" = "yes" ; then
1526 echo "#define HAVE_FDT 1" >> $config_h 1543 echo "#define HAVE_FDT 1" >> $config_h
1527 echo "FDT_LIBS=-lfdt" >> $config_mak 1544 echo "FDT_LIBS=-lfdt" >> $config_mak
posix-aio-compat.c
@@ -33,6 +33,12 @@ static int cur_threads = 0; @@ -33,6 +33,12 @@ static int cur_threads = 0;
33 static int idle_threads = 0; 33 static int idle_threads = 0;
34 static TAILQ_HEAD(, qemu_paiocb) request_list; 34 static TAILQ_HEAD(, qemu_paiocb) request_list;
35 35
  36 +#ifdef HAVE_PREADV
  37 +static int preadv_present = 1;
  38 +#else
  39 +static int preadv_present = 0;
  40 +#endif
  41 +
36 static void die2(int err, const char *what) 42 static void die2(int err, const char *what)
37 { 43 {
38 fprintf(stderr, "%s failed: %s\n", what, strerror(err)); 44 fprintf(stderr, "%s failed: %s\n", what, strerror(err));
@@ -87,6 +93,36 @@ static size_t handle_aiocb_ioctl(struct qemu_paiocb *aiocb) @@ -87,6 +93,36 @@ static size_t handle_aiocb_ioctl(struct qemu_paiocb *aiocb)
87 return ret; 93 return ret;
88 } 94 }
89 95
  96 +#ifdef HAVE_PREADV
  97 +
  98 +static ssize_t
  99 +qemu_preadv(int fd, const struct iovec *iov, int nr_iov, off_t offset)
  100 +{
  101 + return preadv(fd, iov, nr_iov, offset);
  102 +}
  103 +
  104 +static ssize_t
  105 +qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
  106 +{
  107 + return pwritev(fd, iov, nr_iov, offset);
  108 +}
  109 +
  110 +#else
  111 +
  112 +static ssize_t
  113 +qemu_preadv(int fd, const struct iovec *iov, int nr_iov, off_t offset)
  114 +{
  115 + return -ENOSYS;
  116 +}
  117 +
  118 +static ssize_t
  119 +qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
  120 +{
  121 + return -ENOSYS;
  122 +}
  123 +
  124 +#endif
  125 +
90 /* 126 /*
91 * Check if we need to copy the data in the aiocb into a new 127 * Check if we need to copy the data in the aiocb into a new
92 * properly aligned buffer. 128 * properly aligned buffer.
@@ -104,6 +140,29 @@ static int aiocb_needs_copy(struct qemu_paiocb *aiocb) @@ -104,6 +140,29 @@ static int aiocb_needs_copy(struct qemu_paiocb *aiocb)
104 return 0; 140 return 0;
105 } 141 }
106 142
  143 +static size_t handle_aiocb_rw_vector(struct qemu_paiocb *aiocb)
  144 +{
  145 + size_t offset = 0;
  146 + ssize_t len;
  147 +
  148 + do {
  149 + if (aiocb->aio_type == QEMU_PAIO_WRITE)
  150 + len = qemu_pwritev(aiocb->aio_fildes,
  151 + aiocb->aio_iov,
  152 + aiocb->aio_niov,
  153 + aiocb->aio_offset + offset);
  154 + else
  155 + len = qemu_preadv(aiocb->aio_fildes,
  156 + aiocb->aio_iov,
  157 + aiocb->aio_niov,
  158 + aiocb->aio_offset + offset);
  159 + } while (len == -1 && errno == EINTR);
  160 +
  161 + if (len == -1)
  162 + return -errno;
  163 + return len;
  164 +}
  165 +
107 static size_t handle_aiocb_rw_linear(struct qemu_paiocb *aiocb, char *buf) 166 static size_t handle_aiocb_rw_linear(struct qemu_paiocb *aiocb, char *buf)
108 { 167 {
109 size_t offset = 0; 168 size_t offset = 0;
@@ -140,12 +199,34 @@ static size_t handle_aiocb_rw(struct qemu_paiocb *aiocb) @@ -140,12 +199,34 @@ static size_t handle_aiocb_rw(struct qemu_paiocb *aiocb)
140 size_t nbytes; 199 size_t nbytes;
141 char *buf; 200 char *buf;
142 201
143 - if (!aiocb_needs_copy(aiocb) && aiocb->aio_niov == 1) { 202 + if (!aiocb_needs_copy(aiocb)) {
144 /* 203 /*
145 * If there is just a single buffer, and it is properly aligned 204 * If there is just a single buffer, and it is properly aligned
146 * we can just use plain pread/pwrite without any problems. 205 * we can just use plain pread/pwrite without any problems.
147 */ 206 */
148 - return handle_aiocb_rw_linear(aiocb, aiocb->aio_iov->iov_base); 207 + if (aiocb->aio_niov == 1)
  208 + return handle_aiocb_rw_linear(aiocb, aiocb->aio_iov->iov_base);
  209 +
  210 + /*
  211 + * We have more than one iovec, and all are properly aligned.
  212 + *
  213 + * Try preadv/pwritev first and fall back to linearizing the
  214 + * buffer if it's not supported.
  215 + */
  216 + if (preadv_present) {
  217 + nbytes = handle_aiocb_rw_vector(aiocb);
  218 + if (nbytes == aiocb->aio_nbytes)
  219 + return nbytes;
  220 + if (nbytes < 0 && nbytes != -ENOSYS)
  221 + return nbytes;
  222 + preadv_present = 0;
  223 + }
  224 +
  225 + /*
  226 + * XXX(hch): short read/write. no easy way to handle the reminder
  227 + * using these interfaces. For now retry using plain
  228 + * pread/pwrite?
  229 + */
149 } 230 }
150 231
151 /* 232 /*