From: Paolo Bonzini pbonz...@redhat.com
Add a bs-request_alignment field that contains the required
offset/length alignment for I/O requests and fill it in the raw block
drivers. Use ioctls if possible, else see what alignment it takes for
O_DIRECT to succeed.
While at it, also expose the memory alignment requirements, which may be
(and in practice are) different from the disk alignment requirements.
Signed-off-by: Paolo Bonzini pbonz...@redhat.com
Signed-off-by: Kevin Wolf kw...@redhat.com
---
block.c | 3 ++
block/raw-posix.c | 102 ++
block/raw-win32.c | 41 +++
include/block/block_int.h | 3 ++
4 files changed, 132 insertions(+), 17 deletions(-)
diff --git a/block.c b/block.c
index 3504d17..b86e754 100644
--- a/block.c
+++ b/block.c
@@ -813,6 +813,7 @@ static int bdrv_open_common(BlockDriverState *bs,
BlockDriverState *file,
bs-open_flags = flags;
bs-guest_block_size = 512;
+bs-request_alignment = 512;
bs-zero_beyond_eof = true;
open_flags = bdrv_open_flags(bs, flags);
bs-read_only = !(open_flags BDRV_O_RDWR);
@@ -881,6 +882,8 @@ static int bdrv_open_common(BlockDriverState *bs,
BlockDriverState *file,
}
bdrv_refresh_limits(bs);
+assert(bdrv_opt_mem_align(bs) != 0);
+assert(bs-request_alignment != 0);
#ifndef _WIN32
if (bs-is_temporary) {
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 10c6b34..e8e75a7 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -127,6 +127,8 @@ typedef struct BDRVRawState {
int fd;
int type;
int open_flags;
+size_t buf_align;
+
#if defined(__linux__)
/* linux floppy specific */
int64_t fd_open_time;
@@ -213,6 +215,76 @@ static int raw_normalize_devicepath(const char **filename)
}
#endif
+static void raw_probe_alignment(BlockDriverState *bs)
+{
+BDRVRawState *s = bs-opaque;
+char *buf;
+unsigned int sector_size;
+
+/* For /dev/sg devices the alignment is not really used.
+ With buffered I/O, we don't have any restrictions. */
+if (bs-sg || !(s-open_flags O_DIRECT)) {
+bs-request_alignment = 1;
+s-buf_align = 1;
+return;
+}
+
+/* Try a few ioctls to get the right size */
+bs-request_alignment = 0;
+s-buf_align = 0;
+
+#ifdef BLKSSZGET
+if (ioctl(s-fd, BLKSSZGET, sector_size) = 0) {
+bs-request_alignment = sector_size;
+}
+#endif
+#ifdef DKIOCGETBLOCKSIZE
+if (ioctl(s-fd, DKIOCGETBLOCKSIZE, sector_size) = 0) {
+bs-request_alignment = sector_size;
+}
+#endif
+#ifdef DIOCGSECTORSIZE
+if (ioctl(s-fd, DIOCGSECTORSIZE, sector_size) = 0) {
+bs-request_alignment = sector_size;
+}
+#endif
+#ifdef CONFIG_XFS
+if (s-is_xfs) {
+struct dioattr da;
+if (xfsctl(NULL, s-fd, XFS_IOC_DIOINFO, da) = 0) {
+bs-request_alignment = da.d_miniosz;
+/* The kernel returns wrong information for d_mem */
+/* s-buf_align = da.d_mem; */
+}
+}
+#endif
+
+/* If we could not get the sizes so far, we can only guess them */
+if (!s-buf_align) {
+size_t align;
+buf = qemu_memalign(MAX_BLOCKSIZE, 2 * MAX_BLOCKSIZE);
+for (align = 512; align = MAX_BLOCKSIZE; align = 1) {
+if (pread(s-fd, buf + align, MAX_BLOCKSIZE, 0) = 0) {
+s-buf_align = align;
+break;
+}
+}
+qemu_vfree(buf);
+}
+
+if (!bs-request_alignment) {
+size_t align;
+buf = qemu_memalign(s-buf_align, MAX_BLOCKSIZE);
+for (align = 512; align = MAX_BLOCKSIZE; align = 1) {
+if (pread(s-fd, buf, align, 0) = 0) {
+bs-request_alignment = align;
+break;
+}
+}
+qemu_vfree(buf);
+}
+}
+
static void raw_parse_flags(int bdrv_flags, int *open_flags)
{
assert(open_flags != NULL);
@@ -463,7 +535,6 @@ static int raw_reopen_prepare(BDRVReopenState *state,
return ret;
}
-
static void raw_reopen_commit(BDRVReopenState *state)
{
BDRVRawReopenState *raw_s = state-opaque;
@@ -499,23 +570,15 @@ static void raw_reopen_abort(BDRVReopenState *state)
state-opaque = NULL;
}
+static int raw_refresh_limits(BlockDriverState *bs)
+{
+BDRVRawState *s = bs-opaque;
-/* XXX: use host sector size if necessary with:
-#ifdef DIOCGSECTORSIZE
-{
-unsigned int sectorsize = 512;
-if (!ioctl(fd, DIOCGSECTORSIZE, sectorsize)
-sectorsize bufsize)
-bufsize = sectorsize;
-}
-#endif
-#ifdef CONFIG_COCOA
-uint32_t blockSize = 512;
-if ( !ioctl( fd, DKIOCGETBLOCKSIZE, blockSize ) blockSize
bufsize) {
-bufsize = blockSize;
-}
-#endif
-*/
+raw_probe_alignment(bs);
+bs-bl.opt_mem_alignment = s-buf_align;
+
+return 0;
+}
static ssize_t