[Lguest] [PATCH] lguest.c: truncate problems in handle_block_output
Chris Malley
mail at chrismalley.co.uk
Wed Sep 26 02:13:51 EST 2007
Hi
I have been experiencing consistent problems with an lguest under moderate
I/O conditions (e.g. when updating the distribution with yum) where the guest
crashes with "Write past end 2965302784+4294967295", and I end up with a
zero-length disk image.
Turns out this is because (a) the offset is *not* 4294967295, but the failure
code -1 (so in fact it isn't a "Write past end" at all, just a write failure).
And (b) because my block device is 4G and ftruncate() can't handle it, the
file is truncated to zero bytes.
Patch is against v2.6.23-rc7.
[PATCH] lguest.c: truncate problems in handle_block_output
Properly handle the condition where writev (or readv) fail, returning -1.
Currently the return value is handled as unsigned int, rather than ssize_t
so it incorrectly appears to be a large positive number. This leads to
a false assumption that a large write has taken place, and that the file should
be truncated.
The function should also use ftruncate64() rather than ftruncate() to prevent
files over 4GB (not uncommon for a root filesystem) being zeroed.
Signed-off-by: Chris Malley <mail at chrismalley.co.uk>
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c
index f791840..10c0a96 100644
--- a/Documentation/lguest/lguest.c
+++ b/Documentation/lguest/lguest.c
@@ -848,7 +848,8 @@ static u32 handle_block_output(int fd, const struct iovec *iov,
{
struct lguest_block_page *p = dev->mem;
u32 irq, *lenp;
- unsigned int len, reply_num;
+ ssize_t len;
+ unsigned int reply_num;
struct iovec reply[LGUEST_MAX_DMA_SECTIONS];
off64_t device_len, off = (off64_t)p->sector * 512;
@@ -877,12 +878,14 @@ static u32 handle_block_output(int fd, const struct iovec *iov,
/* A write request. The DMA they sent contained the data, so
* write it out. */
len = writev(dev->fd, iov, num);
+ if (len < 0)
+ err(1, "Write failed with error %u", errno);
/* Grr... Now we know how long the "struct lguest_dma" they
* sent was, we make sure they didn't try to write over the end
* of the block file (possibly extending it). */
- if (off + len > device_len) {
+ else if (off + len > device_len) {
/* Trim it back to the correct length */
- ftruncate(dev->fd, device_len);
+ ftruncate64(dev->fd, device_len);
/* Die, bad Guest, die. */
errx(1, "Write past end %llu+%u", off, len);
}
@@ -894,7 +897,11 @@ static u32 handle_block_output(int fd, const struct iovec *iov,
* request, and we put the read contents into the reply
* buffer. */
len = readv(dev->fd, reply, reply_num);
- *lenp = len;
+ if (len < 0) {
+ err(1, "Read failed with error %u", errno);
+ *lenp = 0;
+ } else
+ *lenp = len;
}
/* The result is 1 (done), 2 if there was an error (short read or
More information about the Lguest
mailing list