Revision d80b60fc2433cc934533f594bfa4e2b6c6103ba3 authored by Alberto Garcia on 08 June 2018, 15:15:36 UTC, committed by Michael Roth on 21 June 2018, 01:45:06 UTC
The throttle block filter can be reopened, and with this it is possible to change the throttle group that the filter belongs to. The way the code does that is the following: - On throttle_reopen_prepare(): create a new ThrottleGroupMember and attach it to the new throttle group. - On throttle_reopen_commit(): detach the old ThrottleGroupMember, delete it and replace it with the new one. The problem with this is that by replacing the ThrottleGroupMember the previous value of io_limits_disabled is lost, causing an assertion failure in throttle_co_drain_end(). This problem can be reproduced by reopening a throttle node: $QEMU -monitor stdio -object throttle-group,id=tg0,x-iops-total=1000 \ -blockdev node-name=hd0,driver=qcow2,file.driver=file,file.filename=hd.qcow2 \ -blockdev node-name=root,driver=throttle,throttle-group=tg0,file=hd0,read-only=on (qemu) block_stream root block/throttle.c:214: throttle_co_drain_end: Assertion `tgm->io_limits_disabled' failed. Since we only want to change the throttle group on reopen there's no need to create a ThrottleGroupMember and discard the old one. It's easier if we simply detach it from its current group and attach it to the new one. Signed-off-by: Alberto Garcia <berto@igalia.com> Message-id: 20180608151536.7378-1-berto@igalia.com Signed-off-by: Max Reitz <mreitz@redhat.com> (cherry picked from commit bc33c047d1ec0b35c9cd8be62bcefae2da28654f) Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
1 parent f647a4f
cacheinfo.c
/*
* cacheinfo.c - helpers to query the host about its caches
*
* Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
* License: GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
int qemu_icache_linesize = 0;
int qemu_dcache_linesize = 0;
/*
* Operating system specific detection mechanisms.
*/
#if defined(_WIN32)
static void sys_cache_info(int *isize, int *dsize)
{
SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buf;
DWORD size = 0;
BOOL success;
size_t i, n;
/* Check for the required buffer size first. Note that if the zero
size we use for the probe results in success, then there is no
data available; fail in that case. */
success = GetLogicalProcessorInformation(0, &size);
if (success || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
return;
}
n = size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
size = n * sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
buf = g_new0(SYSTEM_LOGICAL_PROCESSOR_INFORMATION, n);
if (!GetLogicalProcessorInformation(buf, &size)) {
goto fail;
}
for (i = 0; i < n; i++) {
if (buf[i].Relationship == RelationCache
&& buf[i].Cache.Level == 1) {
switch (buf[i].Cache.Type) {
case CacheUnified:
*isize = *dsize = buf[i].Cache.LineSize;
break;
case CacheInstruction:
*isize = buf[i].Cache.LineSize;
break;
case CacheData:
*dsize = buf[i].Cache.LineSize;
break;
default:
break;
}
}
}
fail:
g_free(buf);
}
#elif defined(__APPLE__) \
|| defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
# include <sys/sysctl.h>
# if defined(__APPLE__)
# define SYSCTL_CACHELINE_NAME "hw.cachelinesize"
# else
# define SYSCTL_CACHELINE_NAME "machdep.cacheline_size"
# endif
static void sys_cache_info(int *isize, int *dsize)
{
/* There's only a single sysctl for both I/D cache line sizes. */
long size;
size_t len = sizeof(size);
if (!sysctlbyname(SYSCTL_CACHELINE_NAME, &size, &len, NULL, 0)) {
*isize = *dsize = size;
}
}
#else
/* POSIX */
static void sys_cache_info(int *isize, int *dsize)
{
# ifdef _SC_LEVEL1_ICACHE_LINESIZE
*isize = sysconf(_SC_LEVEL1_ICACHE_LINESIZE);
# endif
# ifdef _SC_LEVEL1_DCACHE_LINESIZE
*dsize = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
# endif
}
#endif /* sys_cache_info */
/*
* Architecture (+ OS) specific detection mechanisms.
*/
#if defined(__aarch64__)
static void arch_cache_info(int *isize, int *dsize)
{
if (*isize == 0 || *dsize == 0) {
unsigned long ctr;
/* The real cache geometry is in CCSIDR_EL1/CLIDR_EL1/CSSELR_EL1,
but (at least under Linux) these are marked protected by the
kernel. However, CTR_EL0 contains the minimum linesize in the
entire hierarchy, and is used by userspace cache flushing. */
asm volatile("mrs\t%0, ctr_el0" : "=r"(ctr));
if (*isize == 0) {
*isize = 4 << (ctr & 0xf);
}
if (*dsize == 0) {
*dsize = 4 << ((ctr >> 16) & 0xf);
}
}
}
#elif defined(_ARCH_PPC) && defined(__linux__)
# include "elf.h"
static void arch_cache_info(int *isize, int *dsize)
{
if (*isize == 0) {
*isize = qemu_getauxval(AT_ICACHEBSIZE);
}
if (*dsize == 0) {
*dsize = qemu_getauxval(AT_DCACHEBSIZE);
}
}
#else
static void arch_cache_info(int *isize, int *dsize) { }
#endif /* arch_cache_info */
/*
* ... and if all else fails ...
*/
static void fallback_cache_info(int *isize, int *dsize)
{
/* If we can only find one of the two, assume they're the same. */
if (*isize) {
if (*dsize) {
/* Success! */
} else {
*dsize = *isize;
}
} else if (*dsize) {
*isize = *dsize;
} else {
#if defined(_ARCH_PPC)
/* For PPC, we're going to use the icache size computed for
flush_icache_range. Which means that we must use the
architecture minimum. */
*isize = *dsize = 16;
#else
/* Otherwise, 64 bytes is not uncommon. */
*isize = *dsize = 64;
#endif
}
}
static void __attribute__((constructor)) init_cache_info(void)
{
int isize = 0, dsize = 0;
sys_cache_info(&isize, &dsize);
arch_cache_info(&isize, &dsize);
fallback_cache_info(&isize, &dsize);
qemu_icache_linesize = isize;
qemu_dcache_linesize = dsize;
}
Computing file changes ...