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 D912D80069 for ; Thu, 27 Aug 2026 16:10: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 67RG9Zq9001663; Thu, 27 Aug 2026 19:09:36 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 67RG9Zq9001663 Authentication-Results: mail.openvz.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=virtuozzo.com header.i=@virtuozzo.com header.b="F5B4sRvl" Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 67RG9B8E001579 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=FAIL) for ; Thu, 27 Aug 2026 19:09:11 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 67RG9B8E001579 Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-482e05af072so1388295f8f.3 for ; Thu, 27 Aug 2026 09:09:11 -0700 (PDT) X-Gm-Message-State: AFuF++mQUJLxbJJuofM+luFng4hqnUUVGlrVf6KCmmVAXUfQTO6/Piuj 7HSCvGNhiyYJFLhkEmByyzH2xwRKPWmRx6uYROxrWyN9M6GKtI053WsEGHTfU6A78MjPXEibJyU HTBkXaNL1dVKj8YIiaxolulp4SmUkVAz6wNjeKY5j1Wh+Xkjgi9VxOA== X-Gm-Gg: AR+sD11uUtthq+ZWlB36hrMdpWoX8sGmaZzBBArPVScbiAokQWwi9EJ9/SKjJrE2ZFi TZChkmX1ZeIRm7QILBkb/kOcUYl7WqlupW6OgrJitqI1JLOgMNb6/UIcv0VuqHe10m+zB86v9ol yqX3w1d6eWzxOutSfdxfqlMuYHqwNEJwEH7dIXW/BRGS/OIK3/OP0wRQRr66dt92bUZUmX1RPoT IxiyVJsED2vJ/mf9Rq3A9IJ+LXhBkWC2OsgFQ6lsQiLqtuilopd6VDiPHTkyw5OKxcsv+WQv4au okjtjm3eHCRiZZGE7bfyf9VDsGlKZx4GY5Fuhr/DKgokFMGxbpW5/PP0aHQ5beaolW82iT2S0vH XREAPxvGsznQHzphkP8VkC39wlbCr X-Received: by 2002:a05:6000:4a0b:b0:482:a8b1:aa6d with SMTP id ffacd0b85a97d-482e26d8887mr23322166f8f.10.1787846951519; Thu, 27 Aug 2026 09:09:11 -0700 (PDT) X-Received: by 2002:a05:6000:4a0b:b0:482:a8b1:aa6d with SMTP id ffacd0b85a97d-482e26d8887mr23322004f8f.10.1787846950921; Thu, 27 Aug 2026 09:09:10 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1787846950; cv=none; d=google.com; s=arc-20260327; b=seLKznDPyAqfSBZ/PGVVgXwmZvpWnwWoD+Jouhx8lPTi1P5ZbQZuKfrRX6/n+WLHLt KsXgQ+UX332187UQbnXt2qUwPk80bukJixrVcoEmU3HJ98vAqdB0vx9F2bJgLgrfPq9M p4AyDs6oSUNQPZ714QcowjByrzGlwGdr82VP+B/Nwm/5WS+q/1lWHHCchoGgaq1c1CoI DdpzG1RUnQnkiyLC0rykniXIs3XDicKHUG0ZTBk2DFYz/4phfsNkAqLQCpuaS+JOF154 BaTKVy35Fxr5980XbdFl0NnqozKmOZI4oqRe4lV7RtXCafKIJDB8fXb9opeJOX3vDu99 ngwA== 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=ARmG4bWzSv+2P96x85jPba9CLNBZ79i2YXRDDzlRgYc=; fh=0/brz1B8ohImS2ERrXZY0dPGpSEyX2H6iLC7bneXJkE=; b=PK234gxWJfHVsGPJjsP01HoXbxat3AZmWKKDkGX36VaJnRarytG2Xui1DhOXYUoLm4 M9Q9STGOv3DhVzUcWt4Wdgp7f7+4S4pQV/fuT3IJp+flvQxdisRZ9nsPrE/bBtnMPkjs /M0W/wUGJb9wqUKwGm+NL4exakHmyw8dtARpcIeG0jnwbUHt+yQBJov2NRVslEvizd6t AkFfp5Rbbdk72KGD9VHG9YV3rn3rKe6KNLV5kLGf3ePJ198bkWCSPwyXi96ThtMVbvAU xl+YdPfPZ96tg/swH3VntNEPy1uYudV7n5qIXkP2GN/xxA84bd8EgY2lMo5Iv1J0Zmvb Rasg==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=F5B4sRvl; spf=pass (google.com: domain of andrey.zhadchenko@virtuozzo.com designates 130.117.225.111 as permitted sender) smtp.mailfrom=andrey.zhadchenko@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-482e515a281si7766056f8f.206.2026.08.27.09.09.10 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Aug 2026 09:09:10 -0700 (PDT) Received-SPF: pass (google.com: domain of andrey.zhadchenko@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=F5B4sRvl; spf=pass (google.com: domain of andrey.zhadchenko@virtuozzo.com designates 130.117.225.111 as permitted sender) smtp.mailfrom=andrey.zhadchenko@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=ARmG4bWzSv+2P96x85jPba9CLNBZ79i2YXRDDzlRgYc=; b=F5B4sRvlQAcz Tjf/qktYcP20Pk4XWVEPWsoFA9xQhR4dqjwlMR3dHZX3IfOtO2xQ7sYeCc485F298hmC84CBzuHBo aMESWc+ocIMgh7/X2RFbdETopF/chBc3Mv4QdY9UR2ZWZ7/vmz2srtf6RE46APXvehEQJZDMuOIMT BP9ZeVEryqcKrtaF5Qu/T6Ssi0cKC4+9bkdAI9626hK89o6k3GiQfHsBJ6lzXjfUkdLN8JH/ULCeP ViQmbmP/6Bh7X2FZtrAqX1IL21yRDbXchPQiNycn3sdmJK2v56W654EzzvbBWZz98VH7IjjpdHqJ3 /+cI7PYsVlbq+t9CY4rzrw==; Received: from [130.117.225.5] (helo=vz9-demens-1.aci.vzint.dev) by relay.virtuozzo.com with esmtp (Exim 4.96) (envelope-from ) id 1wzccs-00FHQJ-1K; Thu, 27 Aug 2026 18:09:08 +0200 From: Andrey Zhadchenko To: ptikhomirov@virtuozzo.com, vasileios.almpanis@virtuozzo.com Date: Thu, 27 Aug 2026 19:06:15 +0300 Message-ID: <20260827160619.303398-8-andrey.zhadchenko@virtuozzo.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20260827160619.303398-1-andrey.zhadchenko@virtuozzo.com> References: <20260827160619.303398-1-andrey.zhadchenko@virtuozzo.com> MIME-Version: 1.0 X-OZ-Fwd: true Cc: devel@openvz.org Subject: [Devel] [PATCH VZ10 v4 07/11] drivers/md/dm-qcow2: update metadata on subclusters discard 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 images with extended L2 entries a discard smaller than the whole cluster only punches a hole in the image file, while the subcluster allocation bitmap still reports the range as allocated. Extend prepare_cluster_discard() to also handle discards covering whole subclusters of a mapped non-compressed cluster: clear the "allocated" bits of the covered subclusters in the extended L2 entry via the existing only_set_ext_l2 machinery. If the range may be mapped in lower delta, set the "reads as zeroes" bits instead, so the discarded range doesn't expose stale lower data. The cluster itself remains allocated, so refcounts are not touched and the unuse stage has nothing to do (empty unuse range). The covered range is hole punched unless the cluster is shared with a snapshot. ext_l2 and unuse range handling are in different if blocks for a while: next patch will cover the case when we need uncoupling. Feature: dm-qcow2: block device over QCOW2 files driver https://virtuozzo.atlassian.net/browse/VSTOR-139406 Signed-off-by: Andrey Zhadchenko --- drivers/md/dm-qcow2-map.c | 69 ++++++++++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c index 52a630685518b..609cdd8837b8d 100644 --- a/drivers/md/dm-qcow2-map.c +++ b/drivers/md/dm-qcow2-map.c @@ -107,6 +107,21 @@ static bool qio_covers_full_clu(struct qcow2 *qcow2, struct qio *qio) qio->bi_iter.bi_size == qcow2->clu_size; } +/* Mask of subclusters fully covered by qio (qio is trimmed inward) */ +static u32 qio_full_subclus_mask(struct qcow2 *qcow2, struct qio *qio) +{ + u32 off = bytes_off_in_cluster(qcow2, qio); + u32 first_bit = DIV_ROUND_UP(off, qcow2->subclu_size); + u32 end_bit = (off + qio->bi_iter.bi_size) / qcow2->subclu_size; + + WARN_ON_ONCE(!qcow2->ext_l2); + + if (end_bit <= first_bit) + return 0; + + return GENMASK(end_bit - 1, first_bit); +} + static loff_t compressed_clu_end_pos(loff_t start, sector_t compressed_sectors) { if (start % SECTOR_SIZE == 0) @@ -3357,11 +3372,21 @@ static void issue_discard(struct qcow2_map *map, struct qio *qio) static bool qio_discard_updates_metadata(struct qcow2 *qcow2, struct qio *qio, struct qcow2_map *map) { + u32 mask; + if (!(map->level & L2_LEVEL) || !map->data_clu_alloced) return false; if (qio_covers_full_clu(qcow2, qio)) return true; - return false; + if (!qcow2->ext_l2 || map->compressed) + return false; + + mask = qio_full_subclus_mask(qcow2, qio); + if ((u32)map->ext_l2 & mask) + return true; + + return maybe_mapped_in_lower_delta(qcow2, qio) && + (mask & ~(u32)(map->ext_l2 >> 32)); } /* @@ -3371,6 +3396,9 @@ static bool qio_discard_updates_metadata(struct qcow2 *qcow2, struct qio *qio, * * Discard covering the whole cluster replaces the entry and unuses * the discarded (or COW source) cluster. + * Subclusters fully covered by the discard are marked unallocated in + * ext_l2 bitmap: the cluster itself remains allocated, so refcounts + * are not touched (hence empty unuse range). * If the backing is present, set 'reads as zeroes' to avoid exposing * stale data. */ @@ -3381,6 +3409,7 @@ static int prepare_cluster_discard(struct qcow2 *qcow2, struct qio **qio, u32 index_in_page = map->l2.index_in_page; struct md_page *md = map->l2.md; loff_t unuse_pos, unuse_end; + bool whole_clu; struct qio_ext *ext; u64 new_ext_l2 = 0; int ret; @@ -3397,17 +3426,33 @@ static int prepare_cluster_discard(struct qcow2 *qcow2, struct qio **qio, } spin_unlock_irq(&qcow2->md_pages_lock); - if (map->clu_is_cow) { - /* Cluster is shared or compressed. Decrement refcount. */ - unuse_pos = map->cow_clu_pos; - unuse_end = map->cow_clu_end; + whole_clu = qio_covers_full_clu(qcow2, *qio); + if (whole_clu) { + if (zeroes && qcow2->ext_l2) + new_ext_l2 = (u64)U32_MAX << 32; + } else { + u64 mask = qio_full_subclus_mask(qcow2, *qio); + + new_ext_l2 = map->ext_l2 & ~(mask << 32 | mask); + if (zeroes) + new_ext_l2 |= mask << 32; + } + + if (whole_clu) { + if (map->clu_is_cow) { + /* Cluster is shared or compressed. Decrement refcount. */ + unuse_pos = map->cow_clu_pos; + unuse_end = map->cow_clu_end; + } else { + /* Nobody else refers the cluster: unuse it */ + unuse_pos = map->data_clu_pos; + unuse_end = map->data_clu_pos + qcow2->clu_size; + } } else { - /* Nobody else refers the cluster: unuse it after discard */ - unuse_pos = map->data_clu_pos; - unuse_end = map->data_clu_pos + qcow2->clu_size; + /* Subclusters become unallocated, cluster remains */ + unuse_pos = 0; + unuse_end = 0; } - if (zeroes && qcow2->ext_l2) - new_ext_l2 = (u64)U32_MAX << 32; ret = prepare_l_entry_replace(qcow2, map, *qio, md, index_in_page, unuse_pos, unuse_end, L2_LEVEL); @@ -3418,7 +3463,9 @@ static int prepare_cluster_discard(struct qcow2 *qcow2, struct qio **qio, ext->lx_md = md; ext->new_ext_l2 = new_ext_l2; - if (zeroes && !qcow2->ext_l2) + if (!whole_clu) + ext->only_set_ext_l2 = true; + else if (zeroes && !qcow2->ext_l2) ext->set_all_zeroes = true; (*qio)->flags |= QIO_IS_DISCARD_FL; -- 2.43.5 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel