qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: qemu-devel@nongnu.org
Cc: kwolf@redhat.com
Subject: [Qemu-devel] [PATCH v2 10/18] raw: probe host_block_size
Date: Thu, 26 Jan 2012 18:22:41 +0100	[thread overview]
Message-ID: <1327598569-5199-11-git-send-email-pbonzini@redhat.com> (raw)
In-Reply-To: <1327598569-5199-1-git-send-email-pbonzini@redhat.com>

Use ioctls if possible, else see what alignment it takes for O_DIRECT
to succeed.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 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, &sector_size) >= 0) {
+        bs->host_block_size = sector_size;
+    }
+#endif
+#ifdef DKIOCGETBLOCKSIZE
+    if (ioctl(s->fd, DKIOCGETBLOCKSIZE, &sector_size) >= 0) {
+        bs->host_block_size = sector_size;
+    }
+#endif
+#ifdef DIOCGSECTORSIZE
+    if (ioctl(s->fd, DIOCGSECTORSIZE, &sector_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, &sectorsize) &&
-                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, &sectorsPerCluster,
+                         &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

  parent reply	other threads:[~2012-01-26 17:23 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-01-26 17:22 [Qemu-devel] [PATCH v2 00/18] Support mismatched host and guest logical block sizes Paolo Bonzini
2012-01-26 17:22 ` [Qemu-devel] [PATCH v2 01/18] block: do not rely on open_flags for bdrv_is_snapshot Paolo Bonzini
2012-01-26 17:22 ` [Qemu-devel] [PATCH v2 02/18] block: store actual flags in bs->open_flags Paolo Bonzini
2012-01-26 17:22 ` [Qemu-devel] [PATCH v2 03/18] block: pass protocol flags up to the format Paolo Bonzini
2012-01-26 17:22 ` [Qemu-devel] [PATCH v2 04/18] block: non-raw protocols never cache Paolo Bonzini
2012-01-26 17:22 ` [Qemu-devel] [PATCH v2 05/18] block: remove enable_write_cache Paolo Bonzini
2012-01-26 17:22 ` [Qemu-devel] [PATCH v2 06/18] block: move flag bits together Paolo Bonzini
2012-01-26 17:22 ` [Qemu-devel] [PATCH v2 07/18] raw: remove the aligned_buf Paolo Bonzini
2012-01-26 17:22 ` [Qemu-devel] [PATCH v2 08/18] block: rename buffer_alignment to guest_block_size Paolo Bonzini
2012-01-26 17:22 ` [Qemu-devel] [PATCH v2 09/18] block: add host_block_size Paolo Bonzini
2012-01-26 17:22 ` Paolo Bonzini [this message]
2012-01-26 17:22 ` [Qemu-devel] [PATCH v2 11/18] iscsi: save host block size Paolo Bonzini
2012-01-26 17:22 ` [Qemu-devel] [PATCH v2 12/18] block: allow waiting only for overlapping writes Paolo Bonzini
2012-01-26 17:22 ` [Qemu-devel] [PATCH v2 13/18] block: allow waiting at arbitrary granularity Paolo Bonzini
2012-01-26 17:22 ` [Qemu-devel] [PATCH v2 14/18] block: protect against "torn reads" for guest_block_size > host_block_size Paolo Bonzini
2012-01-26 17:22 ` [Qemu-devel] [PATCH v2 15/18] block: align and serialize I/O when guest_block_size < host_block_size Paolo Bonzini
2012-01-26 17:22 ` [Qemu-devel] [PATCH v2 16/18] block: default physical block size to host block size Paolo Bonzini
2012-01-26 17:22 ` [Qemu-devel] [PATCH v2 17/18] block: default min_io_size to host block size when doing rmw Paolo Bonzini
2012-01-26 17:22 ` [Qemu-devel] [PATCH v2 18/18] qemu-io: add blocksize argument to open Paolo Bonzini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1327598569-5199-11-git-send-email-pbonzini@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).