>From 5ab001859f3abeb792ef22d073d2bc38f6bb8604 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 22 Jan 2009 16:22:41 +0100 Subject: [PATCH] preadv/writev code for qemu. --- Makefile | 1 + configure | 14 +++++ qemu-common.h | 3 + qemu-io-syscalls.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+), 0 deletions(-) create mode 100644 qemu-io-syscalls.c diff --git a/Makefile b/Makefile index 4f7a55a..7921d54 100644 --- a/Makefile +++ b/Makefile @@ -85,6 +85,7 @@ OBJS+=sd.o ssi-sd.o OBJS+=bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o OBJS+=buffered_file.o migration.o migration-tcp.o net.o qemu-sockets.o OBJS+=qemu-char.o aio.o net-checksum.o savevm.o cache-utils.o +OBJS+=qemu-io-syscalls.o ifdef CONFIG_BRLAPI OBJS+= baum.o diff --git a/configure b/configure index c3fbbbe..a873cf4 100755 --- a/configure +++ b/configure @@ -1037,6 +1037,17 @@ if $cc $ARCH_CFLAGS -o $TMPE $TMPC > /dev/null 2> /dev/null ; then fi ########################################## +# preadv probe +cat > $TMPC < +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 if test "$fdt" = "yes" ; then fdt=no @@ -1432,6 +1443,9 @@ fi if test "$iovec" = "yes" ; then echo "#define HAVE_IOVEC 1" >> $config_h fi +if test "$preadv" = "yes" ; then + echo "#define HAVE_PREADV 1" >> $config_h +fi if test "$fdt" = "yes" ; then echo "#define HAVE_FDT 1" >> $config_h echo "FDT_LIBS=-lfdt" >> $config_mak diff --git a/qemu-common.h b/qemu-common.h index 42d5e49..0dfc575 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -204,6 +204,9 @@ void qemu_iovec_destroy(QEMUIOVector *qiov); void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf); void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count); +ssize_t qemu_preadv(int fd, QEMUIOVector *qiov, off_t offset); +ssize_t qemu_pwritev(int fd, QEMUIOVector *qiov, off_t offset); + #endif /* dyngen-exec.h hack */ #endif diff --git a/qemu-io-syscalls.c b/qemu-io-syscalls.c new file mode 100644 index 0000000..f96e35a --- /dev/null +++ b/qemu-io-syscalls.c @@ -0,0 +1,140 @@ +/* + * preadv/pwritev implementation + * (c) 2008 Gerd Hoffmann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + */ + +#include +#include + +/* --------------------------------------------------------------- */ +/* linux: preadv/pwritev syscall windup */ + +#ifndef HAVE_PREADV +# ifdef __linux__ +# include + +#if 0 +/* WARNING: Be sure you know what you are doing if you enable this. + * linux syscall code isn't upstream yet, syscall numbers are subject + * to change */ +# ifndef __NR_preadv +# ifdef __i386__ +# define __NR_preadv 333 +# define __NR_pwritev 334 +# endif +# ifdef __x86_64__ +# define __NR_preadv 295 +# define __NR_pwritev 296 +# endif +# endif +#endif + +# ifdef __NR_preadv +# define HAVE_PREADV 1 + +static ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) +{ + uint32_t pos_high = (offset >> 32) & 0xffffffff; + uint32_t pos_low = offset & 0xffffffff; + + return syscall(__NR_preadv, fd, iov, iovcnt, pos_high, pos_low); +} + +static ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) +{ + uint32_t pos_high = (offset >> 32) & 0xffffffff; + uint32_t pos_low = offset & 0xffffffff; + + return syscall(__NR_pwritev, fd, iov, iovcnt, pos_high, pos_low); +} + +# endif /* __NR_preadv */ +# endif /* __linux__ */ + +#endif /* HAVE_PREADV */ + +/* --------------------------------------------------------------- */ +/* preadv/pwritev emulation */ + +static ssize_t emulate_prwv(int fd, QEMUIOVector *qiov, + off_t offset, int is_write) +{ + uint8_t *buf; + ssize_t ret; + + buf = malloc(qiov->size); + if (NULL == buf) { + errno = ENOMEM; + return -1; + } + + if (is_write) { + qemu_iovec_to_buffer(qiov, buf); + ret = pwrite(fd, buf, qiov->size, offset); + } else { + ret = pread(fd, buf, qiov->size, offset); + if (ret > 0) + qemu_iovec_from_buffer(qiov, buf, ret); + } + + free(buf); + return ret; +} + +/* --------------------------------------------------------------- */ +/* qemu preadv/pwritev interface */ + +#ifdef HAVE_PREADV +static int preadv_present = 1; +#endif + +ssize_t qemu_preadv(int fd, QEMUIOVector *qiov, off_t offset) +{ +#ifdef HAVE_PREADV + ssize_t ret; + + if (preadv_present) { + ret = preadv(fd, qiov->iov, qiov->niov, offset); + if (ret < 0 && errno == ENOSYS) { + preadv_present = 0; + goto emulate; + } + return ret; + } +emulate: +#endif + + return emulate_prwv(fd, qiov, offset, 0); +} + +ssize_t qemu_pwritev(int fd, QEMUIOVector *qiov, off_t offset) +{ +#ifdef HAVE_PREADV + ssize_t ret; + + if (preadv_present) { + ret = pwritev(fd, qiov->iov, qiov->niov, offset); + if (ret < 0 && errno == ENOSYS) { + preadv_present = 0; + goto emulate; + } + return ret; + } +emulate: +#endif + + return emulate_prwv(fd, qiov, offset, 1); +} -- 1.6.1.3