Skip to content

Commit

Permalink
block: round up file size to nearest sector
Browse files Browse the repository at this point in the history
Currently the file size requested by user is rounded down to nearest
sector, causing the actual file size could be a bit less than the size
user requested. Since some formats (like qcow2) record virtual disk
size in bytes, this can make the last few bytes cannot be accessed.

This patch fixes it by rounding up file size to nearest sector so that
the actual file size is no less than the requested file size.

Signed-off-by: Hu Tao <[email protected]>
Reviewed-by: Kevin Wolf <[email protected]>
Reviewed-by: Eric Blake <[email protected]>
Reviewed-by: Max Reitz <[email protected]>
Signed-off-by: Kevin Wolf <[email protected]>
  • Loading branch information
Hu Tao authored and kevmw committed Sep 12, 2014
1 parent be2bfb9 commit c2eb918
Show file tree
Hide file tree
Showing 21 changed files with 127 additions and 23 deletions.
3 changes: 2 additions & 1 deletion block/archipelago.c
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,8 @@ static int qemu_archipelago_create(const char *filename,

parse_filename_opts(filename, errp, &volname, &segment_name, &mport,
&vport);
total_size = qemu_opt_get_size_del(options, BLOCK_OPT_SIZE, 0);
total_size = ROUND_UP(qemu_opt_get_size_del(options, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);

if (segment_name == NULL) {
segment_name = g_strdup("archipelago");
Expand Down
3 changes: 2 additions & 1 deletion block/cow.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,8 @@ static int cow_create(const char *filename, QemuOpts *opts, Error **errp)
BlockDriverState *cow_bs = NULL;

/* Read out options */
image_sectors = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / 512;
image_sectors = DIV_ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
image_filename = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);

ret = bdrv_create_file(filename, opts, &local_err);
Expand Down
4 changes: 2 additions & 2 deletions block/gluster.c
Original file line number Diff line number Diff line change
Expand Up @@ -494,8 +494,8 @@ static int qemu_gluster_create(const char *filename,
goto out;
}

total_size =
qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
total_size = DIV_ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);

tmp = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
if (!tmp || !strcmp(tmp, "off")) {
Expand Down
4 changes: 2 additions & 2 deletions block/iscsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1531,8 +1531,8 @@ static int iscsi_create(const char *filename, QemuOpts *opts, Error **errp)
bs = bdrv_new("", &error_abort);

/* Read out options */
total_size =
qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
total_size = DIV_ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
bs->opaque = g_new0(struct IscsiLun, 1);
iscsilun = bs->opaque;

Expand Down
3 changes: 2 additions & 1 deletion block/nfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,8 @@ static int nfs_file_create(const char *url, QemuOpts *opts, Error **errp)
client->aio_context = qemu_get_aio_context();

/* Read out options */
total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);

ret = nfs_client_open(client, url, O_CREAT, errp);
if (ret < 0) {
Expand Down
3 changes: 2 additions & 1 deletion block/qcow.c
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,8 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
BlockDriverState *qcow_bs;

/* Read out options */
total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / 512;
total_size = DIV_ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
flags |= BLOCK_FLAG_ENCRYPT;
Expand Down
3 changes: 2 additions & 1 deletion block/qcow2.c
Original file line number Diff line number Diff line change
Expand Up @@ -1921,7 +1921,8 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
int ret;

/* Read out options */
sectors = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / 512;
sectors = DIV_ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT);
if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
Expand Down
3 changes: 2 additions & 1 deletion block/qed.c
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,8 @@ static int bdrv_qed_create(const char *filename, QemuOpts *opts, Error **errp)
char *backing_fmt = NULL;
int ret;

image_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
image_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT);
cluster_size = qemu_opt_get_size_del(opts,
Expand Down
8 changes: 4 additions & 4 deletions block/raw-posix.c
Original file line number Diff line number Diff line change
Expand Up @@ -1369,8 +1369,8 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
strstart(filename, "file:", &filename);

/* Read out options */
total_size =
qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
total_size = DIV_ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false);

fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Expand Down Expand Up @@ -1966,8 +1966,8 @@ static int hdev_create(const char *filename, QemuOpts *opts,
(void)has_prefix;

/* Read out options */
total_size =
qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
total_size = DIV_ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);

fd = qemu_open(filename, O_WRONLY | O_BINARY);
if (fd < 0) {
Expand Down
4 changes: 2 additions & 2 deletions block/raw-win32.c
Original file line number Diff line number Diff line change
Expand Up @@ -511,8 +511,8 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
strstart(filename, "file:", &filename);

/* Read out options */
total_size =
qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / 512;
total_size = DIV_ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);

fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
0644);
Expand Down
3 changes: 2 additions & 1 deletion block/rbd.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,8 @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
}

