Index: block-raw-posix.c =================================================================== --- block-raw-posix.c.orig +++ block-raw-posix.c @@ -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 @@ static int raw_open(BlockDriverState *bs BDRVRawState *s = bs->opaque; int fd, open_flags, ret; + s->flags = flags; s->lseek_err_cnt = 0; open_flags = O_BINARY; @@ -141,7 +143,14 @@ static int raw_open(BlockDriverState *bs #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 then. + * + * This function may be called without alignment if the caller ensures + * that O_DIRECT is not in effect. + */ +static int raw_pread_aligned(BlockDriverState *bs, int64_t offset, uint8_t *buf, int count) { BDRVRawState *s = bs->opaque; @@ -194,7 +203,14 @@ label__raw_read__success: 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 then. + * + * This function may be called without alignment if the caller ensures + * that O_DIRECT is not in effect. + */ +static int raw_pwrite_aligned(BlockDriverState *bs, int64_t offset, const uint8_t *buf, int count) { BDRVRawState *s = bs->opaque; @@ -230,6 +246,69 @@ label__raw_write__success: 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))) { + + int flags, ret; + + // Temporarily disable O_DIRECT for unaligned access + flags = fcntl(s->fd, F_GETFL); + fcntl(s->fd, F_SETFL, flags & ~O_DIRECT); + ret = raw_pread_aligned(bs, offset, buf, count); + fcntl(s->fd, F_SETFL, flags); + + 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))) { + + int flags, ret; + + // Temporarily disable O_DIRECT for unaligned access + flags = fcntl(s->fd, F_GETFL); + fcntl(s->fd, F_SETFL, flags & ~O_DIRECT); + ret = raw_pwrite_aligned(bs, offset, buf, count); + fcntl(s->fd, F_SETFL, flags); + + 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 */