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 2941080726 for ; Thu, 8 Oct 2026 17:03:26 +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 698H2Anm026191; Thu, 8 Oct 2026 20:02:11 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 698H2Anm026191 Authentication-Results: mail.openvz.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=virtuozzo.com header.i=@virtuozzo.com header.b="sMKu0eBe" Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 698H25N6026172 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=FAIL) for ; Thu, 8 Oct 2026 20:02:05 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 698H25N6026172 Received: by mail-wr1-f69.google.com with SMTP id ffacd0b85a97d-48b09f01f56so3442320f8f.1 for ; Thu, 08 Oct 2026 10:02:05 -0700 (PDT) X-Forwarded-Encrypted: i=2; AKwUvByxzNa1uTHN8KRw0l81JaBOvmj9EfIbanjp1AqXAk5FhZPLXIsaiLx9JeVz8uG2YzPnowQa6A==@openvz.org X-Gm-Message-State: AFq9FYL4jFVwj9tcSh7gWPxKKD/gTMnQUWkE1f5dqwt+/RjsqTzfL9RC eX6yI60A4lCvT6hZ40WWUpSaNGHFBrzD5Ngb2rLjYCv1laWumQ0J5rRx2Trn1WfKHILr+m7EjBk qsH1g2B2db386JroOshxi1xGApmEsb/5sC1MozdPpyJ/b8vxqBJZCHg== X-Gm-Gg: AYBFou0/KoUrXmKesLImnmc59/w9LHqebCdIrXg5FYC0xdWGxBLZvWoAzhASJU+RR9c /Ls05Xr+qBL9S4RFuZL3b1SggA2hMdlFgxsEwecBrjP0gAU5j6vAZfu8PoZxysaoNzCOB2oQ3/M +IpIuSYeZvD/XQuvJ/MM5DiHgsJi0HiJ9uclh2jVl/4HE5H0x5w0qODFYAzfgv2pG+r64zqy+11 rx0eZugs10QhbfzjaHJHD+mJRVpHzdzBkUj6sEBXrGaHEkSY2Hlwk2bYCdsasv3eK/iUBYsrQLU 8SNji8ixcH/pA9/A1l/WdVb3aJgqrVMu8FQRM6AhUE/SYFGR5sh2ywmB06w9q7vnCb9L2L6VBWK Ne9ltd2zcSnJMPyeKcmsqciqwJPY= X-Received: by 2002:adf:eacf:0:b0:48b:3b4:1c8e with SMTP id ffacd0b85a97d-48c72754aa0mr8452101f8f.20.1791478925187; Thu, 08 Oct 2026 10:02:05 -0700 (PDT) X-Received: by 2002:adf:eacf:0:b0:48b:3b4:1c8e with SMTP id ffacd0b85a97d-48c72754aa0mr8452014f8f.20.1791478924409; Thu, 08 Oct 2026 10:02:04 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1791478924; cv=none; d=google.com; s=arc-20260327; b=flx5KPiDVJ5hCyTvhM2be+mQhgBpB0W3o0TclJfpGF2T1Fof3qqPGMr9zsdO43IBig hqMYnLovEZswOUKzp35GWxw9wzo8edG4XW7JxMn0iU+pXYwVCW1pTZyRaU+y1wt9I2AX ShROYPz4E0XQOod/z+eYSM+bwaMuOA58vLFwkDPKC/KW1MJebQ0PjgJE5WpeMCt7lsXz t8jdda7IGRxKk1UeZZfQwDBUTNGIvX0996T6HsvLRSWTYePcQc5rv7vC8ohKfOT7xfWG e8jI6KCwGiZ4tlU1kl2aP5MB14saQMdk80bCfa4lAB4F1MIPw0UfLFOd5gMoaDvqELeL WfYg== 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=qKoo7xc+bHPETfp8aNmF9JOWA+i1bKuJe7m1KFu1G2w=; fh=jiFD8gjZllyls1UFJ+1kA4uyOnjRU7bVpV3P+S6CTV8=; b=B7olF/pf+TZAZdWMTKZrCW9UYpp7rRtMup4KaGuH3HJtXywhnY8V7KivcLsFNYlItm tXf+r/RU1Gv9MODMioJAnNfsR8LLbwEdNQSHsCS8LwuKO587wv5XUXaZTicSJYi5JtD/ VnLv0sFKH/lJz99pxU/SbD8W/68FYIw5t7jNX7iqdncmEdlPiknTuEL6NZudTlclaVy/ IMu/Kbfb9gH2ABb73a+Wpc0hJJJxwwRL+o4GvsuFsaX+wHE76/Ls9WxnJ6PGPnHbBiFQ ZV8H7fQjnmsVPh9035kEgldHOFTt0h6rEv6LHQUXRzpQrY883E0GmVUrn5R3Dt9yTFh4 i3vg==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=sMKu0eBe; 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-48db654af63si485302f8f.77.2026.10.08.10.02.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Oct 2026 10:02:04 -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=sMKu0eBe; 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=qKoo7xc+bHPETfp8aNmF9JOWA+i1bKuJe7m1KFu1G2w=; b=sMKu0eBe5YPj O3Zj2xEUo3/JDfFwanDNnM0nSwj3AlI6wedr6vNjgbhmt3KiAr7Hapq6pSz4rddxHBiDgVo44iha9 p4Dgmaxzp/GId7nIb1xQflAuIfe+mCiRkviFN6gn5t5vFCzfcg2uPwSD3dS4LlmNzwM3CKBD7iCuA XwwAHAyWzB3njsAWO6rXm4sHNi2fXZ8tyDafVNv35DJjMVFEhIgH4px4gwm2plH9G02F1Vc/7/4Hw 9Wee3qM3x1V5n0YUJKRl2mWRfOcUg3fbHKWI15gj8UEvZCyikM0iF2Xd5eZnHTQzH/249Yt+ItX1k 6OexUM5Ss5FlNvuPspuVEw==; 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 1xErS3-000z63-1S; Thu, 08 Oct 2026 19:02:01 +0200 From: Alexander Ivanov To: den@openvz.org Date: Thu, 8 Oct 2026 19:02:00 +0200 Message-ID: <20261008170200.646208-4-alexander.ivanov@virtuozzo.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20261008170200.646208-1-alexander.ivanov@virtuozzo.com> References: <20261008170200.646208-1-alexander.ivanov@virtuozzo.com> MIME-Version: 1.0 X-OZ-Fwd: true Cc: devel@openvz.org Subject: [Devel] [PATCH hci-8.1 v4 3/3] 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 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. Truncate the file to the 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. Close and reload to RO go through postsuspend too: on remove, __dm_destroy() suspends the live table if it isn't suspended yet, and on table swap do_resume() suspends the old (RW) table before dm_swap_table(). So the tail is given back 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-map.c | 56 ++++++++++++++++++++++++++++++++++++ drivers/md/dm-qcow2-target.c | 12 +++++++- drivers/md/dm-qcow2.h | 1 + 3 files changed, 68 insertions(+), 1 deletion(-) diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c index 78ee7cf5e881..65ee6ae144bf 100644 --- a/drivers/md/dm-qcow2-map.c +++ b/drivers/md/dm-qcow2-map.c @@ -2208,6 +2208,62 @@ 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. 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_preallocated_area_start - 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; + + 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; diff --git a/drivers/md/dm-qcow2-target.c b/drivers/md/dm-qcow2-target.c index bb11b8a74598..8555494a0c1c 100644 --- a/drivers/md/dm-qcow2-target.c +++ b/drivers/md/dm-qcow2-target.c @@ -1047,11 +1047,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, "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..73d3cf175bbf 100644 --- a/drivers/md/dm-qcow2.h +++ b/drivers/md/dm-qcow2.h @@ -411,6 +411,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