From patchwork Thu Aug 9 13:44:13 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alberto Garcia X-Patchwork-Id: 955631 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=igalia.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=igalia.com header.i=@igalia.com header.b="br5hGV9Z"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41mTyl5XRcz9s4c for ; Thu, 9 Aug 2018 23:45:03 +1000 (AEST) Received: from localhost ([::1]:50938 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fnlFN-0005qN-HC for incoming@patchwork.ozlabs.org; Thu, 09 Aug 2018 09:45:01 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:60229) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fnlF2-0005qD-OR for qemu-devel@nongnu.org; Thu, 09 Aug 2018 09:44:41 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fnlF0-0001JE-3P for qemu-devel@nongnu.org; Thu, 09 Aug 2018 09:44:40 -0400 Received: from fanzine.igalia.com ([91.117.99.155]:56789) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fnlEz-0001I2-Mt; Thu, 09 Aug 2018 09:44:38 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com; s=20170329; h=Message-Id:Date:Subject:Cc:To:From; bh=XDr2sJzPCIWjoLUHjSR6AOdsG48cAQ1nnc0JASUSvdU=; b=br5hGV9ZLZlSzkbAMzEo921JbYpYdOHmgTfxvNMYEOf9XKqA967KbY6kNS17DIMv1OSETtiaRvhmWVnzWNnxDLDHWjgY82KvND+aB3XYiBG5IGDZqdeXdqAlaDNU3ODkfzCZ5qQenrynS5HYXrwQmjRVN9tucOpJf60oPstUv14XukYAEC+3GU5aCUDtL56Fl/tTQeLz6nQOZRZuYPcxm1/Z0jhJ+JaPd9k2/hyvKJ0+cGnK4JP6f48L2OhOe9P2Ym5Abvq0udEZG1aI8iMI3DAZWoG4538oth9PqCpkY7KxzZz39gDHbGlfero8ujr65Gk8s1sybMTsF2l+/DPEqQ==; Received: from [194.100.51.2] (helo=perseus.local) by fanzine.igalia.com with esmtpsa (Cipher TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim) id 1fnlEw-00079z-WE; Thu, 09 Aug 2018 15:44:35 +0200 Received: from berto by perseus.local with local (Exim 4.89) (envelope-from ) id 1fnlEg-00081v-Aw; Thu, 09 Aug 2018 16:44:18 +0300 From: Alberto Garcia To: qemu-devel@nongnu.org Date: Thu, 9 Aug 2018 16:44:13 +0300 Message-Id: <20180809134413.30823-1-berto@igalia.com> X-Mailer: git-send-email 2.11.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x (no timestamps) [generic] [fuzzy] X-Received-From: 91.117.99.155 Subject: [Qemu-devel] [PATCH v2] qcow2: Release dirty entries with cache-clean-interval X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Alberto Garcia , qemu-block@nongnu.org, Max Reitz Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" The cache-clean-interval option is used to periodically release unused entries from the L2 and refcount caches. Dirty cache entries are left untouched, even if they are otherwise valid candidates for removal. This patch allows releasing those entries by flushing them to disk first. This is a blocking operation, so we need to do it in coroutine context. Signed-off-by: Alberto Garcia --- block/qcow2-cache.c | 26 ++++++++++++++++++++------ block/qcow2.c | 15 ++++++++++++--- block/qcow2.h | 2 +- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c index d9dafa31e5..33207eca9b 100644 --- a/block/qcow2-cache.c +++ b/block/qcow2-cache.c @@ -46,6 +46,8 @@ struct Qcow2Cache { uint64_t cache_clean_lru_counter; }; +static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i); + static inline void *qcow2_cache_get_table_addr(Qcow2Cache *c, int table) { return (uint8_t *) c->table_array + (size_t) table * c->table_size; @@ -86,26 +88,36 @@ static void qcow2_cache_table_release(Qcow2Cache *c, int i, int num_tables) #endif } -static inline bool can_clean_entry(Qcow2Cache *c, int i) +static inline bool can_clean_entry(BlockDriverState *bs, Qcow2Cache *c, int i) { Qcow2CachedTable *t = &c->entries[i]; - return t->ref == 0 && !t->dirty && t->offset != 0 && - t->lru_counter <= c->cache_clean_lru_counter; + if (t->ref || !t->offset || t->lru_counter > c->cache_clean_lru_counter) { + return false; + } + + if (qcow2_cache_entry_flush(bs, c, i) < 0) { + return false; + } + + return true; } -void qcow2_cache_clean_unused(Qcow2Cache *c) +void qcow2_cache_clean_unused(BlockDriverState *bs, Qcow2Cache *c) { int i = 0; + + bdrv_inc_in_flight(bs); + while (i < c->size) { int to_clean = 0; /* Skip the entries that we don't need to clean */ - while (i < c->size && !can_clean_entry(c, i)) { + while (i < c->size && !can_clean_entry(bs, c, i)) { i++; } /* And count how many we can clean in a row */ - while (i < c->size && can_clean_entry(c, i)) { + while (i < c->size && can_clean_entry(bs, c, i)) { c->entries[i].offset = 0; c->entries[i].lru_counter = 0; i++; @@ -118,6 +130,8 @@ void qcow2_cache_clean_unused(Qcow2Cache *c) } c->cache_clean_lru_counter = c->lru_counter; + + bdrv_dec_in_flight(bs); } Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables, diff --git a/block/qcow2.c b/block/qcow2.c index ec9e6238a0..2fcb41b12f 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -728,16 +728,25 @@ static const char *overlap_bool_option_names[QCOW2_OL_MAX_BITNR] = { [QCOW2_OL_BITMAP_DIRECTORY_BITNR] = QCOW2_OPT_OVERLAP_BITMAP_DIRECTORY, }; -static void cache_clean_timer_cb(void *opaque) +static void coroutine_fn cache_co_clean_unused(void *opaque) { BlockDriverState *bs = opaque; BDRVQcow2State *s = bs->opaque; - qcow2_cache_clean_unused(s->l2_table_cache); - qcow2_cache_clean_unused(s->refcount_block_cache); + + qemu_co_mutex_lock(&s->lock); + qcow2_cache_clean_unused(bs, s->l2_table_cache); + qcow2_cache_clean_unused(bs, s->refcount_block_cache); + qemu_co_mutex_unlock(&s->lock); + timer_mod(s->cache_clean_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + (int64_t) s->cache_clean_interval * 1000); } +static void cache_clean_timer_cb(void *opaque) +{ + qemu_coroutine_enter(qemu_coroutine_create(cache_co_clean_unused, opaque)); +} + static void cache_clean_timer_init(BlockDriverState *bs, AioContext *context) { BDRVQcow2State *s = bs->opaque; diff --git a/block/qcow2.h b/block/qcow2.h index 81b844e936..e8b390ba4b 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -659,7 +659,7 @@ int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c, Qcow2Cache *dependency); void qcow2_cache_depends_on_flush(Qcow2Cache *c); -void qcow2_cache_clean_unused(Qcow2Cache *c); +void qcow2_cache_clean_unused(BlockDriverState *bs, Qcow2Cache *c); int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c); int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,