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
This commit is contained in:
aliguori 2009-04-07 18:43:28 +00:00
parent f141eafe28
commit ceb42de899
3 changed files with 101 additions and 4 deletions

View File

@ -1354,10 +1354,9 @@ static void bdrv_aio_bh_cb(void *opaque)
{ {
BlockDriverAIOCBSync *acb = opaque; BlockDriverAIOCBSync *acb = opaque;
qemu_vfree(acb->bounce);
if (!acb->is_write) if (!acb->is_write)
qemu_iovec_from_buffer(acb->qiov, acb->bounce, acb->qiov->size); qemu_iovec_from_buffer(acb->qiov, acb->bounce, acb->qiov->size);
qemu_vfree(acb->bounce);
acb->common.cb(acb->common.opaque, acb->ret); acb->common.cb(acb->common.opaque, acb->ret);
qemu_aio_release(acb); qemu_aio_release(acb);

17
configure vendored
View File

@ -1107,6 +1107,19 @@ if $cc $ARCH_CFLAGS -o $TMPE $TMPC > /dev/null 2> /dev/null ; then
iovec=yes iovec=yes
fi fi
##########################################
# preadv probe
cat > $TMPC <<EOF
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
int main(void) { preadv; }
EOF
preadv=no
if $cc $ARCH_CFLAGS -o $TMPE $TMPC > /dev/null 2> /dev/null ; then
preadv=yes
fi
########################################## ##########################################
# fdt probe # fdt probe
if test "$fdt" = "yes" ; then if test "$fdt" = "yes" ; then
@ -1221,6 +1234,7 @@ echo "AIO support $aio"
echo "Install blobs $blobs" echo "Install blobs $blobs"
echo "KVM support $kvm" echo "KVM support $kvm"
echo "fdt support $fdt" echo "fdt support $fdt"
echo "preadv support $preadv"
if test $sdl_too_old = "yes"; then if test $sdl_too_old = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support" echo "-> Your SDL version is too old - please upgrade to have SDL support"
@ -1522,6 +1536,9 @@ fi
if test "$iovec" = "yes" ; then if test "$iovec" = "yes" ; then
echo "#define HAVE_IOVEC 1" >> $config_h echo "#define HAVE_IOVEC 1" >> $config_h
fi fi
if test "$preadv" = "yes" ; then
echo "#define HAVE_PREADV 1" >> $config_h
fi
if test "$fdt" = "yes" ; then if test "$fdt" = "yes" ; then
echo "#define HAVE_FDT 1" >> $config_h echo "#define HAVE_FDT 1" >> $config_h
echo "FDT_LIBS=-lfdt" >> $config_mak echo "FDT_LIBS=-lfdt" >> $config_mak

View File

@ -33,6 +33,12 @@ static int cur_threads = 0;
static int idle_threads = 0; static int idle_threads = 0;
static TAILQ_HEAD(, qemu_paiocb) request_list; static TAILQ_HEAD(, qemu_paiocb) request_list;
#ifdef HAVE_PREADV
static int preadv_present = 1;
#else
static int preadv_present = 0;
#endif
static void die2(int err, const char *what) static void die2(int err, const char *what)
{ {
fprintf(stderr, "%s failed: %s\n", what, strerror(err)); fprintf(stderr, "%s failed: %s\n", what, strerror(err));
@ -87,6 +93,36 @@ static size_t handle_aiocb_ioctl(struct qemu_paiocb *aiocb)
return ret; return ret;
} }
#ifdef HAVE_PREADV
static ssize_t
qemu_preadv(int fd, const struct iovec *iov, int nr_iov, off_t offset)
{
return preadv(fd, iov, nr_iov, offset);
}
static ssize_t
qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
{
return pwritev(fd, iov, nr_iov, offset);
}
#else
static ssize_t
qemu_preadv(int fd, const struct iovec *iov, int nr_iov, off_t offset)
{
return -ENOSYS;
}
static ssize_t
qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
{
return -ENOSYS;
}
#endif
/* /*
* Check if we need to copy the data in the aiocb into a new * Check if we need to copy the data in the aiocb into a new
* properly aligned buffer. * properly aligned buffer.
@ -104,6 +140,29 @@ static int aiocb_needs_copy(struct qemu_paiocb *aiocb)
return 0; return 0;
} }
static size_t handle_aiocb_rw_vector(struct qemu_paiocb *aiocb)
{
size_t offset = 0;
ssize_t len;
do {
if (aiocb->aio_type == QEMU_PAIO_WRITE)
len = qemu_pwritev(aiocb->aio_fildes,
aiocb->aio_iov,
aiocb->aio_niov,
aiocb->aio_offset + offset);
else
len = qemu_preadv(aiocb->aio_fildes,
aiocb->aio_iov,
aiocb->aio_niov,
aiocb->aio_offset + offset);
} while (len == -1 && errno == EINTR);
if (len == -1)
return -errno;
return len;
}
static size_t handle_aiocb_rw_linear(struct qemu_paiocb *aiocb, char *buf) static size_t handle_aiocb_rw_linear(struct qemu_paiocb *aiocb, char *buf)
{ {
size_t offset = 0; size_t offset = 0;
@ -140,12 +199,34 @@ static size_t handle_aiocb_rw(struct qemu_paiocb *aiocb)
size_t nbytes; size_t nbytes;
char *buf; char *buf;
if (!aiocb_needs_copy(aiocb) && aiocb->aio_niov == 1) { if (!aiocb_needs_copy(aiocb)) {
/* /*
* If there is just a single buffer, and it is properly aligned * If there is just a single buffer, and it is properly aligned
* we can just use plain pread/pwrite without any problems. * we can just use plain pread/pwrite without any problems.
*/ */
return handle_aiocb_rw_linear(aiocb, aiocb->aio_iov->iov_base); if (aiocb->aio_niov == 1)
return handle_aiocb_rw_linear(aiocb, aiocb->aio_iov->iov_base);
/*
* We have more than one iovec, and all are properly aligned.
*
* Try preadv/pwritev first and fall back to linearizing the
* buffer if it's not supported.
*/
if (preadv_present) {
nbytes = handle_aiocb_rw_vector(aiocb);
if (nbytes == aiocb->aio_nbytes)
return nbytes;
if (nbytes < 0 && nbytes != -ENOSYS)
return nbytes;
preadv_present = 0;
}
/*
* XXX(hch): short read/write. no easy way to handle the reminder
* using these interfaces. For now retry using plain
* pread/pwrite?
*/
} }
/* /*