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 1354 {
1355 1355 BlockDriverAIOCBSync *acb = opaque;
1356 1356  
1357   - qemu_vfree(acb->bounce);
1358   -
1359 1357 if (!acb->is_write)
1360 1358 qemu_iovec_from_buffer(acb->qiov, acb->bounce, acb->qiov->size);
  1359 + qemu_vfree(acb->bounce);
1361 1360 acb->common.cb(acb->common.opaque, acb->ret);
1362 1361  
1363 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 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 1124 # fdt probe
1112 1125 if test "$fdt" = "yes" ; then
1113 1126 fdt=no
... ... @@ -1221,6 +1234,7 @@ echo &quot;AIO support $aio&quot;
1221 1234 echo "Install blobs $blobs"
1222 1235 echo "KVM support $kvm"
1223 1236 echo "fdt support $fdt"
  1237 +echo "preadv support $preadv"
1224 1238  
1225 1239 if test $sdl_too_old = "yes"; then
1226 1240 echo "-> Your SDL version is too old - please upgrade to have SDL support"
... ... @@ -1522,6 +1536,9 @@ fi
1522 1536 if test "$iovec" = "yes" ; then
1523 1537 echo "#define HAVE_IOVEC 1" >> $config_h
1524 1538 fi
  1539 +if test "$preadv" = "yes" ; then
  1540 + echo "#define HAVE_PREADV 1" >> $config_h
  1541 +fi
1525 1542 if test "$fdt" = "yes" ; then
1526 1543 echo "#define HAVE_FDT 1" >> $config_h
1527 1544 echo "FDT_LIBS=-lfdt" >> $config_mak
... ...
posix-aio-compat.c
... ... @@ -33,6 +33,12 @@ static int cur_threads = 0;
33 33 static int idle_threads = 0;
34 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 42 static void die2(int err, const char *what)
37 43 {
38 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 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 127 * Check if we need to copy the data in the aiocb into a new
92 128 * properly aligned buffer.
... ... @@ -104,6 +140,29 @@ static int aiocb_needs_copy(struct qemu_paiocb *aiocb)
104 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 166 static size_t handle_aiocb_rw_linear(struct qemu_paiocb *aiocb, char *buf)
108 167 {
109 168 size_t offset = 0;
... ... @@ -140,12 +199,34 @@ static size_t handle_aiocb_rw(struct qemu_paiocb *aiocb)
140 199 size_t nbytes;
141 200 char *buf;
142 201  
143   - if (!aiocb_needs_copy(aiocb) && aiocb->aio_niov == 1) {
  202 + if (!aiocb_needs_copy(aiocb)) {
144 203 /*
145 204 * If there is just a single buffer, and it is properly aligned
146 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 /*
... ...