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 69F25808A3 for ; Mon, 12 Oct 2026 13:28:51 +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 69CDRdJQ022971; Mon, 12 Oct 2026 16:27:39 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 69CDRdJQ022971 Authentication-Results: mail.openvz.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=virtuozzo.com header.i=@virtuozzo.com header.b="ftmA0xpc" Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 69CDRalO022958 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=FAIL) for ; Mon, 12 Oct 2026 16:27:36 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 69CDRalO022958 Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-4a19df2328cso13401105e9.3 for ; Mon, 12 Oct 2026 06:27:36 -0700 (PDT) X-Gm-Message-State: AFq9FYIF7BOOVTZTLDwcqSUoAUYqAl0lHyKY9OE/LSJFNRS0QdzoWYoi 3uIHTt/ItmIUifg4Rfe+Diynpz9WJkc4jWRy7hHHmCT3XdQ6BfT5s54VmEoMKxYElT+Q8Z68U5x 9tL+MdgvxYcKmOekR0zKtvFsoiD178yFwLzJ+BcBRsD6bHXR3g81WIA== X-Gm-Gg: AYBFou0B7wpYtan8LWP17se3qA2Hqygn+PZMXhjyvt1kZbHrAS4YscZtW5hN71RwDQ5 7m1zROIO3UTjEQIBmC6r5ZniJ1GH7SeGoplF3RewtsE0kKGvqU9WTzjvbbx8b2Pw9TgsJI4MIky wltMz5rBCAA8hDCVVbqD6ec3sMOAjBIMRvAN/9hnePvqHz1XdicpXgBEhCs+KXBCLNDeaFGKoKo EzRo8JkDCEehdM6yo4KkwAM9kjvc5JdU9K28z9qKu1bQPzZgWoHE0pWyrvuCWZsAiYvBPgBA1/N OJ40juDWM0N4ikSHw0bkHHCd6MRVTENjnxhGRkZTsf3bjxJkHC4fYCNR7B+XgoXALrOiM/1dRKE DjbgjBScr/hgf1csVvGblqSYY00GH X-Received: by 2002:a05:600c:8214:b0:4a1:6425:be69 with SMTP id 5b1f17b1804b1-4a18e4b4db8mr176958095e9.17.1791811656107; Mon, 12 Oct 2026 06:27:36 -0700 (PDT) X-Received: by 2002:a05:600c:8214:b0:4a1:6425:be69 with SMTP id 5b1f17b1804b1-4a18e4b4db8mr176957195e9.17.1791811655362; Mon, 12 Oct 2026 06:27:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1791811655; cv=none; d=google.com; s=arc-20260327; b=qxeI/bBMAg7m1kpt6SHGVvBKzkwiLHHMeHtGWjNUC1UZusA67EZ5ASiUXq65Zi7Q87 w7pwejw4ARf4yvP1Cil2gIVjtH+UPPCyYtrOq/fWDovKy2zDPWYj9f6VK8SY6KvwYxPr /Hf4I8UCb9PPBdA6p1D77VGhXa9xExr44gbSOObr802Qk4aXqxEKbDeWCTx6okd0zvQo snqRiWkq9drtKuJPvDK8YuKwKQjc+qGvmPl/f7USFiqnFYtQJ/RUOD2BTrer5nK1zD+M aq4pP9f6e8hr0gqCjTfbkLLzL/2jlXs2HitrNb0VO3DqcQK/OkljeL83f1JoQwx8NbB3 QUhw== 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=hN3B8JXQQ1y5iiYZzt0vV6RmPJ8qeeuV5MgNsbo3lRw=; fh=M+TyAUhAp4+t7uzAVeqNdLHW5eNz2FQXSv4TjrRhpCk=; b=Ifl4wTNxyP/o1ZfQwmYTCeAsUxq0gB2Tj/q9iUL7tkGwRPRUvtk3mEvwHJfqr9ZlHn euRN1DiDmOcjHFpdpSfoVvTcg7kW9bKzNmkLJ9M3ml+8sxg9Ej0udYxFOeJcEpiz6bL9 3Hvbj+9MNbYxLG3Y+uMNXXu7r57G3bw5TItMU1qdRCJhYJuForaGdpQdBpRc334L2SL4 Rnd3e+U4T69gKzyF0ZwlaaHEqafPn7z0WWETapkJCKvIoGNTbu9U+SmSkBqxYBBF6mCs qLBYb7n30XSlfe5n8U0qAGOz22qIhrmwej1Dgokhmr5SKcd1k3qRbuiPa/WRFRsCIuLT 8fjw==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=ftmA0xpc; 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-48db9b0b1e5si18093274f8f.439.2026.10.12.06.27.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 12 Oct 2026 06:27:35 -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=ftmA0xpc; 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=hN3B8JXQQ1y5iiYZzt0vV6RmPJ8qeeuV5MgNsbo3lRw=; b=ftmA0xpc7ZH4 rGVPzLiPXHDBwMsjGhOYgExoNMA+CCgCCUSIWKPwyg9Suoh33ky88vCqThESgjxD1puE74Xrs9a+z aNm7S4lbqsu1WgFZHqcGtLsFS/rmSlWrPhay1e/RfEmJt2pIVKyyIl+t0ZJlLZwSDKLghmyHMGkl4 l0srAKT1VL6ntZd5HRZmnimqOJSQJbbYyhv8bKI4Z/FdsQVYk/dnMxzr5Ys+QxPUpbrBdsliaYMAH X3kyaZ1ImicI0WrRR7NRadzfKt5zf6d//R1PQMi8/F/Ic0FIBsA+o/J6hneFpNsmU9hZWJV3I7dpO zgbs6I65pGKSxVNvjQN38w==; 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 1xGFzx-001WAY-2G; Mon, 12 Oct 2026 15:26:47 +0200 From: Alexander Ivanov To: den@openvz.org Date: Mon, 12 Oct 2026 15:26:46 +0200 Message-ID: <20261012132646.41494-12-alexander.ivanov@virtuozzo.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20261012132646.41494-1-alexander.ivanov@virtuozzo.com> References: <20261012132646.41494-1-alexander.ivanov@virtuozzo.com> MIME-Version: 1.0 X-OZ-Fwd: true Cc: devel@openvz.org Subject: [Devel] [PATCH hci-8.1 v4 11/11] 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. The field was never interpreted before, so if it is not cluster-aligned or out of range, don't truncate anything: unaligned truncation would make the next resume fail with -EPROTO. 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. Skip devices in standby mode as well: the top delta file is dead then, and the truncation may hang with md->suspend_lock held, so dm_replace() of libploop could neither replace nor remove the device. Also skip it if the file size differs from top->file_size. Then another ploop on the same images writes to the top delta (e.g. a live one left by libploop error path), and on-disk BAT may miss clusters it has just allocated, so the truncation would cut its data. 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 | 64 +++++++++++++++++++++++++++++++++--- drivers/md/dm-ploop.h | 3 +- 3 files changed, 118 insertions(+), 5 deletions(-) diff --git a/drivers/md/dm-ploop-bat.c b/drivers/md/dm-ploop-bat.c index c060afdd8d3e..7bab746a3707 100644 --- a/drivers/md/dm-ploop-bat.c +++ b/drivers/md/dm-ploop-bat.c @@ -709,6 +709,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 used by BAT area, + * mapped clusters or format extension, according to on-disk metadata. + * 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; + struct rb_node *node; + struct md_page *md; + u64 ext_off, ext_clu; + loff_t used_end; + 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; + } + } + + /* The header is the last cluster, see delta_save_optional_header() */ + hdr = ploop_md_first_entry(&md_root)->kmpage; + ext_off = le64_to_cpu(hdr->m_FormatExtensionOffset); + if (ext_off) { + ext_clu = SEC_TO_CLU(ploop, ext_off); + if (CLU_TO_SEC(ploop, ext_clu) != ext_off || + ext_clu >= BAT_ENTRY_NONE) { + used_end = -EPROTO; + goto out; + } + if (ext_clu >= used_clus) + used_clus = ext_clu + 1; + } + + used_end = CLU_TO_POS(ploop, used_clus); +out: + 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 208480d049fb..9c655bf9399f 100644 --- a/drivers/md/dm-ploop-target.c +++ b/drivers/md/dm-ploop-target.c @@ -449,8 +449,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) { @@ -746,10 +747,59 @@ 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; + if (ploop_is_standby(ploop)) + return; + if (!ploop_no_pending_prealloc(ploop)) + return; + if (i_size_read(file_inode(top->file)) != top->file_size) { + PL_ERR("Top delta is changed by someone else, don't truncate it"); + 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; + unsigned int noio_flags; + down_write(&ploop->ctl_rwsem); /* * Let the next resumed ploop (maybe of reloaded table) * see final size of the top delta. Don't wait in standby @@ -765,10 +815,16 @@ static void ploop_postsuspend(struct dm_target *ti) /* * Data bios are completed before BAT writeback is finished * (see ploop_put_piwb()), so wait for it explicitly to make - * md pages clean for ploop_reload_metadata(). + * md pages clean for ploop_reload_metadata() and + * ploop_calc_used_end(). */ wait_event(ploop->inflight_md_wq, !atomic_read(&ploop->inflight_md)); - ploop_set_suspended(ti, true); + /* The device is suspended, see ploop_preresume() */ + noio_flags = memalloc_noio_save(); + ploop_truncate_unused_tail(ploop); + memalloc_noio_restore(noio_flags); + 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 5750eafc8a1b..bdc8033c9cc5 100644 --- a/drivers/md/dm-ploop.h +++ b/drivers/md/dm-ploop.h @@ -37,7 +37,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) @@ -643,6 +643,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