[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