/* Read out options */
bytes = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
bytes = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
objsize = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE, 0);
if (objsize) {
if ((objsize - 1) & objsize) { /* not a power of 2? */
Expand Down
3 changes: 2 additions & 1 deletion block/sheepdog.c
Original file line number Diff line number Diff line change
Expand Up @@ -1702,7 +1702,8 @@ static int sd_create(const char *filename, QemuOpts *opts,
goto out;
}

s->inode.vdi_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
s->inode.vdi_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
if (!buf || !strcmp(buf, "off")) {
Expand Down
3 changes: 2 additions & 1 deletion block/ssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,8 @@ static int ssh_create(const char *filename, QemuOpts *opts, Error **errp)
ssh_state_init(&s);

/* Get desired file size. */
total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
DPRINTF("total_size=%" PRIi64, total_size);

uri_options = qdict_new();
Expand Down
3 changes: 2 additions & 1 deletion block/vdi.c
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,8 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
logout("\n");

/* Read out options. */
bytes = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
bytes = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
#if defined(CONFIG_VDI_BLOCK_SIZE)
/* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */
block_size = qemu_opt_get_size_del(opts,
Expand Down
3 changes: 2 additions & 1 deletion block/vhdx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1766,7 +1766,8 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
VHDXImageType image_type;
Error *local_err = NULL;

image_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
image_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
log_size = qemu_opt_get_size_del(opts, VHDX_BLOCK_OPT_LOG_SIZE, 0);
block_size = qemu_opt_get_size_del(opts, VHDX_BLOCK_OPT_BLOCK_SIZE, 0);
type = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT);
Expand Down
3 changes: 2 additions & 1 deletion block/vmdk.c
Original file line number Diff line number Diff line change
Expand Up @@ -1807,7 +1807,8 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
goto exit;
}
/* Read out options */
total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
adapter_type = qemu_opt_get_del(opts, BLOCK_OPT_ADAPTER_TYPE);
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
if (qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false)) {
Expand Down
3 changes: 2 additions & 1 deletion block/vpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -757,7 +757,8 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
BlockDriverState *bs = NULL;

/* Read out options */
total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
disk_type_param = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT);
if (disk_type_param) {
if (!strcmp(disk_type_param, "dynamic")) {
Expand Down
57 changes: 57 additions & 0 deletions tests/qemu-iotests/104
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/bin/bash
#
# Test image creation with aligned and unaligned sizes
#
# Copyright (C) 2014 Fujitsu.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

# creator
[email protected]

seq=`basename $0`
echo "QA output created by $seq"

here=`pwd`
tmp=/tmp/$$
status=1 # failure is the default!

_cleanup()
{
_cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15

# get standard environment, filters and checks
. ./common.rc
. ./common.filter

_supported_fmt generic
_supported_proto generic
_supported_os Linux

echo "=== Check qemu-img info output ==="
echo
image_sizes="1024 1234"

for s in $image_sizes; do
_make_test_img $s | _filter_img_create
_img_info | _filter_img_info
done

# success, all done
echo "*** done"
rm -f $seq.full
status=0
12 changes: 12 additions & 0 deletions tests/qemu-iotests/104.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
QA output created by 104
=== Check qemu-img info output ===

Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1024
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 1.0K (1024 bytes)
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1234
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 1.5K (1536 bytes)
***done
21 changes: 21 additions & 0 deletions tests/qemu-iotests/common.filter
Original file line number Diff line number Diff line change
Expand Up @@ -192,5 +192,26 @@ _filter_img_create()
-e "s/archipelago:a/TEST_DIR\//g"
}

_filter_img_info()
{
sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
-e "s#$TEST_DIR#TEST_DIR#g" \
-e "s#$IMGFMT#IMGFMT#g" \
-e "/encrypted: yes/d" \
-e "/cluster_size: [0-9]\\+/d" \
-e "/table_size: [0-9]\\+/d" \
-e "/compat: '[^']*'/d" \
-e "/compat6: \\(on\\|off\\)/d" \
-e "/static: \\(on\\|off\\)/d" \
-e "/zeroed_grain: \\(on\\|off\\)/d" \
-e "/subformat: '[^']*'/d" \
-e "/adapter_type: '[^']*'/d" \
-e "/lazy_refcounts: \\(on\\|off\\)/d" \
-e "/block_size: [0-9]\\+/d" \
-e "/block_state_zero: \\(on\\|off\\)/d" \
-e "/log_size: [0-9]\\+/d" \
-e "s/archipelago:a/TEST_DIR\//g"
}

# make sure this script returns success
/bin/true
1 change: 1 addition & 0 deletions tests/qemu-iotests/group
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,4 @@
100 rw auto quick
101 rw auto quick
103 rw auto quick
104 rw auto

0 comments on commit c2eb918

Please sign in to comment.