[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v2 10/18] raw: probe host_block_size
From: |
Paolo Bonzini |
Subject: |
[Qemu-devel] [PATCH v2 10/18] raw: probe host_block_size |
Date: |
Thu, 26 Jan 2012 18:22:41 +0100 |
Use ioctls if possible, else see what alignment it takes for O_DIRECT
to succeed.
Signed-off-by: Paolo Bonzini <address@hidden>
---
block/raw-posix.c | 72 ++++++++++++++++++++++++++++++++++++++++------------
block/raw-win32.c | 42 +++++++++++++++++++++++++++++++
2 files changed, 97 insertions(+), 17 deletions(-)
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 49a8c21..3537394 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -52,6 +52,7 @@
#include <sys/param.h>
#include <linux/cdrom.h>
#include <linux/fd.h>
+#include <linux/fs.h>
#endif
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
#include <sys/disk.h>
@@ -179,6 +180,58 @@ 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. */
+ if (bs->sg) {
+ return;
+ }
+
+ /* For block devices, try to get the actual sector size even if we
+ * do not need it, so that it can be passed down to the guest.
+ */
+#ifdef BLKSSZGET
+ if (ioctl(s->fd, BLKSSZGET, §or_size) >= 0) {
+ bs->host_block_size = sector_size;
+ }
+#endif
+#ifdef DKIOCGETBLOCKSIZE
+ if (ioctl(s->fd, DKIOCGETBLOCKSIZE, §or_size) >= 0) {
+ bs->host_block_size = sector_size;
+ }
+#endif
+#ifdef DIOCGSECTORSIZE
+ if (ioctl(s->fd, DIOCGSECTORSIZE, §or_size) >= 0) {
+ bs->host_block_size = sector_size;
+ }
+#endif
+
+ /* If we could not get the size so far, we can only guess it if the file
+ * was opened with O_DIRECT. Using the minimal value (512) is okay.
+ * It may or may not be safe if the guest logical block size is >512;
+ * however, we will print a scary message suggesting usage of cache=none.
+ * If they hear our advice, the host block size will be detected correctly
+ * and the scary message will go away.
+ */
+ if (!(bs->open_flags & BDRV_O_NOCACHE)) {
+ return;
+ }
+
+ buf = qemu_memalign(MAX_BLOCKSIZE, MAX_BLOCKSIZE);
+ for (sector_size = 512; sector_size < MAX_BLOCKSIZE; sector_size <<= 1) {
+ /* The buffer must be aligned to sector_size, but not sector_size*2.
*/
+ if (pread(s->fd, buf + sector_size, sector_size, 0) >= 0) {
+ break;
+ }
+ }
+ bs->host_block_size = sector_size;
+ qemu_vfree(buf);
+}
+
static int raw_open_common(BlockDriverState *bs, const char *filename,
int bdrv_flags, int open_flags)
{
@@ -214,6 +267,7 @@ static int raw_open_common(BlockDriverState *bs, const char
*filename,
return ret;
}
s->fd = fd;
+ raw_probe_alignment(bs);
/* We're falling back to POSIX AIO in some cases so init always */
if (paio_init() < 0) {
@@ -262,22 +316,6 @@ static int raw_open(BlockDriverState *bs, const char
*filename, int flags)
return raw_open_common(bs, filename, flags, 0);
}
-/* XXX: use host sector size if necessary with:
-#ifdef DIOCGSECTORSIZE
- {
- unsigned int sectorsize = 512;
- if (!ioctl(fd, DIOCGSECTORSIZE, §orsize) &&
- sectorsize > bufsize)
- bufsize = sectorsize;
- }
-#endif
-#ifdef CONFIG_COCOA
- uint32_t blockSize = 512;
- if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize >
bufsize) {
- bufsize = blockSize;
- }
-#endif
-*/
/*
* Check if all memory in this vector is sector aligned.
@@ -287,7 +325,7 @@ static int qiov_is_aligned(BlockDriverState *bs,
QEMUIOVector *qiov)
int i;
for (i = 0; i < qiov->niov; i++) {
- if ((uintptr_t) qiov->iov[i].iov_base % bs->guest_block_size) {
+ if ((uintptr_t) qiov->iov[i].iov_base % bs->host_block_size) {
return 0;
}
}
diff --git a/block/raw-win32.c b/block/raw-win32.c
index e4b0b75..d8b76de 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -77,6 +77,35 @@ static int set_sparse(int fd)
NULL, 0, NULL, 0, &returned, NULL);
}
+static void raw_probe_alignment(BlockDriverState *bs)
+{
+ BDRVRawState *s = bs->opaque;
+ DWORD sectorsPerCluster, freeClusters, totalClusters, count;
+ DISK_GEOMETRY_EX dg;
+ BOOL status;
+
+ if (s->type == FTYPE_CD) {
+ bs->host_block_size = 2048;
+ return;
+ }
+ if (s->type == FTYPE_HARDDISK) {
+ status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
+ NULL, 0, &dg, sizeof(dg), &count, NULL);
+ if (status != 0) {
+ bs->host_block_size = dg.Geometry.BytesPerSector;
+ return;
+ }
+ /* try GetDiskFreeSpace too */
+ }
+
+ if (s->drive_path[0]) {
+ GetDiskFreeSpace(s->drive_path, §orsPerCluster,
+ &dg.Geometry.BytesPerSector,
+ &freeClusters, &totalClusters);
+ bs->host_block_size = dg.Geometry.BytesPerSector;
+ }
+}
+
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
@@ -96,6 +125,18 @@ static int raw_open(BlockDriverState *bs, const char
*filename, int flags)
overlapped |= FILE_FLAG_NO_BUFFERING;
if (!(flags & BDRV_O_CACHE_WB))
overlapped |= FILE_FLAG_WRITE_THROUGH;
+
+ if (filename[0] && filename[1] == ':') {
+ snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", filename[0]);
+ } else if (filename[0] == '\\' && filename[1] == '\\') {
+ s->drive_path[0] = 0;
+ } else {
+ /* Relative path. */
+ char buf[MAX_PATH];
+ GetCurrentDirectory(MAX_PATH, buf);
+ snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", buf[0]);
+ }
+
s->hfile = CreateFile(filename, access_flags,
FILE_SHARE_READ, NULL,
OPEN_EXISTING, overlapped, NULL);
@@ -106,6 +147,7 @@ static int raw_open(BlockDriverState *bs, const char
*filename, int flags)
return -EACCES;
return -1;
}
+ raw_probe_alignment(bs);
return 0;
}
--
1.7.7.6
- [Qemu-devel] [PATCH v2 01/18] block: do not rely on open_flags for bdrv_is_snapshot, (continued)
- [Qemu-devel] [PATCH v2 01/18] block: do not rely on open_flags for bdrv_is_snapshot, Paolo Bonzini, 2012/01/26
- [Qemu-devel] [PATCH v2 03/18] block: pass protocol flags up to the format, Paolo Bonzini, 2012/01/26
- [Qemu-devel] [PATCH v2 02/18] block: store actual flags in bs->open_flags, Paolo Bonzini, 2012/01/26
- [Qemu-devel] [PATCH v2 04/18] block: non-raw protocols never cache, Paolo Bonzini, 2012/01/26
- [Qemu-devel] [PATCH v2 05/18] block: remove enable_write_cache, Paolo Bonzini, 2012/01/26
- [Qemu-devel] [PATCH v2 06/18] block: move flag bits together, Paolo Bonzini, 2012/01/26
- [Qemu-devel] [PATCH v2 07/18] raw: remove the aligned_buf, Paolo Bonzini, 2012/01/26
- [Qemu-devel] [PATCH v2 09/18] block: add host_block_size, Paolo Bonzini, 2012/01/26
- [Qemu-devel] [PATCH v2 11/18] iscsi: save host block size, Paolo Bonzini, 2012/01/26
- [Qemu-devel] [PATCH v2 08/18] block: rename buffer_alignment to guest_block_size, Paolo Bonzini, 2012/01/26
- [Qemu-devel] [PATCH v2 10/18] raw: probe host_block_size,
Paolo Bonzini <=
- [Qemu-devel] [PATCH v2 12/18] block: allow waiting only for overlapping writes, Paolo Bonzini, 2012/01/26
- [Qemu-devel] [PATCH v2 14/18] block: protect against "torn reads" for guest_block_size > host_block_size, Paolo Bonzini, 2012/01/26
- [Qemu-devel] [PATCH v2 17/18] block: default min_io_size to host block size when doing rmw, Paolo Bonzini, 2012/01/26
- [Qemu-devel] [PATCH v2 16/18] block: default physical block size to host block size, Paolo Bonzini, 2012/01/26
- [Qemu-devel] [PATCH v2 18/18] qemu-io: add blocksize argument to open, Paolo Bonzini, 2012/01/26
- [Qemu-devel] [PATCH v2 15/18] block: align and serialize I/O when guest_block_size < host_block_size, Paolo Bonzini, 2012/01/26
- [Qemu-devel] [PATCH v2 13/18] block: allow waiting at arbitrary granularity, Paolo Bonzini, 2012/01/26