mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-03 07:43:54 -06:00
Merge remote-tracking branch 'kwolf/for-anthony' into staging
# By Paolo Bonzini (14) and others # Via Kevin Wolf * kwolf/for-anthony: (24 commits) ide: Add fall through annotations block: Create proper size file for disk mirror ahci: Add migration support ahci: Change data types in preparation for migration ahci: Remove unused AHCIDevice fields hbitmap: add assertion on hbitmap_iter_init mirror: do nothing on zero-sized disk block/vdi: Check for bad signature block/vdi: Improved return values from vdi_open block/vdi: Improve debug output for signature block: Use error code EMEDIUMTYPE for wrong format in some block drivers block: Add special error code for wrong format mirror: support arbitrarily-sized iterations mirror: support more than one in-flight AIO operation mirror: add buf-size argument to drive-mirror mirror: switch mirror_iteration to AIO mirror: allow customizing the granularity block: allow customizing the granularity of the dirty bitmap block: return count of dirty sectors, not chunks mirror: perform COW if the cluster size is bigger than the granularity ...
This commit is contained in:
commit
503cb22e05
30 changed files with 1729 additions and 231 deletions
|
@ -309,6 +309,10 @@ int bdrv_get_flags(BlockDriverState *bs);
|
|||
int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors);
|
||||
int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
|
||||
void bdrv_round_to_clusters(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
int64_t *cluster_sector_num,
|
||||
int *cluster_nb_sectors);
|
||||
|
||||
const char *bdrv_get_encrypted_filename(BlockDriverState *bs);
|
||||
void bdrv_get_backing_filename(BlockDriverState *bs,
|
||||
|
@ -351,13 +355,12 @@ void bdrv_set_buffer_alignment(BlockDriverState *bs, int align);
|
|||
void *qemu_blockalign(BlockDriverState *bs, size_t size);
|
||||
bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov);
|
||||
|
||||
#define BDRV_SECTORS_PER_DIRTY_CHUNK 2048
|
||||
|
||||
void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable);
|
||||
struct HBitmapIter;
|
||||
void bdrv_set_dirty_tracking(BlockDriverState *bs, int granularity);
|
||||
int bdrv_get_dirty(BlockDriverState *bs, int64_t sector);
|
||||
void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors);
|
||||
void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors);
|
||||
int64_t bdrv_get_next_dirty(BlockDriverState *bs, int64_t sector);
|
||||
void bdrv_dirty_iter_init(BlockDriverState *bs, struct HBitmapIter *hbi);
|
||||
int64_t bdrv_get_dirty_count(BlockDriverState *bs);
|
||||
|
||||
void bdrv_enable_copy_on_read(BlockDriverState *bs);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "qapi-types.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "qemu/hbitmap.h"
|
||||
|
||||
#define BLOCK_FLAG_ENCRYPT 1
|
||||
#define BLOCK_FLAG_COMPAT6 4
|
||||
|
@ -275,8 +276,7 @@ struct BlockDriverState {
|
|||
bool iostatus_enabled;
|
||||
BlockDeviceIoStatus iostatus;
|
||||
char device_name[32];
|
||||
unsigned long *dirty_bitmap;
|
||||
int64_t dirty_count;
|
||||
HBitmap *dirty_bitmap;
|
||||
int in_use; /* users other than guest access, eg. block migration */
|
||||
QTAILQ_ENTRY(BlockDriverState) list;
|
||||
|
||||
|
@ -344,6 +344,8 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base,
|
|||
* @bs: Block device to operate on.
|
||||
* @target: Block device to write to.
|
||||
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
|
||||
* @granularity: The chosen granularity for the dirty bitmap.
|
||||
* @buf_size: The amount of data that can be in flight at one time.
|
||||
* @mode: Whether to collapse all images in the chain to the target.
|
||||
* @on_source_error: The action to take upon error reading from the source.
|
||||
* @on_target_error: The action to take upon error writing to the target.
|
||||
|
@ -357,8 +359,8 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base,
|
|||
* @bs will be switched to read from @target.
|
||||
*/
|
||||
void mirror_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
int64_t speed, MirrorSyncMode mode,
|
||||
BlockdevOnError on_source_error,
|
||||
int64_t speed, int64_t granularity, int64_t buf_size,
|
||||
MirrorSyncMode mode, BlockdevOnError on_source_error,
|
||||
BlockdevOnError on_target_error,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque, Error **errp);
|
||||
|
|
|
@ -68,6 +68,9 @@
|
|||
#if !defined(ECANCELED)
|
||||
#define ECANCELED 4097
|
||||
#endif
|
||||
#if !defined(EMEDIUMTYPE)
|
||||
#define EMEDIUMTYPE 4098
|
||||
#endif
|
||||
#ifndef TIME_MAX
|
||||
#define TIME_MAX LONG_MAX
|
||||
#endif
|
||||
|
|
208
include/qemu/hbitmap.h
Normal file
208
include/qemu/hbitmap.h
Normal file
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* Hierarchical Bitmap Data Type
|
||||
*
|
||||
* Copyright Red Hat, Inc., 2012
|
||||
*
|
||||
* Author: Paolo Bonzini <pbonzini@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* later. See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef HBITMAP_H
|
||||
#define HBITMAP_H 1
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "bitops.h"
|
||||
|
||||
typedef struct HBitmap HBitmap;
|
||||
typedef struct HBitmapIter HBitmapIter;
|
||||
|
||||
#define BITS_PER_LEVEL (BITS_PER_LONG == 32 ? 5 : 6)
|
||||
|
||||
/* For 32-bit, the largest that fits in a 4 GiB address space.
|
||||
* For 64-bit, the number of sectors in 1 PiB. Good luck, in
|
||||
* either case... :)
|
||||
*/
|
||||
#define HBITMAP_LOG_MAX_SIZE (BITS_PER_LONG == 32 ? 34 : 41)
|
||||
|
||||
/* We need to place a sentinel in level 0 to speed up iteration. Thus,
|
||||
* we do this instead of HBITMAP_LOG_MAX_SIZE / BITS_PER_LEVEL. The
|
||||
* difference is that it allocates an extra level when HBITMAP_LOG_MAX_SIZE
|
||||
* is an exact multiple of BITS_PER_LEVEL.
|
||||
*/
|
||||
#define HBITMAP_LEVELS ((HBITMAP_LOG_MAX_SIZE / BITS_PER_LEVEL) + 1)
|
||||
|
||||
struct HBitmapIter {
|
||||
const HBitmap *hb;
|
||||
|
||||
/* Copied from hb for access in the inline functions (hb is opaque). */
|
||||
int granularity;
|
||||
|
||||
/* Entry offset into the last-level array of longs. */
|
||||
size_t pos;
|
||||
|
||||
/* The currently-active path in the tree. Each item of cur[i] stores
|
||||
* the bits (i.e. the subtrees) yet to be processed under that node.
|
||||
*/
|
||||
unsigned long cur[HBITMAP_LEVELS];
|
||||
};
|
||||
|
||||
/**
|
||||
* hbitmap_alloc:
|
||||
* @size: Number of bits in the bitmap.
|
||||
* @granularity: Granularity of the bitmap. Aligned groups of 2^@granularity
|
||||
* bits will be represented by a single bit. Each operation on a
|
||||
* range of bits first rounds the bits to determine which group they land
|
||||
* in, and then affect the entire set; iteration will only visit the first
|
||||
* bit of each group.
|
||||
*
|
||||
* Allocate a new HBitmap.
|
||||
*/
|
||||
HBitmap *hbitmap_alloc(uint64_t size, int granularity);
|
||||
|
||||
/**
|
||||
* hbitmap_empty:
|
||||
* @hb: HBitmap to operate on.
|
||||
*
|
||||
* Return whether the bitmap is empty.
|
||||
*/
|
||||
bool hbitmap_empty(const HBitmap *hb);
|
||||
|
||||
/**
|
||||
* hbitmap_granularity:
|
||||
* @hb: HBitmap to operate on.
|
||||
*
|
||||
* Return the granularity of the HBitmap.
|
||||
*/
|
||||
int hbitmap_granularity(const HBitmap *hb);
|
||||
|
||||
/**
|
||||
* hbitmap_count:
|
||||
* @hb: HBitmap to operate on.
|
||||
*
|
||||
* Return the number of bits set in the HBitmap.
|
||||
*/
|
||||
uint64_t hbitmap_count(const HBitmap *hb);
|
||||
|
||||
/**
|
||||
* hbitmap_set:
|
||||
* @hb: HBitmap to operate on.
|
||||
* @start: First bit to set (0-based).
|
||||
* @count: Number of bits to set.
|
||||
*
|
||||
* Set a consecutive range of bits in an HBitmap.
|
||||
*/
|
||||
void hbitmap_set(HBitmap *hb, uint64_t start, uint64_t count);
|
||||
|
||||
/**
|
||||
* hbitmap_reset:
|
||||
* @hb: HBitmap to operate on.
|
||||
* @start: First bit to reset (0-based).
|
||||
* @count: Number of bits to reset.
|
||||
*
|
||||
* Reset a consecutive range of bits in an HBitmap.
|
||||
*/
|
||||
void hbitmap_reset(HBitmap *hb, uint64_t start, uint64_t count);
|
||||
|
||||
/**
|
||||
* hbitmap_get:
|
||||
* @hb: HBitmap to operate on.
|
||||
* @item: Bit to query (0-based).
|
||||
*
|
||||
* Return whether the @item-th bit in an HBitmap is set.
|
||||
*/
|
||||
bool hbitmap_get(const HBitmap *hb, uint64_t item);
|
||||
|
||||
/**
|
||||
* hbitmap_free:
|
||||
* @hb: HBitmap to operate on.
|
||||
*
|
||||
* Free an HBitmap and all of its associated memory.
|
||||
*/
|
||||
void hbitmap_free(HBitmap *hb);
|
||||
|
||||
/**
|
||||
* hbitmap_iter_init:
|
||||
* @hbi: HBitmapIter to initialize.
|
||||
* @hb: HBitmap to iterate on.
|
||||
* @first: First bit to visit (0-based, must be strictly less than the
|
||||
* size of the bitmap).
|
||||
*
|
||||
* Set up @hbi to iterate on the HBitmap @hb. hbitmap_iter_next will return
|
||||
* the lowest-numbered bit that is set in @hb, starting at @first.
|
||||
*
|
||||
* Concurrent setting of bits is acceptable, and will at worst cause the
|
||||
* iteration to miss some of those bits. Resetting bits before the current
|
||||
* position of the iterator is also okay. However, concurrent resetting of
|
||||
* bits can lead to unexpected behavior if the iterator has not yet reached
|
||||
* those bits.
|
||||
*/
|
||||
void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first);
|
||||
|
||||
/* hbitmap_iter_skip_words:
|
||||
* @hbi: HBitmapIter to operate on.
|
||||
*
|
||||
* Internal function used by hbitmap_iter_next and hbitmap_iter_next_word.
|
||||
*/
|
||||
unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi);
|
||||
|
||||
/**
|
||||
* hbitmap_iter_next:
|
||||
* @hbi: HBitmapIter to operate on.
|
||||
*
|
||||
* Return the next bit that is set in @hbi's associated HBitmap,
|
||||
* or -1 if all remaining bits are zero.
|
||||
*/
|
||||
static inline int64_t hbitmap_iter_next(HBitmapIter *hbi)
|
||||
{
|
||||
unsigned long cur = hbi->cur[HBITMAP_LEVELS - 1];
|
||||
int64_t item;
|
||||
|
||||
if (cur == 0) {
|
||||
cur = hbitmap_iter_skip_words(hbi);
|
||||
if (cur == 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* The next call will resume work from the next bit. */
|
||||
hbi->cur[HBITMAP_LEVELS - 1] = cur & (cur - 1);
|
||||
item = ((uint64_t)hbi->pos << BITS_PER_LEVEL) + ffsl(cur) - 1;
|
||||
|
||||
return item << hbi->granularity;
|
||||
}
|
||||
|
||||
/**
|
||||
* hbitmap_iter_next_word:
|
||||
* @hbi: HBitmapIter to operate on.
|
||||
* @p_cur: Location where to store the next non-zero word.
|
||||
*
|
||||
* Return the index of the next nonzero word that is set in @hbi's
|
||||
* associated HBitmap, and set *p_cur to the content of that word
|
||||
* (bits before the index that was passed to hbitmap_iter_init are
|
||||
* trimmed on the first call). Return -1, and set *p_cur to zero,
|
||||
* if all remaining words are zero.
|
||||
*/
|
||||
static inline size_t hbitmap_iter_next_word(HBitmapIter *hbi, unsigned long *p_cur)
|
||||
{
|
||||
unsigned long cur = hbi->cur[HBITMAP_LEVELS - 1];
|
||||
|
||||
if (cur == 0) {
|
||||
cur = hbitmap_iter_skip_words(hbi);
|
||||
if (cur == 0) {
|
||||
*p_cur = 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* The next call will resume work from the next word. */
|
||||
hbi->cur[HBITMAP_LEVELS - 1] = 0;
|
||||
*p_cur = cur;
|
||||
return hbi->pos;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -26,6 +26,7 @@
|
|||
#define HOST_UTILS_H 1
|
||||
|
||||
#include "qemu/compiler.h" /* QEMU_GNUC_PREREQ */
|
||||
#include <string.h> /* ffsl */
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#define __HAVE_FAST_MULU64__
|
||||
|
@ -237,4 +238,29 @@ static inline int ctpop64(uint64_t val)
|
|||
#endif
|
||||
}
|
||||
|
||||
/* glibc does not provide an inline version of ffsl, so always define
|
||||
* ours. We need to give it a different name, however.
|
||||
*/
|
||||
#ifdef __GLIBC__
|
||||
#define ffsl qemu_ffsl
|
||||
#endif
|
||||
static inline int ffsl(long val)
|
||||
{
|
||||
if (!val) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if QEMU_GNUC_PREREQ(3, 4)
|
||||
return __builtin_ctzl(val) + 1;
|
||||
#else
|
||||
if (sizeof(long) == 4) {
|
||||
return ctz32(val) + 1;
|
||||
} else if (sizeof(long) == 8) {
|
||||
return ctz64(val) + 1;
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue