diff options
author | Anthony Liguori <anthony@codemonkey.ws> | 2013-09-11 14:45:37 -0500 |
---|---|---|
committer | Anthony Liguori <anthony@codemonkey.ws> | 2013-09-11 14:45:37 -0500 |
commit | 964737ea195de1560f3bcf55b8b6d4f7d0d4a619 (patch) | |
tree | ba09d2699bb1ce902161fa7bd3fe410492c775a2 /include | |
parent | ce2b69417caae3731fb50f67854afa006f624a2d (diff) | |
parent | 8f94b077877151de93a63c73f796897309568ddb (diff) |
Merge remote-tracking branch 'stefanha/block' into staging
# By Paolo Bonzini (21) and others
# Via Stefan Hajnoczi
* stefanha/block: (42 commits)
qemu-iotests: Fixed test case 026
qemu-iotests: Whitespace cleanup
dataplane: Fix startup race.
block: look for zero blocks in bs->file
block: add default get_block_status implementation for protocols
raw-posix: report unwritten extents as zero
raw-posix: return get_block_status data and flags
docs, qapi: document qemu-img map
qemu-img: add a "map" subcommand
block: return BDRV_BLOCK_ZERO past end of backing file
block: use bdrv_has_zero_init to return BDRV_BLOCK_ZERO
block: return get_block_status data and flags for formats
block: define get_block_status return value
block: introduce bdrv_get_block_status API
block: make bdrv_has_zero_init return false for copy-on-write-images
qemu-img: always probe the input image for allocated sectors
block: expect errors from bdrv_co_is_allocated
block: remove bdrv_is_allocated_above/bdrv_co_is_allocated_above distinction
block: do not use ->total_sectors in bdrv_co_is_allocated
block: make bdrv_co_is_allocated static
...
Message-id: 1378481953-23099-1-git-send-email-stefanha@redhat.com
Signed-off-by: Anthony Liguori <anthony@codemonkey.ws>
Diffstat (limited to 'include')
-rw-r--r-- | include/block/block.h | 38 | ||||
-rw-r--r-- | include/block/block_int.h | 35 | ||||
-rw-r--r-- | include/qemu/throttle.h | 110 |
3 files changed, 148 insertions, 35 deletions
diff --git a/include/block/block.h b/include/block/block.h index e6b391ce88..728ec1aebf 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -81,6 +81,32 @@ typedef struct BlockDevOps { #define BDRV_SECTOR_SIZE (1ULL << BDRV_SECTOR_BITS) #define BDRV_SECTOR_MASK ~(BDRV_SECTOR_SIZE - 1) +/* BDRV_BLOCK_DATA: data is read from bs->file or another file + * BDRV_BLOCK_ZERO: sectors read as zero + * BDRV_BLOCK_OFFSET_VALID: sector stored in bs->file as raw data + * + * If BDRV_BLOCK_OFFSET_VALID is set, bits 9-62 represent the offset in + * bs->file where sector data can be read from as raw data. + * + * DATA == 0 && ZERO == 0 means that data is read from backing_hd if present. + * + * DATA ZERO OFFSET_VALID + * t t t sectors read as zero, bs->file is zero at offset + * t f t sectors read as valid from bs->file at offset + * f t t sectors preallocated, read as zero, bs->file not + * necessarily zero at offset + * f f t sectors preallocated but read from backing_hd, + * bs->file contains garbage at offset + * t t f sectors preallocated, read as zero, unknown offset + * t f f sectors read from unknown file or offset + * f t f not allocated or unknown offset, read as zero + * f f f not allocated or unknown offset, read from backing_hd + */ +#define BDRV_BLOCK_DATA 1 +#define BDRV_BLOCK_ZERO 2 +#define BDRV_BLOCK_OFFSET_VALID 4 +#define BDRV_BLOCK_OFFSET_MASK BDRV_SECTOR_MASK + typedef enum { BDRV_ACTION_REPORT, BDRV_ACTION_IGNORE, BDRV_ACTION_STOP } BlockErrorAction; @@ -107,7 +133,6 @@ void bdrv_info_stats(Monitor *mon, QObject **ret_data); /* disk I/O throttling */ void bdrv_io_limits_enable(BlockDriverState *bs); void bdrv_io_limits_disable(BlockDriverState *bs); -bool bdrv_io_limits_enabled(BlockDriverState *bs); void bdrv_init(void); void bdrv_init_with_whitelist(void); @@ -123,7 +148,6 @@ BlockDriverState *bdrv_new(const char *device_name); void bdrv_make_anon(BlockDriverState *bs); void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old); void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top); -void bdrv_delete(BlockDriverState *bs); int bdrv_parse_cache_flags(const char *mode, int *flags); int bdrv_parse_discard_flags(const char *mode, int *flags); int bdrv_file_open(BlockDriverState **pbs, const char *filename, @@ -181,12 +205,6 @@ int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num, */ int coroutine_fn bdrv_co_write_zeroes(BlockDriverState *bs, int64_t sector_num, int nb_sectors); -int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t sector_num, - int nb_sectors, int *pnum); -int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top, - BlockDriverState *base, - int64_t sector_num, - int nb_sectors, int *pnum); BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, const char *backing_file); int bdrv_get_backing_file_depth(BlockDriverState *bs); @@ -277,6 +295,8 @@ int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors); int bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors); int bdrv_has_zero_init_1(BlockDriverState *bs); int bdrv_has_zero_init(BlockDriverState *bs); +int64_t bdrv_get_block_status(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, int *pnum); int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum); int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, @@ -356,6 +376,8 @@ int64_t bdrv_get_dirty_count(BlockDriverState *bs); void bdrv_enable_copy_on_read(BlockDriverState *bs); void bdrv_disable_copy_on_read(BlockDriverState *bs); +void bdrv_ref(BlockDriverState *bs); +void bdrv_unref(BlockDriverState *bs); void bdrv_set_in_use(BlockDriverState *bs, int in_use); int bdrv_in_use(BlockDriverState *bs); diff --git a/include/block/block_int.h b/include/block/block_int.h index 8012e253c9..7c35198ad7 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -35,18 +35,12 @@ #include "qemu/hbitmap.h" #include "block/snapshot.h" #include "qemu/main-loop.h" +#include "qemu/throttle.h" #define BLOCK_FLAG_ENCRYPT 1 #define BLOCK_FLAG_COMPAT6 4 #define BLOCK_FLAG_LAZY_REFCOUNTS 8 -#define BLOCK_IO_LIMIT_READ 0 -#define BLOCK_IO_LIMIT_WRITE 1 -#define BLOCK_IO_LIMIT_TOTAL 2 - -#define BLOCK_IO_SLICE_TIME 100000000 -#define NANOSECONDS_PER_SECOND 1000000000.0 - #define BLOCK_OPT_SIZE "size" #define BLOCK_OPT_ENCRYPT "encryption" #define BLOCK_OPT_COMPAT6 "compat6" @@ -70,17 +64,6 @@ typedef struct BdrvTrackedRequest { CoQueue wait_queue; /* coroutines blocked on this request */ } BdrvTrackedRequest; - -typedef struct BlockIOLimit { - int64_t bps[3]; - int64_t iops[3]; -} BlockIOLimit; - -typedef struct BlockIOBaseValue { - uint64_t bytes[2]; - uint64_t ios[2]; -} BlockIOBaseValue; - struct BlockDriver { const char *format_name; int instance_size; @@ -135,7 +118,7 @@ struct BlockDriver { int64_t sector_num, int nb_sectors); int coroutine_fn (*bdrv_co_discard)(BlockDriverState *bs, int64_t sector_num, int nb_sectors); - int coroutine_fn (*bdrv_co_is_allocated)(BlockDriverState *bs, + int64_t coroutine_fn (*bdrv_co_get_block_status)(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum); /* @@ -264,13 +247,9 @@ struct BlockDriverState { /* number of in-flight copy-on-read requests */ unsigned int copy_on_read_in_flight; - /* the time for latest disk I/O */ - int64_t slice_start; - int64_t slice_end; - BlockIOLimit io_limits; - BlockIOBaseValue slice_submitted; - CoQueue throttled_reqs; - QEMUTimer *block_timer; + /* I/O throttling */ + ThrottleState throttle_state; + CoQueue throttled_reqs[2]; bool io_limits_enabled; /* I/O stats (display with "info blockstats"). */ @@ -298,6 +277,7 @@ struct BlockDriverState { BlockDeviceIoStatus iostatus; char device_name[32]; HBitmap *dirty_bitmap; + int refcnt; int in_use; /* users other than guest access, eg. block migration */ QTAILQ_ENTRY(BlockDriverState) list; @@ -312,7 +292,8 @@ struct BlockDriverState { int get_tmp_filename(char *filename, int size); void bdrv_set_io_limits(BlockDriverState *bs, - BlockIOLimit *io_limits); + ThrottleConfig *cfg); + /** * bdrv_add_before_write_notifier: diff --git a/include/qemu/throttle.h b/include/qemu/throttle.h new file mode 100644 index 0000000000..ab29b0b918 --- /dev/null +++ b/include/qemu/throttle.h @@ -0,0 +1,110 @@ +/* + * QEMU throttling infrastructure + * + * Copyright (C) Nodalink, SARL. 2013 + * + * Author: + * BenoƮt Canet <benoit.canet@irqsave.net> + * + * 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 or + * (at your option) version 3 of the License. + * + * 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/>. + */ + +#ifndef THROTTLE_H +#define THROTTLE_H + +#include <stdint.h> +#include "qemu-common.h" +#include "qemu/timer.h" + +#define NANOSECONDS_PER_SECOND 1000000000.0 + +typedef enum { + THROTTLE_BPS_TOTAL, + THROTTLE_BPS_READ, + THROTTLE_BPS_WRITE, + THROTTLE_OPS_TOTAL, + THROTTLE_OPS_READ, + THROTTLE_OPS_WRITE, + BUCKETS_COUNT, +} BucketType; + +/* + * The max parameter of the leaky bucket throttling algorithm can be used to + * allow the guest to do bursts. + * The max value is a pool of I/O that the guest can use without being throttled + * at all. Throttling is triggered once this pool is empty. + */ + +typedef struct LeakyBucket { + double avg; /* average goal in units per second */ + double max; /* leaky bucket max burst in units */ + double level; /* bucket level in units */ +} LeakyBucket; + +/* The following structure is used to configure a ThrottleState + * It contains a bit of state: the bucket field of the LeakyBucket structure. + * However it allows to keep the code clean and the bucket field is reset to + * zero at the right time. + */ +typedef struct ThrottleConfig { + LeakyBucket buckets[BUCKETS_COUNT]; /* leaky buckets */ + uint64_t op_size; /* size of an operation in bytes */ +} ThrottleConfig; + +typedef struct ThrottleState { + ThrottleConfig cfg; /* configuration */ + int64_t previous_leak; /* timestamp of the last leak done */ + QEMUTimer * timers[2]; /* timers used to do the throttling */ + QEMUClockType clock_type; /* the clock used */ +} ThrottleState; + +/* operations on single leaky buckets */ +void throttle_leak_bucket(LeakyBucket *bkt, int64_t delta); + +int64_t throttle_compute_wait(LeakyBucket *bkt); + +/* expose timer computation function for unit tests */ +bool throttle_compute_timer(ThrottleState *ts, + bool is_write, + int64_t now, + int64_t *next_timestamp); + +/* init/destroy cycle */ +void throttle_init(ThrottleState *ts, + QEMUClockType clock_type, + void (read_timer)(void *), + void (write_timer)(void *), + void *timer_opaque); + +void throttle_destroy(ThrottleState *ts); + +bool throttle_have_timer(ThrottleState *ts); + +/* configuration */ +bool throttle_enabled(ThrottleConfig *cfg); + +bool throttle_conflicting(ThrottleConfig *cfg); + +bool throttle_is_valid(ThrottleConfig *cfg); + +void throttle_config(ThrottleState *ts, ThrottleConfig *cfg); + +void throttle_get_config(ThrottleState *ts, ThrottleConfig *cfg); + +/* usage */ +bool throttle_schedule_timer(ThrottleState *ts, bool is_write); + +void throttle_account(ThrottleState *ts, bool is_write, uint64_t size); + +#endif |