Bug 1549231

Summary: Unable to resize image with preallocation=full mode
Product: Red Hat Enterprise Linux 7 Reporter: Daniel Berrangé <berrange>
Component: qemu-kvm-rhevAssignee: Max Reitz <mreitz>
Status: CLOSED ERRATA QA Contact: Tingting Mao <timao>
Severity: high Docs Contact:
Priority: high    
Version: 7.5CC: berrange, chayang, coli, egallen, hhuang, juzhang, kchamart, michen, mreitz, mrezanin, mtessun, ngu, qzhang, timao, tnisan, virt-maint, ylavi
Target Milestone: rcKeywords: ZStream
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: qemu-kvm-rhev-2.12.0-1.el7 Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of:
: 1566587 (view as bug list) Environment:
Last Closed: 2018-11-01 11:04:15 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Bug Depends On:    
Bug Blocks: 1537985, 1566587    

Description Daniel Berrangé 2018-02-26 18:53:28 UTC
Description of problem:

It is impossible to resize a file with preallocation=full, if its current size would correspond to a negative number when represented as an int32

eg create a 5GB raw file initially

$  qemu-img create -f raw demo.img 5G
Formatting 'demo.img', fmt=raw size=5368709120

We can successfully extend it one 1GB in size

$ qemu-img resize -f raw --preallocation=full demo.img +1G
Image resized.

But trying to further extend it fails

$ qemu-img resize -f raw --preallocation=full demo.img +1G
qemu-img: Failed to seek to the old end of file: Invalid argument

If you strace it, we can see the lseek() succeeded, despite the message

$ strace -e trace=lseek qemu-img resize -f raw --preallocation=full demo.img +1G
lseek(10, 0, SEEK_END)                  = 6442450944
lseek(10, 6442450944, SEEK_SET)         = 6442450944
qemu-img: Failed to seek to the old end of file: Invalid argument
+++ exited with 1 +++



The problem appears to be caused by this commit:

commit d0bc9e5d5e86d5dd566e2d967af8476cee351c93
Author: Max Reitz <mreitz@redhat.com>
Date:   Tue Jun 13 22:20:58 2017 +0200

    block/file-posix: Generalize raw_regular_truncate

which added this bit of code to the preallocation=full 

 
+        result = lseek(fd, current_length, SEEK_SET);
+        if (result < 0) {
+            result = -errno;
+            error_setg_errno(errp, -result,
+                             "Failed to seek to the old end of file");
+            goto out;
+        }
+

The 'result' variable here is a plain 'int', so 32-bits, causing the lseek result to overflow & wrap around.

This patch is new in QEMU 2.10.0, so would be a regression compared to earlier 7.x releases.

Version-Release number of selected component (if applicable):
qemu-kvm-rhev-2.10.0-21.el7.x86_64

Comment 3 Ping Li 2018-02-27 09:37:27 UTC
Hi Daniel,

I cannot reproduce the bug. The issue i met is that further extending passed, but the image is not fully allocated. It should be same issue as the bug 1537985.

Version-Release number of selected component:
qemu-kvm-rhev-2.10.0-21.el7
kernel-3.10.0-856.el7.x86_64

Test steps:
1. Create the image.
# qemu-img create -f raw demo.img 5G
Formatting 'demo.img', fmt=raw size=5368709120

2. Extend the image with 'full' mode, and the image is grown with full allocated.
# qemu-img resize -f raw --preallocation=full demo.img +1G
Image resized.
# qemu-img map --output=json demo.img
[{ "start": 0, "length": 5368709120, "depth": 0, "zero": true, "data": false, "offset": 0},
{ "start": 5368709120, "length": 1073741824, "depth": 0, "zero": false, "data": true, "offset": 5368709120}]

3. Further extend the image with 'full' mode. The command passed but the image isn't grown with full allocated.
# strace -e trace=lseek qemu-img resize -f raw --preallocation=full demo.img +1G
lseek(10, 0, SEEK_END)                  = 6442450944
lseek(10, 6442450944, SEEK_SET)         = 6442450944
lseek(10, 0, SEEK_END)                  = 7516192768
Image resized.
+++ exited with 0 +++
# qemu-img map --output=json demo.img
[{ "start": 0, "length": 5368709120, "depth": 0, "zero": true, "data": false, "offset": 0},
{ "start": 5368709120, "length": 1073741824, "depth": 0, "zero": false, "data": true, "offset": 5368709120},
{ "start": 6442450944, "length": 1073741824, "depth": 0, "zero": true, "data": false, "offset": 6442450944}]

Comment 4 Daniel Berrangé 2018-02-27 10:45:53 UTC
I think your result can be explained by the flawed code I identified. It sets 'result = -errno' when it gets integer wraparound. The 'lseek' syscall did not fail though, so this 'errno' value is going to be completely random garbage - in fact it could even be 'zero' in which case it will skip the preallocation logic thinking it has an error, but then return 0 from this method indicating success to the caller.

Comment 7 Max Reitz 2018-03-26 20:26:51 UTC
Hi,

Sorry, for some reason this got lost in my queue.  I didn't even merge the upstream patches until now...

Max

Comment 18 errata-xmlrpc 2018-11-01 11:04:15 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHBA-2018:3443