Skip to content

Commit

Permalink
Merge remote-tracking branch 'kwolf/for-anthony' into staging
Browse files Browse the repository at this point in the history
# By Fam Zheng (8) and others
# Via Kevin Wolf
* kwolf/for-anthony:
  vmdk: rename num_gtes_per_gte to num_gtes_per_gt
  vmdk: use heap allocation for whole_grain
  vmdk: check l1 size before opening image
  vmdk: check l2 table size when opening
  vmdk: check granularity field in opening
  qemu-iotests: add empty test case for vmdk
  qemu-iotests: add poke_file utility function
  vmdk: use unsigned values for on disk header fields
  vmdk: Make VMDK3Header and VmdkGrainMarker QEMU_PACKED
  sheepdog: add missing .bdrv_has_zero_init
  qemu-iotests: filter QEMU version in monitor banner
  iov: handle EOF in iov_send_recv
  ignore SIGPIPE in qemu-img and qemu-io
  qemu-img: Error out for excess arguments

Message-id: [email protected]
Signed-off-by: Anthony Liguori <[email protected]>
  • Loading branch information
Anthony Liguori committed Aug 7, 2013
2 parents a1fc624 + ca8804c commit cafffa5
Show file tree
Hide file tree
Showing 11 changed files with 237 additions and 77 deletions.
2 changes: 2 additions & 0 deletions block/sheepdog.c
Original file line number Diff line number Diff line change
Expand Up @@ -2347,6 +2347,7 @@ static BlockDriver bdrv_sheepdog = {
.bdrv_file_open = sd_open,
.bdrv_close = sd_close,
.bdrv_create = sd_create,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_getlength = sd_getlength,
.bdrv_truncate = sd_truncate,

Expand Down Expand Up @@ -2374,6 +2375,7 @@ static BlockDriver bdrv_sheepdog_tcp = {
.bdrv_file_open = sd_open,
.bdrv_close = sd_close,
.bdrv_create = sd_create,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_getlength = sd_getlength,
.bdrv_truncate = sd_truncate,

Expand Down
115 changes: 78 additions & 37 deletions block/vmdk.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,20 @@ typedef struct {
uint32_t cylinders;
uint32_t heads;
uint32_t sectors_per_track;
} VMDK3Header;
} QEMU_PACKED VMDK3Header;

typedef struct {
uint32_t version;
uint32_t flags;
int64_t capacity;
int64_t granularity;
int64_t desc_offset;
int64_t desc_size;
int32_t num_gtes_per_gte;
int64_t rgd_offset;
int64_t gd_offset;
int64_t grain_offset;
uint64_t capacity;
uint64_t granularity;
uint64_t desc_offset;
uint64_t desc_size;
/* Number of GrainTableEntries per GrainTable */
uint32_t num_gtes_per_gt;
uint64_t rgd_offset;
uint64_t gd_offset;
uint64_t grain_offset;
char filler[1];
char check_bytes[4];
uint16_t compressAlgorithm;
Expand Down Expand Up @@ -109,7 +110,7 @@ typedef struct VmdkExtent {

typedef struct BDRVVmdkState {
CoMutex lock;
int desc_offset;
uint64_t desc_offset;
bool cid_updated;
uint32_t parent_cid;
int num_extents;
Expand All @@ -131,7 +132,7 @@ typedef struct VmdkGrainMarker {
uint64_t lba;
uint32_t size;
uint8_t data[0];
} VmdkGrainMarker;
} QEMU_PACKED VmdkGrainMarker;

enum {
MARKER_END_OF_STREAM = 0,
Expand Down Expand Up @@ -385,15 +386,22 @@ static int vmdk_parent_open(BlockDriverState *bs)

/* Create and append extent to the extent array. Return the added VmdkExtent
* address. return NULL if allocation failed. */
static VmdkExtent *vmdk_add_extent(BlockDriverState *bs,
static int vmdk_add_extent(BlockDriverState *bs,
BlockDriverState *file, bool flat, int64_t sectors,
int64_t l1_offset, int64_t l1_backup_offset,
uint32_t l1_size,
int l2_size, unsigned int cluster_sectors)
int l2_size, uint64_t cluster_sectors,
VmdkExtent **new_extent)
{
VmdkExtent *extent;
BDRVVmdkState *s = bs->opaque;

if (cluster_sectors > 0x200000) {
/* 0x200000 * 512Bytes = 1GB for one cluster is unrealistic */
error_report("invalid granularity, image may be corrupt");
return -EINVAL;
}

s->extents = g_realloc(s->extents,
(s->num_extents + 1) * sizeof(VmdkExtent));
extent = &s->extents[s->num_extents];
Expand All @@ -416,7 +424,10 @@ static VmdkExtent *vmdk_add_extent(BlockDriverState *bs,
extent->end_sector = extent->sectors;
}
bs->total_sectors = extent->end_sector;
return extent;
if (new_extent) {
*new_extent = extent;
}
return 0;
}

static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent)
Expand Down Expand Up @@ -475,12 +486,17 @@ static int vmdk_open_vmdk3(BlockDriverState *bs,
if (ret < 0) {
return ret;
}
extent = vmdk_add_extent(bs,

ret = vmdk_add_extent(bs,
bs->file, false,
le32_to_cpu(header.disk_sectors),
le32_to_cpu(header.l1dir_offset) << 9,
0, 1 << 6, 1 << 9,
le32_to_cpu(header.granularity));
le32_to_cpu(header.granularity),
&extent);
if (ret < 0) {
return ret;
}
ret = vmdk_init_tables(bs, extent);
if (ret) {
/* free extent allocated by vmdk_add_extent */
Expand All @@ -490,7 +506,7 @@ static int vmdk_open_vmdk3(BlockDriverState *bs,
}

static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
int64_t desc_offset);
uint64_t desc_offset);

static int vmdk_open_vmdk4(BlockDriverState *bs,
BlockDriverState *file,
Expand All @@ -508,7 +524,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
return ret;
}
if (header.capacity == 0) {
int64_t desc_offset = le64_to_cpu(header.desc_offset);
uint64_t desc_offset = le64_to_cpu(header.desc_offset);
if (desc_offset) {
return vmdk_open_desc_file(bs, flags, desc_offset << 9);
}
Expand Down Expand Up @@ -570,23 +586,40 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
return -ENOTSUP;
}

l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte)
if (le32_to_cpu(header.num_gtes_per_gt) > 512) {
error_report("L2 table size too big");
return -EINVAL;
}

l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gt)
* le64_to_cpu(header.granularity);
if (l1_entry_sectors == 0) {
return -EINVAL;
}
l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1)
/ l1_entry_sectors;
if (l1_size > 512 * 1024 * 1024) {
/* although with big capacity and small l1_entry_sectors, we can get a
* big l1_size, we don't want unbounded value to allocate the table.
* Limit it to 512M, which is 16PB for default cluster and L2 table
* size */
error_report("L1 size too big");
return -EFBIG;
}
if (le32_to_cpu(header.flags) & VMDK4_FLAG_RGD) {
l1_backup_offset = le64_to_cpu(header.rgd_offset) << 9;
}
extent = vmdk_add_extent(bs, file, false,
ret = vmdk_add_extent(bs, file, false,
le64_to_cpu(header.capacity),
le64_to_cpu(header.gd_offset) << 9,
l1_backup_offset,
l1_size,
le32_to_cpu(header.num_gtes_per_gte),
le64_to_cpu(header.granularity));
le32_to_cpu(header.num_gtes_per_gt),
le64_to_cpu(header.granularity),
&extent);
if (ret < 0) {
return ret;
}
extent->compressed =
le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE;
extent->has_marker = le32_to_cpu(header.flags) & VMDK4_FLAG_MARKER;
Expand Down Expand Up @@ -702,8 +735,11 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
/* FLAT extent */
VmdkExtent *extent;

