diff options
author | Stefan Hajnoczi <stefanha@redhat.com> | 2015-03-05 15:38:17 -0600 |
---|---|---|
committer | Kevin Wolf <kwolf@redhat.com> | 2015-03-10 14:02:24 +0100 |
commit | 22d182e82b4ba2fb78b2cc22bcec4e6a440b0ad6 (patch) | |
tree | e7ee073dd85357041aa7d9d21169e20e09853dd9 /block | |
parent | c095348b914b740d8364a2ccf748e4284de3b68b (diff) |
block/raw-posix: fix launching with failed disks
Since commit c25f53b06eba1575d5d0e92a0132455c97825b83 ("raw: Probe
required direct I/O alignment") QEMU has failed to launch if image files
produce I/O errors.
Previously, QEMU would launch successfully and the guest would see the
errors when attempting I/O.
This is a regression and may prevent multipath I/O inside the guest,
where QEMU must launch and let the guest figure out by itself which
disks are online.
Tweak the alignment probing code in raw-posix.c to explicitly look for
EINVAL on Linux instead of bailing. The kernel refuses misaligned
requests with this error code and other error codes can be ignored.
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'block')
-rw-r--r-- | block/raw-posix.c | 29 |
1 files changed, 27 insertions, 2 deletions
diff --git a/block/raw-posix.c b/block/raw-posix.c index 3263d2b5a1..f0b4488d1e 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -272,6 +272,31 @@ static int probe_physical_blocksize(int fd, unsigned int *blk_size) #endif } +/* Check if read is allowed with given memory buffer and length. + * + * This function is used to check O_DIRECT memory buffer and request alignment. + */ +static bool raw_is_io_aligned(int fd, void *buf, size_t len) +{ + ssize_t ret = pread(fd, buf, len, 0); + + if (ret >= 0) { + return true; + } + +#ifdef __linux__ + /* The Linux kernel returns EINVAL for misaligned O_DIRECT reads. Ignore + * other errors (e.g. real I/O error), which could happen on a failed + * drive, since we only care about probing alignment. + */ + if (errno != EINVAL) { + return true; + } +#endif + + return false; +} + static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp) { BDRVRawState *s = bs->opaque; @@ -307,7 +332,7 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp) size_t align; buf = qemu_memalign(MAX_BLOCKSIZE, 2 * MAX_BLOCKSIZE); for (align = 512; align <= MAX_BLOCKSIZE; align <<= 1) { - if (pread(fd, buf + align, MAX_BLOCKSIZE, 0) >= 0) { + if (raw_is_io_aligned(fd, buf + align, MAX_BLOCKSIZE)) { s->buf_align = align; break; } @@ -319,7 +344,7 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp) size_t align; buf = qemu_memalign(s->buf_align, MAX_BLOCKSIZE); for (align = 512; align <= MAX_BLOCKSIZE; align <<= 1) { - if (pread(fd, buf, align, 0) >= 0) { + if (raw_is_io_aligned(fd, buf, align)) { bs->request_alignment = align; break; } |