/** * do_balloon(): Request VM to change its memory allocation */ int do_balloon(Monitor *mon, const QDict *params, MonitorCompletion cb, void *opaque) { int64_t target; int ret; if (kvm_enabled() && !kvm_has_sync_mmu()) { qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon"); return -1; } target = qdict_get_int(params, "value"); if (target <= 0) { qerror_report(QERR_INVALID_PARAMETER_VALUE, "target", "a size"); return -1; } ret = qemu_balloon(target); if (ret == 0) { qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon"); return -1; } cb(opaque, NULL); return 0; }
/** * do_info_balloon(): Balloon information * * Make an asynchronous request for balloon info. When the request completes * a QDict will be returned according to the following specification: * * - "actual": current balloon value in bytes * The following fields may or may not be present: * - "mem_swapped_in": Amount of memory swapped in (bytes) * - "mem_swapped_out": Amount of memory swapped out (bytes) * - "major_page_faults": Number of major faults * - "minor_page_faults": Number of minor faults * - "free_mem": Total amount of free and unused memory (bytes) * - "total_mem": Total amount of available memory (bytes) * * Example: * * { "actual": 1073741824, "mem_swapped_in": 0, "mem_swapped_out": 0, * "major_page_faults": 142, "minor_page_faults": 239245, * "free_mem": 1014185984, "total_mem": 1044668416 } */ int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque) { int ret; if (kvm_enabled() && !kvm_has_sync_mmu()) { qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon"); return -1; } ret = qemu_balloon_status(cb, opaque); if (!ret) { qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon"); return -1; } return 0; }
static int cloop_open(BlockDriverState *bs, int flags) { BDRVCloopState *s = bs->opaque; uint32_t offsets_size, max_compressed_block_size = 1, i; int ret; bs->read_only = 1; /* read header */ ret = bdrv_pread(bs->file, 128, &s->block_size, 4); if (ret < 0) { return ret; } s->block_size = be32_to_cpu(s->block_size); if (s->block_size % 512) { qerror_report(QERR_GENERIC_ERROR, "block_size must be a multiple of 512"); return -EINVAL; } if (s->block_size == 0) { qerror_report(QERR_GENERIC_ERROR, "block_size cannot be zero"); return -EINVAL; } /* cloop's create_compressed_fs.c warns about block sizes beyond 256 KB but * we can accept more. Prevent ridiculous values like 4 GB - 1 since we * need a buffer this big. */ if (s->block_size > MAX_BLOCK_SIZE) { qerror_report(QERR_GENERIC_ERROR, "block_size too large"); return -EINVAL; } ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4); if (ret < 0) { return ret; } s->n_blocks = be32_to_cpu(s->n_blocks); /* read offsets */ if (s->n_blocks > (UINT32_MAX - 1) / sizeof(uint64_t)) { /* Prevent integer overflow */ qerror_report(QERR_GENERIC_ERROR, "n_blocks too large"); return -EINVAL; } offsets_size = (s->n_blocks + 1) * sizeof(uint64_t); if (offsets_size > 512 * 1024 * 1024) { /* Prevent ridiculous offsets_size which causes memory allocation to * fail or overflows bdrv_pread() size. In practice the 512 MB * offsets[] limit supports 16 TB images at 256 KB block size. */ qerror_report(QERR_GENERIC_ERROR, "image requires too many offsets, " "try increasing block size"); return -EINVAL; } s->offsets = g_malloc(offsets_size); ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size); if (ret < 0) { goto fail; } for (i = 0; i < s->n_blocks + 1; i++) { uint64_t size; s->offsets[i] = be64_to_cpu(s->offsets[i]); if (i == 0) { continue; } if (s->offsets[i] < s->offsets[i - 1]) { qerror_report(QERR_GENERIC_ERROR, "offsets not monotonically increasing, " "image file is corrupt"); ret = -EINVAL; goto fail; } size = s->offsets[i] - s->offsets[i - 1]; /* Compressed blocks should be smaller than the uncompressed block size * but maybe compression performed poorly so the compressed block is * actually bigger. Clamp down on unrealistic values to prevent * ridiculous s->compressed_block allocation. */ if (size > 2 * MAX_BLOCK_SIZE) { qerror_report(QERR_GENERIC_ERROR, "invalid compressed block size, " "image file is corrupt"); ret = -EINVAL; goto fail; } if (size > max_compressed_block_size) { max_compressed_block_size = size; } } /* initialize zlib engine */ s->compressed_block = g_malloc(max_compressed_block_size + 1); s->uncompressed_block = g_malloc(s->block_size); if (inflateInit(&s->zstream) != Z_OK) { ret = -EINVAL; goto fail; } s->current_block = s->n_blocks; s->sectors_per_block = s->block_size/512; bs->total_sectors = s->n_blocks * s->sectors_per_block; qemu_co_mutex_init(&s->lock); return 0; fail: g_free(s->offsets); g_free(s->compressed_block); g_free(s->uncompressed_block); return ret; }
static int bdrv_qed_open(BlockDriverState *bs, int flags) { BDRVQEDState *s = bs->opaque; QEDHeader le_header; int64_t file_size; int ret; s->bs = bs; QSIMPLEQ_INIT(&s->allocating_write_reqs); ret = bdrv_pread(bs->file, 0, &le_header, sizeof(le_header)); if (ret < 0) { return ret; } qed_header_le_to_cpu(&le_header, &s->header); if (s->header.magic != QED_MAGIC) { return -EINVAL; } if (s->header.features & ~QED_FEATURE_MASK) { /* image uses unsupported feature bits */ char buf[64]; snprintf(buf, sizeof(buf), "%" PRIx64, s->header.features & ~QED_FEATURE_MASK); qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, bs->device_name, "QED", buf); return -ENOTSUP; } if (!qed_is_cluster_size_valid(s->header.cluster_size)) { return -EINVAL; } /* Round down file size to the last cluster */ file_size = bdrv_getlength(bs->file); if (file_size < 0) { return file_size; } s->file_size = qed_start_of_cluster(s, file_size); if (!qed_is_table_size_valid(s->header.table_size)) { return -EINVAL; } if (!qed_is_image_size_valid(s->header.image_size, s->header.cluster_size, s->header.table_size)) { return -EINVAL; } if (!qed_check_table_offset(s, s->header.l1_table_offset)) { return -EINVAL; } s->table_nelems = (s->header.cluster_size * s->header.table_size) / sizeof(uint64_t); s->l2_shift = ffs(s->header.cluster_size) - 1; s->l2_mask = s->table_nelems - 1; s->l1_shift = s->l2_shift + ffs(s->table_nelems) - 1; if ((s->header.features & QED_F_BACKING_FILE)) { if ((uint64_t)s->header.backing_filename_offset + s->header.backing_filename_size > s->header.cluster_size * s->header.header_size) { return -EINVAL; } ret = qed_read_string(bs->file, s->header.backing_filename_offset, s->header.backing_filename_size, bs->backing_file, sizeof(bs->backing_file)); if (ret < 0) { return ret; } if (s->header.features & QED_F_BACKING_FORMAT_NO_PROBE) { pstrcpy(bs->backing_format, sizeof(bs->backing_format), "raw"); } } /* Reset unknown autoclear feature bits. This is a backwards * compatibility mechanism that allows images to be opened by older * programs, which "knock out" unknown feature bits. When an image is * opened by a newer program again it can detect that the autoclear * feature is no longer valid. */ if ((s->header.autoclear_features & ~QED_AUTOCLEAR_FEATURE_MASK) != 0 && !bdrv_is_read_only(bs->file)) { s->header.autoclear_features &= QED_AUTOCLEAR_FEATURE_MASK; ret = qed_write_header_sync(s); if (ret) { return ret; } /* From here on only known autoclear feature bits are valid */ bdrv_flush(bs->file); } s->l1_table = qed_alloc_table(s); qed_init_l2_cache(&s->l2_cache); ret = qed_read_l1_table_sync(s); if (ret) { goto out; } /* If image was not closed cleanly, check consistency */ if (s->header.features & QED_F_NEED_CHECK) { /* Read-only images cannot be fixed. There is no risk of corruption * since write operations are not possible. Therefore, allow * potentially inconsistent images to be opened read-only. This can * aid data recovery from an otherwise inconsistent image. */ if (!bdrv_is_read_only(bs->file)) { BdrvCheckResult result = {0}; ret = qed_check(s, &result, true); if (ret) { goto out; } if (!result.corruptions && !result.check_errors) { /* Ensure fixes reach storage before clearing check bit */ bdrv_flush(s->bs); s->header.features &= ~QED_F_NEED_CHECK; qed_write_header_sync(s); } } } s->need_check_timer = qemu_new_timer_ns(vm_clock, qed_need_check_timer_cb, s); out: if (ret) { qed_free_l2_cache(&s->l2_cache); qemu_vfree(s->l1_table); } return ret; }
static int curl_open(BlockDriverState *bs, QDict *options, int flags) { BDRVCURLState *s = bs->opaque; CURLState *state = NULL; QemuOpts *opts; Error *local_err = NULL; const char *file; double d; static int inited = 0; if (flags & BDRV_O_RDWR) { qerror_report(ERROR_CLASS_GENERIC_ERROR, "curl block device does not support writes"); return -EROFS; } opts = qemu_opts_create_nofail(&runtime_opts); qemu_opts_absorb_qdict(opts, options, &local_err); if (error_is_set(&local_err)) { qerror_report_err(local_err); error_free(local_err); goto out_noclean; } s->readahead_size = qemu_opt_get_size(opts, "readahead", READ_AHEAD_SIZE); if ((s->readahead_size & 0x1ff) != 0) { fprintf(stderr, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512\n", s->readahead_size); goto out_noclean; } file = qemu_opt_get(opts, "url"); if (file == NULL) { qerror_report(ERROR_CLASS_GENERIC_ERROR, "curl block driver requires " "an 'url' option"); goto out_noclean; } if (!inited) { curl_global_init(CURL_GLOBAL_ALL); inited = 1; } DPRINTF("CURL: Opening %s\n", file); s->url = g_strdup(file); state = curl_init_state(s); if (!state) goto out_noclean; // Get file size s->accept_range = false; curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1); curl_easy_setopt(state->curl, CURLOPT_HEADERFUNCTION, curl_header_cb); curl_easy_setopt(state->curl, CURLOPT_HEADERDATA, s); if (curl_easy_perform(state->curl)) goto out; curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d); if (d) s->len = (size_t)d; else if(!s->len) goto out; if ((!strncasecmp(s->url, "http://", strlen("http://")) || !strncasecmp(s->url, "https://", strlen("https://"))) && !s->accept_range) { pstrcpy(state->errmsg, CURL_ERROR_SIZE, "Server does not support 'range' (byte ranges)."); goto out; } DPRINTF("CURL: Size = %zd\n", s->len); curl_clean_state(state); curl_easy_cleanup(state->curl); state->curl = NULL; // Now we know the file exists and its size, so let's // initialize the multi interface! s->multi = curl_multi_init(); curl_multi_setopt(s->multi, CURLMOPT_SOCKETDATA, s); curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb); curl_multi_do(s); qemu_opts_del(opts); return 0; out: fprintf(stderr, "CURL: Error opening file: %s\n", state->errmsg); curl_easy_cleanup(state->curl); state->curl = NULL; out_noclean: g_free(s->url); qemu_opts_del(opts); return -EINVAL; }
/* opens the specified header block from the VHDX file header section */ static int vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s) { int ret = 0; VHDXHeader *header1; VHDXHeader *header2; bool h1_valid = false; bool h2_valid = false; uint64_t h1_seq = 0; uint64_t h2_seq = 0; uint8_t *buffer; header1 = qemu_blockalign(bs, sizeof(VHDXHeader)); header2 = qemu_blockalign(bs, sizeof(VHDXHeader)); buffer = qemu_blockalign(bs, VHDX_HEADER_SIZE); s->headers[0] = header1; s->headers[1] = header2; /* We have to read the whole VHDX_HEADER_SIZE instead of * sizeof(VHDXHeader), because the checksum is over the whole * region */ ret = bdrv_pread(bs->file, VHDX_HEADER1_OFFSET, buffer, VHDX_HEADER_SIZE); if (ret < 0) { goto fail; } /* copy over just the relevant portion that we need */ memcpy(header1, buffer, sizeof(VHDXHeader)); vhdx_header_le_import(header1); if (vhdx_checksum_is_valid(buffer, VHDX_HEADER_SIZE, 4) && !memcmp(&header1->signature, "head", 4) && header1->version == 1) { h1_seq = header1->sequence_number; h1_valid = true; } ret = bdrv_pread(bs->file, VHDX_HEADER2_OFFSET, buffer, VHDX_HEADER_SIZE); if (ret < 0) { goto fail; } /* copy over just the relevant portion that we need */ memcpy(header2, buffer, sizeof(VHDXHeader)); vhdx_header_le_import(header2); if (vhdx_checksum_is_valid(buffer, VHDX_HEADER_SIZE, 4) && !memcmp(&header2->signature, "head", 4) && header2->version == 1) { h2_seq = header2->sequence_number; h2_valid = true; } /* If there is only 1 valid header (or no valid headers), we * don't care what the sequence numbers are */ if (h1_valid && !h2_valid) { s->curr_header = 0; } else if (!h1_valid && h2_valid) { s->curr_header = 1; } else if (!h1_valid && !h2_valid) { ret = -EINVAL; goto fail; } else { /* If both headers are valid, then we choose the active one by the * highest sequence number. If the sequence numbers are equal, that is * invalid */ if (h1_seq > h2_seq) { s->curr_header = 0; } else if (h2_seq > h1_seq) { s->curr_header = 1; } else { ret = -EINVAL; goto fail; } } ret = 0; goto exit; fail: qerror_report(ERROR_CLASS_GENERIC_ERROR, "No valid VHDX header found"); qemu_vfree(header1); qemu_vfree(header2); s->headers[0] = NULL; s->headers[1] = NULL; exit: qemu_vfree(buffer); return ret; }