From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail.openvz.org (mail.openvz.org [69.168.225.77]) by lore.virtuozzo.com (Postfix) with ESMTPS id D6772802A5 for ; Thu, 22 Oct 2026 12:18:57 +0000 (UTC) Received: from mail.openvz.org (localhost [127.0.0.1]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 69MCHhAt008155; Thu, 22 Oct 2026 15:17:44 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 69MCHhAt008155 Authentication-Results: mail.openvz.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=virtuozzo.com header.i=@virtuozzo.com header.b="GMHsNmCk" Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 69MCHKUC008089 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=FAIL) for ; Thu, 22 Oct 2026 15:17:20 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 69MCHKUC008089 Received: by mail-wr1-f71.google.com with SMTP id ffacd0b85a97d-48af4a0bd0fso1006455f8f.2 for ; Thu, 22 Oct 2026 05:17:20 -0700 (PDT) X-Forwarded-Encrypted: i=2; AKwUvBxMv5lR3o7oy8zH6UZfd3xILqrBNaKiWpfPrV0IeTSb8iB4xMBIkfSu2T0vRoGfrVk7iXgYRA==@openvz.org X-Gm-Message-State: AFq9FYJyyO4QLKfPG7q8D4h5heIDp/MKZN9fvlOE1VUtyEhNayG1hH+1 SC9CjxESoV8GqACGQ7Rtnj1dfA6Ub9CNr39uihFoc7w7GX9L9XLgzXf4b7KK1eyBy5lCkMiKfFP Y8Pqac98mRR4AFQ4sRQUb5VEpBVaVkSbg8vpA8dfiUZSpce4UPmqwNw== X-Gm-Gg: AYBFou29X2YFqRRJB7aFNpoDISesGLOBjgWWTBD5dAx6+R1g8s2B+tvHwCHQQsR1DOS LuKd7WRMBbNBHEO+9Un+wZyFvCGHx78H+jTNc+T+pVhXLwkqLlOHFHJjeACj1a/Fl2RkNnuI2AD aKvqrWYy9nOp3AzuNKy0p4q6Thb/r7VogKvRmKmC7bflhaCHsQ8cOKf+FU+6r5OXKM1gF3rTEJQ 4ZWYHbqOXjgWjfbAIXCrAvmeayFa6VXhecm6b0AFJGYUdvyolsriJoHsloyRwFabhq9CUSg5coJ KsZbUGyvy/OquMVvjardUc9gIEGvay4jfHIzZzqWLDiRqpOYRG1Khf0hDFEx3Qwdhv2jyUWz/f0 nlHQ16fxlxVUevGy4yFARt1MUKHSN X-Received: by 2002:a05:6000:1869:b0:48e:25d7:d276 with SMTP id ffacd0b85a97d-48e264239e4mr11127230f8f.2.1792671439912; Thu, 22 Oct 2026 05:17:19 -0700 (PDT) X-Received: by 2002:a05:6000:1869:b0:48e:25d7:d276 with SMTP id ffacd0b85a97d-48e264239e4mr11127146f8f.2.1792671438987; Thu, 22 Oct 2026 05:17:18 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1792671438; cv=none; d=google.com; s=arc-20260327; b=WNpcH4EhL+bZapmZJEkv3G2mbfs50PtTBeTdnuWvw7i2txGJjbzolarhEmDlNlkiL7 UO+3AdOVeBaWDUmtAz3aQJrQS1SDltFQ8V2If1ZSRcbmIqojWzIUGugpwhS7LaJPBQKr X0qvJEqjEaz7a9F+5jN4KbDHOt6nadnTVA6AmXpI89fNEv/CCLnD6qfPhMJWhUsubVv0 7GINcsZx3p2rFaVuTbPd6EfwPP1GA30Si64ynCNJjv8YQEavDnSrwnctLpTZkXu5Z/Cc BW9I0kEz/kTJe3GOn6ltFuDBrfVeQzlfiv5PZS6CTiWGA+TILJErVJPN0xluNhEs88k8 f7jA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=nEz+TFvUDoPNjEjXZ6RMqOISL+FRXJEmZjSKqXueR7k=; fh=1MEQxOGYABaQPNQS1Ckioh0rrUOwgCYjd8t5csgx5as=; b=ltB60k7gSn9olF5ukDKcrZfMTYI6fVsS8b+QXJ49yydKluvqxbhjkAGwPoaBMY26N1 I4dL58EizRU2RaGf5gd6Vgal/t9bi3CwkG2dduMQiGvk1zWgSki+2n8K7icggpJFtgEL NLgoU/eWV8qBCDgwAv+fnHxqxtVn6N0P5TNtImwgZ7RI2QPuF8Cu4oCPj3Fg38WWgMue +hyv1XA2mvD8EsIXjnRXHZ10itoB4RrD3G1jgx2VG+Eke7OiIGIDFjNYIgUzk2XJXvva UfwOJdmAu4zQdy2v8tM3DXKD8fyYTUSsbIrAO2Vvbgs0nIboDEpfk2JjVmSVaeBkDAHK WRDw==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=GMHsNmCk; spf=pass (google.com: domain of alexander.ivanov@virtuozzo.com designates 130.117.225.111 as permitted sender) smtp.mailfrom=alexander.ivanov@virtuozzo.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=virtuozzo.com Received: from relay.virtuozzo.com (relay.virtuozzo.com. [130.117.225.111]) by mx.google.com with ESMTPS id ffacd0b85a97d-48e258585c8si11267719f8f.197.2026.10.22.05.17.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 22 Oct 2026 05:17:18 -0700 (PDT) Received-SPF: pass (google.com: domain of alexander.ivanov@virtuozzo.com designates 130.117.225.111 as permitted sender) client-ip=130.117.225.111; Authentication-Results: mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=GMHsNmCk; spf=pass (google.com: domain of alexander.ivanov@virtuozzo.com designates 130.117.225.111 as permitted sender) smtp.mailfrom=alexander.ivanov@virtuozzo.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=virtuozzo.com DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=virtuozzo.com; s=relay; h=MIME-Version:Message-ID:Date:Subject:From: Content-Type; bh=nEz+TFvUDoPNjEjXZ6RMqOISL+FRXJEmZjSKqXueR7k=; b=GMHsNmCkXGek ptN6MN1rR93T1DZ0GpUZ+3kOl4LjAGIiiLn+VLPpx7hDccJlBoajAij84twG0SYzPMic6hGEo1kMj MnBboUdoxe1Fa1/PIaoKvYinhXdM9QT3Qk1Wil4VqrXNuYUtfq38O2chn7wi+GYxQAB+lqb5I3sFe SpB6LA/VeQyNNWimo4ZWJ9DmoI6XCzMHl5nS4otSiclvgamdW27xRF3b3rORHTezDKyOIBv6/b8WW GRWa1drLibUd3kTsRdS4xf9nw+lC3P6OzPqUazqqtz2KpA1LjAGKFYnU/Ds2VJga9QXWu/RXW6Ol7 TZpaGb7GXrlwuI7SQBd2kA==; Received: from ch-vpn.virtuozzo.com ([130.117.225.6] helo=sky) by relay.virtuozzo.com with esmtps (TLS1.3) tls TLS_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1xJrfo-00Dc1n-35; Thu, 22 Oct 2026 14:17:15 +0200 From: Alexander Ivanov To: andrey.zhadchenko@virtuozzo.com Date: Thu, 22 Oct 2026 14:17:06 +0200 Message-ID: <20261022121706.1890593-7-alexander.ivanov@virtuozzo.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20261022121706.1890593-1-alexander.ivanov@virtuozzo.com> References: <20261022121706.1890593-1-alexander.ivanov@virtuozzo.com> MIME-Version: 1.0 X-OZ-Fwd: true Cc: devel@openvz.org Subject: [Devel] [PATCH hci-8.1 v6 6/6] dm-qcow2: truncate unused tail of image on suspend X-BeenThere: devel@openvz.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: OpenVZ development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: devel-bounces@openvz.org Errors-To: devel-bounces@openvz.org Discard punches holes in place of freed clusters, so they hold no physical extents, but it doesn't change the file size. On postsuspend we truncate the image file only down to file_preallocated_area_start, i.e. we drop preallocations only. So if clusters at the end of the file are freed (refcount dropped to zero), the file size stays the same and the image never shrinks. Add qcow2_calc_used_end(), which scans refcount blocks backward from file_preallocated_area_start and returns the end of the last cluster with non-zero refcount. Refcount ranges with no allocated refblock are skipped at once. Metadata pages are taken from md cache or read synchronously. This is called on suspended device after md writeback, so R1 and R2 can't change under us. A failed relocation of the reftable leaves file_preallocated_area_start beyond the space covered by the reftable, so the scan starts at most from its end. If the relocation fails after the new header is written, refcounts no longer match the header, so set md_writeback_error there. Truncate the file to the used end. Fall back to the old behaviour on scan error and after any failed md writeback. A failed R1/R2 write leaves refcounts on disk stale. A failed L1/L2 write reverts the refcount of a newly allocated cluster to zero, while L1/L2 on disk may still point to it. Mark such an L1/L2 page with MD_LX_REVERTED and clear the mark on its next successful writeback, which rewrites the whole page, e.g. when a request delayed on ENOSPC is resubmitted. On md writeback flush a still marked page sets a new lx_writeback_error flag, which is reported in get_errors and logged when the scan is skipped. The flag is lost on target reload, after which the scan would trust the reverted refcount, so include it in wants_check like md_writeback_error: resume is refused until the image is checked and the target reloaded. Refcounts may also be below real usage after a crash, since both QEMU with lazy_refcounts and this driver write L2 before refcounts. The scan would then cut off clusters L2 still points to, even in a session without guest writes. With kernel_sets_dirty_bit such an image has the dirty bit set at open, and the disabled dirty bit check lets it be opened RW, so skip the scan for it. Otherwise userspace sets the dirty bit on every RW open, so the bit doesn't mean the image is inconsistent. Userspace checks the image before opening it RW, which find_unused_cluster() already relies on when it reuses clusters with zero refcount. Close and reload to RO go through postsuspend too. On remove, __dm_destroy() calls the presuspend and postsuspend hooks if the live table isn't suspended yet. It neither stops the queue nor waits for I/O, but the device is idle there, because dm_lock_for_deletion() refuses to remove an open device. On table swap, do_resume() suspends the old (RW) table before dm_swap_table(). So the file is shrunk in these cases as well. https://virtuozzo.atlassian.net/browse/VSTOR-148171 Feature: dm-qcow2: block device over QCOW2 files driver Signed-off-by: Alexander Ivanov --- drivers/md/dm-qcow2-cmd.c | 4 +- drivers/md/dm-qcow2-map.c | 96 +++++++++++++++++++++++++++++++++--- drivers/md/dm-qcow2-target.c | 40 ++++++++++++--- drivers/md/dm-qcow2.h | 6 ++- 4 files changed, 129 insertions(+), 17 deletions(-) diff --git a/drivers/md/dm-qcow2-cmd.c b/drivers/md/dm-qcow2-cmd.c index 2865940cff30..1520733c962c 100644 --- a/drivers/md/dm-qcow2-cmd.c +++ b/drivers/md/dm-qcow2-cmd.c @@ -20,9 +20,9 @@ static int qcow2_get_errors(struct qcow2_target *tgt, char *result, int ret; ret = DMEMIT("wants_check=%d\nmd_writeback_error=%d\ntruncate_error=%d\n" - "merge_backward_error=%d\n", + "merge_backward_error=%d\nlx_writeback_error=%d\n", wants_check, tgt->md_writeback_error, tgt->truncate_error, - tgt->backward_merge.error); + tgt->backward_merge.error, tgt->lx_writeback_error); return ret ? 1 : 0; } diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c index ef832813b718..860095a59f4f 100644 --- a/drivers/md/dm-qcow2-map.c +++ b/drivers/md/dm-qcow2-map.c @@ -1091,6 +1091,11 @@ static int calc_refcounters_map(struct qcow2 *qcow2, loff_t pos, return -EIO; } +static bool r1_entry_is_valid(struct qcow2 *qcow2, u64 entry) +{ + return !(entry & R1_RESERVED_ZERO_MASK) && CLU_OFF(qcow2, entry) == 0; +} + static int calc_r2_page_id(struct qcow2 *qcow2, struct qcow2_map_item *r1, struct qcow2_map_item *r2) { @@ -1098,8 +1103,7 @@ static int calc_r2_page_id(struct qcow2 *qcow2, struct qcow2_map_item *r1, u32 bits = qcow2->refblock_bits; loff_t pos; - if (WARN_ON_ONCE((entry & R1_RESERVED_ZERO_MASK) || - (CLU_OFF(qcow2, entry) != 0))) + if (WARN_ON_ONCE(!r1_entry_is_valid(qcow2, entry))) return -EIO; /* The corresponding refcount block has not yet been allocated */ @@ -1363,6 +1367,8 @@ static void revert_l_entries_update(struct qcow2 *qcow2, struct wb_desc *wbd) if (cleared) continue; /* no cluster was allocated */ + /* L1/L2 on disk may point to the cluster */ + wbd->md->status |= MD_LX_REVERTED; spin_unlock(&qcow2->md_pages_lock); pos &= ~LX_REFCOUNT_EXACTLY_ONE; @@ -1386,6 +1392,8 @@ static void clear_writeback_status(struct qcow2 *qcow2, struct md_page *md, lockdep_assert_held(&qcow2->md_pages_lock); md->status &= ~(MD_WRITEBACK|MD_WRITEBACK_ERROR); + if (!ret) + md->status &= ~MD_LX_REVERTED; list_splice_init(&md->wait_list, wait_list); if (ret && !md->wbd) { /* @@ -2216,6 +2224,74 @@ int qcow2_truncate_safe(struct file *file, loff_t new_len) return do_ftruncate(file, new_len, 0); } +/* + * Returns the end of the last cluster, which is used according + * to refcount table, clamped to file_preallocated_area_start since + * the last cluster may be partial. Clusters freed by discard may + * leave the tail of file unused. Everything at or above + * file_preallocated_area_start is unused by construction, so the scan + * starts below it. Failed relocate_refcount_table() leaves it beyond + * reftable_max_file_size, so clamp the start to the reftable coverage. + * This must be called on suspended device after md writeback, so + * nobody changes R1 and R2. + */ +loff_t qcow2_calc_used_end(struct qcow2 *qcow2) +{ + u32 clu_size = qcow2->clu_size; + struct qcow2_map_item r1, r2; + struct md_page *r1_md = NULL; + loff_t pos; + s32 i; + int ret; + + pos = min(qcow2->file_preallocated_area_start, + qcow2->reftable_max_file_size); + pos = round_down(pos - 1, clu_size); + while (pos >= 0) { + if (calc_refcounters_map(qcow2, pos, &r1, &r2) < 0) + return -EIO; + + if (!r1_md || r1_md->id != r1.page_id) { + ret = qcow2_md_page_read_sync(qcow2, r1.page_id, &r1_md); + if (ret) + return ret; + } + r1.md = r1_md; + + /* + * The scan walks R1 entries normal I/O may never touch, + * so don't let calc_r2_page_id() WARN on a corrupted one. + */ + if (!r1_entry_is_valid(qcow2, get_u64_from_be_page(r1_md->page, + r1.index_in_page))) + return -EIO; + + ret = calc_r2_page_id(qcow2, &r1, &r2); + if (ret == -ENOENT) { + /* No R2 cluster, so all clusters it covers are unused */ + pos = (loff_t)r1.index * qcow2->refblock_entries * clu_size; + pos -= clu_size; + continue; + } + + if (ret < 0) + return ret; + + ret = qcow2_md_page_read_sync(qcow2, r2.page_id, &r2.md); + if (ret) + return ret; + + for (i = r2.index_in_page; i >= 0; i--, pos -= clu_size) { + /* Last cluster is partial if size isn't cluster-aligned */ + if (get_r2_entry(qcow2, r2.md, i)) + return min_t(loff_t, pos + clu_size, + qcow2->file_preallocated_area_start); + } + } + + return -EIO; +} + static int truncate_prealloc_safe(struct qcow2 *qcow2, loff_t len, const char *func) { loff_t prealloc_len, max_prealloc_len = qcow2->reftable_max_file_size; @@ -2387,21 +2463,21 @@ static int relocate_refcount_table(struct qcow2 *qcow2, struct qio **qio) if (!WARN_ON_ONCE(!md)) qcow2_md_make_dirty(qcow2, md, true); if (!md) - break; /* goto err_free_r2_pages */ + break; /* goto err_hdr_written */ } spin_unlock_irq(&qcow2->md_pages_lock); if (i != nr_pages) - goto err_free_r2_pages; + goto err_hdr_written; /* Connect new R2 to new R1 */ for (i = end; i < r2_end; i += clu_size) { if (calc_refcounters_map(qcow2, i, &r1, &r2) < 0) { WARN_ON_ONCE(1); - goto err_free_r2_pages; + goto err_hdr_written; } ret = handle_md_page(qcow2, r1.page_id, NULL, &md); if (WARN_ON_ONCE(ret <= 0)) - goto err_free_r2_pages; + goto err_hdr_written; spin_lock_irq(&qcow2->md_pages_lock); set_u64_to_be_page(md->page, r1.index_in_page, i); qcow2_md_make_dirty(qcow2, md, true); @@ -2412,7 +2488,7 @@ static int relocate_refcount_table(struct qcow2 *qcow2, struct qio **qio) for (i = pos; i < r2_end; i += clu_size) { ret = qcow2_handle_r1r2_maps(qcow2, i, NULL, &r1, &r2, false); if (WARN_ON_ONCE(ret <= 0)) - goto err_free_r2_pages; + goto err_hdr_written; mark_cluster_used(qcow2, r2.md, r2.index_in_page); } @@ -2420,12 +2496,16 @@ static int relocate_refcount_table(struct qcow2 *qcow2, struct qio **qio) for (i = old_pos; i < old_end; i += clu_size) { ret = qcow2_handle_r1r2_maps(qcow2, i, NULL, &r1, &r2, false); if (WARN_ON_ONCE(ret <= 0)) - goto err_free_r2_pages; + goto err_hdr_written; mark_cluster_unused(qcow2, r2.md, r2.index_in_page, i); } return 1; +err_hdr_written: + /* Header on disk points to new R1, refcounts may be inconsistent */ + QC_ERR(qcow2->tgt->ti, "failed to relocate refcount table"); + qcow2->tgt->md_writeback_error = true; err_free_r2_pages: for (i = end; i < r2_end; i += clu_size) { ret = handle_md_page(qcow2, i >> PAGE_SHIFT, NULL, &md); diff --git a/drivers/md/dm-qcow2-target.c b/drivers/md/dm-qcow2-target.c index eb56c8de65c3..832cdbc8de33 100644 --- a/drivers/md/dm-qcow2-target.c +++ b/drivers/md/dm-qcow2-target.c @@ -170,6 +170,7 @@ static void qcow2_free_md_pages_tree(struct rb_root *root) void qcow2_flush_deferred_activity(struct qcow2_target *tgt, struct qcow2 *qcow2) { struct rb_node *node; + bool wb_error = false; struct md_page *md; int i; @@ -191,13 +192,17 @@ void qcow2_flush_deferred_activity(struct qcow2_target *tgt, struct qcow2 *qcow2 node; node = rb_next(node)) { md = rb_entry(node, struct md_page, node); /* FIXME: call md_make_dirty() and try once again? */ - if (md->status & MD_WRITEBACK_ERROR) { - QC_ERR(tgt->ti, "Failed to write dirty pages"); - tgt->md_writeback_error = true; - break; - } + if (md->status & MD_WRITEBACK_ERROR) + wb_error = true; + if (md->status & MD_LX_REVERTED) + tgt->lx_writeback_error = true; } spin_unlock_irq(&qcow2->md_pages_lock); + + if (wb_error) { + QC_ERR(tgt->ti, "Failed to write dirty pages"); + tgt->md_writeback_error = true; + } } static void qcow2_flush_deferred_activity_all(struct qcow2_target *tgt) @@ -1048,11 +1053,34 @@ static void qcow2_truncate_preallocations(struct dm_target *ti) { struct qcow2_target *tgt = to_qcow2_target(ti); struct qcow2 *qcow2 = top_qcow2_protected(ti); - loff_t end = qcow2->file_preallocated_area_start; + loff_t used_end, end = qcow2->file_preallocated_area_start; int ret; if (!(dm_table_get_mode(ti->table) & FMODE_WRITE)) return; + + /* + * Refcounts don't match L1/L2 on disk after failed md writeback. + * They may also be below real usage in an image opened dirty, + * e.g. after a crash. If userspace sets the dirty bit, it is set + * on every RW open and userspace checks the image before that. + */ + if (tgt->md_writeback_error) { + QC_INFO(ti, "Skip shrinking to used end after md writeback error"); + } else if (tgt->lx_writeback_error) { + QC_INFO(ti, "Skip shrinking to used end after reverted L1/L2 writeback"); + } else if (kernel_sets_dirty_bit && + (qcow2->hdr.incompatible_features & + INCOMPATIBLE_FEATURES_DIRTY_BIT)) { + QC_INFO(ti, "Skip shrinking to used end of dirty image"); + } else { + used_end = qcow2_calc_used_end(qcow2); + if (used_end < 0) + QC_ERR(ti, "Can't find used end: %pe", ERR_PTR(used_end)); + else + end = used_end; + } + if (end == qcow2->file_size) return; diff --git a/drivers/md/dm-qcow2.h b/drivers/md/dm-qcow2.h index 69d3ae6fca8a..95d0ec09c169 100644 --- a/drivers/md/dm-qcow2.h +++ b/drivers/md/dm-qcow2.h @@ -134,6 +134,7 @@ struct md_page { #define MD_DIRTY (1U << 1) /* Page contains changes and wants writeback */ #define MD_WRITEBACK (1U << 2) /* Writeback was submitted */ #define MD_WRITEBACK_ERROR (1U << 3) /* Last writeback failed with error */ +#define MD_LX_REVERTED (1U << 4) /* L1/L2 on disk may point to freed cluster */ unsigned int status; struct page *page; struct list_head wait_list; @@ -200,6 +201,7 @@ struct qcow2_target { bool service_operations_allowed; bool wants_suspend; bool md_writeback_error; + bool lx_writeback_error; bool truncate_error; bool event_enospc; @@ -411,6 +413,7 @@ void qcow2_ref_dec(struct qcow2_target *tgt, u8 ref_index); int qcow2_inflight_ref_switch(struct qcow2_target *tgt); void qcow2_flush_deferred_activity(struct qcow2_target *tgt, struct qcow2 *qcow2); int qcow2_truncate_safe(struct file *file, loff_t new_len); +loff_t qcow2_calc_used_end(struct qcow2 *qcow2); void qcow2_merge_backward_work(struct work_struct *work); void qcow2_merge_backward_cancel(struct qcow2_target *tgt); @@ -459,7 +462,8 @@ static inline bool fake_service_qio(struct qio *qio) static inline bool qcow2_wants_check(struct qcow2_target *tgt) { - return !!(tgt->md_writeback_error|tgt->truncate_error); + return !!(tgt->md_writeback_error|tgt->lx_writeback_error| + tgt->truncate_error); } static inline bool qcow2_file_is_writable(struct qcow2 *qcow2) -- 2.53.0 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel