Index: block-raw-posix.c =================================================================== --- block-raw-posix.c (Revision 4215) +++ block-raw-posix.c (Arbeitskopie) @@ -77,6 +77,7 @@ typedef struct BDRVRawState { int fd; int type; + int flags; unsigned int lseek_err_cnt; #if defined(__linux__) /* linux floppy specific */ @@ -95,6 +96,7 @@ BDRVRawState *s = bs->opaque; int fd, open_flags, ret; + s->flags = flags; s->lseek_err_cnt = 0; open_flags = O_BINARY; @@ -141,7 +143,11 @@ #endif */ -static int raw_pread(BlockDriverState *bs, int64_t offset, +/* + * offset and count are in bytes, but must be multiples of 512 (for files + * opened with O_DIRECT). buf must be aligned to 512 bytes. + */ +static int raw_pread_aligned(BlockDriverState *bs, int64_t offset, uint8_t *buf, int count) { BDRVRawState *s = bs->opaque; @@ -194,7 +200,11 @@ return ret; } -static int raw_pwrite(BlockDriverState *bs, int64_t offset, +/* + * offset and count are in bytes, but must be multiples of 512 (for files + * opened with O_DIRECT). buf must be aligned to 512 bytes. + */ +static int raw_pwrite_aligned(BlockDriverState *bs, int64_t offset, const uint8_t *buf, int count) { BDRVRawState *s = bs->opaque; @@ -230,6 +240,92 @@ return ret; } + +#ifdef O_DIRECT +/* + * offset and count are in bytes and possibly not aligned. For files opened + * with O_DIRECT, necessary alignments are ensured before calling + * raw_pread_aligned to do the actual read. + */ +static int raw_pread(BlockDriverState *bs, int64_t offset, + uint8_t *buf, int count) +{ + BDRVRawState *s = bs->opaque; + + if (unlikely((s->flags & BDRV_O_DIRECT) && + (offset % 512 != 0 || (uintptr_t) buf % 512))) { + + uint8_t* aligned_buf; + int64_t aligned_offs = offset & ~511; + int aligned_count = (count + offset - aligned_offs + 511) & ~511; + int ret; + + aligned_buf = qemu_memalign(512, 512 * aligned_count); + ret = raw_pread_aligned(bs, aligned_offs, aligned_buf, aligned_count); + + if (ret > count) + ret = count; + if (ret > 0) + memcpy(buf, aligned_buf + (offset - aligned_offs), ret); + + qemu_free(aligned_buf); + return ret; + + } else { + return raw_pread_aligned(bs, offset, buf, count); + } +} + +/* + * offset and count are in bytes and possibly not aligned. For files opened + * with O_DIRECT, necessary alignments are ensured before calling + * raw_pwrite_aligned to do the actual write. + */ +static int raw_pwrite(BlockDriverState *bs, int64_t offset, + const uint8_t *buf, int count) +{ + BDRVRawState *s = bs->opaque; + + if (unlikely((s->flags & BDRV_O_DIRECT) && + (offset % 512 != 0 || (uintptr_t) buf % 512))) { + + uint8_t* aligned_buf; + int64_t aligned_offs = offset & ~511; + int aligned_count = (count + offset - aligned_offs + 511) & ~511; + int ret; + + aligned_buf = qemu_memalign(512, 512 * aligned_count); + + /* Read in the first block if needed */ + if (offset - aligned_offs != 0) + raw_pread_aligned(bs, aligned_offs, aligned_buf, 512); + + /* Read in the last block if needed */ + if ((aligned_count > 512) && ((offset + count) % 512 != 0)) + raw_pread_aligned(bs, + aligned_offs + aligned_count - 512, + aligned_buf + aligned_count - 512, + 512); + + memcpy(aligned_buf + (offset - aligned_offs), buf, count); + ret = raw_pwrite_aligned(bs, aligned_offs, aligned_buf, aligned_count); + + if (ret > count) + ret = count; + + qemu_free(aligned_buf); + return ret; + } else { + return raw_pwrite_aligned(bs, offset, buf, count); + } +} + +#else +#define raw_pread raw_pread_aligned +#define raw_pwrite raw_pwrite_aligned +#endif + + /***********************************************************/ /* Unix AIO using POSIX AIO */ Index: Makefile =================================================================== --- Makefile (Revision 4215) +++ Makefile (Arbeitskopie) @@ -34,7 +34,7 @@ ####################################################################### # BLOCK_OBJS is code used by both qemu system emulation and qemu-img -BLOCK_OBJS=cutils.o +BLOCK_OBJS=cutils.o osdep.o BLOCK_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o BLOCK_OBJS+=block-dmg.o block-bochs.o block-vpc.o block-vvfat.o BLOCK_OBJS+=block-qcow2.o block-parallels.o