extent = vmdk_add_extent(bs, extent_file, true, sectors,
0, 0, 0, 0, sectors);
ret = vmdk_add_extent(bs, extent_file, true, sectors,
0, 0, 0, 0, sectors, &extent);
if (ret < 0) {
return ret;
}
extent->flat_start_offset = flat_offset << 9;
} else if (!strcmp(type, "SPARSE")) {
/* SPARSE extent */
Expand All @@ -728,7 +764,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
}

static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
int64_t desc_offset)
uint64_t desc_offset)
{
int ret;
char *buf = NULL;
Expand Down Expand Up @@ -807,34 +843,39 @@ static int get_whole_cluster(BlockDriverState *bs,
uint64_t offset,
bool allocate)
{
/* 128 sectors * 512 bytes each = grain size 64KB */
uint8_t whole_grain[extent->cluster_sectors * 512];
int ret = VMDK_OK;
uint8_t *whole_grain = NULL;

/* we will be here if it's first write on non-exist grain(cluster).
* try to read from parent image, if exist */
if (bs->backing_hd) {
int ret;

whole_grain =
qemu_blockalign(bs, extent->cluster_sectors << BDRV_SECTOR_BITS);
if (!vmdk_is_cid_valid(bs)) {
return VMDK_ERROR;
ret = VMDK_ERROR;
goto exit;
}

/* floor offset to cluster */
offset -= offset % (extent->cluster_sectors * 512);
ret = bdrv_read(bs->backing_hd, offset >> 9, whole_grain,
extent->cluster_sectors);
if (ret < 0) {
return VMDK_ERROR;
ret = VMDK_ERROR;
goto exit;
}

/* Write grain only into the active image */
ret = bdrv_write(extent->file, cluster_offset, whole_grain,
extent->cluster_sectors);
if (ret < 0) {
return VMDK_ERROR;
ret = VMDK_ERROR;
goto exit;
}
}
return VMDK_OK;
exit:
qemu_vfree(whole_grain);
return ret;
}

static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data)
Expand Down Expand Up @@ -1371,12 +1412,12 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
header.compressAlgorithm = compress ? VMDK4_COMPRESSION_DEFLATE : 0;
header.capacity = filesize / 512;
header.granularity = 128;
header.num_gtes_per_gte = 512;
header.num_gtes_per_gt = 512;

grains = (filesize / 512 + header.granularity - 1) / header.granularity;
gt_size = ((header.num_gtes_per_gte * sizeof(uint32_t)) + 511) >> 9;
gt_size = ((header.num_gtes_per_gt * sizeof(uint32_t)) + 511) >> 9;
gt_count =
(grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte;
(grains + header.num_gtes_per_gt - 1) / header.num_gtes_per_gt;
gd_size = (gt_count * sizeof(uint32_t) + 511) >> 9;

header.desc_offset = 1;
Expand All @@ -1392,7 +1433,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
header.flags = cpu_to_le32(header.flags);
header.capacity = cpu_to_le64(header.capacity);
header.granularity = cpu_to_le64(header.granularity);
header.num_gtes_per_gte = cpu_to_le32(header.num_gtes_per_gte);
header.num_gtes_per_gt = cpu_to_le32(header.num_gtes_per_gt);
header.desc_offset = cpu_to_le64(header.desc_offset);
header.desc_size = cpu_to_le64(header.desc_size);
header.rgd_offset = cpu_to_le64(header.rgd_offset);
Expand Down
21 changes: 14 additions & 7 deletions qemu-img.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,9 @@ static int img_create(int argc, char **argv)
}
img_size = (uint64_t)sval;
}
if (optind != argc) {
help();
}

if (options && is_help_option(options)) {
return print_block_option_help(filename, fmt);
Expand Down Expand Up @@ -573,7 +576,7 @@ static int img_check(int argc, char **argv)
break;
}
}
if (optind >= argc) {
if (optind != argc - 1) {
help();
}
filename = argv[optind++];
Expand Down Expand Up @@ -684,7 +687,7 @@ static int img_commit(int argc, char **argv)
break;
}
}
if (optind >= argc) {
if (optind != argc - 1) {
help();
}
filename = argv[optind++];
Expand Down Expand Up @@ -930,7 +933,7 @@ static int img_compare(int argc, char **argv)
}


if (optind > argc - 2) {
if (optind != argc - 2) {
help();
}
filename1 = argv[optind++];
Expand Down Expand Up @@ -1741,7 +1744,7 @@ static int img_info(int argc, char **argv)
break;
}
}
if (optind >= argc) {
if (optind != argc - 1) {
help();
}
filename = argv[optind++];
Expand Down Expand Up @@ -1842,7 +1845,7 @@ static int img_snapshot(int argc, char **argv)
}
}

if (optind >= argc) {
if (optind != argc - 1) {
help();
}
filename = argv[optind++];
Expand Down Expand Up @@ -1953,7 +1956,7 @@ static int img_rebase(int argc, char **argv)
progress = 0;
}

if ((optind >= argc) || (!unsafe && !out_baseimg)) {
if ((optind != argc - 1) || (!unsafe && !out_baseimg)) {
help();
}
filename = argv[optind++];
Expand Down Expand Up @@ -2232,7 +2235,7 @@ static int img_resize(int argc, char **argv)
break;
}
}
if (optind >= argc) {
if (optind != argc - 1) {
help();
}
filename = argv[optind++];
Expand Down Expand Up @@ -2319,6 +2322,10 @@ int main(int argc, char **argv)
const img_cmd_t *cmd;
const char *cmdname;

#ifdef CONFIG_POSIX
signal(SIGPIPE, SIG_IGN);
#endif

error_set_progname(argv[0]);

qemu_init_main_loop();
Expand Down
4 changes: 4 additions & 0 deletions qemu-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,10 @@ int main(int argc, char **argv)
int opt_index = 0;
int flags = BDRV_O_UNMAP;

#ifdef CONFIG_POSIX
signal(SIGPIPE, SIG_IGN);
#endif

progname = basename(argv[0]);

while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
Expand Down
Loading

0 comments on commit cafffa5

Please sign in to comment.