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 EF4F58017D for ; Thu, 8 Oct 2026 07:40:21 +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 6987d7M2021083; Thu, 8 Oct 2026 10:39:08 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 6987d7M2021083 Authentication-Results: mail.openvz.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=virtuozzo.com header.i=@virtuozzo.com header.b="bb24k194" Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 6987cjwC021037 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=FAIL) for ; Thu, 8 Oct 2026 10:38:45 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 6987cjwC021037 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-48c6a1d4034so1970742f8f.0 for ; Thu, 08 Oct 2026 00:38:45 -0700 (PDT) X-Forwarded-Encrypted: i=2; AKwUvByq3GVH45b8nfC1vY2qevsIpnEToptokAynDE4muubIIKdZsQwPcnUfiiWfrNlihoOrXeB/zw==@openvz.org X-Gm-Message-State: AFq9FYJU2QtL01w+LZdy/rRykUv5jwwtSfXeUAeyCJGAGwo8NUZ1dO5+ gCnajKtdED3RBc8PL3Oq7VqyGPR2fVfnHQs0pfY4szX2/wgAomnAXT34sKpiamJnI7h+ZCV5CUV dHxgwSyTOOnk5EA+9JSl99lkWOlS6OzIl6GiTVT+lS2wVm1p3/4fUvw== X-Gm-Gg: AYBFou2k/JW/aJlJt+q1oMrTjPZsgzAc0u+Cqt5abDA9WYNvcbuEop0UvSAniTOsXyV AbYNsR59VT3qYLVpYBHDFkOaHBTqniikszK/jKJvyhsAW+MiSU2UE8Q6AsbumhGjElyKFIxlT6h lqX7FiCnbM0xzFfI0KrRVrXrICjC15UDjm9uss0CMe+XEGB3M0qG4u2pE8wZQqKUFTKdD6r9dgD p63ftb7oZEOBzRQjwdPm+U0SfNzfWli1Bn/3m6eq+L5aosNvAnT8JrWFQmAxvYOg/shPSSMPAt6 APyDrJs58nuV/h/PxPdKLdxvNoMYN7gKz8nwue1HaGJJ3u7QQkfYSO3cw2AK9sMzX1GVbkdg6SN g87g3KvhL2GsK5aux9lLmEeDqqR7q X-Received: by 2002:adf:e186:0:b0:48b:1b6:3df8 with SMTP id ffacd0b85a97d-48c7288e4bemr9271097f8f.35.1791445125520; Thu, 08 Oct 2026 00:38:45 -0700 (PDT) X-Received: by 2002:adf:e186:0:b0:48b:1b6:3df8 with SMTP id ffacd0b85a97d-48c7288e4bemr9271053f8f.35.1791445124884; Thu, 08 Oct 2026 00:38:44 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1791445124; cv=none; d=google.com; s=arc-20260327; b=eqGkN15CBMtDjy2ZadXASHcjKc7aw2K199eNCwwJlQnPlDwBzudCwNSq+avX2fed4u e5E/8/XVBesLkC/4bNClKdyDUQOyjHyLDndBeNaCKGNhgtc3VF/u4+k1/H7YtVgikfCp 9cjF22m5DJaw6ugBApcCSBZYs+dicmpGCX4uCjuaCBJG6Z3dc/3f2B1RWB5ld89dyYeT 8I1lSEAZPEBNjfvocJRabD2bhpF96dk7CVygR1gk15dqwl2QVvg3IMtVNoudzDOXGybM /bCQyxqQ7n3z4OYnQEQDn/GUQLPpitenZGxpOJs0T3WW9R/x5KszvNdXlB/kycT8KR92 V5UA== 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=gOgSWhYLm9ateQaPHvU9xCd3iYrF6OBswJU4dXFK8hE=; fh=iR+h9bi3Bh9zMcmhT/g9qNPJn2rboPnO22cA9JfMqyc=; b=FG1l1hVfahJ8ygS/sF0rf6aSIKc0/yD81gOAC0q74Ri1i/TVc2Nnt1U8v0xDyGw3T2 sEFKBTHvXLOXFz1sPBN7GzNhVeulE/AMvEl6GuQZcXIdAwzVmGVWkopkD0MwXChtBp6g EXNxelZb11PxHvlFWHl5Pdz/dVdz/KrsZ5jfqRNiuP2C4u6rZ2KN1Y9TCPDNfgU9lm2n ajDnL72/Z8W9O8kHHC94YNQ9MFbbXwkarfftqC6r18bL0sdlNzMeZq+CEMK6+ML33peQ gXX0WO82S/QsOxBH0ph/b9c7Zw7QtZgewam4upSZ5porBbneARmO3rYDqIpylTrsIvhS l34g==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=bb24k194; 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-48c7249e4e5si8632464f8f.307.2026.10.08.00.38.44 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Oct 2026 00:38:44 -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=bb24k194; 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=gOgSWhYLm9ateQaPHvU9xCd3iYrF6OBswJU4dXFK8hE=; b=bb24k194BV5N yKXtk+o5CTroY3O1lPmvad/KzsMFKAav5TqeLwM2QyXasc9hsyJ8scVTLfpIBofjQSulJ75d9FRrf Qm+7iZ93Eqgz6YlGAcb98QZxLxR6JNv84muNPOjRVkUqZ0rgcWHGyagJjVAc6iWEPB3ddJim3FS4a tyQnM1CHDcj/ZTDFYwX+KwbHcCdIoBDPwNE+7Hf9DGq+rgF8d5/nmc+F67sQk8EcRXGsWQ3/8X/OW sH4J5vyVvEf8LA8BTgrw+Pq0ZTpN3Dk8JT4Z25gwVEvSTzfq99szj4cWWiBGeqj0x3JClFtHx30+3 qhzNrjxYtW2p7nhMeG+MbA==; 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 1xEiev-007naT-0T; Thu, 08 Oct 2026 09:38:42 +0200 From: Alexander Ivanov To: den@virtuozzo.com Date: Thu, 8 Oct 2026 09:38:36 +0200 Message-ID: <20261008073837.510678-7-alexander.ivanov@virtuozzo.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20261008073837.510678-1-alexander.ivanov@virtuozzo.com> References: <20261008073837.510678-1-alexander.ivanov@virtuozzo.com> MIME-Version: 1.0 X-OZ-Fwd: true Cc: devel@openvz.org Subject: [Devel] [PATCH hci-8.1 v2 6/6] dm-ploop: truncate unused tail of top delta 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 Preallocated space and clusters at the end of the top delta freed by discard are never given back, so the file size never shrinks. Now that ploop reloads metadata on resume, we can truncate the top delta on suspend: the next resumed ploop (maybe of reloaded table) picks up the new file size. Add ploop_calc_used_end(), which returns the end of the last cluster used by the delta: either BAT area, the last mapped cluster or format extension. Metadata is read from disk rather than taken from memory: the next table load checks BAT entries against the file size (-EPROTO otherwise), while in-memory BAT may differ from on-disk one after failed BAT writeback. Skip it if md pages are not clean, as on-disk BAT may miss allocated clusters then. Userspace writes format extension (CBT) behind the last data cluster of suspended device on umount, resumes it, and then removes the device, which suspends it again. So keep the area up to the end of format extension header, which is the last cluster of the extension, as userspace does. Name the corresponding header field properly instead of m_Reserved. Truncate the top delta to the used end in ploop_postsuspend() after pending preallocation is completed. Do it under ctl_rwsem, so that ploop messages (e.g. resize) don't change the image in parallel. Skip read-only devices and raw top delta. On error just leave the file as is. https://virtuozzo.atlassian.net/browse/VSTOR-148171 Feature: dm-ploop: ploop target driver Signed-off-by: Alexander Ivanov --- drivers/md/dm-ploop-bat.c | 56 ++++++++++++++++++++++++++++++++++++ drivers/md/dm-ploop-target.c | 49 +++++++++++++++++++++++++++++-- drivers/md/dm-ploop.h | 3 +- 3 files changed, 104 insertions(+), 4 deletions(-) diff --git a/drivers/md/dm-ploop-bat.c b/drivers/md/dm-ploop-bat.c index fa87dd248f5b..0a40702fb7d3 100644 --- a/drivers/md/dm-ploop-bat.c +++ b/drivers/md/dm-ploop-bat.c @@ -682,6 +682,62 @@ int ploop_reload_metadata(struct ploop *ploop) } ALLOW_ERROR_INJECTION(ploop_reload_metadata, ERRNO); +/* + * Returns the end of the last cluster of delta @file, which is used + * according to its header and BAT: either BAT area, the last mapped + * cluster or format extension. Clusters freed by discard may leave the + * tail of file unused. Metadata is read from disk, as the next table + * load checks BAT entries against the file size, while in-memory BAT + * may differ from it after failed BAT writeback. Also userspace may + * write format extension (e.g. CBT) behind the last data cluster of + * suspended device. This must be called on suspended device. + */ +loff_t ploop_calc_used_end(struct ploop *ploop, struct file *file) +{ + u32 i, end, nr_be, dst_clu, used_clus, *bat_entries; + struct rb_root md_root = RB_ROOT; + struct ploop_pvd_header *hdr; + loff_t used_end, ext_end; + struct rb_node *node; + struct md_page *md; + u64 ext_off; + int ret; + + /* BAT on disk may miss allocated clusters until writeback is done */ + if (WARN_ON_ONCE(!ploop_md_pages_are_clean(ploop))) + return -EBUSY; + + ret = ploop_read_delta_metadata(ploop, file, &md_root, &nr_be); + if (ret) + return ret; + + used_clus = ploop_nr_bat_clusters(ploop, nr_be); + rb_root_for_each_md_page(&md_root, md, node) { + bat_entries = md->kmpage; + init_be_iter(nr_be, md->id, &i, &end); + for (; i <= end; i++) { + dst_clu = READ_ONCE(bat_entries[i]); + if (dst_clu != BAT_ENTRY_NONE && dst_clu >= used_clus) + used_clus = dst_clu + 1; + } + } + + used_end = CLU_TO_POS(ploop, used_clus); + + /* Format extension header is the last cluster of extension */ + hdr = ploop_md_first_entry(&md_root)->kmpage; + ext_off = le64_to_cpu(hdr->m_FormatExtensionOffset); + if (ext_off) { + ext_end = to_bytes(ext_off) + CLU_SIZE(ploop); + if (ext_end > used_end) + used_end = ext_end; + } + + ploop_free_md_pages_tree(&md_root); + return used_end; +} +ALLOW_ERROR_INJECTION(ploop_calc_used_end, ERRNO); + void ploop_put_delta(struct ploop *ploop, struct ploop_delta *delta) { int i; diff --git a/drivers/md/dm-ploop-target.c b/drivers/md/dm-ploop-target.c index c9183fa9d3ca..88cc91a3d03a 100644 --- a/drivers/md/dm-ploop-target.c +++ b/drivers/md/dm-ploop-target.c @@ -441,8 +441,9 @@ static struct ploop_worker *ploop_worker_create(struct ploop *ploop, * ploop_dtr, as ploop_dtr is called on the old ploop after the new one is * resumed, so we can't possibly modify the image from the old ploop context * at this point, as new ploop may be already doing its own IO or - * preallocation. This truncation should be done on ploop_*suspend (see - * dm-qcow2 as it already implements that in qcow2_truncate_preallocations). + * preallocation. So this truncation is done on ploop_postsuspend (see + * ploop_truncate_unused_tail), and the new ploop picks up the new size + * of the top delta on metadata reload. */ static int ploop_ctr(struct dm_target *ti, unsigned int argc, char **argv) { @@ -733,16 +734,58 @@ static void ploop_presuspend_undo(struct dm_target *ti) { ploop_set_wants_suspend(ti, false); } + +/* + * Truncate preallocations and the tail of the top delta, which became + * unused after discard. The next resumed ploop (maybe of reloaded + * table) re-reads the size of the top delta in ploop_preresume(). + */ +static void ploop_truncate_unused_tail(struct ploop *ploop) +{ + struct ploop_delta *top = ploop_top_delta(ploop); + unsigned long flags; + loff_t end; + int ret; + + lockdep_assert_held_write(&ploop->ctl_rwsem); + + if (ploop_is_ro(ploop) || top->is_raw) + return; + + end = ploop_calc_used_end(ploop, top->file); + if (end < 0) { + PL_ERR("Can't find used end of top delta: %lld", end); + return; + } + if (end >= top->file_size) + return; + + ret = do_ftruncate(top->file, end, 0); + if (ret) { + PL_ERR("Can't truncate unused tail of top delta: %d", ret); + return; + } + + spin_lock_irqsave(&ploop->bat_lock, flags); + top->file_size = end; + if (top->file_preallocated_area_start > end) + top->file_preallocated_area_start = end; + spin_unlock_irqrestore(&ploop->bat_lock, flags); +} + static void ploop_postsuspend(struct dm_target *ti) { struct ploop *ploop = ti->private; + down_write(&ploop->ctl_rwsem); /* * Let the next resumed ploop (maybe of reloaded table) * see final size of the top delta. */ ploop_wait_prealloc(ploop); - ploop_set_suspended(ti, true); + ploop_truncate_unused_tail(ploop); + ploop->suspended = true; + up_write(&ploop->ctl_rwsem); } static int ploop_preresume(struct dm_target *ti) { diff --git a/drivers/md/dm-ploop.h b/drivers/md/dm-ploop.h index 1cf0d5e0cea8..e46d6efdce59 100644 --- a/drivers/md/dm-ploop.h +++ b/drivers/md/dm-ploop.h @@ -35,7 +35,7 @@ struct ploop_pvd_header { __u32 m_DiskInUse; /* Disk in use */ __u32 m_FirstBlockOffset; /* First data block offset (in sectors) */ __u32 m_Flags; /* Misc flags */ - __u8 m_Reserved[8]; /* Reserved */ + __u64 m_FormatExtensionOffset; /* Format extension offset (in sectors) */ }; #pragma pack(pop) @@ -634,6 +634,7 @@ extern void ploop_pio_prepare_offsets(struct ploop *ploop, struct pio *pio, u32 extern int ploop_setup_metadata(struct ploop *ploop, struct page *page, bool check_in_use); extern int ploop_reload_metadata(struct ploop *ploop); +extern loff_t ploop_calc_used_end(struct ploop *ploop, struct file *file); extern int ploop_read_delta_metadata(struct ploop *ploop, struct file *file, struct rb_root *md_root, u32 *delta_nr_be); extern void ploop_index_wb_init(struct ploop_index_wb *piwb, -- 2.53.0 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel