From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail.openvz.org (unknown [69.168.225.77]) by lore.virtuozzo.com (Postfix) with ESMTPS id C91F18017D for ; Tue, 6 Oct 2026 14:46:48 +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 696EjOGU025445; Tue, 6 Oct 2026 17:45:25 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 696EjOGU025445 Authentication-Results: mail.openvz.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=virtuozzo.com header.i=@virtuozzo.com header.b="AUDgFw5A" Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 696EjMcC025441 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=FAIL) for ; Tue, 6 Oct 2026 17:45:22 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 696EjMcC025441 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-4a1721559b4so20382255e9.1 for ; Tue, 06 Oct 2026 07:45:22 -0700 (PDT) X-Forwarded-Encrypted: i=2; AKwUvBzY7+ynnzdDv3CCZDurAKYt8l2lcOuz/EScnyJ8q30/xHsuEu8nodDtYGEyNIwq1CWhWsKmCQ==@openvz.org X-Gm-Message-State: AFuF++lFztiPD6vT+iImm7osT4sTnyNfaGkTPvXhj+Bu/oUklQawi94e MzS8/9tbuo6CqO4PosGZpcXtRTDhU2YAQGkptog3JPPSguvTvu6+rBPcXx37IW+QW+hANHETi4c ODzVxbkrNyjljhxR8z56kTtRY+rSIT6SWblM9Y3vKz6k4NAslgN5xGA== X-Gm-Gg: AYBFou3uou53bdRI/VM7oHqUify8jssm5Ax5p8YIdiil9Cl0q99ngTvZuAdN4Q32x3y 9H174gl5Zp0lsGPCxg4qB+6wFgBMyXcWk+q4uyZMN5c1UrVHjeigoKR/jTFu2PbhJEe9qceVtTu R0o3yHK2E9xS/eHRXgZW+5DtmsTB/rH0595QVD9H++n51ArW83YUI+f2pq/ZvxWMcYhmBCNVmWG IvZIJH0/YI/pZjBTiPMue9tJNR53lmFHFDbISAvOBuHy54fDOh6yaNNEnLxcdpiC9D2zYOgyvOV H6KC/I/l5v8JQ4NJE943pOMhPHin3411+/ouSHmZu9G8KxZtsi31Y3vYJHhJW+3zUyzRngJEtiy rErga01JrOjHbrA0SQZZEhpRcyhZ6 X-Received: by 2002:a05:600c:4e43:b0:4a0:c4:a1e0 with SMTP id 5b1f17b1804b1-4a17b53bec8mr27504305e9.9.1791297921760; Tue, 06 Oct 2026 07:45:21 -0700 (PDT) X-Received: by 2002:a05:600c:4e43:b0:4a0:c4:a1e0 with SMTP id 5b1f17b1804b1-4a17b53bec8mr27503775e9.9.1791297921035; Tue, 06 Oct 2026 07:45:21 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1791297921; cv=none; d=google.com; s=arc-20260327; b=g+k+ccppBz+xZwj1v8LuwnXpx1YyfPR6j/u5yq1KVa5NeFjlHTK8TD/Nv89/5KsyAi MkpdEtjrO/HWqw71GOwzw8eiQSwAt6gMSVG6ndolF+8qmcEEjbU9WShY9895hhihIet4 XHfjYwMeC6nYYdzZL5+A7GrtmQcVTJyhC44oBdt/KfwSw9KDVEDVAW2qLdMCV2+mVLXv wuy1vuRdCLxEWwMcT5kdZHNQDtnfXa0FkerkXyA3Ib8l+YsFzc6V5Y/AvPc3XofhCNxg 0mjf0hACxcBtmSREWxhuN80XNb5b4p45ARg3s/nhlQ8j2uUxXHYZOBONLJjA8q1spVCl aEqA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:dkim-signature; bh=31FdIHrRSht+luvfZNo/Th0CLfMUyNRYseR5miV8hYw=; fh=iR+h9bi3Bh9zMcmhT/g9qNPJn2rboPnO22cA9JfMqyc=; b=QarR4JCKmuJQ42ssN4dm6MG3uWGFx+AuBtnpoZxdKSXcFKnm4zKGCJsGLH6r2gwWRn NuiU3JkRjjUdLG18lfCJP0PnMVGUdv4WqlWPlJgTIQvs9jL6my23BoUNzMuIp46U5K8+ 7JOvp2Wn+MnOIzkbEGWVHpp2WzecwOa7cKKCLZtJqeOHDxyzpJbvxdqJMQPkza0JEQIc lh8hL1VyjLxCImnLphqy+kkC2RgNlPLQpJ6mT8aLekM1K1ddraHtdzBfUorbypXC3l6W 2D9QKF1APSMKnnOVob2DhEBIA/Hi4weBXirLYb0y7VIXFcQsJepbKKE3H3uAUqCx74eQ 5oeQ==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=AUDgFw5A; 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-48b5b320b24si24597046f8f.200.2026.10.06.07.45.20 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 Oct 2026 07:45:20 -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=AUDgFw5A; 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=31FdIHrRSht+luvfZNo/Th0CLfMUyNRYseR5miV8hYw=; b=AUDgFw5ADmED +CPhJDQ7iOaWo0Iv1uVqXGv6ZHe6sEegUGFqrlkup24l/s1AoYbGpTNncpMxN9+x3CnIs67Fc5wbh fzk3fBvK1KD36dxWxC7qQc+8Cn1qDfE4XkvMGVwhQgPWnll17B3L2Wk1Dyfvs9F1LxCU3wNbCuR8k H7VG5u6S/0caCxp+PZnhg+X1oBXy2Y9MJ0mnGkx/83MfRoXcRo4QCTyNgJaadvW5iJ/ZD9E72Knrh 9mnIT1fzZRknEJXWl+2hcNhcx7wwZWcRNGZ8CFEOdaTQRN/3SixMM+ppS9VugfoZHc2n5OFiF3e+w R/4x/SjXVvHYJbDqQ4VcGQ==; 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 1xE6Mh-00DacA-21; Tue, 06 Oct 2026 16:45:10 +0200 From: Alexander Ivanov To: den@virtuozzo.com Date: Tue, 6 Oct 2026 16:44:28 +0200 Message-ID: <20261006144428.341824-1-alexander.ivanov@virtuozzo.com> X-Mailer: git-send-email 2.53.0 MIME-Version: 1.0 X-OZ-Fwd: true Cc: devel@openvz.org Subject: [Devel] [PATCH hci-8.1] drivers/md/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 On postsuspend we truncate the image file only down to file_preallocated_area_start, i.e. we drop preallocations only. Clusters at the end of the file freed by discard (refcount dropped to zero) are never given back, so the file size never shrinks. Add qcow2_calc_used_end(), which scans refcount blocks backward from the end of the file 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. Truncate the file to min(file_preallocated_area_start, used end). Skip the scan if md writeback failed, as refcounts on disk are stale then, and fall back to the old behaviour on scan error. 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-map.c | 77 ++++++++++++++++++++++++++++++++++++ drivers/md/dm-qcow2-target.c | 12 +++++- drivers/md/dm-qcow2.h | 1 + 3 files changed, 89 insertions(+), 1 deletion(-) diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c index 78ee7cf5e881..39d465343d8b 100644 --- a/drivers/md/dm-qcow2-map.c +++ b/drivers/md/dm-qcow2-map.c @@ -2208,6 +2208,83 @@ int qcow2_truncate_safe(struct file *file, loff_t new_len) return do_ftruncate(file, new_len, 0); } +static int get_md_page_sync(struct qcow2 *qcow2, u64 id, struct md_page **md) +{ + int ret; + + spin_lock_irq(&qcow2->md_pages_lock); + *md = qcow2_md_page_find_or_postpone(qcow2, id, NULL); + spin_unlock_irq(&qcow2->md_pages_lock); + if (*md) + return 0; + + ret = qcow2_alloc_and_insert_md_page(qcow2, id, md); + if (ret) + return ret; + + ret = qcow2_rw_page_sync(READ, qcow2, id, (*md)->page); + spin_lock_irq(&qcow2->md_pages_lock); + if (ret) + qcow2_md_page_erase(qcow2, *md); + else + (*md)->status |= MD_UPTODATE; + spin_unlock_irq(&qcow2->md_pages_lock); + if (ret) + qcow2_free_md_page(*md); + return ret; +} + +/* + * Returns the end of the last cluster, which is used according + * to refcount table. Clusters freed by discard may leave the tail + * of file unused. 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 = round_down(qcow2->file_size - 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 = get_md_page_sync(qcow2, r1.page_id, &r1_md); + if (ret) + return ret; + } + r1.md = r1_md; + + 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 = get_md_page_sync(qcow2, r2.page_id, &r2.md); + if (ret) + return ret; + + for (i = r2.index_in_page; i >= 0; i--, pos -= clu_size) { + if (get_r2_entry(qcow2, r2.md, i)) + return pos + clu_size; + } + } + + 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; diff --git a/drivers/md/dm-qcow2-target.c b/drivers/md/dm-qcow2-target.c index be09615eb8e2..95c8b114d92f 100644 --- a/drivers/md/dm-qcow2-target.c +++ b/drivers/md/dm-qcow2-target.c @@ -1016,11 +1016,21 @@ 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 on disk are stale after failed md writeback */ + if (!tgt->md_writeback_error) { + used_end = qcow2_calc_used_end(qcow2); + if (used_end < 0) + QC_ERR(ti, "dm-qcow2: Can't find used end: %lld", used_end); + else if (used_end < end) + end = used_end; + } + if (end == qcow2->file_size) return; diff --git a/drivers/md/dm-qcow2.h b/drivers/md/dm-qcow2.h index d9b8c38e093f..2c5eb7578316 100644 --- a/drivers/md/dm-qcow2.h +++ b/drivers/md/dm-qcow2.h @@ -409,6 +409,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); -- 2.53.0 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel