Bug 1549231 - Unable to resize image with preallocation=full mode
Summary: Unable to resize image with preallocation=full mode
Keywords:
Status: CLOSED ERRATA
Alias: None
Product: Red Hat Enterprise Linux 7
Classification: Red Hat
Component: qemu-kvm-rhev
Version: 7.5
Hardware: Unspecified
OS: Unspecified
high
high
Target Milestone: rc
: ---
Assignee: Max Reitz
QA Contact: Tingting Mao
URL:
Whiteboard:
Depends On:
Blocks: 1537985 1566587
TreeView+ depends on / blocked
 
Reported: 2018-02-26 18:53 UTC by Daniel Berrangé
Modified: 2018-11-01 11:06 UTC (History)
17 users (show)

Fixed In Version: qemu-kvm-rhev-2.12.0-1.el7
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
: 1566587 (view as bug list)
Environment:
Last Closed: 2018-11-01 11:04:15 UTC


Attachments (Terms of Use)


Links
System ID Priority Status Summary Last Updated
Red Hat Product Errata RHBA-2018:3443 None None None 2018-11-01 11:06:44 UTC

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


Note You need to log in before you can comment on or make changes to this bug.