@@ -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;
}
}
@@ -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;
}
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(-)