From nobody Thu Jun 25 06:56:52 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1782218941; cv=none; d=zohomail.com; s=zohoarc; b=bLldZn9fOWlv/8c2sAKL9ykL6XoT4Qn8u+JIDY67KPjI+yCxaFG0Q7ZVAm68YPrd2kbTKMHtyBwYpISBou2iuF8Gu19RUL6zGEDuANzDZptT9hLxBKXKhpCXqCB3DSvi37tBCc/KVmgiJymEZG/GVVxYjpD7g/AbW4GO/LFX22w= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1782218941; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=NxxzS1Ry/8cdZldgWf/p8MR2BUoUQOLrlYZHskkcFmA=; b=IQYi02VsfMWbe11aB9Nwycq0k7HWoYwTLqi/1BnyPF0rwGZzi5CraUX+lclEQ091vP+xW+y1FjScMC3ixdYewrlGcR6MOF/10QE3/3129IQas2mLirJf1yKSKTeNa4CE57exfdobjsXNLtk4hD0Wins7pVxAzRcGs9Lo1gu6Dvs= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 178221894165932.89843739756088; Tue, 23 Jun 2026 05:49:01 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wc0YL-0004UY-GF; Tue, 23 Jun 2026 08:48:33 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YH-0004Tz-N9 for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:29 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YA-0006yj-8A for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:23 -0400 Received: from mail-qt1-f197.google.com (mail-qt1-f197.google.com [209.85.160.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-375-bL95UU_eMSCBRPrlFu4i_g-1; Tue, 23 Jun 2026 08:48:18 -0400 Received: by mail-qt1-f197.google.com with SMTP id d75a77b69052e-517d766e05aso21529301cf.0 for ; Tue, 23 Jun 2026 05:48:18 -0700 (PDT) Received: from x1.com ([174.91.117.157]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51a51106a09sm22288351cf.0.2026.06.23.05.48.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jun 2026 05:48:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782218899; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=NxxzS1Ry/8cdZldgWf/p8MR2BUoUQOLrlYZHskkcFmA=; b=BkynJU7piM/o+kYIj4rnlIge0MKevSq9PPuu+BhHuhR/g8ShrCnvabMylr3400m97G5CiF uvu3ZINYyR8s0JBNfYVS+7BeaqvnyIsrNIM1CW6MIxZKqF5GJ75e21qe0pB1q3iYcOv6XR 4yC34EaFDrB9OECLGlXgiF2D1TW3MGk= X-MC-Unique: bL95UU_eMSCBRPrlFu4i_g-1 X-Mimecast-MFC-AGG-ID: bL95UU_eMSCBRPrlFu4i_g_1782218898 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1782218898; x=1782823698; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=NxxzS1Ry/8cdZldgWf/p8MR2BUoUQOLrlYZHskkcFmA=; b=fVJRLLPuaIfhbcufL9QTGT9oLErcZu6fAxz02CkEpFjCBfQytKcxu98qQP386vkC5V qeu9hL6SN8+NTayTWVaeGq327XG5EmI3sQjIhOGLV2aISJ9St2tteil3CQUK9DqKtMdL sDFuRHBayuVT/6qkEOWVf6AXs3b9KTLS9dkIxblRSdHLca4J9Ov/lLSynXhWFLv/BnJP ycpQx1xnHTFNBbb2a4J6gF2z0axxo5pyE9szI/ARLcR6mH/FFUa3wpjWBn7Z2ARUKGOd O9/Zy3I6Tps2RE0DdYhjriaIX04Y349An0reFoAjWa2O37R2R4w+10Ns/IKtIk5307js AWZQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782218898; x=1782823698; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=NxxzS1Ry/8cdZldgWf/p8MR2BUoUQOLrlYZHskkcFmA=; b=qbzkLv2yGmSslmTtUts8U9iQcBCaii4QAUZ1uyFK2I/7c/9lFl16Fs+/GOZGBd4i27 CBCkoTizc254fvaMQkfSxqY+OsoH2pSeOSFqyAEWtnXrdkIhN28LJjSiOFX3SKKel73F eRLVFh6vmGVI5Dx7FpfOJY5iNzu41kCvr0sJd7khdibtFonkIafG9men13qqt84maroR yd4uNP6i9OLLYVjhAydtBVGmmxSgOVFSSxOEPdeEU45T9GnXRYJWWjbOO/lAWeJar2dt ECLz30f152SEN68/zyxpGh608dIrAnzrC/E+UvpcwBPDC9e3nyoe1ezlCXEL/b5GrNWH G8Pw== X-Gm-Message-State: AOJu0Yx2tl/pe3NgmcUSkNa70tKXtqVmTUfFaN6m6xOgKqNsaPBHPBAY K8I3nG/varMPTMwtz/0o6inZzOHg/hoKesw5wKtX7erCtWZ04dA5f3eBtQiZIa3g1TIZfyB9WbC +dPsWxSkSJYPHnNpKwuxVgIGy/vxBGJ1kP166vttWdtnF5xpYnEj+KdI6c8e1tE0qs09jPbedbI UOIW05M1Q7tNVN1y1r6yjie3j4jRgOMvih0mZG9Q== X-Gm-Gg: AfdE7ck1drrnVyrapB5iUkuBwRkEAEUHQOs3WpqqYO/xyU5EkF2vHrBi2fSgvufjgyO ZjaS+QlDq1p8zjTFUPgd9KIX3pdlYeTBRqYWNrnafGbsOCGlvayn/3kWpywNuTf4g/DQTkYc1kQ zKWCr+sAi1SjscR85koEJLVljbpTkf3MEfCbI49FgXvJm7Ivbf6PnP/kMBKPtzoQNquRIVRezik rQnLcWnkc+GBz3x5P15OKyjUbbSODziZui6v/C4NCd7WSwxoKjr6gb2XwM2/hZ2iIKviuoMn1lz 2diOF2/f+LGPqWHwVFCDHc5+1HVfl7gHN5nlEmPY5NHX0urM9fcXfip25uJ/6Z95/ssfMOdI5J1 +2w== X-Received: by 2002:ac8:5985:0:b0:519:b82d:fe6a with SMTP id d75a77b69052e-51a51b6891cmr48599721cf.28.1782218897829; Tue, 23 Jun 2026 05:48:17 -0700 (PDT) X-Received: by 2002:ac8:5985:0:b0:519:b82d:fe6a with SMTP id d75a77b69052e-51a51b6891cmr48598921cf.28.1782218897057; Tue, 23 Jun 2026 05:48:17 -0700 (PDT) From: Peter Xu To: qemu-devel@nongnu.org Cc: Peter Xu , Fabiano Rosas , Paolo Bonzini , "Maciej S. Szmigiero" Subject: [PULL 01/18] thread-pool: Allow at least 1 thread in thread_pool_adjust_max_threads_to_work() Date: Tue, 23 Jun 2026 08:47:42 -0400 Message-ID: <20260623124759.125399-2-peterx@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260623124759.125399-1-peterx@redhat.com> References: <20260623124759.125399-1-peterx@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=peterx@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1782218943588158500 Content-Type: text/plain; charset="utf-8" From: "Maciej S. Szmigiero" thread_pool_adjust_max_threads_to_work() is supposed to give each task its own thread by setting the pool max thread count limit accordingly. However, if there aren't any tasks currently in the pool the pool max thread count will be set to 0, which will trigger an assertion failure in thread_pool_set_max_threads() - because setting this value would completely block the pool by not allowing it to process any submitted tasks. This also can happen if a task is submitted via thread_pool_submit_immediate() to an empty pool but the task completes so quickly that by the time this function calls thread_pool_adjust_max_threads_to_work() the pool again has no unfinished tasks in it. Quoting from Maciej on reproducing this issue: It's difficult to reproduce in most setups. My main VFIO live migration setup never hit it for more than a year, other similar setup hit it recently 3 times. On the other hand, putting sleep(5) in the middle of thread_pool_submit_immediate() makes it reproduce nearly always for me. Fix this by making sure that the pool is allowed to create at least 1 thread. Fixes: b5aa74968b27 ("thread-pool: Implement generic (non-AIO) pool support= ") Signed-off-by: Maciej S. Szmigiero Reviewed-by: Fabiano Rosas Link: https://lore.kernel.org/r/b76c763f576b0fb8a35960a8e3c3da59701d2a74.17= 79390317.git.maciej.szmigiero@oracle.com [peterx: added quote into commit message on reproduce details of the issue] Signed-off-by: Peter Xu --- util/thread-pool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/thread-pool.c b/util/thread-pool.c index 8f8cb38d5c..4e75191c98 100644 --- a/util/thread-pool.c +++ b/util/thread-pool.c @@ -493,5 +493,5 @@ bool thread_pool_adjust_max_threads_to_work(ThreadPool = *pool) { QEMU_LOCK_GUARD(&pool->cur_work_lock); =20 - return thread_pool_set_max_threads(pool, pool->cur_work); + return thread_pool_set_max_threads(pool, MAX(pool->cur_work, 1)); } --=20 2.54.0 From nobody Thu Jun 25 06:56:52 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1782218942; cv=none; d=zohomail.com; s=zohoarc; b=CQFbZ3NxKYF+nI4gZnqBnl/4q2Im/HucaatQeyYXLAf3M3oBrZktazsI+0mc0ry+fse7qvGw/l3X5DdWyQlSpVoT6ytPEP5fAsHRmDzN6W8Wq3AGfbILl1RF9tA5F2fpMG/cAAUVsnCuPlAlxElkz3Z5FVsGELqjKGG1NJt8Qug= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1782218942; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=gOsG14fEqTlYQ297R49E+Gd2yYFc8Kw5gv+a8J9fr4M=; b=I4ZVlxnK2co7VPgAk1m2fHJAngH5cIrcsC6s1XPjVRIit0MoxTE9lBntVs+fHpnEtYhV2Z2PYElIiVsgx/pdIJXnsrcqQN9d0dEqabb5dHn/d6VHvFXcIFP8bsVDAx38lYsZN7i4K+ARmPbXm/6eQGp+gEfizAe/5FnQOc77DdM= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1782218942465910.6180475306884; Tue, 23 Jun 2026 05:49:02 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wc0YO-0004VI-SW; Tue, 23 Jun 2026 08:48:36 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YK-0004UZ-OI for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:33 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YE-0006z2-9s for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:30 -0400 Received: from mail-qt1-f199.google.com (mail-qt1-f199.google.com [209.85.160.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-118-hOFi3nwJNhqJvGVQxdtQKg-1; Tue, 23 Jun 2026 08:48:21 -0400 Received: by mail-qt1-f199.google.com with SMTP id d75a77b69052e-517c65c019bso140800401cf.0 for ; Tue, 23 Jun 2026 05:48:21 -0700 (PDT) Received: from x1.com ([174.91.117.157]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51a51106a09sm22288351cf.0.2026.06.23.05.48.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jun 2026 05:48:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782218903; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=gOsG14fEqTlYQ297R49E+Gd2yYFc8Kw5gv+a8J9fr4M=; b=f5axdb/roxNxke44FG3J34KrldKkFs+tyeFbwW1OJW6C7vIMkjdG7w64iY0J5BR2ksNTuU nDdiwJFFNXJlmJBwVls7fFXpC4FyEomr7+BKyun/pyHqO2r6XJ3tDQ22mIiPjgrAeTM+Lf 2xvEUY+ILivvSzEgOeNxLDUZ36z5+9s= X-MC-Unique: hOFi3nwJNhqJvGVQxdtQKg-1 X-Mimecast-MFC-AGG-ID: hOFi3nwJNhqJvGVQxdtQKg_1782218901 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1782218901; x=1782823701; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=gOsG14fEqTlYQ297R49E+Gd2yYFc8Kw5gv+a8J9fr4M=; b=oxk3JmkoM++pi7Ne1b+g6dgeHpQaPh8J5y6wfupd7xulGv6s/FHW7MI6o44Ba8M3Oz r2qrjaFgmkPeGUUyJBzXRhVOu6ovUR157ePrk33V6iM81jArbuGE6LVy3qEetgPdytGM 5K13aOUzPECFF+YN25gv9FHC+23NAq4L2+H7lGd9Leoqye8P73A/wtclrR4gsplcWuhv 61LuBDEiE/tw9iC1PKlL+qfKESIagpzRPNoNZiaQhdOa77XEq2aWCzNvTV8IvZIO/t2d PrVtOPqFSuOukHRQuwtOGsswsXMkddbYztCU4k0FzNvJ0PIxq5999eVwk6ZKfsfFoMTQ Q2WA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782218901; x=1782823701; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=gOsG14fEqTlYQ297R49E+Gd2yYFc8Kw5gv+a8J9fr4M=; b=DhZ1J14+2XfAStztMA4OXtMILnKNYesc/SVcvWqL27i2Ew2rqcfkqxrzv6U2xbQZuV eSQ/BNV8D/OYY59DkQplG2ZnCeJh32O6l02aT4HBWhvN6PAMH1R+Jj4ZieaH08BB5TdX TP3c05i+fdSUZ4AvwLcdVgmyqsGH38CCadxwYt0W5m5GItllgHrixFp5rIa70ZTPsOcj JcgM+qk22VexbHlhjjJLRNe3/GCLhTA/GY3KY1KaYrh0DV37Hhv1K3VvNI82pgpMpska 45pOCRBE8BUujtLrj9BP+AUtWbAACEcDLOdSY21Jn0harhKf+dibDEeG+sxAu0vp+9Ad 4icA== X-Gm-Message-State: AOJu0YwdpvhxCLev6dRDz1Mr/FUeAQomukj0ywqFGZFHesxG0PkZ3ZD4 07EPBu56ufSa2OjplaQchbiE7yKPlzdHcJ9Iy2ff2i707JI5v1d8fzwDWszOP3i0Hh+rvxm0nov sgTN9kktA3HyZJdlNnZvGUrM20jMkelkzWMjzc9HEdnGd2pGrvK7OvGsDmo4j3uxQC1e8VhPcFC 7V+5YIPiPTgcXwQeSgfEDViyKaVL2Gglg2jMjtaw== X-Gm-Gg: AfdE7ckqvP6y+XQ/k83qNzG2AgCw+9IGnOiTwArKwMZ8WObc4qddh5J3pQtENJaU7OK KML4D2xt6WQW6w9q1RPB1OwK+EhflSgFfu7O5VoKGpeK4qnRcQyItT2qM7gC1fdVquj9V6Um6uJ 7ULOkegLmHkOISz/YPwuQglLpBcgNYbFhxZzw2C5FqwEr0wyP/3rVhrcwexDwHb+1QkL0XfQScO o6Q+yAQV661hWhEdrOC4BMcMeai8/EXF1oGZvV+momgGrfgxj83FOrq8iorayAcR9yn7EVOFEUq NKG93pTLBbaxgNqVHX0FL2Z3EIaDgvNXIzEUQMstqbGv+2exK90rWMXE70P8MzeubD51g4CW7O9 Txw== X-Received: by 2002:a05:622a:1a81:b0:516:e10f:7140 with SMTP id d75a77b69052e-51a55d479c7mr30830321cf.35.1782218900840; Tue, 23 Jun 2026 05:48:20 -0700 (PDT) X-Received: by 2002:a05:622a:1a81:b0:516:e10f:7140 with SMTP id d75a77b69052e-51a55d479c7mr30829791cf.35.1782218900251; Tue, 23 Jun 2026 05:48:20 -0700 (PDT) From: Peter Xu To: qemu-devel@nongnu.org Cc: Peter Xu , Fabiano Rosas , Paolo Bonzini , Markus Armbruster Subject: [PULL 02/18] qapi/migration: Remove @cpr-exec-command doc in MigrationParameter Date: Tue, 23 Jun 2026 08:47:43 -0400 Message-ID: <20260623124759.125399-3-peterx@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260623124759.125399-1-peterx@redhat.com> References: <20260623124759.125399-1-peterx@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=peterx@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1782218943574158500 Content-Type: text/plain; charset="utf-8" This parameter was developed during similar window when the deduplication work was done in commit 2220c2b9ef ("qapi/migration: Don't document MigrationParameter"), hence it was overlooked. Remove the leftover parameter. After all, MigrationParameter is already in the exception list of the doc sanity checker. Reviewed-by: Fabiano Rosas Reviewed-by: Markus Armbruster Link: https://lore.kernel.org/r/20260528201236.359452-1-peterx@redhat.com Signed-off-by: Peter Xu --- qapi/migration.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/qapi/migration.json b/qapi/migration.json index 27a7970556..e8756308cf 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -804,10 +804,6 @@ # Migration parameters enumeration. The enumeration values mirror the # members of @MigrationParameters. # -# @cpr-exec-command: Command to start the new QEMU process when @mode -# is @cpr-exec. The first list element is the program's filename, -# the remainder its arguments. (Since 10.2) -# # Features: # # @unstable: Members @x-checkpoint-delay, @x-rdma-chunk-size, and --=20 2.54.0 From nobody Thu Jun 25 06:56:52 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1782219021; cv=none; d=zohomail.com; s=zohoarc; b=e0UMI6quFwfISVeidsu8uF593eVZKAx6hWoErhvyUQpJBgN64lgJuz1jBAjsHUukN3//dquVCtKxV/qO/Q3GCp0n4IRrn/FveTzi5PyhsXsH/H5HNdeJKwhNrlIDpQGAmAkuopzDn4YPx55cOPFvrxmqxv8BlBMM8LdtCnhu/YQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1782219021; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=yUAaem2nilSMECZVVibrZOmODUF58+NtOhllRUin4yQ=; b=HyyCw9ulIJq2wBvz4JnY57oPszrPcfPEEsaGevj4w+4abwjEdthM705n4gYKlw9nEpbul5qprL2M4ftqR7/+F12UZ3cc7M34T1+HjHRvgEhJJcQN0pKWpp67n19UZlrHRv+/43e6974jtTZRcdvmc81FyfdkC/BGkdbmQV1e0U4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1782219021032986.5345235547015; Tue, 23 Jun 2026 05:50:21 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wc0YQ-0004VR-A2; Tue, 23 Jun 2026 08:48:38 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YM-0004Up-6v for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:35 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YH-0006z7-GG for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:32 -0400 Received: from mail-qt1-f198.google.com (mail-qt1-f198.google.com [209.85.160.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-631-ra1xBVbAOaSV8_ay7PpGmg-1; Tue, 23 Jun 2026 08:48:24 -0400 Received: by mail-qt1-f198.google.com with SMTP id d75a77b69052e-519ed1acb05so58743371cf.3 for ; Tue, 23 Jun 2026 05:48:23 -0700 (PDT) Received: from x1.com ([174.91.117.157]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51a51106a09sm22288351cf.0.2026.06.23.05.48.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jun 2026 05:48:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782218905; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=yUAaem2nilSMECZVVibrZOmODUF58+NtOhllRUin4yQ=; b=JcaAUgHnicXshJnctYpWP5FOY3rFrOfDG8jIcNKEEtZItn34Jfvxwz1/e2S7BLFSNtRv9B aR/S5IvxtpHmtFjWWnZDCDevX6OXm4KN6XXz0e3chPHuh6rGAx5CLzugUvzkEhTogEBCo4 3MxheVxuy8nbNWhhrRGMA1r8XX+L0IE= X-MC-Unique: ra1xBVbAOaSV8_ay7PpGmg-1 X-Mimecast-MFC-AGG-ID: ra1xBVbAOaSV8_ay7PpGmg_1782218903 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1782218903; x=1782823703; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=yUAaem2nilSMECZVVibrZOmODUF58+NtOhllRUin4yQ=; b=Hd60JMhcZD0+vsYfRw4DLvm8Z1Da1D0/UhQjDjhwinO0nBPpkkuY20v0hx2zZbzoFb 93dQ3xG8+B61lywFLw9bM7yHJe69ZZfm3WFS1voEv7AGDrg4wHbARBlzqYb7I7x+eDtM TBbePy6kfxB0yKte+wfzTSPPAgD4qu1cTv4K0KaY/PArycWHg4O3KvNVdnxuDBU0CBM4 uv3iUVBp01ASTF0yVR7u/NB6xPYVxOl/PK/U1HAdAaWHWsach9GC8RL7QPfJ9Id7z8A6 Uvycd+C0N7TzVSpwLldRiWy2EvU8S/HtkuY7VyF7bemQbxUfVTfMJ/om781R2CcIa5PZ uStQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782218903; x=1782823703; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=yUAaem2nilSMECZVVibrZOmODUF58+NtOhllRUin4yQ=; b=sHN+xlaVnfZ4JkYuA0uwNZyoZALGEgIGKBqq5Vwg4/JjROvH2uQAt3vNsnrvBpil+j lZ7yQqUWqyUZCf5MBgXOOC9EsVfKcsOCtepPP+KQgAxMUrYSv8/M1bcApktw5PDqdM5z SVTaA5r9l+VLUa1xDRVE82NT2gTshX+w18gI0V947F48LvJKGJQkUZ3TzJpLLJ4jr98z uHUdWmKzIKWYsfAdjYEcet803RYQ1uHjCwNSeQ8qCiq/mXtjB0rVAc36ZzGwDWhcBXem hA0IdDa6Kr20ujWPmGvUSa+t+AKd86RUog3Ihep4BUs1/8bMZqTEix+9hsaeKVRrPx1E iRVQ== X-Gm-Message-State: AOJu0Yzyvr3x9UP2K8ZR/iBhlrO/bSEv8G3zJ4abfhQTNfAMiAIxb/JJ 8OY8WtuuyL68zh4LqdCYkwVw3LVeSJsr15YRV00kxLjTrGYlloTukqBdxXTMOf3l9yd3A0ZERif kFzF7MFJjdrZrxT2s6dLkAKyuH4UZTOoC+0rpS1r95VD5U1ygfvHSjnbxCREs41NM6IL3bPbTOA eQFmY9K2f1x0FADktt8zXrMccosOqBUqFUPkLD9Q== X-Gm-Gg: AfdE7cnB969MFkWh2tolnuKo5yfMksZ79iuOQuEzjdA2qYjy4kHi24ln3rZFOjYbPEe sR5MIPZbQFUfgbVMc3ePLEfYuoJA29KbG3qlXzOG5ft6SF6ZDavWjAD1GdGE3gYhwq6vSBzzL+k o5zVCZulwl9bwcCeXWBLdqWYYHBlHcHYBsVimzeqGlhWc35p+nDTjVXue1VDK9s5WpiDVwG+Zdy 8/iwzTm+bXrOdqOV54QM5Aaq7Ttv0TVfE4CUnnV6/mSv8efrVgp9z9tx8pk21CU1W0nfx55eP7w 28TUkXQZoutV8/91nUshTMVh7pjf7N6h+xQn4nwijtxM0oPBCdRWlLYMwHbzHEUSVyQb1O5yonr aIg== X-Received: by 2002:a05:622a:1456:b0:517:8e3c:efc6 with SMTP id d75a77b69052e-51a55a150b1mr33683581cf.24.1782218903122; Tue, 23 Jun 2026 05:48:23 -0700 (PDT) X-Received: by 2002:a05:622a:1456:b0:517:8e3c:efc6 with SMTP id d75a77b69052e-51a55a150b1mr33682661cf.24.1782218902273; Tue, 23 Jun 2026 05:48:22 -0700 (PDT) From: Peter Xu To: qemu-devel@nongnu.org Cc: Peter Xu , Fabiano Rosas , Paolo Bonzini , Akihiko Odaki , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Subject: [PULL 03/18] system/physmem: Synchronize ram_list accesses Date: Tue, 23 Jun 2026 08:47:44 -0400 Message-ID: <20260623124759.125399-4-peterx@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260623124759.125399-1-peterx@redhat.com> References: <20260623124759.125399-1-peterx@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=peterx@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1782219022106158500 From: Akihiko Odaki Alex Benn=C3=A9e reported a ThreadSanitizer warning about a plain concurrent access to ram_list [1]. Ensure the concurrent accesses to ram_list are properly synchronized with atomic accesses, mutexes, or RCU. First, the plain assignments of ram_list.mru_block are replaced with qatomic_set(). A comment in qemu_get_ram_block() explains why the ordering requirement is relaxed, but it still needs to be atomically accessed. include/qemu/atomic.h says: > The C11 memory model says that variables that are accessed from > different threads should at least be done with __ATOMIC_RELAXED > primitives or the result is undefined. Generally this has little to > no effect on the generated code but not using the atomic primitives > will get flagged by sanitizers as a violation. Second, ram_list.version accesses are replaced with atomic operations or protected with a mutex. Unlike ram_list.mru_block, ram_list.version has tighter ordering requirements for one of its goals: ensuring that the reader-held rs->last_seen_block value is invalidated whenever a RAM block is reclaimed between two RCU reader critical sections. Below are steps a reader and an updater follow: Reader: R-1. Enter the first RCU read-side critical section: R-1-1. rs->last_version =3D qatomic_load_acquire(&ram_list.version) R-1-2. rs->last_seen_block =3D an element of ram_list.blocks R-2. Enter the second RCU read-side critical section: R-2-1. if (qatomic_read(&ram_list.version) !=3D rs->last_version) R-2-2. rs->last_seen_block =3D NULL Updater: W-1. Enter a ram_list.mutex critical section W-1-1. Update ram_list.blocks W-1-2. qatomic_store_release(&ram_list.version, ram_list.version + 1) W-2. Enter another ram_list.mutex critical section W-2-1. QLIST_REMOVE_RCU(block, next) W-2-2. qatomic_store_release(&ram_list.version, ram_list.version + 1) W-2-3. call_rcu(block, reclaim_ramblock, rcu) W-1-2 represents the write observed by R-1-1. ram_list.version is read non-atomically on the update side because the update side is serialized with ram_list.mutex. The other ram_list accesses in these steps are reasoned about in two cases. When the grace period of W-2-3 contains R-2: qatomic_load_acquire() at R-1-1 and qatomic_store_release() at W-1-2 enforce the following ordering: W-1-1 -> W-1-2 -> R-1-1 -> R-1-2 The value of ram_list.blocks stored by W-1-1 or a newer value that was loaded by R-1-2 is still valid because of the grace period. When the grace period of W-2-3 ends before R-2: call_rcu() at W-2-3 and the read-side critical section at R-2 ensure the following ordering: W-2-2 -> W-2-3 -> the grace period -> R-2 -> R-2-1 The value of ram_list.version stored by W-2-2 or a newer value that was loaded by R-2-1 differs from rs->last_version and the reader invalidates rs->last_seen_block. Together, these steps ensure that rs->last_seen_block is invalidated whenever necessary. With added atomic operations, pre-existing memory barriers are no longer necessary and are removed. Any other ram_list accesses are already properly synchronized. [1] https://lore.kernel.org/qemu-devel/878q9fbmap.fsf@draig.linaro.org/ Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daud=C3=A9 Link: https://lore.kernel.org/r/20260523-tsan-v1-1-07d5eb9dcaa2@rsg.ci.i.u-= tokyo.ac.jp Signed-off-by: Peter Xu --- migration/ram.c | 10 +++++----- system/physmem.c | 16 +++++++--------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index fc38ffbf8a..6da24d7258 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -2495,7 +2495,10 @@ static void ram_state_reset(RAMState *rs) =20 rs->last_seen_block =3D NULL; rs->last_page =3D 0; - rs->last_version =3D ram_list.version; + + /* Read version before ram_list.blocks */ + rs->last_version =3D qatomic_load_acquire(&ram_list.version); + rs->xbzrle_started =3D false; =20 ram_page_hint_reset(&rs->page_hint); @@ -3270,13 +3273,10 @@ static int ram_save_iterate(QEMUFile *f, void *opaq= ue) */ WITH_QEMU_LOCK_GUARD(&rs->bitmap_mutex) { WITH_RCU_READ_LOCK_GUARD() { - if (ram_list.version !=3D rs->last_version) { + if (qatomic_read(&ram_list.version) !=3D rs->last_version) { ram_state_reset(rs); } =20 - /* Read version before ram_list.blocks */ - smp_rmb(); - ret =3D rdma_registration_start(f, RAM_CONTROL_ROUND); if (ret < 0) { qemu_file_set_error(f, ret); diff --git a/system/physmem.c b/system/physmem.c index 9e5b50c5b1..db8ad84ab6 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -839,12 +839,12 @@ found: /* It is safe to write mru_block outside the BQL. This * is what happens: * - * mru_block =3D xxx + * qatomic_set(&mru_block, xxx) * rcu_read_unlock() * xxx removed from list * rcu_read_lock() * read mru_block - * mru_block =3D NULL; + * qatomic_set(&mru_block, NULL= ); * call_rcu(reclaim_ramblock, x= xx); * rcu_read_unlock() * @@ -852,7 +852,7 @@ found: * when it was placed into the list. Here we're just making an extra * copy of the pointer. */ - ram_list.mru_block =3D block; + qatomic_set(&ram_list.mru_block, block); return block; } =20 @@ -2260,11 +2260,10 @@ static void ram_block_add(RAMBlock *new_block, Erro= r **errp) } else { /* list is empty */ QLIST_INSERT_HEAD_RCU(&ram_list.blocks, new_block, next); } - ram_list.mru_block =3D NULL; + qatomic_set(&ram_list.mru_block, NULL); =20 /* Write list before version */ - smp_wmb(); - ram_list.version++; + qatomic_store_release(&ram_list.version, ram_list.version + 1); qemu_mutex_unlock_ramlist(); =20 physical_memory_set_dirty_range(new_block->offset, @@ -2608,10 +2607,9 @@ void qemu_ram_free(RAMBlock *block) name =3D cpr_name(block->mr); cpr_delete_fd(name, 0); QLIST_REMOVE_RCU(block, next); - ram_list.mru_block =3D NULL; + qatomic_set(&ram_list.mru_block, NULL); /* Write list before version */ - smp_wmb(); - ram_list.version++; + qatomic_store_release(&ram_list.version, ram_list.version + 1); call_rcu(block, reclaim_ramblock, rcu); qemu_mutex_unlock_ramlist(); } --=20 2.54.0 From nobody Thu Jun 25 06:56:52 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1782218957; cv=none; d=zohomail.com; s=zohoarc; b=MdRsdQq0UuTxwnflNV2Iwyf3dipMeSOCO0wTaPbICWV2thooEQv9AvKJdPsOmLGvTMIACzuiDeiQfM5ves7vlAA31sD50dkT4z1hHMivKE3WnFkFvaESaxRfyYw7GKDp5tzx3JWRUKvgsjnvTyxMm3WpAUQWQpuIFqFjNHsCXgc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1782218957; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=H2BVHPyZHE2bjo0Z0lXNm9ZRKJa09Goy2Jb1Na43N7s=; b=SvDeo1Jn1YkCi/mzXE7DBw4NcPTgemM09elqs7bRRD7LhF1zFxk+0wuV2cNUpDUXwd+caEYUWby7EqpZSoBN7NNwE3mAzz0DFYzsQd83YWDnGGRzEzVUyPUw1d26wjRGK2CRLRUzKxvuxBe3aTqUwctqqdYuVGXjOK9hBIqZum8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1782218957936299.1478245659988; Tue, 23 Jun 2026 05:49:17 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wc0YO-0004VH-Rh; Tue, 23 Jun 2026 08:48:36 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YL-0004Ua-1Z for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:33 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YH-0006zF-G8 for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:31 -0400 Received: from mail-qt1-f200.google.com (mail-qt1-f200.google.com [209.85.160.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-500-ir7RCOLGO1GQ_BVtpSOTEg-1; Tue, 23 Jun 2026 08:48:24 -0400 Received: by mail-qt1-f200.google.com with SMTP id d75a77b69052e-517c65c019bso140801591cf.0 for ; Tue, 23 Jun 2026 05:48:24 -0700 (PDT) Received: from x1.com ([174.91.117.157]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51a51106a09sm22288351cf.0.2026.06.23.05.48.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jun 2026 05:48:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782218906; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=H2BVHPyZHE2bjo0Z0lXNm9ZRKJa09Goy2Jb1Na43N7s=; b=ExBiTYyrRcSV5OXVnog55iclWfDbXnyeK7Bx+LTdzngFYbk8RAhvBPbWoqnG9ZXtwrN6q3 DnC4egcUKsQ2zMkl2uVMWDhtmkGICpuUdvb6sfpNY7bbQw2IDxjjblAJzGJtsJ2yqezFSY Z82cOM5EOpZp5IyEEx/l8J7XDPg0kjI= X-MC-Unique: ir7RCOLGO1GQ_BVtpSOTEg-1 X-Mimecast-MFC-AGG-ID: ir7RCOLGO1GQ_BVtpSOTEg_1782218904 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1782218904; x=1782823704; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=H2BVHPyZHE2bjo0Z0lXNm9ZRKJa09Goy2Jb1Na43N7s=; b=hsX/nrBhgrVwyOGinMaN2qo10nxzPTLZLiDRqGvy85B+7vfKnV9hESQNtcWSfjM+zU 62sZL0q/HcoPH5wAIh6BvJ7QOyZv9WVCRPS9lZZxijZ7gW7x2ELGjpQ47I0ry2zhioWI 3jLmC6AVcbFNp9VZunsIdqNKgHqRM7b8t56zyHL43n32Poj3ia/5WHCCe11P5yAkpPpQ RuSCUR60wr31UHfwVV+Atp4hvexzK82ebrTnK8lnZygc+a4Zn9JAc7mJz3lUaUqnnvrj bTEu3oVOte7a2Cel74DHN5opOpD6EbzutYX5TPc0hOJ2WFR1njwPgKk6sLqhfRLpcrIo ku3A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782218904; x=1782823704; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=H2BVHPyZHE2bjo0Z0lXNm9ZRKJa09Goy2Jb1Na43N7s=; b=o7cyPAJeMjZXHhxWs5onX9aniwz1/ybAO8apqlqcnfszBqQa9fnQ6DB5iSZedYi3Ms NuqroL9Qyql8aBzBE4FW912vNVEqLyxvl1lKDnV/48WVmWe1v8Vs1dep7ufZ4Y/RMfXv dud16+2gyvO/EeTQhLBz7oH6Q1U+fbdcGXNYbTf976rXGL/biRsRvO5u6xeNOy+dhn/E i9A6nl4bUPe03+++d6nLns0AtRAfxfy66IOWwB06D4/FJV8DGJ6ZCPdZhyFVB1Jmc8Zm N1cVE5ACzIHqpZZceeREsvPpqgs7U6kx/28YeZ1Qc8TjXulPtnxmlrrj/FqLfry4i0Hy GXqA== X-Gm-Message-State: AOJu0Yz3V8bghQNhYIAGvwffqET9VKder9HDIk2b6v2tIrIZUaZ/JD01 Gtf7d6k8TfeI1MZiFBwFcLUC593kPnbnFEkJ6UBzQ8GbAwRI2VaFyTzFFfmih4wROogaBeMhI5E l09k+sdX4vJdlzvti2Cd2HSX4RX9+vW/GQUSZKlErHUkO/fR7uemvIG77P8mbDTAOw0AjybPvT4 4bI5llyzY4r9UmGrOFBMfDvVue94yI6fDzndHf8A== X-Gm-Gg: AfdE7cmBvPL2Crywbmfs7AuGSXKjVPqXb75fKR6RZqb45hZDDXCglhGxJOnGliuL3aM 8KhiR0crl+Ou3oM1TpBmZmD6Bu1ltumOJ4bgeDvoHKJrryNdt29FXjU9eRxTcm/YNJ2pPmHpRYh vNs9SfATIVf3P1DaMuF+XzwhNZNoI08wjvDLfIJvhviSiyX0NrqwOkDDFbaNJQ6iZvAl6WXcCBM NRPcfuyLx76o8dYRa4di2k5lOlL1QLXflbD1Z/diwiwSye/9hYZ/imudItSnVRHz3n1vIcc6DA+ yXLMJxjxAsEWRy+PWuyEk/tdQPgfx9N0Zhpbd4hE3kvDTEsobj41qF5t5dWhmOLf73HI+WroR5r CtA== X-Received: by 2002:a05:622a:1a97:b0:519:899a:9b9a with SMTP id d75a77b69052e-51a562828f9mr31596001cf.51.1782218904068; Tue, 23 Jun 2026 05:48:24 -0700 (PDT) X-Received: by 2002:a05:622a:1a97:b0:519:899a:9b9a with SMTP id d75a77b69052e-51a562828f9mr31595311cf.51.1782218903326; Tue, 23 Jun 2026 05:48:23 -0700 (PDT) From: Peter Xu To: qemu-devel@nongnu.org Cc: Peter Xu , Fabiano Rosas , Paolo Bonzini , Gavin Shan Subject: [PULL 04/18] system/memory: Remove MAX_PHYS_ADDR Date: Tue, 23 Jun 2026 08:47:45 -0400 Message-ID: <20260623124759.125399-5-peterx@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260623124759.125399-1-peterx@redhat.com> References: <20260623124759.125399-1-peterx@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=peterx@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1782218959268158500 Content-Type: text/plain; charset="utf-8" From: Gavin Shan Remove MAX_PHYS_ADDR and MAX_PHYS_ADDR_SPACE_BITS as they're not used since the addition by commit 052e87b073cb ("memory: make section size a 128-bit integer"). Signed-off-by: Gavin Shan Link: https://lore.kernel.org/r/20260608002303.851456-1-gshan@redhat.com Signed-off-by: Peter Xu --- include/system/memory.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/system/memory.h b/include/system/memory.h index e143c9c3f3..582de45c34 100644 --- a/include/system/memory.h +++ b/include/system/memory.h @@ -36,9 +36,6 @@ enum device_endian { =20 #define RAM_ADDR_INVALID (~(ram_addr_t)0) =20 -#define MAX_PHYS_ADDR_SPACE_BITS 62 -#define MAX_PHYS_ADDR (((hwaddr)1 << MAX_PHYS_ADDR_SPACE_BITS) = - 1) - #define TYPE_MEMORY_REGION "memory-region" DECLARE_INSTANCE_CHECKER(MemoryRegion, MEMORY_REGION, TYPE_MEMORY_REGION) --=20 2.54.0 From nobody Thu Jun 25 06:56:52 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1782218986; cv=none; d=zohomail.com; s=zohoarc; b=gv9G+nO2UXppIwmt3JUdGknIpVv+i7BCe5iCecUiiGtIV8uwvPibW3BxF7OKeoqh2vGNcJpoJtVSeqUmNHG+7xvW07wuWELRcEEnxS6AQwHjwIskOTKxXhezUltUeY1xQ/ykQzkLlMp6e6qWohmbap4bW3Qc5Lj5cKl+8sPt+XI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1782218986; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=hDX2xpxPgNeOlEtNfh7SmSQxG2EOjd0N5xJ4fQJcAqM=; b=ldVSrkfJsij/G3ofDURtpHjq8qopWnjeHMC3ae1rd1KLb9VGsw+bwaPJgRgLS2aqMrPFw39EHdwEiHCubPdQqCE09dnIZRLFOKZkd12hmKUD+4IGWZ6O8vVMOHxzX9CWO0FOIfkvAXCqQdyl/oSL368gXd5bFJ+Jwgb8D+EVejU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1782218986533153.10861372609338; Tue, 23 Jun 2026 05:49:46 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wc0YS-0004W3-4s; Tue, 23 Jun 2026 08:48:40 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YN-0004V6-KV for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:36 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YH-0006zJ-Ge for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:32 -0400 Received: from mail-qt1-f198.google.com (mail-qt1-f198.google.com [209.85.160.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-675-7xcxJg14MJy4Udd_KdG0VA-1; Tue, 23 Jun 2026 08:48:26 -0400 Received: by mail-qt1-f198.google.com with SMTP id d75a77b69052e-51a0761fdbdso66710761cf.1 for ; Tue, 23 Jun 2026 05:48:26 -0700 (PDT) Received: from x1.com ([174.91.117.157]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51a51106a09sm22288351cf.0.2026.06.23.05.48.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jun 2026 05:48:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782218907; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=hDX2xpxPgNeOlEtNfh7SmSQxG2EOjd0N5xJ4fQJcAqM=; b=E7rgz2+ztkMXV8vl6pRBYbEb/3+kFlE+p9QW9jftmZyHQfxS7noHZc0ghCFZLey2NwrZTL FuMJ6rRja30HnWoOba/EggdRbDoJ+n3BG7iOdhAzach9nuHtS36dsVtxLYTHPXwYgHm9rs wEZepUqn7r+w4unk7m64v4eJ1vgBv44= X-MC-Unique: 7xcxJg14MJy4Udd_KdG0VA-1 X-Mimecast-MFC-AGG-ID: 7xcxJg14MJy4Udd_KdG0VA_1782218906 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1782218906; x=1782823706; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=hDX2xpxPgNeOlEtNfh7SmSQxG2EOjd0N5xJ4fQJcAqM=; b=ZvyZenXejmMpY9079cs5uKbg8dvQTzMDMPpf4F6JHGuSksZyO4x1vuo/uERONrEFS4 hvWegoON4uvQwTYcDDg1MKaVgbUFj0gs4w4xcrVuPHRpseRUURLTp7Na69exQWW4qC8H 8BelEF/ESGsI/k6Ltv1ZdhsmSaNOX/+MAy4a9rLHGqCSe/N7A0J5NgZyklFEBd1zvX2h y+bGUlDnQDK3uxobpq9t0CXROBPZemgcanHmOWrzkslfbq8tbQhlrtksrVg6j80gOFo0 QPyK6kh//uzVT0DnJm17AgJ+N7FjTnpRg4a2guC70DTl4NpkHgllVm2S+nY3OTYI26O2 KsSA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782218906; x=1782823706; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=hDX2xpxPgNeOlEtNfh7SmSQxG2EOjd0N5xJ4fQJcAqM=; b=ft2/niCXH4pu6DeER9FJycBiI8aCABk9HWN1HwEGYvz/VLWAQxwvhjUEnf/nemlmgC JgWcvxziQZG9bXBAEuZogbQeI5RimZJih4+RnpCKgl8ajNSl86CQsPWxo7WzxfPQZEu6 CAjaJMN/xUz391niwsDpUpMb/0oAw951jjedLhKIvcfmSaqJhmxaumjk0XHHtaj4U8QX 0TEdhyIl8IDgR/QRKv13xyHFupT2PU9lsUUuxFmXUIq7qLo0Sn3SoNBkt0JobVOHSFog s19MgeiaXM8isMX8DTEW384eCztYYfJ9S7Z6VUcMRGyyBoYUZs395UDgpjAenu8LeFwE VaMA== X-Gm-Message-State: AOJu0YzvXRZA5lPPKovyQsvigCSP+ws8mV4t+2PH4er6fhufag7Ss3Fy NyYuHvzP2ZcHSysc5VKjLHnn8xpJg7bohwWfemzTNZTZ1Av0y663l9uvCQd9Ya8P7HMlD2bbMfQ QyJEUkw+xAXJK3O41tXaiKkDmc4uegX0mBs+U/G0V3gjhORlhfiXN5SADvNbKVzKGWEPHIUf0sj DSsT8NawJ2MLe0ZTabg/6aAnZQT2joXdx7joAeCA== X-Gm-Gg: AfdE7clHg/Zr0dtpOWKHNENYJ8oPSLpgQPz3mM2qkqOUeQxvSUzDunmmTxv6ulFntNE +nL4dj4b5fdH33p5bxkFFjT4tF77IM9czfFA9CqBo4qBTkKCirMsLmlADyONBkDrgC2mt5bImlC EsLzgff4K25731cIcKh3UiIsgDQ2KBmuy73OqYBWXgdYD89To/B2MhTMdTftEbxHJk5uT6IIvzn LHkxsuAJdH6Uptv+bw6BrQ0woKQIUMn4pkyJ4KN6ZeGcHv0bc4hPDrJ2PGHVqF1Jl7TqQ3/PlKc ghFTJvwJR+wTWCn2pND6PMAR430+BDYQJt/VMN7cj62VyaG80iPK8uNS3EemMaPW9qOpAworco+ ROg== X-Received: by 2002:a05:622a:389:b0:516:df62:bdd2 with SMTP id d75a77b69052e-51a06b2b24cmr221712631cf.55.1782218905977; Tue, 23 Jun 2026 05:48:25 -0700 (PDT) X-Received: by 2002:a05:622a:389:b0:516:df62:bdd2 with SMTP id d75a77b69052e-51a06b2b24cmr221711781cf.55.1782218905135; Tue, 23 Jun 2026 05:48:25 -0700 (PDT) From: Peter Xu To: qemu-devel@nongnu.org Cc: Peter Xu , Fabiano Rosas , Paolo Bonzini , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Mark Cave-Ayland Subject: [PULL 05/18] migration: Use OBJECT_DECLARE_SIMPLE_TYPE Date: Tue, 23 Jun 2026 08:47:46 -0400 Message-ID: <20260623124759.125399-6-peterx@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260623124759.125399-1-peterx@redhat.com> References: <20260623124759.125399-1-peterx@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=peterx@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1782218987297158501 Migration object's class has nothing special, switch to the newly introduced macro. Suggested-by: Daniel P. Berrang=C3=A9 Reviewed-by: Mark Cave-Ayland Reviewed-by: Daniel P. Berrang=C3=A9 Reviewed-by: Fabiano Rosas Link: https://lore.kernel.org/r/20260609172514.2037645-2-peterx@redhat.com Signed-off-by: Peter Xu --- migration/migration.h | 9 +-------- migration/migration.c | 7 +++---- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/migration/migration.h b/migration/migration.h index 841f49b215..293ad60e07 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -263,14 +263,7 @@ void fill_destination_postcopy_migration_info(Migratio= nInfo *info); =20 #define TYPE_MIGRATION "migration" =20 -typedef struct MigrationClass MigrationClass; -DECLARE_OBJ_CHECKERS(MigrationState, MigrationClass, - MIGRATION_OBJ, TYPE_MIGRATION) - -struct MigrationClass { - /*< private >*/ - DeviceClass parent_class; -}; +OBJECT_DECLARE_SIMPLE_TYPE(MigrationState, MIGRATION); =20 struct MigrationState { /*< private >*/ diff --git a/migration/migration.c b/migration/migration.c index 074d3f2c69..278cad502a 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -297,7 +297,7 @@ void migration_object_init(void) { /* This can only be called once. */ assert(!current_migration); - current_migration =3D MIGRATION_OBJ(object_new(TYPE_MIGRATION)); + current_migration =3D MIGRATION(object_new(TYPE_MIGRATION)); =20 /* * Init the migrate incoming object as well no matter whether @@ -3975,7 +3975,7 @@ static void migration_class_init(ObjectClass *klass, = const void *data) =20 static void migration_instance_finalize(Object *obj) { - MigrationState *ms =3D MIGRATION_OBJ(obj); + MigrationState *ms =3D MIGRATION(obj); =20 qapi_free_BitmapMigrationNodeAliasList(ms->parameters.block_bitmap_map= ping); qapi_free_strList(ms->parameters.cpr_exec_command); @@ -3993,7 +3993,7 @@ static void migration_instance_finalize(Object *obj) =20 static void migration_instance_init(Object *obj) { - MigrationState *ms =3D MIGRATION_OBJ(obj); + MigrationState *ms =3D MIGRATION(obj); =20 ms->state =3D MIGRATION_STATUS_NONE; ms->mbps =3D -1; @@ -4040,7 +4040,6 @@ static const TypeInfo migration_type =3D { */ .parent =3D TYPE_DEVICE, .class_init =3D migration_class_init, - .class_size =3D sizeof(MigrationClass), .instance_size =3D sizeof(MigrationState), .instance_init =3D migration_instance_init, .instance_finalize =3D migration_instance_finalize, --=20 2.54.0 From nobody Thu Jun 25 06:56:52 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1782218988; cv=none; d=zohomail.com; s=zohoarc; b=hW+3kXsPYqE1jwwusC5zAknb56MLiqGGokOAJcSH5XH1fcKdc3poM4O95zCvOU4PHkiXph7KXehrQ1fBqHYUPK3kKSA+L0keK6nFZKIM2OA/KWUbFsipLta1zYRs2hFSKWIfCOxDZcTnh+Kcw9M8MXtuwU8QG4eUSgUXaeugQxM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1782218988; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=rJtx2znA2d/l9+h2Q+gjbVY5u+1PyMSw9GQjwFQZoeM=; b=TaZhMH5nnOf2yKAv7QW7lrmynHfxVyZjljOqO+GlY7wbOQdqhJ+PLWRHLwvHxU1E3EmYeYqy1s+DYhjc1u4rMZ7U+t+5dqmOr4k3gvJznoBSDvmqLLn1Z2dgWgxiqt5KsWE1fZHm09YXff9IK51GMYIoz7+PHsvAJnztQPY/Bf0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 178221898863478.8045338419937; Tue, 23 Jun 2026 05:49:48 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wc0YS-0004W7-73; Tue, 23 Jun 2026 08:48:40 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YO-0004VG-Cx for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:36 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YI-0006za-Dg for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:33 -0400 Received: from mail-qt1-f198.google.com (mail-qt1-f198.google.com [209.85.160.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-110-uIXF4D1_Omisy02cu5la2w-1; Tue, 23 Jun 2026 08:48:28 -0400 Received: by mail-qt1-f198.google.com with SMTP id d75a77b69052e-517878a92c5so100456011cf.3 for ; Tue, 23 Jun 2026 05:48:28 -0700 (PDT) Received: from x1.com ([174.91.117.157]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51a51106a09sm22288351cf.0.2026.06.23.05.48.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jun 2026 05:48:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782218909; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rJtx2znA2d/l9+h2Q+gjbVY5u+1PyMSw9GQjwFQZoeM=; b=JtllMbJvlFExVkguJ7HoGfUDxI1JUCXv5u1SE1+J1FaVE1ZmbIV/bKXLPdjcweaCHzcAc3 OkTEHKjzv9fRA1BMAvuxMhtF+01oBvTXNHhv5Ix1p1QA3sRqx2vFUbFrmhdTjX5MIC7tcY Lb+eccsDXgG46ArC/VSXDdOa/PDKISk= X-MC-Unique: uIXF4D1_Omisy02cu5la2w-1 X-Mimecast-MFC-AGG-ID: uIXF4D1_Omisy02cu5la2w_1782218908 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1782218908; x=1782823708; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=rJtx2znA2d/l9+h2Q+gjbVY5u+1PyMSw9GQjwFQZoeM=; b=kLS30ncyea6fgYI7zTs0AVr47UwMYnElB8Mpg/LQvd0GbGXy4A2lSHiiQHk9FJsKT9 1sJX+DCaO5HUSrokTicqUbG1GIiTSvO9TwuyPaPyAFZtu1IIsdKgJCAxomr/99WRQMol 2Ly4GumRqDub6hNTYI2pDbzo1OoGLkB3lTuiYcsFTtdkjFCpv7JM1+X9NfVwx1JKDs/W 4E5PvhEsGogMMyY0H7PokFxTgdZ6eerxNhiHRIG+uBLsSaUELt+49/Ctj31AnTmdqgUp WeLeve2esFIU1yWbEkAC5BxAViC0ixcCHLnscGzfA/tZA+/rLXctbqqKhbMt0UdZkSYv vGMA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782218908; x=1782823708; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=rJtx2znA2d/l9+h2Q+gjbVY5u+1PyMSw9GQjwFQZoeM=; b=E+qgst0jGbM0qpODkTXqr3d4qaZbZm0EKeP9xtzGCqRY1hoahqLGLRcA2Zj0PZbG+L iTfzDvhy7wEoykRWUNYJX9P3D4ehFskz3M+C8f8IeOF2jjgaqPmdE6tXRGrjT64ISuOb JybxfX9oxKYYS5dawTOCpMviZ9M95Tb5iCq3UOoe8lXLGQTjTPSgbrCFJsN8UO3dsaD/ F/lIcpX/zmPp3Y6WYtYzAo9EtjUf/A6EYKc3be8nAKpitBgxnB8j2Lbqq9rXywXZkzHD YBQ2ZIsJyQMBUljfIqqTw1koqc055rB2iBHfNT+UdFi/kqYfV+Wj5jPO3grK0YlNcEkS aGdQ== X-Gm-Message-State: AOJu0Yxt1+jKocuPgKZXZsi3v/Nec1EFt5GIoAbeHPcHa/jt0F9skjWc k9xKZ8dig9BkmNkAnPa2tFJTBJdotX1C6lxa68XXEdqP6A9WVAdQmoEmb7Ida3mjUt03onfGh7N c1z7DYTXiFC+03jEZwxWecmZagogyZWfM509xVl16Q7OczsrM9RmRtoz3OIOyLCc0WVY24oJ2/G XWJjBcj+BS9ZrSvfbSRYeOSB+yRApKbxBLRJvMQQ== X-Gm-Gg: AfdE7clD95/xqxt37LRRb1OMGaHdsaFdTzelwHN5D4w7/v5kfktYfKHGXiSmSJnbRPp DM3bKZWzPXmMgrDRFgjUOLmYGR3JVR/gOR3jTCi9KWDnZO0Wdl6wF518jvbHO+kQLYeNExBgLJB jW46vmmLkHJ7wY8x8GMjnf8E0OFS34+DYSN/rRm9KmjaVKtBtTGB48SkHwlnzg+mg2CPVGJPgHM pibxDt+PmP0pqyfVZFVSeJXX0EffOgegkLQq6IDL0KtXJJAK3fJnsnA3bO2TlGj28t2Wt4UJDsx pQrAAxRxUuaYzSsyM07rfkqbpk42Ec35IZJnV6R7Ov8jll70NbPHrlZWJqcDG+4sn2geSim/E2c 1AA== X-Received: by 2002:a05:622a:1c0f:b0:50d:7c18:c66e with SMTP id d75a77b69052e-519e4a4307bmr288597891cf.13.1782218907487; Tue, 23 Jun 2026 05:48:27 -0700 (PDT) X-Received: by 2002:a05:622a:1c0f:b0:50d:7c18:c66e with SMTP id d75a77b69052e-519e4a4307bmr288597271cf.13.1782218906854; Tue, 23 Jun 2026 05:48:26 -0700 (PDT) From: Peter Xu To: qemu-devel@nongnu.org Cc: Peter Xu , Fabiano Rosas , Paolo Bonzini , Bibo Mao , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Subject: [PULL 06/18] tests/qtest/migration: Add migration test on loongarch Date: Tue, 23 Jun 2026 08:47:47 -0400 Message-ID: <20260623124759.125399-7-peterx@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260623124759.125399-1-peterx@redhat.com> References: <20260623124759.125399-1-peterx@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=peterx@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1782218989920158500 From: Bibo Mao Add migration qtest on loongarch64 system, the test passes to run with the following result: qemu:qtest+qtest-loongarch64/qtest-loongarch64/migration-test OK 15.94s 9= subtests passed Signed-off-by: Bibo Mao Acked-by: Fabiano Rosas Reviewed-by: Philippe Mathieu-Daud=C3=A9 Link: https://lore.kernel.org/r/20260611084312.70042-1-maobibo@loongson.cn Signed-off-by: Peter Xu --- MAINTAINERS | 1 + tests/qtest/migration/bootfile.h | 4 ++ .../qtest/migration/loongarch64/a-b-kernel.h | 20 ++++++++ tests/qtest/migration/bootfile.c | 4 ++ tests/qtest/migration/framework.c | 6 +++ tests/qtest/meson.build | 3 +- tests/qtest/migration/Makefile | 4 +- tests/qtest/migration/loongarch64/Makefile | 20 ++++++++ .../qtest/migration/loongarch64/a-b-kernel.S | 46 +++++++++++++++++++ 9 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 tests/qtest/migration/loongarch64/a-b-kernel.h create mode 100644 tests/qtest/migration/loongarch64/Makefile create mode 100644 tests/qtest/migration/loongarch64/a-b-kernel.S diff --git a/MAINTAINERS b/MAINTAINERS index 93df53d87f..d609692d9a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1359,6 +1359,7 @@ F: hw/intc/loongarch_*.c F: hw/intc/loongson_ipi_common.c F: hw/rtc/ls7a_rtc.c F: gdbstub/gdb-xml/loongarch*.xml +F: tests/qtest/migration/loongarch64/ =20 M68K Machines ------------- diff --git a/tests/qtest/migration/bootfile.h b/tests/qtest/migration/bootf= ile.h index 0ce5b34433..a4060ea4f7 100644 --- a/tests/qtest/migration/bootfile.h +++ b/tests/qtest/migration/bootfile.h @@ -42,6 +42,10 @@ */ #define ARM_TEST_MAX_KERNEL_SIZE (512 * 1024) =20 +/* LoongArch64 */ +#define LOONGARCH_TEST_MEM_START (32 * 1024 * 1024) +#define LOONGARCH_TEST_MEM_END (100 * 1024 * 1024) + #ifndef MIGRATION_GUEST_CODE void bootfile_delete(void); char *bootfile_create(const char *arch, const char *dir, bool suspend_me); diff --git a/tests/qtest/migration/loongarch64/a-b-kernel.h b/tests/qtest/m= igration/loongarch64/a-b-kernel.h new file mode 100644 index 0000000000..6d5d811f79 --- /dev/null +++ b/tests/qtest/migration/loongarch64/a-b-kernel.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * This file is automatically generated from the assembly file in + * tests/qtest/migration/loongarch64. Edit that file and then run "make" + * inside tests/qtest/migration to update, and then remember to send both + * the header and the assembler differences in your patch submission. + */ +unsigned char loongarch64_kernel[] =3D { + 0x0c, 0xc0, 0x3f, 0x14, 0x8c, 0x81, 0x87, 0x03, 0x0d, 0x04, 0x81, 0x03, + 0x8d, 0x01, 0x00, 0x29, 0x0c, 0x00, 0x04, 0x14, 0x0d, 0x80, 0x0c, 0x14, + 0x2e, 0x00, 0x00, 0x14, 0x10, 0xc0, 0x3f, 0x14, 0x10, 0x82, 0x87, 0x03, + 0x11, 0x08, 0x81, 0x03, 0x80, 0x01, 0x00, 0x29, 0x8c, 0xb9, 0x10, 0x00, + 0x8d, 0xf9, 0xff, 0x5f, 0x12, 0x00, 0xc0, 0x02, 0x0c, 0x00, 0x04, 0x14, + 0x8f, 0x01, 0x00, 0x2a, 0xef, 0x05, 0x80, 0x02, 0xef, 0x5d, 0x00, 0x00, + 0x8f, 0x01, 0x00, 0x29, 0x8c, 0xb9, 0x10, 0x00, 0x8d, 0xed, 0xff, 0x5f, + 0x52, 0x06, 0xc0, 0x02, 0x52, 0x7e, 0x40, 0x03, 0x5f, 0xde, 0xff, 0x47, + 0x11, 0x02, 0x00, 0x29, 0xff, 0xd7, 0xff, 0x53 +}; + diff --git a/tests/qtest/migration/bootfile.c b/tests/qtest/migration/bootf= ile.c index 479c43231d..e46ad09de7 100644 --- a/tests/qtest/migration/bootfile.c +++ b/tests/qtest/migration/bootfile.c @@ -19,6 +19,7 @@ #include "bootfile.h" #include "i386/a-b-bootblock.h" #include "aarch64/a-b-kernel.h" +#include "loongarch64/a-b-kernel.h" #include "ppc64/a-b-kernel.h" #include "s390x/a-b-bios.h" =20 @@ -57,6 +58,9 @@ char *bootfile_create(const char *arch, const char *dir, = bool suspend_me) content =3D aarch64_kernel; len =3D sizeof(aarch64_kernel); g_assert(sizeof(aarch64_kernel) <=3D ARM_TEST_MAX_KERNEL_SIZE); + } else if (strcmp(arch, "loongarch64") =3D=3D 0) { + content =3D loongarch64_kernel; + len =3D sizeof(loongarch64_kernel); } else { g_assert_not_reached(); } diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/fram= ework.c index a9b58d03aa..a830b96f41 100644 --- a/tests/qtest/migration/framework.c +++ b/tests/qtest/migration/framework.c @@ -360,6 +360,12 @@ int migrate_args(char **from, char **to, MigrateStart = *args) arch_opts =3D g_strdup_printf("-cpu max -kernel %s", bootpath); start_address =3D ARM_TEST_MEM_START; end_address =3D ARM_TEST_MEM_END; + } else if (strcmp(arch, "loongarch64") =3D=3D 0) { + memory_size =3D "256M"; + machine_alias =3D "virt"; + arch_opts =3D g_strdup_printf("-bios %s", bootpath); + start_address =3D LOONGARCH_TEST_MEM_START; + end_address =3D LOONGARCH_TEST_MEM_END; } else { g_assert_not_reached(); } diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 4897325d84..e154abb05d 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -155,7 +155,8 @@ qtests_loongarch64 =3D qtests_filter + \ (config_all_devices.has_key('CONFIG_LOONGARCH_VIRT') ? ['numa-test'] : [= ]) + \ (unpack_edk2_blobs ? ['bios-tables-test'] : []) + \ ['boot-serial-test', - 'cpu-plug-test'] + 'cpu-plug-test', + 'migration-test'] =20 qtests_m68k =3D ['boot-serial-test'] + \ qtests_filter diff --git a/tests/qtest/migration/Makefile b/tests/qtest/migration/Makefile index c183b69941..626e3974f7 100644 --- a/tests/qtest/migration/Makefile +++ b/tests/qtest/migration/Makefile @@ -5,7 +5,7 @@ # See the COPYING file in the top-level directory. # =20 -TARGET_LIST =3D i386 aarch64 s390x ppc64 +TARGET_LIST =3D i386 aarch64 s390x ppc64 loongarch64 =20 SRC_PATH =3D ../../../.. =20 @@ -23,6 +23,8 @@ help: @echo " Possible targets are: $(TARGET_LIST)" =20 override define __note +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * This file is automatically generated from the assembly file in * tests/qtest/migration/$@. Edit that file and then run "make" diff --git a/tests/qtest/migration/loongarch64/Makefile b/tests/qtest/migra= tion/loongarch64/Makefile new file mode 100644 index 0000000000..3c8cfeee86 --- /dev/null +++ b/tests/qtest/migration/loongarch64/Makefile @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# To specify cross compiler prefix, use CROSS_PREFIX=3D +# $ make CROSS_PREFIX=3Dloongarch64-linux-gnu- + +.PHONY: all clean +all: a-b-kernel.h + +a-b-kernel.h: loongarch64.kernel + echo "$$__note" > $@ + xxd -i $< | sed -e 's/.*int.*//' >> $@ + +loongarch64.kernel: loongarch64.elf + $(CROSS_PREFIX)objcopy -j .text -O binary $< $@ + +loongarch64.elf: a-b-kernel.S + $(CROSS_PREFIX)gcc -o $@ -nostdlib -Wl,--build-id=3Dnone $< + +clean: + $(RM) *.kernel *.elf diff --git a/tests/qtest/migration/loongarch64/a-b-kernel.S b/tests/qtest/m= igration/loongarch64/a-b-kernel.S new file mode 100644 index 0000000000..577d4b238c --- /dev/null +++ b/tests/qtest/migration/loongarch64/a-b-kernel.S @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "../bootfile.h" + +#define LOONGARCH_CSR_CRMD 0 +#define LOONGARCH_VIRT_UART 0x1FE001E0 +.section .text + + .globl _start +_start: + /* output char 'A' to UART16550 */ + li.d $t0, LOONGARCH_VIRT_UART + li.w $t1, 'A' + st.b $t1, $t0, 0 + + /* traverse test memory region */ + li.d $t0, LOONGARCH_TEST_MEM_START + li.d $t1, LOONGARCH_TEST_MEM_END + li.d $t2, TEST_MEM_PAGE_SIZE + li.d $t4, LOONGARCH_VIRT_UART + li.w $t5, 'B' + +clean: + st.b $zero, $t0, 0 + add.d $t0, $t0, $t2 + bne $t0, $t1, clean + /* keeps a counter so we can limit the output speed */ + addi.d $t6, $zero, 0 + +mainloop: + li.d $t0, LOONGARCH_TEST_MEM_START + +innerloop: + ld.bu $t3, $t0, 0 + addi.w $t3, $t3, 1 + ext.w.b $t3, $t3 + st.b $t3, $t0, 0 + add.d $t0, $t0, $t2 + bne $t0, $t1, innerloop + + addi.d $t6, $t6, 1 + andi $t6, $t6, 31 + bnez $t6, mainloop + + st.b $t5, $t4, 0 + b mainloop --=20 2.54.0 From nobody Thu Jun 25 06:56:52 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1782218988; cv=none; d=zohomail.com; s=zohoarc; b=BWPTKYy9pjeoE1pX1WOm/7WPMXjASGQRNatCSIAnbE3rIH08JdG7juFdgtyceSEsVTavfoUxP0l7YM1DcaFKlgdSbJgF9y3rRgfO5bszr9aq/R++Knf+FAQSU42XVry6dYjXzLYeOc8wksdivtd2DEdu0yrkFP0t50AP/idqfqI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1782218988; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=IPawD74Ky15VoSdg0D+RW45mIh7erqlzbXpZjD2iMnc=; b=HhS3jvpfGE3XvTCpVASMRL8Ogdbeo2ZDYJnvXKA+3MDN/DULyQDK/0XI1qt8Jmn7BeAcbtkKzED8DaTHqU3wPfA70ZH6S4ECbe/rlFWqPE7vIP2QOovOq+7kTjW8pwebsD5fwhyA8WvrOB80LVVA3T2Ezrg7mO/D2tEuYJNU8jk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1782218988681642.1447503420695; Tue, 23 Jun 2026 05:49:48 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wc0YT-0004Wy-9b; Tue, 23 Jun 2026 08:48:41 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YR-0004W2-QL for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:40 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YL-0006zz-7d for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:38 -0400 Received: from mail-qt1-f199.google.com (mail-qt1-f199.google.com [209.85.160.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-5-GpysJqJ-MmK9E1uXrwExnw-1; Tue, 23 Jun 2026 08:48:30 -0400 Received: by mail-qt1-f199.google.com with SMTP id d75a77b69052e-5174a23afcbso63512201cf.3 for ; Tue, 23 Jun 2026 05:48:30 -0700 (PDT) Received: from x1.com ([174.91.117.157]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51a51106a09sm22288351cf.0.2026.06.23.05.48.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jun 2026 05:48:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782218912; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=IPawD74Ky15VoSdg0D+RW45mIh7erqlzbXpZjD2iMnc=; b=al2h5xqik/RJD7W/h5HLJLCR4FZCb5/kERPgyt0XlpqcHTOZzWH9uPRySHY1fu4AuYj4Hr qsPxV03gaOqWmzpkLk/YKA9hXpCBBo5BZqyxIsIxgY8K5uKJeoIjT0xg1ERGP1QgTqUHTV kIRkYpBFrenMyVA3FUZ9P0PLjH2Tk9I= X-MC-Unique: GpysJqJ-MmK9E1uXrwExnw-1 X-Mimecast-MFC-AGG-ID: GpysJqJ-MmK9E1uXrwExnw_1782218910 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1782218910; x=1782823710; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=IPawD74Ky15VoSdg0D+RW45mIh7erqlzbXpZjD2iMnc=; b=bC6/FFkqkPZq02xkEyrO4tsULAcsC4MOpqX5ekQmCFHHR7gitcVOYssqvJ7zlfmS9Q k8riOTxsHohPfmbSUz3xPHjxxQ4NOkMvfuiAJEJ81i94ZFoBzHXKKKa91U5jvXgjWDkD 52HKW15LDzO8hq71NBn+mUH05cbaWaeIuctNglBq1qZd9s7xje9+GzKFeDVhBU+K4UIi SY9soI7uOHaef8Gi54YoaHE7RndOln6cfBjYjwnGqYTxqCOTunXYWkhQCO1jxOEWNaKa o/COpqgWX+lFUCzAzY5NdRuoRDpqFEAg2wx4qqBroiXUqvPVg8N+fKHPbz3B5JCsoQXK enqA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782218910; x=1782823710; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=IPawD74Ky15VoSdg0D+RW45mIh7erqlzbXpZjD2iMnc=; b=q0RIZL6fO/wMkCi1ZvEBv7/alsJ3Dbs2PXgIN0ImR5fvrcr1SVtdQURMml5O2h36P+ F7dx9gQdrcIZsqUUv3DhRFW7tjvACiUT7CNHlqYUGM3pNP2ocelcO6jcYRrPTCFD5sGd Eau7ew/AlAEdhKTqlvZzOwCJet2uv2eP7YlLTFonu2Q8EZ7mnsxJOqHNr8clPrrykEGC hfJOYgq+yzODvABxsxbA5DngTLApvrit5mjtftvOSL9UQ8j7EvRePxUOpTYyJmfDuhzo a01diYHNKmQKlUCiz9oQjGp3WrZ/9VX/Z+iuszHaNbAfOpC2+K7c+zGerA/RcuVjimU9 QB8Q== X-Gm-Message-State: AOJu0Yx0PsHKiV0FaH2uTIlXBZkSsfvFj4DbVVdFQueIsTuz/0hRhMP2 RN8n8/jvZoGUDggLLTpRGX0V/PoFfOTlutnkUDDkUVlwCrWRVZh+iySOOYQ9F46f8l+LgszfV4T 0XWlYTVT1ScM7Uoc23yOfDbpvYZ1ZgfIlUI8SzDFjn2d/BZBDZhn3X2fkqAdw7rYwn2B2U9IaLG AMZLXaiOfcMysbQQtAAXXYrJ76LpxgP2hxFvCe2Q== X-Gm-Gg: AfdE7cndciNyT+IrwRYQZKZW0t0rH7Iko9I6bmtEYJgGtqNRecyKpsMqIe9Hgbcr6vV lnsxzMq0wXRZlmWB2DVDvCNU+KUienNMM4uYM4rCxLVtQlhbBcWoqVQ49jbOELW76cKYjIn52KO 55hZJ3jxKSszT+OKfWIiuGXp+LS/ghvlntCsxCNZfA6CPcF4UOB581T7tGaOCIlhb5q7Oskr8fH OlbKvNn96wnn9Nyve6GDSL8/EUTjJoHR7WBhpdYbgyVmjSsZ2SwS5MC/XA6tjEbvusSfAdwd5DW BzRS9ttDAZfPLgHMNvl+VcoY3E2PC03xtco8F9PCNS/KWECYGU9YVzFs0WdXKF+KLu9l+v868RM KdA== X-Received: by 2002:a05:622a:1b8c:b0:517:5e32:af20 with SMTP id d75a77b69052e-519e490624dmr275872611cf.6.1782218909783; Tue, 23 Jun 2026 05:48:29 -0700 (PDT) X-Received: by 2002:a05:622a:1b8c:b0:517:5e32:af20 with SMTP id d75a77b69052e-519e490624dmr275871671cf.6.1782218908838; Tue, 23 Jun 2026 05:48:28 -0700 (PDT) From: Peter Xu To: qemu-devel@nongnu.org Cc: Peter Xu , Fabiano Rosas , Paolo Bonzini , Bibo Mao , Cornelia Huck , Eric Farman , Matthew Rosato , Richard Henderson , Ilya Leoshkevich , David Hildenbrand , qemu-s390x@nongnu.org Subject: [PULL 07/18] migration/tests: Update a-b-boot images for all archs Date: Tue, 23 Jun 2026 08:47:48 -0400 Message-ID: <20260623124759.125399-8-peterx@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260623124759.125399-1-peterx@redhat.com> References: <20260623124759.125399-1-peterx@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=peterx@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1782218989796158500 Content-Type: text/plain; charset="utf-8" We just added a GPLv2 licence identifier to __note, update all headers with that. When at this, s390 seems to generate a new binary with the latest cross-compiler I have here: s390x-linux-gnu-gcc (GCC) 15.2.1 20250808 (Red Hat Cross 15.2.1-1) The hope is the new generated should normally be better. Update them. Cc: Bibo Mao Cc: Cornelia Huck Cc: Eric Farman Cc: Matthew Rosato Cc: Richard Henderson Cc: Ilya Leoshkevich Cc: David Hildenbrand Cc: qemu-s390x@nongnu.org Reviewed-by: Bibo Mao Based-on: <20260611084312.70042-1-maobibo@loongson.cn> Acked-by: Fabiano Rosas Link: https://lore.kernel.org/r/20260612155307.2172358-1-peterx@redhat.com Signed-off-by: Peter Xu --- tests/qtest/migration/aarch64/a-b-kernel.h | 2 + tests/qtest/migration/i386/a-b-bootblock.h | 2 + tests/qtest/migration/ppc64/a-b-kernel.h | 2 + tests/qtest/migration/s390x/a-b-bios.h | 272 ++++++++++----------- 4 files changed, 138 insertions(+), 140 deletions(-) diff --git a/tests/qtest/migration/aarch64/a-b-kernel.h b/tests/qtest/migra= tion/aarch64/a-b-kernel.h index c444cdaf73..4d46997354 100644 --- a/tests/qtest/migration/aarch64/a-b-kernel.h +++ b/tests/qtest/migration/aarch64/a-b-kernel.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * This file is automatically generated from the assembly file in * tests/qtest/migration/aarch64. Edit that file and then run "make" diff --git a/tests/qtest/migration/i386/a-b-bootblock.h b/tests/qtest/migra= tion/i386/a-b-bootblock.h index 3b5de60161..356392b83a 100644 --- a/tests/qtest/migration/i386/a-b-bootblock.h +++ b/tests/qtest/migration/i386/a-b-bootblock.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * This file is automatically generated from the assembly file in * tests/qtest/migration/i386. Edit that file and then run "make" diff --git a/tests/qtest/migration/ppc64/a-b-kernel.h b/tests/qtest/migrati= on/ppc64/a-b-kernel.h index 8dc2bcd61a..11477c1554 100644 --- a/tests/qtest/migration/ppc64/a-b-kernel.h +++ b/tests/qtest/migration/ppc64/a-b-kernel.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * This file is automatically generated from the assembly file in * tests/qtest/migration/ppc64. Edit that file and then run "make" diff --git a/tests/qtest/migration/s390x/a-b-bios.h b/tests/qtest/migration= /s390x/a-b-bios.h index f8e385c75c..c1d6e0846c 100644 --- a/tests/qtest/migration/s390x/a-b-bios.h +++ b/tests/qtest/migration/s390x/a-b-bios.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * This file is automatically generated from the assembly file in * tests/qtest/migration/s390x. Edit that file and then run "make" @@ -7,10 +9,10 @@ unsigned char s390x_elf[] =3D { 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x98, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xd8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0x07, 0x00, 0x40, - 0x00, 0x10, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x88, 0x00, 0x00, 0x00, 0x00, @@ -22,86 +24,87 @@ unsigned char s390x_elf[] =3D { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x88, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x88, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xd8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1e, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xd8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x21, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xe8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xe8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x21, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0e, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xd8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xd8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, + 0x00, 0x00, 0x0e, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xe8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xe8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x64, 0x74, 0xe5, 0x51, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x64, 0x74, 0xe5, 0x52, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xd8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1e, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xd8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x28, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xe8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xe8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x6c, 0x64, 0x36, 0x34, 0x2e, 0x73, 0x6f, - 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0xeb, 0xdf, 0xf0, 0x68, + 0x00, 0x24, 0xc0, 0xd0, 0x00, 0x00, 0x01, 0x05, 0xa7, 0xfb, 0xff, 0x60, + 0xc0, 0x10, 0x00, 0x00, 0x96, 0xd4, 0xa7, 0x28, 0x00, 0x1c, 0x40, 0x20, + 0x10, 0x00, 0xa5, 0x2c, 0x00, 0x04, 0xe3, 0x20, 0x10, 0x0a, 0x00, 0x24, + 0xa7, 0x28, 0x00, 0x40, 0x40, 0x20, 0x10, 0x12, 0x58, 0x20, 0xd0, 0x00, + 0xb2, 0x20, 0x00, 0x21, 0xb2, 0x22, 0x00, 0x30, 0x88, 0x30, 0x00, 0x1c, + 0xc0, 0xe5, 0x00, 0x00, 0x00, 0x63, 0xa7, 0x29, 0x00, 0x41, 0xc0, 0xe5, + 0x00, 0x00, 0x00, 0xbf, 0xa5, 0x2e, 0x00, 0x10, 0xa7, 0x19, 0x63, 0x00, + 0x92, 0x00, 0x20, 0x00, 0xa7, 0x2b, 0x10, 0x00, 0xa7, 0x17, 0xff, 0xfc, + 0xa5, 0x1e, 0x00, 0x10, 0xa7, 0x29, 0x63, 0x00, 0xe3, 0x30, 0x10, 0x00, + 0x00, 0x90, 0xa7, 0x3a, 0x00, 0x01, 0x42, 0x30, 0x10, 0x00, 0xa7, 0x1b, + 0x10, 0x00, 0xa7, 0x27, 0xff, 0xf7, 0xa7, 0x29, 0x00, 0x42, 0xc0, 0xe5, + 0x00, 0x00, 0x00, 0xa1, 0xa7, 0xf4, 0xff, 0xec, 0xc0, 0xf0, 0x00, 0x00, + 0x56, 0x44, 0xc0, 0x20, 0x00, 0x00, 0x0e, 0x91, 0xe3, 0x20, 0x20, 0x00, + 0x00, 0x04, 0xc0, 0x30, 0x00, 0x00, 0x9e, 0x8b, 0xb9, 0x0b, 0x00, 0x32, + 0xb9, 0x02, 0x00, 0x33, 0xa7, 0x84, 0x00, 0x19, 0xa7, 0x3b, 0xff, 0xff, + 0xeb, 0x43, 0x00, 0x08, 0x00, 0x0c, 0xb9, 0x02, 0x00, 0x44, 0xb9, 0x04, + 0x00, 0x12, 0xa7, 0x84, 0x00, 0x09, 0xd7, 0xff, 0x10, 0x00, 0x10, 0x00, + 0x41, 0x10, 0x11, 0x00, 0xa7, 0x47, 0xff, 0xfb, 0xc0, 0x20, 0x00, 0x00, + 0x00, 0x0d, 0x44, 0x30, 0x20, 0x00, 0xc0, 0x20, 0x00, 0x00, 0x00, 0x57, + 0xd2, 0x0f, 0x01, 0xd0, 0x20, 0x00, 0xa7, 0xf4, 0xff, 0x89, 0xd7, 0x00, + 0x10, 0x00, 0x10, 0x00, 0xc0, 0x10, 0x00, 0x00, 0x00, 0x4c, 0xb2, 0xb2, + 0x10, 0x00, 0xa7, 0xf4, 0x00, 0x00, 0xeb, 0x00, 0xf0, 0x00, 0x00, 0x25, + 0x96, 0x02, 0xf0, 0x06, 0xeb, 0x00, 0xf0, 0x00, 0x00, 0x2f, 0xc0, 0x10, + 0x00, 0x00, 0x00, 0x2a, 0xe3, 0x10, 0x01, 0xb8, 0x00, 0x24, 0xc0, 0x10, + 0x00, 0x00, 0x00, 0x47, 0xd2, 0x07, 0x01, 0xb0, 0x10, 0x00, 0xc0, 0x10, + 0x00, 0x00, 0x00, 0x39, 0xb2, 0xb2, 0x10, 0x00, 0xeb, 0x66, 0xf0, 0x00, + 0x00, 0x25, 0x96, 0xff, 0xf0, 0x04, 0xeb, 0x66, 0xf0, 0x00, 0x00, 0x2f, + 0xc0, 0x10, 0x00, 0x00, 0x00, 0x1a, 0xe3, 0x10, 0x01, 0xf8, 0x00, 0x24, + 0xc0, 0x10, 0x00, 0x00, 0x00, 0x32, 0xd2, 0x07, 0x01, 0xf0, 0x10, 0x00, + 0xc0, 0x10, 0x00, 0x00, 0x00, 0x20, 0xb2, 0xb2, 0x10, 0x00, 0xeb, 0x00, + 0xf0, 0x00, 0x00, 0x25, 0x94, 0xfd, 0xf0, 0x06, 0xeb, 0x00, 0xf0, 0x00, + 0x00, 0x2f, 0x07, 0xfe, 0xeb, 0x66, 0xf0, 0x00, 0x00, 0x25, 0x94, 0x00, + 0xf0, 0x04, 0xeb, 0x66, 0xf0, 0x00, 0x00, 0x2f, 0x07, 0xfe, 0x07, 0x07, + 0x00, 0x02, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, + 0x07, 0xfe, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0xc0, 0x50, 0x00, 0x00, + 0x00, 0x20, 0xc0, 0x10, 0x00, 0x00, 0x95, 0xf5, 0x42, 0x20, 0x10, 0x0e, + 0xa7, 0x28, 0x00, 0x0f, 0x40, 0x20, 0x10, 0x00, 0x58, 0x20, 0x50, 0x04, + 0x50, 0x20, 0x10, 0x08, 0x92, 0x00, 0x10, 0x02, 0x58, 0x20, 0x50, 0x00, + 0xb2, 0x20, 0x00, 0x21, 0xb2, 0x22, 0x00, 0x30, 0x88, 0x30, 0x00, 0x1c, + 0xc0, 0xf4, 0xff, 0xff, 0xff, 0x85, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x00, 0x76, 0x00, 0x05, 0x00, 0x07, 0x1a, 0x00, 0x00, 0x78, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x07, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, - 0xeb, 0xdf, 0xf0, 0x68, 0x00, 0x24, 0xc0, 0xd0, 0x00, 0x00, 0x01, 0x05, - 0xa7, 0xfb, 0xff, 0x60, 0xc0, 0x10, 0x00, 0x00, 0x96, 0xc0, 0xa7, 0x28, - 0x00, 0x1c, 0x40, 0x20, 0x10, 0x00, 0xa5, 0x2c, 0x00, 0x04, 0xe3, 0x20, - 0x10, 0x0a, 0x00, 0x24, 0xa7, 0x28, 0x00, 0x40, 0x40, 0x20, 0x10, 0x12, - 0x58, 0x20, 0xd0, 0x00, 0xb2, 0x20, 0x00, 0x21, 0xb2, 0x22, 0x00, 0x30, - 0x88, 0x30, 0x00, 0x1c, 0xc0, 0xe5, 0x00, 0x00, 0x00, 0x63, 0xa7, 0x29, - 0x00, 0x41, 0xc0, 0xe5, 0x00, 0x00, 0x00, 0xbf, 0xa5, 0x2e, 0x00, 0x10, - 0xa7, 0x19, 0x63, 0x00, 0x92, 0x00, 0x20, 0x00, 0xa7, 0x2b, 0x10, 0x00, - 0xa7, 0x17, 0xff, 0xfc, 0xa5, 0x1e, 0x00, 0x10, 0xa7, 0x29, 0x63, 0x00, - 0xe3, 0x30, 0x10, 0x00, 0x00, 0x90, 0xa7, 0x3a, 0x00, 0x01, 0x42, 0x30, - 0x10, 0x00, 0xa7, 0x1b, 0x10, 0x00, 0xa7, 0x27, 0xff, 0xf7, 0xa7, 0x29, - 0x00, 0x42, 0xc0, 0xe5, 0x00, 0x00, 0x00, 0xa1, 0xa7, 0xf4, 0xff, 0xec, - 0xc0, 0xf0, 0x00, 0x00, 0x56, 0x30, 0xc0, 0x20, 0x00, 0x00, 0x0e, 0x7d, - 0xe3, 0x20, 0x20, 0x00, 0x00, 0x04, 0xc0, 0x30, 0x00, 0x00, 0x9e, 0x77, - 0xb9, 0x0b, 0x00, 0x32, 0xb9, 0x02, 0x00, 0x33, 0xa7, 0x84, 0x00, 0x19, - 0xa7, 0x3b, 0xff, 0xff, 0xeb, 0x43, 0x00, 0x08, 0x00, 0x0c, 0xb9, 0x02, - 0x00, 0x44, 0xb9, 0x04, 0x00, 0x12, 0xa7, 0x84, 0x00, 0x09, 0xd7, 0xff, - 0x10, 0x00, 0x10, 0x00, 0x41, 0x10, 0x11, 0x00, 0xa7, 0x47, 0xff, 0xfb, - 0xc0, 0x20, 0x00, 0x00, 0x00, 0x0d, 0x44, 0x30, 0x20, 0x00, 0xc0, 0x20, - 0x00, 0x00, 0x00, 0x57, 0xd2, 0x0f, 0x01, 0xd0, 0x20, 0x00, 0xa7, 0xf4, - 0xff, 0x89, 0xd7, 0x00, 0x10, 0x00, 0x10, 0x00, 0xc0, 0x10, 0x00, 0x00, - 0x00, 0x4c, 0xb2, 0xb2, 0x10, 0x00, 0xa7, 0xf4, 0x00, 0x00, 0xeb, 0x00, - 0xf0, 0x00, 0x00, 0x25, 0x96, 0x02, 0xf0, 0x06, 0xeb, 0x00, 0xf0, 0x00, - 0x00, 0x2f, 0xc0, 0x10, 0x00, 0x00, 0x00, 0x2a, 0xe3, 0x10, 0x01, 0xb8, - 0x00, 0x24, 0xc0, 0x10, 0x00, 0x00, 0x00, 0x47, 0xd2, 0x07, 0x01, 0xb0, - 0x10, 0x00, 0xc0, 0x10, 0x00, 0x00, 0x00, 0x39, 0xb2, 0xb2, 0x10, 0x00, - 0xeb, 0x66, 0xf0, 0x00, 0x00, 0x25, 0x96, 0xff, 0xf0, 0x04, 0xeb, 0x66, - 0xf0, 0x00, 0x00, 0x2f, 0xc0, 0x10, 0x00, 0x00, 0x00, 0x1a, 0xe3, 0x10, - 0x01, 0xf8, 0x00, 0x24, 0xc0, 0x10, 0x00, 0x00, 0x00, 0x32, 0xd2, 0x07, - 0x01, 0xf0, 0x10, 0x00, 0xc0, 0x10, 0x00, 0x00, 0x00, 0x20, 0xb2, 0xb2, - 0x10, 0x00, 0xeb, 0x00, 0xf0, 0x00, 0x00, 0x25, 0x94, 0xfd, 0xf0, 0x06, - 0xeb, 0x00, 0xf0, 0x00, 0x00, 0x2f, 0x07, 0xfe, 0xeb, 0x66, 0xf0, 0x00, - 0x00, 0x25, 0x94, 0x00, 0xf0, 0x04, 0xeb, 0x66, 0xf0, 0x00, 0x00, 0x2f, - 0x07, 0xfe, 0x07, 0x07, 0x00, 0x02, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x01, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x80, 0x00, 0x00, 0x00, 0x07, 0xfe, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0xc0, 0x50, 0x00, 0x00, 0x00, 0x20, 0xc0, 0x10, 0x00, 0x00, 0x95, 0xe1, - 0x42, 0x20, 0x10, 0x0e, 0xa7, 0x28, 0x00, 0x0f, 0x40, 0x20, 0x10, 0x00, - 0x58, 0x20, 0x50, 0x04, 0x50, 0x20, 0x10, 0x08, 0x92, 0x00, 0x10, 0x02, - 0x58, 0x20, 0x50, 0x00, 0xb2, 0x20, 0x00, 0x21, 0xb2, 0x22, 0x00, 0x30, - 0x88, 0x30, 0x00, 0x1c, 0xc0, 0xf4, 0xff, 0xff, 0xff, 0x85, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x00, 0x76, 0x00, 0x05, 0x00, 0x07, 0x1a, 0x00, - 0x00, 0x78, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -322,17 +325,16 @@ unsigned char s390x_elf[] =3D { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xff, 0xfe, 0xf5, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x50, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, + 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x28, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x02, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xff, 0xff, 0xfb, 0x00, 0x00, 0x00, 0x00, @@ -344,105 +346,95 @@ unsigned char s390x_elf[] =3D { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xd8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, - 0x47, 0x43, 0x43, 0x3a, 0x20, 0x28, 0x53, 0x55, 0x53, 0x45, 0x20, 0x4c, - 0x69, 0x6e, 0x75, 0x78, 0x29, 0x20, 0x31, 0x32, 0x2e, 0x33, 0x2e, 0x30, - 0x00, 0x00, 0x2e, 0x73, 0x68, 0x73, 0x74, 0x72, 0x74, 0x61, 0x62, 0x00, - 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x00, 0x2e, 0x67, 0x6e, 0x75, - 0x2e, 0x68, 0x61, 0x73, 0x68, 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x73, 0x79, - 0x6d, 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x73, 0x74, 0x72, 0x00, 0x2e, 0x72, - 0x65, 0x6c, 0x61, 0x2e, 0x64, 0x79, 0x6e, 0x00, 0x2e, 0x74, 0x65, 0x78, - 0x74, 0x00, 0x2e, 0x72, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x00, 0x2e, 0x65, - 0x68, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x00, 0x2e, 0x64, 0x79, 0x6e, - 0x61, 0x6d, 0x69, 0x63, 0x00, 0x2e, 0x67, 0x6f, 0x74, 0x00, 0x2e, 0x64, - 0x61, 0x74, 0x61, 0x00, 0x2e, 0x62, 0x73, 0x73, 0x00, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x43, 0x43, 0x3a, 0x20, 0x28, 0x47, 0x4e, 0x55, 0x29, 0x20, 0x31, + 0x35, 0x2e, 0x32, 0x2e, 0x31, 0x20, 0x32, 0x30, 0x32, 0x35, 0x30, 0x38, + 0x30, 0x38, 0x20, 0x28, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, + 0x43, 0x72, 0x6f, 0x73, 0x73, 0x20, 0x31, 0x35, 0x2e, 0x32, 0x2e, 0x31, + 0x2d, 0x31, 0x29, 0x00, 0x00, 0x2e, 0x73, 0x68, 0x73, 0x74, 0x72, 0x74, + 0x61, 0x62, 0x00, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x00, 0x2e, + 0x67, 0x6e, 0x75, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x00, 0x2e, 0x64, 0x79, + 0x6e, 0x73, 0x79, 0x6d, 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x73, 0x74, 0x72, + 0x00, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x2e, 0x64, 0x79, 0x6e, 0x00, 0x2e, + 0x74, 0x65, 0x78, 0x74, 0x00, 0x2e, 0x72, 0x6f, 0x64, 0x61, 0x74, 0x61, + 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x00, 0x2e, 0x67, + 0x6f, 0x74, 0x00, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x00, 0x2e, 0x62, 0x73, + 0x73, 0x00, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, - 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x6f, 0xff, 0xff, 0xf6, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x50, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x28, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x58, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x58, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x70, + 0x00, 0x00, 0x02, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x78, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x50, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x88, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x88, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xe8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xe8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1e, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xd8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x1f, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x58, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0f, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, + 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; --=20 2.54.0 From nobody Thu Jun 25 06:56:52 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1782218977; cv=none; d=zohomail.com; s=zohoarc; b=JQTYckVPDrgaWnYLY3yv/HksBb0gJh5/yMFaxF/VWqeFGLIOlnCGpychogezmazYhR++KA/p05sx3Kb3Rn0qj01yvecvYk9NY9Sh2i+rlx3+8Leyq6QNfIyg7UaMH2QbdXqNPT+Al3QfTTwuT/CsdqB2S0n/s4uEEPKrnck6mwI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1782218977; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=Il5iK25Y6CznYnUOybhwna0ZlVo3TOkP2UIgDiZHbQ8=; b=NYbHGIvaAs6N2WyibgQVFfkRN7Z8g2vko3NE9KfhX063rDINn9Ar3VveiULFZIbqsLaJ2iPwqq19diA4UK7P5UJizwsF5B1+ZuTzIuoUu+Ne0W/DWy4EgrHPI5Nb/zQqZO5IK0TRwi373n9uOJ7bNRucgs3uB5XOlgKnBPY3D1s= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1782218977355430.0036627627237; Tue, 23 Jun 2026 05:49:37 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wc0YZ-0004Yb-2x; Tue, 23 Jun 2026 08:48:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YW-0004XQ-Te for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:44 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YO-00070V-66 for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:42 -0400 Received: from mail-qt1-f198.google.com (mail-qt1-f198.google.com [209.85.160.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-613-BqVIPtzbOC6IYzp4FQ5YnQ-1; Tue, 23 Jun 2026 08:48:33 -0400 Received: by mail-qt1-f198.google.com with SMTP id d75a77b69052e-5176d949c58so117464651cf.0 for ; Tue, 23 Jun 2026 05:48:32 -0700 (PDT) Received: from x1.com ([174.91.117.157]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51a51106a09sm22288351cf.0.2026.06.23.05.48.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jun 2026 05:48:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782218914; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Il5iK25Y6CznYnUOybhwna0ZlVo3TOkP2UIgDiZHbQ8=; b=LeifJHVaWzE7t7MSHuLh92JGC6mJ2n5h5V35NcYTxsbtW3fO9YtYcMYw2C87mPRKORDF10 NIEoeENG7ZmukWYWtFiKcbGjqZfn1gPHerpjtIFwyvYFiHf33BfYqP09rl7TnvVuNcbS+V mPvi2YjbVRfdUWEmTyzlWP0BxYEF3Yc= X-MC-Unique: BqVIPtzbOC6IYzp4FQ5YnQ-1 X-Mimecast-MFC-AGG-ID: BqVIPtzbOC6IYzp4FQ5YnQ_1782218912 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1782218912; x=1782823712; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Il5iK25Y6CznYnUOybhwna0ZlVo3TOkP2UIgDiZHbQ8=; b=TvtrVSqeQzQ9OYNq2MVZWcsKw7CMiytQW6d5FFFfpMMTu4OnsXhsL/mXM0EehH6zYx +EV20sA3Y3N1oA1HGLlrOVFcJzDQ9EH1dR02VdatOCInUs6iUJuc/7lD/0Tkvz1dTrWe 8Ljd/pNb8RoIUDca6MG5Or8jJzRrbiSNhYb34OCx9ln+lkP9VlJVmFD+7tFqFPFJvnok 1mirZOOPzPLtZVP7/Fam9kUI/k0xTcOpoRpHMX4rx7DGvCTUJxis1JnMSxhLu79b15hv 8l5r8YAb+5Sruq4fbaglaA9D0qtn7VFLa0zA64eTDYC+aoMB7hGZBFs1+Fndt8LRtewX 3UiQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782218912; x=1782823712; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=Il5iK25Y6CznYnUOybhwna0ZlVo3TOkP2UIgDiZHbQ8=; b=We9xTAhZrP/HR1w2NsHAp+BZJ1qnEpFTAOiOFYzCwguF/vpwSwFHW/7NSQd4sXUyi3 ZXK0M4P/tqYalswT3AP6BCh/MeNvLbML8m2Nn7R9OiU8mlRFiJLkQ6Syk0xEHvUuibnQ GeOQTawNTStFMq0UYqHevmFlRa3iurcaNz9RSbzh9Y9oyMKnynVpHpZY9Kn27/hczRqd ir7Qhi2PqLaEq8pB/nKuefLyP2+dJxPXwpwG/JxbRGVLv3/KSATEup28ahO+VbBsnP1x pQgKMHgFVifDnSKipu5ABhc4dw/CH7McLrhYGxlx21fkfiJj6TFB41h3ptQ1y4O4/crX ATwQ== X-Gm-Message-State: AOJu0YwVzMWAX15rVADxQJG6Z+qPNkZ7YRvt6m0knb3zwenwZMnah5Nz a2Q6aKluL51dotqBVoDgKhN86PyaPxvx39dEbH/II49Wqf84w/AJwDWQh92HYop8BgMxfE+c65c W0cL7ioKgjjWbmSNYgKzwHwvVR7qsrszYoe0heXXGcQoeKjb+JiO1/3C6I40NBopmqJJE7N52TF 2xyHVZ0khz+H6QMnFsJ1LEW9fRs4anLROhIRilhw== X-Gm-Gg: AfdE7cnzf3LpQNhYSxfCUiQcT5ISydJJEJAuAuLnQB7KAvmJ44uukYyaMhokYrG6873 ENKO+h6zbGwxTBIefJDaTBBUDwuwgV2hS+GJG6/RAuy3/2buiC+vMrViOfyhtBaBvnc7Xn2bmS7 9uFXNKP2vYl+qHBQzL1AVchMAYYZORs5XymHOTqvlMBgXouTNcgjs1psR+5zRhJiL3xkPlObX0/ rMV3vzRGyegq76gSnV7rvkc7+UYO90Z60o5snxm5uf4jGo8vfqYGus40vny2v4tN100yiDgr8X2 u4tQMaQ5vSEExZL/P3vsnjd3aW1LWQ3Iy2dgOcqfnLNH9Zzx4SBkef6v0/wiUaAdFcrOUnOHtPp bSw== X-Received: by 2002:a05:622a:342:b0:517:8a18:7624 with SMTP id d75a77b69052e-51a545bb470mr45552201cf.3.1782218911731; Tue, 23 Jun 2026 05:48:31 -0700 (PDT) X-Received: by 2002:a05:622a:342:b0:517:8a18:7624 with SMTP id d75a77b69052e-51a545bb470mr45551151cf.3.1782218910681; Tue, 23 Jun 2026 05:48:30 -0700 (PDT) From: Peter Xu To: qemu-devel@nongnu.org Cc: Peter Xu , Fabiano Rosas , Paolo Bonzini , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , David Hildenbrand , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Subject: [PULL 08/18] system/memory: split RamDiscardManager into source and manager Date: Tue, 23 Jun 2026 08:47:49 -0400 Message-ID: <20260623124759.125399-9-peterx@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260623124759.125399-1-peterx@redhat.com> References: <20260623124759.125399-1-peterx@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=peterx@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1782218979542158500 From: Marc-Andr=C3=A9 Lureau Refactor the RamDiscardManager interface into two distinct components: - RamDiscardSource: An interface that state providers (virtio-mem, RamBlockAttributes) implement to provide discard state information (granularity, populated/discarded ranges, replay callbacks). - RamDiscardManager: A concrete QOM object that wraps a source, owns the listener list, and handles listener registration/unregistration and notifications. This separation moves the listener management logic from individual source implementations into the central RamDiscardManager, reducing code duplication between virtio-mem and RamBlockAttributes. The change prepares for future work where a RamDiscardManager could aggregate multiple sources. Note, the original virtio-mem code had conditions before discard: if (vmem->size) { rdl->notify_discard(rdl, rdl->section); } however, the new code calls discard unconditionally. This is considered safe, since the populate/discard of sections are already asymmetrical (unplug & unregister all listener section unconditionally). Reviewed-by: Peter Xu Acked-by: David Hildenbrand Signed-off-by: Marc-Andr=C3=A9 Lureau Reviewed-by: Philippe Mathieu-Daud=C3=A9 Link: https://lore.kernel.org/r/20260604-rdm5-v5-1-5768e6a0943d@redhat.com Signed-off-by: Peter Xu --- include/hw/virtio/virtio-mem.h | 3 - include/system/memory.h | 197 ++++++++++++++++------------- include/system/ramblock.h | 2 - hw/virtio/virtio-mem.c | 163 +++++------------------- system/memory.c | 218 +++++++++++++++++++++++++++++---- system/ram-block-attributes.c | 171 ++++++++------------------ 6 files changed, 385 insertions(+), 369 deletions(-) diff --git a/include/hw/virtio/virtio-mem.h b/include/hw/virtio/virtio-mem.h index 221cfd76bf..5d1d19c6be 100644 --- a/include/hw/virtio/virtio-mem.h +++ b/include/hw/virtio/virtio-mem.h @@ -118,9 +118,6 @@ struct VirtIOMEM { /* notifiers to notify when "size" changes */ NotifierList size_change_notifiers; =20 - /* listeners to notify on plug/unplug activity. */ - QLIST_HEAD(, RamDiscardListener) rdl_list; - /* Catch system resets -> qemu_devices_reset() only. */ VirtioMemSystemReset *system_reset; }; diff --git a/include/system/memory.h b/include/system/memory.h index 582de45c34..ffdf95f2f2 100644 --- a/include/system/memory.h +++ b/include/system/memory.h @@ -51,6 +51,12 @@ typedef struct RamDiscardManager RamDiscardManager; DECLARE_OBJ_CHECKERS(RamDiscardManager, RamDiscardManagerClass, RAM_DISCARD_MANAGER, TYPE_RAM_DISCARD_MANAGER); =20 +#define TYPE_RAM_DISCARD_SOURCE "ram-discard-source" +typedef struct RamDiscardSourceClass RamDiscardSourceClass; +typedef struct RamDiscardSource RamDiscardSource; +DECLARE_OBJ_CHECKERS(RamDiscardSource, RamDiscardSourceClass, + RAM_DISCARD_SOURCE, TYPE_RAM_DISCARD_SOURCE); + #ifdef CONFIG_FUZZ void fuzz_dma_read_cb(size_t addr, size_t len, @@ -592,8 +598,8 @@ static inline void ram_discard_listener_init(RamDiscard= Listener *rdl, /** * typedef ReplayRamDiscardState: * - * The callback handler for #RamDiscardManagerClass.replay_populated/ - * #RamDiscardManagerClass.replay_discarded to invoke on populated/discard= ed + * The callback handler for #RamDiscardSourceClass.replay_populated/ + * #RamDiscardSourceClass.replay_discarded to invoke on populated/discarded * parts. * * @section: the #MemoryRegionSection of populated/discarded part @@ -605,40 +611,17 @@ typedef int (*ReplayRamDiscardState)(MemoryRegionSect= ion *section, void *opaque); =20 /* - * RamDiscardManagerClass: - * - * A #RamDiscardManager coordinates which parts of specific RAM #MemoryReg= ion - * regions are currently populated to be used/accessed by the VM, notifying - * after parts were discarded (freeing up memory) and before parts will be - * populated (consuming memory), to be used/accessed by the VM. + * RamDiscardSourceClass: * - * A #RamDiscardManager can only be set for a RAM #MemoryRegion while the - * #MemoryRegion isn't mapped into an address space yet (either directly - * or via an alias); it cannot change while the #MemoryRegion is - * mapped into an address space. + * A #RamDiscardSource provides information about which parts of a specific + * RAM #MemoryRegion are currently populated (accessible) vs discarded. * - * The #RamDiscardManager is intended to be used by technologies that are - * incompatible with discarding of RAM (e.g., VFIO, which may pin all - * memory inside a #MemoryRegion), and require proper coordination to only - * map the currently populated parts, to hinder parts that are expected to - * remain discarded from silently getting populated and consuming memory. - * Technologies that support discarding of RAM don't have to bother and can - * simply map the whole #MemoryRegion. - * - * An example #RamDiscardManager is virtio-mem, which logically (un)plugs - * memory within an assigned RAM #MemoryRegion, coordinated with the VM. - * Logically unplugging memory consists of discarding RAM. The VM agreed t= o not - * access unplugged (discarded) memory - especially via DMA. virtio-mem wi= ll - * properly coordinate with listeners before memory is plugged (populated), - * and after memory is unplugged (discarded). - * - * Listeners are called in multiples of the minimum granularity (unless it - * would exceed the registered range) and changes are aligned to the minim= um - * granularity within the #MemoryRegion. Listeners have to prepare for mem= ory - * becoming discarded in a different granularity than it was populated and= the - * other way around. + * This is an interface that state providers (like virtio-mem or + * RamBlockAttributes) implement to provide discard state information. A + * #RamDiscardManager wraps sources and manages listener registrations and + * notifications. */ -struct RamDiscardManagerClass { +struct RamDiscardSourceClass { /* private */ InterfaceClass parent_class; =20 @@ -648,47 +631,47 @@ struct RamDiscardManagerClass { * @get_min_granularity: * * Get the minimum granularity in which listeners will get notified - * about changes within the #MemoryRegion via the #RamDiscardManager. + * about changes within the #MemoryRegion via the #RamDiscardSource. * - * @rdm: the #RamDiscardManager + * @rds: the #RamDiscardSource * @mr: the #MemoryRegion * * Returns the minimum granularity. */ - uint64_t (*get_min_granularity)(const RamDiscardManager *rdm, + uint64_t (*get_min_granularity)(const RamDiscardSource *rds, const MemoryRegion *mr); =20 /** * @is_populated: * * Check whether the given #MemoryRegionSection is completely populated - * (i.e., no parts are currently discarded) via the #RamDiscardManager. + * (i.e., no parts are currently discarded) via the #RamDiscardSource. * There are no alignment requirements. * - * @rdm: the #RamDiscardManager + * @rds: the #RamDiscardSource * @section: the #MemoryRegionSection * * Returns whether the given range is completely populated. */ - bool (*is_populated)(const RamDiscardManager *rdm, + bool (*is_populated)(const RamDiscardSource *rds, const MemoryRegionSection *section); =20 /** * @replay_populated: * * Call the #ReplayRamDiscardState callback for all populated parts wi= thin - * the #MemoryRegionSection via the #RamDiscardManager. + * the #MemoryRegionSection via the #RamDiscardSource. * * In case any call fails, no further calls are made. * - * @rdm: the #RamDiscardManager + * @rds: the #RamDiscardSource * @section: the #MemoryRegionSection * @replay_fn: the #ReplayRamDiscardState callback * @opaque: pointer to forward to the callback * * Returns 0 on success, or a negative error if any notification faile= d. */ - int (*replay_populated)(const RamDiscardManager *rdm, + int (*replay_populated)(const RamDiscardSource *rds, MemoryRegionSection *section, ReplayRamDiscardState replay_fn, void *opaque); =20 @@ -696,50 +679,60 @@ struct RamDiscardManagerClass { * @replay_discarded: * * Call the #ReplayRamDiscardState callback for all discarded parts wi= thin - * the #MemoryRegionSection via the #RamDiscardManager. + * the #MemoryRegionSection via the #RamDiscardSource. * - * @rdm: the #RamDiscardManager + * @rds: the #RamDiscardSource * @section: the #MemoryRegionSection * @replay_fn: the #ReplayRamDiscardState callback * @opaque: pointer to forward to the callback * * Returns 0 on success, or a negative error if any notification faile= d. */ - int (*replay_discarded)(const RamDiscardManager *rdm, + int (*replay_discarded)(const RamDiscardSource *rds, MemoryRegionSection *section, ReplayRamDiscardState replay_fn, void *opaque); +}; =20 - /** - * @register_listener: - * - * Register a #RamDiscardListener for the given #MemoryRegionSection a= nd - * immediately notify the #RamDiscardListener about all populated parts - * within the #MemoryRegionSection via the #RamDiscardManager. - * - * In case any notification fails, no further notifications are trigge= red - * and an error is logged. - * - * @rdm: the #RamDiscardManager - * @rdl: the #RamDiscardListener - * @section: the #MemoryRegionSection - */ - void (*register_listener)(RamDiscardManager *rdm, - RamDiscardListener *rdl, - MemoryRegionSection *section); +/** + * RamDiscardManager: + * + * A #RamDiscardManager coordinates which parts of specific RAM #MemoryReg= ion + * regions are currently populated to be used/accessed by the VM, notifying + * after parts were discarded (freeing up memory) and before parts will be + * populated (consuming memory), to be used/accessed by the VM. + * + * A #RamDiscardManager can only be set for a RAM #MemoryRegion while the + * #MemoryRegion isn't mapped into an address space yet (either directly + * or via an alias); it cannot change while the #MemoryRegion is + * mapped into an address space. + * + * The #RamDiscardManager is intended to be used by technologies that are + * incompatible with discarding of RAM (e.g., VFIO, which may pin all + * memory inside a #MemoryRegion), and require proper coordination to only + * map the currently populated parts, to hinder parts that are expected to + * remain discarded from silently getting populated and consuming memory. + * Technologies that support discarding of RAM don't have to bother and can + * simply map the whole #MemoryRegion. + * + * An example #RamDiscardSource is virtio-mem, which logically (un)plugs + * memory within an assigned RAM #MemoryRegion, coordinated with the VM. + * Logically unplugging memory consists of discarding RAM. The VM agreed t= o not + * access unplugged (discarded) memory - especially via DMA. virtio-mem wi= ll + * properly coordinate with listeners before memory is plugged (populated), + * and after memory is unplugged (discarded). + * + * Listeners are called in multiples of the minimum granularity (unless it + * would exceed the registered range) and changes are aligned to the minim= um + * granularity within the #MemoryRegion. Listeners have to prepare for mem= ory + * becoming discarded in a different granularity than it was populated and= the + * other way around. + */ +struct RamDiscardManager { + Object parent; =20 - /** - * @unregister_listener: - * - * Unregister a previously registered #RamDiscardListener via the - * #RamDiscardManager after notifying the #RamDiscardListener about all - * populated parts becoming unpopulated within the registered - * #MemoryRegionSection. - * - * @rdm: the #RamDiscardManager - * @rdl: the #RamDiscardListener - */ - void (*unregister_listener)(RamDiscardManager *rdm, - RamDiscardListener *rdl); + RamDiscardSource *rds; + MemoryRegion *mr; + QLIST_HEAD(, RamDiscardListener) rdl_list; }; =20 uint64_t ram_discard_manager_get_min_granularity(const RamDiscardManager *= rdm, @@ -751,8 +744,8 @@ bool ram_discard_manager_is_populated(const RamDiscardM= anager *rdm, /** * ram_discard_manager_replay_populated: * - * A wrapper to call the #RamDiscardManagerClass.replay_populated callback - * of the #RamDiscardManager. + * A wrapper to call the #RamDiscardSourceClass.replay_populated callback + * of the #RamDiscardSource sources. * * @rdm: the #RamDiscardManager * @section: the #MemoryRegionSection @@ -769,8 +762,8 @@ int ram_discard_manager_replay_populated(const RamDisca= rdManager *rdm, /** * ram_discard_manager_replay_discarded: * - * A wrapper to call the #RamDiscardManagerClass.replay_discarded callback - * of the #RamDiscardManager. + * A wrapper to call the #RamDiscardSourceClass.replay_discarded callback + * of the #RamDiscardSource sources. * * @rdm: the #RamDiscardManager * @section: the #MemoryRegionSection @@ -791,6 +784,34 @@ void ram_discard_manager_register_listener(RamDiscardM= anager *rdm, void ram_discard_manager_unregister_listener(RamDiscardManager *rdm, RamDiscardListener *rdl); =20 +/* + * Note: later refactoring should take the source into account and the man= ager + * should be able to aggregate multiple sources. + */ +int ram_discard_manager_notify_populate(RamDiscardManager *rdm, + uint64_t offset, uint64_t size); + + /* + * Note: later refactoring should take the source into account and the ma= nager + * should be able to aggregate multiple sources. + */ +void ram_discard_manager_notify_discard(RamDiscardManager *rdm, + uint64_t offset, uint64_t size); + +/* + * Note: later refactoring should take the source into account and the man= ager + * should be able to aggregate multiple sources. + */ +void ram_discard_manager_notify_discard_all(RamDiscardManager *rdm); + +/* + * Replay populated sections to all registered listeners. + * + * Note: later refactoring should take the source into account and the man= ager + * should be able to aggregate multiple sources. + */ +int ram_discard_manager_replay_populated_to_listeners(RamDiscardManager *r= dm); + /** * memory_translate_iotlb: Extract addresses from a TLB entry. * Called with rcu_read_lock held. @@ -2504,18 +2525,22 @@ static inline bool memory_region_has_ram_discard_ma= nager(MemoryRegion *mr) } =20 /** - * memory_region_set_ram_discard_manager: set the #RamDiscardManager for a + * memory_region_add_ram_discard_source: add a #RamDiscardSource for a * #MemoryRegion * - * This function must not be called for a mapped #MemoryRegion, a #MemoryR= egion - * that does not cover RAM, or a #MemoryRegion that already has a - * #RamDiscardManager assigned. Return 0 if the rdm is set successfully. + * @mr: the #MemoryRegion + * @source: #RamDiscardSource to add + */ +int memory_region_add_ram_discard_source(MemoryRegion *mr, RamDiscardSourc= e *source); + +/** + * memory_region_del_ram_discard_source: remove a #RamDiscardSource for a + * #MemoryRegion * * @mr: the #MemoryRegion - * @rdm: #RamDiscardManager to set + * @source: #RamDiscardSource to remove */ -int memory_region_set_ram_discard_manager(MemoryRegion *mr, - RamDiscardManager *rdm); +void memory_region_del_ram_discard_source(MemoryRegion *mr, RamDiscardSour= ce *source); =20 /** * memory_region_find: translate an address/size relative to a diff --git a/include/system/ramblock.h b/include/system/ramblock.h index 4435f8d55f..2b38718fe5 100644 --- a/include/system/ramblock.h +++ b/include/system/ramblock.h @@ -99,8 +99,6 @@ struct RamBlockAttributes { /* 1-setting of the bitmap represents ram is populated (shared) */ unsigned bitmap_size; unsigned long *bitmap; - - QLIST_HEAD(, RamDiscardListener) rdl_list; }; =20 /* @offset: the offset within the RAMBlock */ diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index a4b71974a1..be149ee944 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -16,6 +16,7 @@ #include "qemu/error-report.h" #include "qemu/units.h" #include "qemu/target-info-qapi.h" +#include "system/memory.h" #include "system/numa.h" #include "system/system.h" #include "system/ramblock.h" @@ -324,74 +325,31 @@ static int virtio_mem_for_each_unplugged_section(cons= t VirtIOMEM *vmem, return ret; } =20 -static int virtio_mem_notify_populate_cb(MemoryRegionSection *s, void *arg) -{ - RamDiscardListener *rdl =3D arg; - - return rdl->notify_populate(rdl, s); -} - static void virtio_mem_notify_unplug(VirtIOMEM *vmem, uint64_t offset, uint64_t size) { - RamDiscardListener *rdl; + RamDiscardManager *rdm =3D memory_region_get_ram_discard_manager(&vmem= ->memdev->mr); =20 - QLIST_FOREACH(rdl, &vmem->rdl_list, next) { - MemoryRegionSection tmp =3D *rdl->section; - - if (!memory_region_section_intersect_range(&tmp, offset, size)) { - continue; - } - rdl->notify_discard(rdl, &tmp); - } + ram_discard_manager_notify_discard(rdm, offset, size); } =20 static int virtio_mem_notify_plug(VirtIOMEM *vmem, uint64_t offset, uint64_t size) { - RamDiscardListener *rdl, *rdl2; - int ret =3D 0; - - QLIST_FOREACH(rdl, &vmem->rdl_list, next) { - MemoryRegionSection tmp =3D *rdl->section; + RamDiscardManager *rdm =3D memory_region_get_ram_discard_manager(&vmem= ->memdev->mr); =20 - if (!memory_region_section_intersect_range(&tmp, offset, size)) { - continue; - } - ret =3D rdl->notify_populate(rdl, &tmp); - if (ret) { - break; - } - } - - if (ret) { - /* Notify all already-notified listeners. */ - QLIST_FOREACH(rdl2, &vmem->rdl_list, next) { - MemoryRegionSection tmp =3D *rdl2->section; - - if (rdl2 =3D=3D rdl) { - break; - } - if (!memory_region_section_intersect_range(&tmp, offset, size)= ) { - continue; - } - rdl2->notify_discard(rdl2, &tmp); - } - } - return ret; + return ram_discard_manager_notify_populate(rdm, offset, size); } =20 static void virtio_mem_notify_unplug_all(VirtIOMEM *vmem) { - RamDiscardListener *rdl; + RamDiscardManager *rdm =3D memory_region_get_ram_discard_manager(&vmem= ->memdev->mr); =20 if (!vmem->size) { return; } =20 - QLIST_FOREACH(rdl, &vmem->rdl_list, next) { - rdl->notify_discard(rdl, rdl->section); - } + ram_discard_manager_notify_discard_all(rdm); } =20 static bool virtio_mem_is_range_plugged(const VirtIOMEM *vmem, @@ -1037,13 +995,9 @@ static void virtio_mem_device_realize(DeviceState *de= v, Error **errp) return; } =20 - /* - * Set ourselves as RamDiscardManager before the plug handler maps the - * memory region and exposes it via an address space. - */ - if (memory_region_set_ram_discard_manager(&vmem->memdev->mr, - RAM_DISCARD_MANAGER(vmem))) { - error_setg(errp, "Failed to set RamDiscardManager"); + if (memory_region_add_ram_discard_source(&vmem->memdev->mr, + RAM_DISCARD_SOURCE(vmem))) { + error_setg(errp, "Failed to add RAM discard source"); ram_block_coordinated_discard_require(false); return; } @@ -1062,7 +1016,8 @@ static void virtio_mem_device_realize(DeviceState *de= v, Error **errp) ret =3D ram_block_discard_range(rb, 0, qemu_ram_get_used_length(rb= )); if (ret) { error_setg_errno(errp, -ret, "Unexpected error discarding RAM"= ); - memory_region_set_ram_discard_manager(&vmem->memdev->mr, NULL); + memory_region_del_ram_discard_source(&vmem->memdev->mr, + RAM_DISCARD_SOURCE(vmem)); ram_block_coordinated_discard_require(false); return; } @@ -1147,7 +1102,7 @@ static void virtio_mem_device_unrealize(DeviceState *= dev) * The unplug handler unmapped the memory region, it cannot be * found via an address space anymore. Unset ourselves. */ - memory_region_set_ram_discard_manager(&vmem->memdev->mr, NULL); + memory_region_del_ram_discard_source(&vmem->memdev->mr, RAM_DISCARD_SO= URCE(vmem)); ram_block_coordinated_discard_require(false); } =20 @@ -1175,9 +1130,7 @@ static int virtio_mem_activate_memslot_range_cb(VirtI= OMEM *vmem, void *arg, =20 static int virtio_mem_post_load_bitmap(VirtIOMEM *vmem) { - RamDiscardListener *rdl; - int ret; - + RamDiscardManager *rdm =3D memory_region_get_ram_discard_manager(&vmem= ->memdev->mr); /* * We restored the bitmap and updated the requested size; activate all * memslots (so listeners register) before notifying about plugged blo= cks. @@ -1195,14 +1148,7 @@ static int virtio_mem_post_load_bitmap(VirtIOMEM *vm= em) * We started out with all memory discarded and our memory region is m= apped * into an address space. Replay, now that we updated the bitmap. */ - QLIST_FOREACH(rdl, &vmem->rdl_list, next) { - ret =3D virtio_mem_for_each_plugged_section(vmem, rdl->section, rd= l, - virtio_mem_notify_populat= e_cb); - if (ret) { - return ret; - } - } - return 0; + return ram_discard_manager_replay_populated_to_listeners(rdm); } =20 static int virtio_mem_post_load(void *opaque, int version_id) @@ -1650,7 +1596,6 @@ static void virtio_mem_instance_init(Object *obj) VirtIOMEM *vmem =3D VIRTIO_MEM(obj); =20 notifier_list_init(&vmem->size_change_notifiers); - QLIST_INIT(&vmem->rdl_list); =20 object_property_add(obj, VIRTIO_MEM_SIZE_PROP, "size", virtio_mem_get_= size, NULL, NULL, NULL); @@ -1694,19 +1639,19 @@ static const Property virtio_mem_legacy_guests_prop= erties[] =3D { unplugged_inaccessible, ON_OFF_AUTO_ON), }; =20 -static uint64_t virtio_mem_rdm_get_min_granularity(const RamDiscardManager= *rdm, +static uint64_t virtio_mem_rds_get_min_granularity(const RamDiscardSource = *rds, const MemoryRegion *mr) { - const VirtIOMEM *vmem =3D VIRTIO_MEM(rdm); + const VirtIOMEM *vmem =3D VIRTIO_MEM(rds); =20 g_assert(mr =3D=3D &vmem->memdev->mr); return vmem->block_size; } =20 -static bool virtio_mem_rdm_is_populated(const RamDiscardManager *rdm, +static bool virtio_mem_rds_is_populated(const RamDiscardSource *rds, const MemoryRegionSection *s) { - const VirtIOMEM *vmem =3D VIRTIO_MEM(rdm); + const VirtIOMEM *vmem =3D VIRTIO_MEM(rds); uint64_t start_gpa =3D vmem->addr + s->offset_within_region; uint64_t end_gpa =3D start_gpa + int128_get64(s->size); =20 @@ -1727,19 +1672,19 @@ struct VirtIOMEMReplayData { void *opaque; }; =20 -static int virtio_mem_rdm_replay_populated_cb(MemoryRegionSection *s, void= *arg) +static int virtio_mem_rds_replay_cb(MemoryRegionSection *s, void *arg) { struct VirtIOMEMReplayData *data =3D arg; =20 return data->fn(s, data->opaque); } =20 -static int virtio_mem_rdm_replay_populated(const RamDiscardManager *rdm, +static int virtio_mem_rds_replay_populated(const RamDiscardSource *rds, MemoryRegionSection *s, ReplayRamDiscardState replay_fn, void *opaque) { - const VirtIOMEM *vmem =3D VIRTIO_MEM(rdm); + const VirtIOMEM *vmem =3D VIRTIO_MEM(rds); struct VirtIOMEMReplayData data =3D { .fn =3D replay_fn, .opaque =3D opaque, @@ -1747,23 +1692,15 @@ static int virtio_mem_rdm_replay_populated(const Ra= mDiscardManager *rdm, =20 g_assert(s->mr =3D=3D &vmem->memdev->mr); return virtio_mem_for_each_plugged_section(vmem, s, &data, - virtio_mem_rdm_replay_populate= d_cb); -} - -static int virtio_mem_rdm_replay_discarded_cb(MemoryRegionSection *s, - void *arg) -{ - struct VirtIOMEMReplayData *data =3D arg; - - return data->fn(s, data->opaque); + virtio_mem_rds_replay_cb); } =20 -static int virtio_mem_rdm_replay_discarded(const RamDiscardManager *rdm, +static int virtio_mem_rds_replay_discarded(const RamDiscardSource *rds, MemoryRegionSection *s, ReplayRamDiscardState replay_fn, void *opaque) { - const VirtIOMEM *vmem =3D VIRTIO_MEM(rdm); + const VirtIOMEM *vmem =3D VIRTIO_MEM(rds); struct VirtIOMEMReplayData data =3D { .fn =3D replay_fn, .opaque =3D opaque, @@ -1771,41 +1708,7 @@ static int virtio_mem_rdm_replay_discarded(const Ram= DiscardManager *rdm, =20 g_assert(s->mr =3D=3D &vmem->memdev->mr); return virtio_mem_for_each_unplugged_section(vmem, s, &data, - virtio_mem_rdm_replay_dis= carded_cb); -} - -static void virtio_mem_rdm_register_listener(RamDiscardManager *rdm, - RamDiscardListener *rdl, - MemoryRegionSection *s) -{ - VirtIOMEM *vmem =3D VIRTIO_MEM(rdm); - int ret; - - g_assert(s->mr =3D=3D &vmem->memdev->mr); - rdl->section =3D memory_region_section_new_copy(s); - - QLIST_INSERT_HEAD(&vmem->rdl_list, rdl, next); - ret =3D virtio_mem_for_each_plugged_section(vmem, rdl->section, rdl, - virtio_mem_notify_populate_c= b); - if (ret) { - error_report("%s: Replaying plugged ranges failed: %s", __func__, - strerror(-ret)); - } -} - -static void virtio_mem_rdm_unregister_listener(RamDiscardManager *rdm, - RamDiscardListener *rdl) -{ - VirtIOMEM *vmem =3D VIRTIO_MEM(rdm); - - g_assert(rdl->section->mr =3D=3D &vmem->memdev->mr); - if (vmem->size) { - rdl->notify_discard(rdl, rdl->section); - } - - memory_region_section_free_copy(rdl->section); - rdl->section =3D NULL; - QLIST_REMOVE(rdl, next); + virtio_mem_rds_replay_cb); } =20 static void virtio_mem_unplug_request_check(VirtIOMEM *vmem, Error **errp) @@ -1837,7 +1740,7 @@ static void virtio_mem_class_init(ObjectClass *klass,= const void *data) DeviceClass *dc =3D DEVICE_CLASS(klass); VirtioDeviceClass *vdc =3D VIRTIO_DEVICE_CLASS(klass); VirtIOMEMClass *vmc =3D VIRTIO_MEM_CLASS(klass); - RamDiscardManagerClass *rdmc =3D RAM_DISCARD_MANAGER_CLASS(klass); + RamDiscardSourceClass *rdsc =3D RAM_DISCARD_SOURCE_CLASS(klass); =20 device_class_set_props(dc, virtio_mem_properties); if (virtio_mem_has_legacy_guests()) { @@ -1861,12 +1764,10 @@ static void virtio_mem_class_init(ObjectClass *klas= s, const void *data) vmc->remove_size_change_notifier =3D virtio_mem_remove_size_change_not= ifier; vmc->unplug_request_check =3D virtio_mem_unplug_request_check; =20 - rdmc->get_min_granularity =3D virtio_mem_rdm_get_min_granularity; - rdmc->is_populated =3D virtio_mem_rdm_is_populated; - rdmc->replay_populated =3D virtio_mem_rdm_replay_populated; - rdmc->replay_discarded =3D virtio_mem_rdm_replay_discarded; - rdmc->register_listener =3D virtio_mem_rdm_register_listener; - rdmc->unregister_listener =3D virtio_mem_rdm_unregister_listener; + rdsc->get_min_granularity =3D virtio_mem_rds_get_min_granularity; + rdsc->is_populated =3D virtio_mem_rds_is_populated; + rdsc->replay_populated =3D virtio_mem_rds_replay_populated; + rdsc->replay_discarded =3D virtio_mem_rds_replay_discarded; } =20 static const TypeInfo virtio_mem_info =3D { @@ -1878,7 +1779,7 @@ static const TypeInfo virtio_mem_info =3D { .class_init =3D virtio_mem_class_init, .class_size =3D sizeof(VirtIOMEMClass), .interfaces =3D (const InterfaceInfo[]) { - { TYPE_RAM_DISCARD_MANAGER }, + { TYPE_RAM_DISCARD_SOURCE }, { } }, }; diff --git a/system/memory.c b/system/memory.c index 8436668c18..52946c5e5d 100644 --- a/system/memory.c +++ b/system/memory.c @@ -2069,34 +2069,88 @@ RamDiscardManager *memory_region_get_ram_discard_ma= nager(MemoryRegion *mr) return mr->rdm; } =20 -int memory_region_set_ram_discard_manager(MemoryRegion *mr, - RamDiscardManager *rdm) +static RamDiscardManager *ram_discard_manager_new(MemoryRegion *mr, + RamDiscardSource *rds) +{ + RamDiscardManager *rdm =3D RAM_DISCARD_MANAGER(object_new(TYPE_RAM_DIS= CARD_MANAGER)); + + rdm->rds =3D rds; + rdm->mr =3D mr; + QLIST_INIT(&rdm->rdl_list); + return rdm; +} + +int memory_region_add_ram_discard_source(MemoryRegion *mr, + RamDiscardSource *source) { g_assert(memory_region_is_ram(mr)); - if (mr->rdm && rdm) { + if (mr->rdm) { return -EBUSY; } =20 - mr->rdm =3D rdm; + mr->rdm =3D ram_discard_manager_new(mr, RAM_DISCARD_SOURCE(source)); return 0; } =20 +void memory_region_del_ram_discard_source(MemoryRegion *mr, + RamDiscardSource *source) +{ + g_assert(mr->rdm->rds =3D=3D source); + + object_unref(mr->rdm); + mr->rdm =3D NULL; +} + +static uint64_t ram_discard_source_get_min_granularity(const RamDiscardSou= rce *rds, + const MemoryRegion = *mr) +{ + RamDiscardSourceClass *rdsc =3D RAM_DISCARD_SOURCE_GET_CLASS(rds); + + g_assert(rdsc->get_min_granularity); + return rdsc->get_min_granularity(rds, mr); +} + +static bool ram_discard_source_is_populated(const RamDiscardSource *rds, + const MemoryRegionSection *sec= tion) +{ + RamDiscardSourceClass *rdsc =3D RAM_DISCARD_SOURCE_GET_CLASS(rds); + + g_assert(rdsc->is_populated); + return rdsc->is_populated(rds, section); +} + +static int ram_discard_source_replay_populated(const RamDiscardSource *rds, + MemoryRegionSection *sectio= n, + ReplayRamDiscardState repla= y_fn, + void *opaque) +{ + RamDiscardSourceClass *rdsc =3D RAM_DISCARD_SOURCE_GET_CLASS(rds); + + g_assert(rdsc->replay_populated); + return rdsc->replay_populated(rds, section, replay_fn, opaque); +} + +static int ram_discard_source_replay_discarded(const RamDiscardSource *rds, + MemoryRegionSection *sectio= n, + ReplayRamDiscardState repla= y_fn, + void *opaque) +{ + RamDiscardSourceClass *rdsc =3D RAM_DISCARD_SOURCE_GET_CLASS(rds); + + g_assert(rdsc->replay_discarded); + return rdsc->replay_discarded(rds, section, replay_fn, opaque); +} + uint64_t ram_discard_manager_get_min_granularity(const RamDiscardManager *= rdm, const MemoryRegion *mr) { - RamDiscardManagerClass *rdmc =3D RAM_DISCARD_MANAGER_GET_CLASS(rdm); - - g_assert(rdmc->get_min_granularity); - return rdmc->get_min_granularity(rdm, mr); + return ram_discard_source_get_min_granularity(rdm->rds, mr); } =20 bool ram_discard_manager_is_populated(const RamDiscardManager *rdm, const MemoryRegionSection *section) { - RamDiscardManagerClass *rdmc =3D RAM_DISCARD_MANAGER_GET_CLASS(rdm); - - g_assert(rdmc->is_populated); - return rdmc->is_populated(rdm, section); + return ram_discard_source_is_populated(rdm->rds, section); } =20 int ram_discard_manager_replay_populated(const RamDiscardManager *rdm, @@ -2104,10 +2158,7 @@ int ram_discard_manager_replay_populated(const RamDi= scardManager *rdm, ReplayRamDiscardState replay_fn, void *opaque) { - RamDiscardManagerClass *rdmc =3D RAM_DISCARD_MANAGER_GET_CLASS(rdm); - - g_assert(rdmc->replay_populated); - return rdmc->replay_populated(rdm, section, replay_fn, opaque); + return ram_discard_source_replay_populated(rdm->rds, section, replay_f= n, opaque); } =20 int ram_discard_manager_replay_discarded(const RamDiscardManager *rdm, @@ -2115,29 +2166,133 @@ int ram_discard_manager_replay_discarded(const Ram= DiscardManager *rdm, ReplayRamDiscardState replay_fn, void *opaque) { - RamDiscardManagerClass *rdmc =3D RAM_DISCARD_MANAGER_GET_CLASS(rdm); + return ram_discard_source_replay_discarded(rdm->rds, section, replay_f= n, opaque); +} + +static void ram_discard_manager_initfn(Object *obj) +{ + RamDiscardManager *rdm =3D RAM_DISCARD_MANAGER(obj); + + QLIST_INIT(&rdm->rdl_list); +} + +static void ram_discard_manager_finalize(Object *obj) +{ + RamDiscardManager *rdm =3D RAM_DISCARD_MANAGER(obj); =20 - g_assert(rdmc->replay_discarded); - return rdmc->replay_discarded(rdm, section, replay_fn, opaque); + g_assert(QLIST_EMPTY(&rdm->rdl_list)); +} + +int ram_discard_manager_notify_populate(RamDiscardManager *rdm, + uint64_t offset, uint64_t size) +{ + RamDiscardListener *rdl, *rdl2; + int ret =3D 0; + + QLIST_FOREACH(rdl, &rdm->rdl_list, next) { + MemoryRegionSection tmp =3D *rdl->section; + + if (!memory_region_section_intersect_range(&tmp, offset, size)) { + continue; + } + ret =3D rdl->notify_populate(rdl, &tmp); + if (ret) { + break; + } + } + + if (ret) { + /* Notify all already-notified listeners about discard. */ + QLIST_FOREACH(rdl2, &rdm->rdl_list, next) { + MemoryRegionSection tmp =3D *rdl2->section; + + if (rdl2 =3D=3D rdl) { + break; + } + if (!memory_region_section_intersect_range(&tmp, offset, size)= ) { + continue; + } + rdl2->notify_discard(rdl2, &tmp); + } + } + return ret; +} + +void ram_discard_manager_notify_discard(RamDiscardManager *rdm, + uint64_t offset, uint64_t size) +{ + RamDiscardListener *rdl; + + QLIST_FOREACH(rdl, &rdm->rdl_list, next) { + MemoryRegionSection tmp =3D *rdl->section; + + if (!memory_region_section_intersect_range(&tmp, offset, size)) { + continue; + } + rdl->notify_discard(rdl, &tmp); + } +} + +void ram_discard_manager_notify_discard_all(RamDiscardManager *rdm) +{ + RamDiscardListener *rdl; + + QLIST_FOREACH(rdl, &rdm->rdl_list, next) { + rdl->notify_discard(rdl, rdl->section); + } +} + +static int rdm_populate_cb(MemoryRegionSection *section, void *opaque) +{ + RamDiscardListener *rdl =3D opaque; + + return rdl->notify_populate(rdl, section); } =20 void ram_discard_manager_register_listener(RamDiscardManager *rdm, RamDiscardListener *rdl, MemoryRegionSection *section) { - RamDiscardManagerClass *rdmc =3D RAM_DISCARD_MANAGER_GET_CLASS(rdm); + int ret; + + g_assert(section->mr =3D=3D rdm->mr); + + rdl->section =3D memory_region_section_new_copy(section); + QLIST_INSERT_HEAD(&rdm->rdl_list, rdl, next); =20 - g_assert(rdmc->register_listener); - rdmc->register_listener(rdm, rdl, section); + ret =3D ram_discard_source_replay_populated(rdm->rds, rdl->section, + rdm_populate_cb, rdl); + if (ret) { + error_report("%s: Replaying populated ranges failed: %s", __func__, + strerror(-ret)); + } } =20 void ram_discard_manager_unregister_listener(RamDiscardManager *rdm, RamDiscardListener *rdl) { - RamDiscardManagerClass *rdmc =3D RAM_DISCARD_MANAGER_GET_CLASS(rdm); + g_assert(rdl->section); + g_assert(rdl->section->mr =3D=3D rdm->mr); + + rdl->notify_discard(rdl, rdl->section); + memory_region_section_free_copy(rdl->section); + rdl->section =3D NULL; + QLIST_REMOVE(rdl, next); +} + +int ram_discard_manager_replay_populated_to_listeners(RamDiscardManager *r= dm) +{ + RamDiscardListener *rdl; + int ret =3D 0; =20 - g_assert(rdmc->unregister_listener); - rdmc->unregister_listener(rdm, rdl); + QLIST_FOREACH(rdl, &rdm->rdl_list, next) { + ret =3D ram_discard_source_replay_populated(rdm->rds, rdl->section, + rdm_populate_cb, rdl); + if (ret) { + break; + } + } + return ret; } =20 /* Called with rcu_read_lock held. */ @@ -3770,9 +3925,17 @@ static const TypeInfo iommu_memory_region_info =3D { }; =20 static const TypeInfo ram_discard_manager_info =3D { - .parent =3D TYPE_INTERFACE, + .parent =3D TYPE_OBJECT, .name =3D TYPE_RAM_DISCARD_MANAGER, - .class_size =3D sizeof(RamDiscardManagerClass), + .instance_size =3D sizeof(RamDiscardManager), + .instance_init =3D ram_discard_manager_initfn, + .instance_finalize =3D ram_discard_manager_finalize, +}; + +static const TypeInfo ram_discard_source_info =3D { + .parent =3D TYPE_INTERFACE, + .name =3D TYPE_RAM_DISCARD_SOURCE, + .class_size =3D sizeof(RamDiscardSourceClass), }; =20 static void memory_register_types(void) @@ -3780,6 +3943,7 @@ static void memory_register_types(void) type_register_static(&memory_region_info); type_register_static(&iommu_memory_region_info); type_register_static(&ram_discard_manager_info); + type_register_static(&ram_discard_source_info); } =20 type_init(memory_register_types) diff --git a/system/ram-block-attributes.c b/system/ram-block-attributes.c index 630b0fda12..a72924eea7 100644 --- a/system/ram-block-attributes.c +++ b/system/ram-block-attributes.c @@ -18,7 +18,7 @@ OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(RamBlockAttribu= tes, ram_block_attributes, RAM_BLOCK_ATTRIBUTES, OBJECT, - { TYPE_RAM_DISCARD_MANAGER }, + { TYPE_RAM_DISCARD_SOURCE }, { }) =20 static size_t @@ -32,35 +32,9 @@ ram_block_attributes_get_block_size(void) return qemu_real_host_page_size(); } =20 - -static bool -ram_block_attributes_rdm_is_populated(const RamDiscardManager *rdm, - const MemoryRegionSection *section) -{ - const RamBlockAttributes *attr =3D RAM_BLOCK_ATTRIBUTES(rdm); - const size_t block_size =3D ram_block_attributes_get_block_size(); - const uint64_t first_bit =3D section->offset_within_region / block_siz= e; - const uint64_t last_bit =3D - first_bit + int128_get64(section->size) / block_size - 1; - unsigned long first_discarded_bit; - - first_discarded_bit =3D find_next_zero_bit(attr->bitmap, last_bit + 1, - first_bit); - return first_discarded_bit > last_bit; -} - typedef int (*ram_block_attributes_section_cb)(MemoryRegionSection *s, void *arg); =20 -static int -ram_block_attributes_notify_populate_cb(MemoryRegionSection *section, - void *arg) -{ - RamDiscardListener *rdl =3D arg; - - return rdl->notify_populate(rdl, section); -} - static int ram_block_attributes_for_each_populated_section(const RamBlockAttributes *= attr, MemoryRegionSection *secti= on, @@ -144,93 +118,73 @@ ram_block_attributes_for_each_discarded_section(const= RamBlockAttributes *attr, return ret; } =20 -static uint64_t -ram_block_attributes_rdm_get_min_granularity(const RamDiscardManager *rdm, - const MemoryRegion *mr) -{ - const RamBlockAttributes *attr =3D RAM_BLOCK_ATTRIBUTES(rdm); =20 - g_assert(mr =3D=3D attr->ram_block->mr); - return ram_block_attributes_get_block_size(); -} +typedef struct RamBlockAttributesReplayData { + ReplayRamDiscardState fn; + void *opaque; +} RamBlockAttributesReplayData; =20 -static void -ram_block_attributes_rdm_register_listener(RamDiscardManager *rdm, - RamDiscardListener *rdl, - MemoryRegionSection *section) +static int ram_block_attributes_rds_replay_cb(MemoryRegionSection *section, + void *arg) { - RamBlockAttributes *attr =3D RAM_BLOCK_ATTRIBUTES(rdm); - int ret; - - g_assert(section->mr =3D=3D attr->ram_block->mr); - rdl->section =3D memory_region_section_new_copy(section); - - QLIST_INSERT_HEAD(&attr->rdl_list, rdl, next); + RamBlockAttributesReplayData *data =3D arg; =20 - ret =3D ram_block_attributes_for_each_populated_section(attr, section,= rdl, - ram_block_attributes_notify_populate_c= b); - if (ret) { - error_report("%s: Failed to register RAM discard listener: %s", - __func__, strerror(-ret)); - exit(1); - } + return data->fn(section, data->opaque); } =20 -static void -ram_block_attributes_rdm_unregister_listener(RamDiscardManager *rdm, - RamDiscardListener *rdl) +/* RamDiscardSource interface implementation */ +static uint64_t +ram_block_attributes_rds_get_min_granularity(const RamDiscardSource *rds, + const MemoryRegion *mr) { - RamBlockAttributes *attr =3D RAM_BLOCK_ATTRIBUTES(rdm); + const RamBlockAttributes *attr =3D RAM_BLOCK_ATTRIBUTES(rds); =20 - g_assert(rdl->section); - g_assert(rdl->section->mr =3D=3D attr->ram_block->mr); - - rdl->notify_discard(rdl, rdl->section); - - memory_region_section_free_copy(rdl->section); - rdl->section =3D NULL; - QLIST_REMOVE(rdl, next); + g_assert(mr =3D=3D attr->ram_block->mr); + return ram_block_attributes_get_block_size(); } =20 -typedef struct RamBlockAttributesReplayData { - ReplayRamDiscardState fn; - void *opaque; -} RamBlockAttributesReplayData; - -static int ram_block_attributes_rdm_replay_cb(MemoryRegionSection *section, - void *arg) +static bool +ram_block_attributes_rds_is_populated(const RamDiscardSource *rds, + const MemoryRegionSection *section) { - RamBlockAttributesReplayData *data =3D arg; + const RamBlockAttributes *attr =3D RAM_BLOCK_ATTRIBUTES(rds); + const size_t block_size =3D ram_block_attributes_get_block_size(); + const uint64_t first_bit =3D section->offset_within_region / block_siz= e; + const uint64_t last_bit =3D + first_bit + int128_get64(section->size) / block_size - 1; + unsigned long first_discarded_bit; =20 - return data->fn(section, data->opaque); + first_discarded_bit =3D find_next_zero_bit(attr->bitmap, last_bit + 1, + first_bit); + return first_discarded_bit > last_bit; } =20 static int -ram_block_attributes_rdm_replay_populated(const RamDiscardManager *rdm, +ram_block_attributes_rds_replay_populated(const RamDiscardSource *rds, MemoryRegionSection *section, ReplayRamDiscardState replay_fn, void *opaque) { - RamBlockAttributes *attr =3D RAM_BLOCK_ATTRIBUTES(rdm); + RamBlockAttributes *attr =3D RAM_BLOCK_ATTRIBUTES(rds); RamBlockAttributesReplayData data =3D { .fn =3D replay_fn, .opaque =3D= opaque }; =20 g_assert(section->mr =3D=3D attr->ram_block->mr); return ram_block_attributes_for_each_populated_section(attr, section, = &data, - ram_block_attributes_rdm_repla= y_cb); + ram_block_attributes_rds_replay_cb); } =20 static int -ram_block_attributes_rdm_replay_discarded(const RamDiscardManager *rdm, +ram_block_attributes_rds_replay_discarded(const RamDiscardSource *rds, MemoryRegionSection *section, ReplayRamDiscardState replay_fn, void *opaque) { - RamBlockAttributes *attr =3D RAM_BLOCK_ATTRIBUTES(rdm); + RamBlockAttributes *attr =3D RAM_BLOCK_ATTRIBUTES(rds); RamBlockAttributesReplayData data =3D { .fn =3D replay_fn, .opaque =3D= opaque }; =20 g_assert(section->mr =3D=3D attr->ram_block->mr); return ram_block_attributes_for_each_discarded_section(attr, section, = &data, - ram_block_attributes_rdm_repla= y_cb); + ram_block_attributes_rds_replay_cb); } =20 static bool @@ -257,42 +211,23 @@ ram_block_attributes_is_valid_range(RamBlockAttribute= s *attr, uint64_t offset, return true; } =20 -static void ram_block_attributes_notify_discard(RamBlockAttributes *attr, - uint64_t offset, - uint64_t size) +static void +ram_block_attributes_notify_discard(RamBlockAttributes *attr, + uint64_t offset, + uint64_t size) { - RamDiscardListener *rdl; + RamDiscardManager *rdm =3D memory_region_get_ram_discard_manager(attr-= >ram_block->mr); =20 - QLIST_FOREACH(rdl, &attr->rdl_list, next) { - MemoryRegionSection tmp =3D *rdl->section; - - if (!memory_region_section_intersect_range(&tmp, offset, size)) { - continue; - } - rdl->notify_discard(rdl, &tmp); - } + ram_discard_manager_notify_discard(rdm, offset, size); } =20 static int ram_block_attributes_notify_populate(RamBlockAttributes *attr, uint64_t offset, uint64_t size) { - RamDiscardListener *rdl; - int ret =3D 0; - - QLIST_FOREACH(rdl, &attr->rdl_list, next) { - MemoryRegionSection tmp =3D *rdl->section; - - if (!memory_region_section_intersect_range(&tmp, offset, size)) { - continue; - } - ret =3D rdl->notify_populate(rdl, &tmp); - if (ret) { - break; - } - } + RamDiscardManager *rdm =3D memory_region_get_ram_discard_manager(attr-= >ram_block->mr); =20 - return ret; + return ram_discard_manager_notify_populate(rdm, offset, size); } =20 int ram_block_attributes_state_change(RamBlockAttributes *attr, @@ -376,7 +311,8 @@ RamBlockAttributes *ram_block_attributes_create(RAMBloc= k *ram_block) attr =3D RAM_BLOCK_ATTRIBUTES(object_new(TYPE_RAM_BLOCK_ATTRIBUTES)); =20 attr->ram_block =3D ram_block; - if (memory_region_set_ram_discard_manager(mr, RAM_DISCARD_MANAGER(attr= ))) { + + if (memory_region_add_ram_discard_source(mr, RAM_DISCARD_SOURCE(attr))= ) { object_unref(OBJECT(attr)); return NULL; } @@ -391,15 +327,12 @@ void ram_block_attributes_destroy(RamBlockAttributes = *attr) g_assert(attr); =20 g_free(attr->bitmap); - memory_region_set_ram_discard_manager(attr->ram_block->mr, NULL); + memory_region_del_ram_discard_source(attr->ram_block->mr, RAM_DISCARD_= SOURCE(attr)); object_unref(OBJECT(attr)); } =20 static void ram_block_attributes_init(Object *obj) { - RamBlockAttributes *attr =3D RAM_BLOCK_ATTRIBUTES(obj); - - QLIST_INIT(&attr->rdl_list); } =20 static void ram_block_attributes_finalize(Object *obj) @@ -409,12 +342,10 @@ static void ram_block_attributes_finalize(Object *obj) static void ram_block_attributes_class_init(ObjectClass *klass, const void *data) { - RamDiscardManagerClass *rdmc =3D RAM_DISCARD_MANAGER_CLASS(klass); - - rdmc->get_min_granularity =3D ram_block_attributes_rdm_get_min_granula= rity; - rdmc->register_listener =3D ram_block_attributes_rdm_register_listener; - rdmc->unregister_listener =3D ram_block_attributes_rdm_unregister_list= ener; - rdmc->is_populated =3D ram_block_attributes_rdm_is_populated; - rdmc->replay_populated =3D ram_block_attributes_rdm_replay_populated; - rdmc->replay_discarded =3D ram_block_attributes_rdm_replay_discarded; + RamDiscardSourceClass *rdsc =3D RAM_DISCARD_SOURCE_CLASS(klass); + + rdsc->get_min_granularity =3D ram_block_attributes_rds_get_min_granula= rity; + rdsc->is_populated =3D ram_block_attributes_rds_is_populated; + rdsc->replay_populated =3D ram_block_attributes_rds_replay_populated; + rdsc->replay_discarded =3D ram_block_attributes_rds_replay_discarded; } --=20 2.54.0 From nobody Thu Jun 25 06:56:52 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1782218996; cv=none; d=zohomail.com; s=zohoarc; b=jl2yiT4ZbUW3t+H78NThtqcOGbPIka/6kovuBhHEltQiqeNL7s9/9lbIaRTgErd64o1zo5a53cem51mn0BcUxD2emrJ2kYpstXZIRd+WpaRSBgV9OEFCEXe55686HvdqZfAr+wi2UritQzbsfFKwAcjcnU02VHDyi5WSXVBFtgs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1782218996; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=26GxW006B57Bmz6auGLFgrKG9QR6nM+fizoWVeQSqnA=; b=gWSIviVLbT0fPmFIti5O3vq4I6Kb4POI2q9tgjvmq+lG5DOU54o6uJOe2Mt7wf94x5pAjBy0gRSFYmp8le4wySSHSM9GXrRTUknqgTm+DP7UWRXYJOMkhXo+0M7yjPiBhQ7k9EkplLFgJak/IKfn/5DA+0SZSANp7A95bokm7KA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1782218996125823.1839549603317; Tue, 23 Jun 2026 05:49:56 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wc0YY-0004YM-MU; Tue, 23 Jun 2026 08:48:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YW-0004XO-St for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:44 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YO-00070i-B8 for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:41 -0400 Received: from mail-qt1-f198.google.com (mail-qt1-f198.google.com [209.85.160.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-258-JMqoi_1hP9WNqfZCMmPkXQ-1; Tue, 23 Jun 2026 08:48:34 -0400 Received: by mail-qt1-f198.google.com with SMTP id d75a77b69052e-5178aed25baso104500231cf.1 for ; Tue, 23 Jun 2026 05:48:34 -0700 (PDT) Received: from x1.com ([174.91.117.157]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51a51106a09sm22288351cf.0.2026.06.23.05.48.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jun 2026 05:48:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782218915; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=26GxW006B57Bmz6auGLFgrKG9QR6nM+fizoWVeQSqnA=; b=ETj8XbliZuS7vwfS7XaH2pxTVgiK/kY2DojV0ik2EDPD5pCJG5Zvy9QOyK0kXAluPj6fwQ pP8OxxJWUy2ytXmqOAHl66KNZ+1aHArD2OY2HwYFJxtlAAtcSkbquj3V/yhVAK5B2VVVpA 063KGvjZSE5ABH/SsrIP2Q9nc718WqQ= X-MC-Unique: JMqoi_1hP9WNqfZCMmPkXQ-1 X-Mimecast-MFC-AGG-ID: JMqoi_1hP9WNqfZCMmPkXQ_1782218914 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1782218914; x=1782823714; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=26GxW006B57Bmz6auGLFgrKG9QR6nM+fizoWVeQSqnA=; b=eGs7MBPPo2BN/w49ZdyEGz2Y9k5QldByBGVzYWuBGpIjBPfFnp1BZD3vUygTEGnRLD hLh3rrVBwn/anAy2I3bA+UHAZKIauQICA3XiFekASs+gqoJ/JF8VTVN8KfU9oYArSkin kvFQwzCjsx3CeXIvGcXVkUaMgZOWL1qcifOcqr11tkmtrZF6AYyddvU23DnGpMSkFAWd a+KQPWerYqhXkdU5DI9gPH6WYxv2XPm82q13FW6lP/uAJ2LqTSYSuYRtabXoIpqNr/Wp 2w9tj5riBcuVMenDbx8UWfccCC6FbXCds9tOMZM4R4H0C6N/vaYU6EC+JHGrF7msvrnw ssug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782218914; x=1782823714; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=26GxW006B57Bmz6auGLFgrKG9QR6nM+fizoWVeQSqnA=; b=KQRrkiWNzBrSKdToTfIIP5Byxi3iabKleWebcOymNxf4MMQvlp4U+iMsNLiTCsSlFE uOpvRd5aht+MWzoct+wLd8mUHChCloOhGg13QLs5ph2DJQ97AtqqBovaMlygg59MZK3j tyMbxaecsPzyuJJ4GCPmY+3so521pJKXG03laif8gJ6Dql/TzBOoADo4IVDNq39kL/zW iiZqpZhjbtLBaMworcOpXQtVT1x4D3qIgVM1Ro5PR48rvoq3ZdFhF1kbaTBmy7CJsY1w pj6GANCR/r98m7r2JXHoxhup5EvRcsRKHT3tSsrXDzFmGt4pwAYUUVeFYePza2o0sCdc N3cQ== X-Gm-Message-State: AOJu0YxsiqOHFg4n0nfbxuEhlP+bag4SYdAK5rtLiCJBxw2zzjewMgOb m9J6dDtsi548n4abmgJTqZWT0bDp3rlJXqCqhN7Bg1PDiZCVHi3/hg+xYGvT5Nl3MenMwJlcUXd EuP9p+eppVrOPy3EjLg3Ei6ltdhfQjkQPVogPA3YhOFyt4rpNqYK6s0cYh/iKDFTyw+6FM94KCb nCuNntvmgv65z4rPLMUl7ZIdF0BBpilz3+AaVMhQ== X-Gm-Gg: AfdE7cl11q57bRtmuztCLFXGu3DK+S8SuhF92VtOmBVswAFKZ2GqTEbUFLEzbLYFoBt Lo/WSAyzrd3KqMFW0g1fFLz7LgHY7nUx0OyAVKg/MqTMXe/MaGwziaE6AuULaMo3oGCa//1ZdBU uRdrQB/WmN7Uq7xqS2cz6wfZI4EoeOBB9m4kXtWXlOJZ06O6DY6/WRsBumbDXoApXATInxLH8Qy 5oLF1zW2SCe3EdbvoUv95iWoyx9VpctJmuLvVnwWE8OOnNg+c3JECKP2AoJR/7yiCOIuqsT09TT cYXJytuvZ5kiEIe6zIj/5XVktUN2a+M1NwbHaX0zDiESlWHtv1F5SKJUyiqXinZcew/y441hvr4 kKQ== X-Received: by 2002:ac8:5f47:0:b0:517:6b9c:58e4 with SMTP id d75a77b69052e-51a548cd7d8mr40713521cf.51.1782218913202; Tue, 23 Jun 2026 05:48:33 -0700 (PDT) X-Received: by 2002:ac8:5f47:0:b0:517:6b9c:58e4 with SMTP id d75a77b69052e-51a548cd7d8mr40712501cf.51.1782218912104; Tue, 23 Jun 2026 05:48:32 -0700 (PDT) From: Peter Xu To: qemu-devel@nongnu.org Cc: Peter Xu , Fabiano Rosas , Paolo Bonzini , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , David Hildenbrand , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Subject: [PULL 09/18] system/memory: move RamDiscardManager to separate compilation unit Date: Tue, 23 Jun 2026 08:47:50 -0400 Message-ID: <20260623124759.125399-10-peterx@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260623124759.125399-1-peterx@redhat.com> References: <20260623124759.125399-1-peterx@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=peterx@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1782218997717158500 From: Marc-Andr=C3=A9 Lureau Extract RamDiscardManager and RamDiscardSource from system/memory.c into dedicated a unit. This reduces coupling and allows code that only needs the RamDiscardManager interface to avoid pulling in all of memory.h dependencies. rust-sys bindings are no longer generated for RamDiscardSourceClass at this point, thus we drop the unneeded InterfaceClass use. Reviewed-by: Peter Xu Acked-by: David Hildenbrand Signed-off-by: Marc-Andr=C3=A9 Lureau Reviewed-by: Philippe Mathieu-Daud=C3=A9 Link: https://lore.kernel.org/r/20260604-rdm5-v5-2-5768e6a0943d@redhat.com Signed-off-by: Peter Xu --- MAINTAINERS | 2 + include/system/memory.h | 280 +------------------------ include/system/ram-discard-manager.h | 297 +++++++++++++++++++++++++++ system/memory.c | 221 -------------------- system/ram-discard-manager.c | 240 ++++++++++++++++++++++ rust/bindings/system-sys/lib.rs | 2 +- system/meson.build | 1 + 7 files changed, 542 insertions(+), 501 deletions(-) create mode 100644 include/system/ram-discard-manager.h create mode 100644 system/ram-discard-manager.c diff --git a/MAINTAINERS b/MAINTAINERS index d609692d9a..18b659a44c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3350,6 +3350,7 @@ F: include/system/memory.h F: include/system/memory_cached.h F: include/system/memory_ldst* F: include/system/physmem.h +F: include/system/ram-discard-manager.h F: include/system/ramblock.h F: include/system/memory_mapping.h F: system/dma-helpers.c @@ -3360,6 +3361,7 @@ F: system/physmem.c F: system/memory_ldst* F: system/memory-internal.h F: system/ram-block-attributes.c +F: system/ram-discard-manager.c F: scripts/coccinelle/memory-region-housekeeping.cocci =20 Memory devices diff --git a/include/system/memory.h b/include/system/memory.h index ffdf95f2f2..4a700cb657 100644 --- a/include/system/memory.h +++ b/include/system/memory.h @@ -16,6 +16,7 @@ =20 #include "exec/hwaddr.h" #include "system/ram_addr.h" +#include "system/ram-discard-manager.h" #include "exec/memattrs.h" #include "exec/memop.h" #include "qemu/bswap.h" @@ -45,18 +46,6 @@ typedef struct IOMMUMemoryRegionClass IOMMUMemoryRegionC= lass; DECLARE_OBJ_CHECKERS(IOMMUMemoryRegion, IOMMUMemoryRegionClass, IOMMU_MEMORY_REGION, TYPE_IOMMU_MEMORY_REGION) =20 -#define TYPE_RAM_DISCARD_MANAGER "ram-discard-manager" -typedef struct RamDiscardManagerClass RamDiscardManagerClass; -typedef struct RamDiscardManager RamDiscardManager; -DECLARE_OBJ_CHECKERS(RamDiscardManager, RamDiscardManagerClass, - RAM_DISCARD_MANAGER, TYPE_RAM_DISCARD_MANAGER); - -#define TYPE_RAM_DISCARD_SOURCE "ram-discard-source" -typedef struct RamDiscardSourceClass RamDiscardSourceClass; -typedef struct RamDiscardSource RamDiscardSource; -DECLARE_OBJ_CHECKERS(RamDiscardSource, RamDiscardSourceClass, - RAM_DISCARD_SOURCE, TYPE_RAM_DISCARD_SOURCE); - #ifdef CONFIG_FUZZ void fuzz_dma_read_cb(size_t addr, size_t len, @@ -545,273 +534,6 @@ struct IOMMUMemoryRegionClass { int (*num_indexes)(IOMMUMemoryRegion *iommu); }; =20 -typedef struct RamDiscardListener RamDiscardListener; -typedef int (*NotifyRamPopulate)(RamDiscardListener *rdl, - MemoryRegionSection *section); -typedef void (*NotifyRamDiscard)(RamDiscardListener *rdl, - MemoryRegionSection *section); - -struct RamDiscardListener { - /* - * @notify_populate: - * - * Notification that previously discarded memory is about to get popul= ated. - * Listeners are able to object. If any listener objects, already - * successfully notified listeners are notified about a discard again. - * - * @rdl: the #RamDiscardListener getting notified - * @section: the #MemoryRegionSection to get populated. The section - * is aligned within the memory region to the minimum granul= arity - * unless it would exceed the registered section. - * - * Returns 0 on success. If the notification is rejected by the listen= er, - * an error is returned. - */ - NotifyRamPopulate notify_populate; - - /* - * @notify_discard: - * - * Notification that previously populated memory was discarded success= fully - * and listeners should drop all references to such memory and prevent - * new population (e.g., unmap). - * - * @rdl: the #RamDiscardListener getting notified - * @section: the #MemoryRegionSection to get discarded. The section - * is aligned within the memory region to the minimum granul= arity - * unless it would exceed the registered section. - */ - NotifyRamDiscard notify_discard; - - MemoryRegionSection *section; - QLIST_ENTRY(RamDiscardListener) next; -}; - -static inline void ram_discard_listener_init(RamDiscardListener *rdl, - NotifyRamPopulate populate_fn, - NotifyRamDiscard discard_fn) -{ - rdl->notify_populate =3D populate_fn; - rdl->notify_discard =3D discard_fn; -} - -/** - * typedef ReplayRamDiscardState: - * - * The callback handler for #RamDiscardSourceClass.replay_populated/ - * #RamDiscardSourceClass.replay_discarded to invoke on populated/discarded - * parts. - * - * @section: the #MemoryRegionSection of populated/discarded part - * @opaque: pointer to forward to the callback - * - * Returns 0 on success, or a negative error if failed. - */ -typedef int (*ReplayRamDiscardState)(MemoryRegionSection *section, - void *opaque); - -/* - * RamDiscardSourceClass: - * - * A #RamDiscardSource provides information about which parts of a specific - * RAM #MemoryRegion are currently populated (accessible) vs discarded. - * - * This is an interface that state providers (like virtio-mem or - * RamBlockAttributes) implement to provide discard state information. A - * #RamDiscardManager wraps sources and manages listener registrations and - * notifications. - */ -struct RamDiscardSourceClass { - /* private */ - InterfaceClass parent_class; - - /* public */ - - /** - * @get_min_granularity: - * - * Get the minimum granularity in which listeners will get notified - * about changes within the #MemoryRegion via the #RamDiscardSource. - * - * @rds: the #RamDiscardSource - * @mr: the #MemoryRegion - * - * Returns the minimum granularity. - */ - uint64_t (*get_min_granularity)(const RamDiscardSource *rds, - const MemoryRegion *mr); - - /** - * @is_populated: - * - * Check whether the given #MemoryRegionSection is completely populated - * (i.e., no parts are currently discarded) via the #RamDiscardSource. - * There are no alignment requirements. - * - * @rds: the #RamDiscardSource - * @section: the #MemoryRegionSection - * - * Returns whether the given range is completely populated. - */ - bool (*is_populated)(const RamDiscardSource *rds, - const MemoryRegionSection *section); - - /** - * @replay_populated: - * - * Call the #ReplayRamDiscardState callback for all populated parts wi= thin - * the #MemoryRegionSection via the #RamDiscardSource. - * - * In case any call fails, no further calls are made. - * - * @rds: the #RamDiscardSource - * @section: the #MemoryRegionSection - * @replay_fn: the #ReplayRamDiscardState callback - * @opaque: pointer to forward to the callback - * - * Returns 0 on success, or a negative error if any notification faile= d. - */ - int (*replay_populated)(const RamDiscardSource *rds, - MemoryRegionSection *section, - ReplayRamDiscardState replay_fn, void *opaque); - - /** - * @replay_discarded: - * - * Call the #ReplayRamDiscardState callback for all discarded parts wi= thin - * the #MemoryRegionSection via the #RamDiscardSource. - * - * @rds: the #RamDiscardSource - * @section: the #MemoryRegionSection - * @replay_fn: the #ReplayRamDiscardState callback - * @opaque: pointer to forward to the callback - * - * Returns 0 on success, or a negative error if any notification faile= d. - */ - int (*replay_discarded)(const RamDiscardSource *rds, - MemoryRegionSection *section, - ReplayRamDiscardState replay_fn, void *opaque); -}; - -/** - * RamDiscardManager: - * - * A #RamDiscardManager coordinates which parts of specific RAM #MemoryReg= ion - * regions are currently populated to be used/accessed by the VM, notifying - * after parts were discarded (freeing up memory) and before parts will be - * populated (consuming memory), to be used/accessed by the VM. - * - * A #RamDiscardManager can only be set for a RAM #MemoryRegion while the - * #MemoryRegion isn't mapped into an address space yet (either directly - * or via an alias); it cannot change while the #MemoryRegion is - * mapped into an address space. - * - * The #RamDiscardManager is intended to be used by technologies that are - * incompatible with discarding of RAM (e.g., VFIO, which may pin all - * memory inside a #MemoryRegion), and require proper coordination to only - * map the currently populated parts, to hinder parts that are expected to - * remain discarded from silently getting populated and consuming memory. - * Technologies that support discarding of RAM don't have to bother and can - * simply map the whole #MemoryRegion. - * - * An example #RamDiscardSource is virtio-mem, which logically (un)plugs - * memory within an assigned RAM #MemoryRegion, coordinated with the VM. - * Logically unplugging memory consists of discarding RAM. The VM agreed t= o not - * access unplugged (discarded) memory - especially via DMA. virtio-mem wi= ll - * properly coordinate with listeners before memory is plugged (populated), - * and after memory is unplugged (discarded). - * - * Listeners are called in multiples of the minimum granularity (unless it - * would exceed the registered range) and changes are aligned to the minim= um - * granularity within the #MemoryRegion. Listeners have to prepare for mem= ory - * becoming discarded in a different granularity than it was populated and= the - * other way around. - */ -struct RamDiscardManager { - Object parent; - - RamDiscardSource *rds; - MemoryRegion *mr; - QLIST_HEAD(, RamDiscardListener) rdl_list; -}; - -uint64_t ram_discard_manager_get_min_granularity(const RamDiscardManager *= rdm, - const MemoryRegion *mr); - -bool ram_discard_manager_is_populated(const RamDiscardManager *rdm, - const MemoryRegionSection *section); - -/** - * ram_discard_manager_replay_populated: - * - * A wrapper to call the #RamDiscardSourceClass.replay_populated callback - * of the #RamDiscardSource sources. - * - * @rdm: the #RamDiscardManager - * @section: the #MemoryRegionSection - * @replay_fn: the #ReplayRamDiscardState callback - * @opaque: pointer to forward to the callback - * - * Returns 0 on success, or a negative error if any notification failed. - */ -int ram_discard_manager_replay_populated(const RamDiscardManager *rdm, - MemoryRegionSection *section, - ReplayRamDiscardState replay_fn, - void *opaque); - -/** - * ram_discard_manager_replay_discarded: - * - * A wrapper to call the #RamDiscardSourceClass.replay_discarded callback - * of the #RamDiscardSource sources. - * - * @rdm: the #RamDiscardManager - * @section: the #MemoryRegionSection - * @replay_fn: the #ReplayRamDiscardState callback - * @opaque: pointer to forward to the callback - * - * Returns 0 on success, or a negative error if any notification failed. - */ -int ram_discard_manager_replay_discarded(const RamDiscardManager *rdm, - MemoryRegionSection *section, - ReplayRamDiscardState replay_fn, - void *opaque); - -void ram_discard_manager_register_listener(RamDiscardManager *rdm, - RamDiscardListener *rdl, - MemoryRegionSection *section); - -void ram_discard_manager_unregister_listener(RamDiscardManager *rdm, - RamDiscardListener *rdl); - -/* - * Note: later refactoring should take the source into account and the man= ager - * should be able to aggregate multiple sources. - */ -int ram_discard_manager_notify_populate(RamDiscardManager *rdm, - uint64_t offset, uint64_t size); - - /* - * Note: later refactoring should take the source into account and the ma= nager - * should be able to aggregate multiple sources. - */ -void ram_discard_manager_notify_discard(RamDiscardManager *rdm, - uint64_t offset, uint64_t size); - -/* - * Note: later refactoring should take the source into account and the man= ager - * should be able to aggregate multiple sources. - */ -void ram_discard_manager_notify_discard_all(RamDiscardManager *rdm); - -/* - * Replay populated sections to all registered listeners. - * - * Note: later refactoring should take the source into account and the man= ager - * should be able to aggregate multiple sources. - */ -int ram_discard_manager_replay_populated_to_listeners(RamDiscardManager *r= dm); - /** * memory_translate_iotlb: Extract addresses from a TLB entry. * Called with rcu_read_lock held. diff --git a/include/system/ram-discard-manager.h b/include/system/ram-disc= ard-manager.h new file mode 100644 index 0000000000..da55658169 --- /dev/null +++ b/include/system/ram-discard-manager.h @@ -0,0 +1,297 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * RAM Discard Manager + * + * Copyright Red Hat, Inc. 2026 + */ + +#ifndef RAM_DISCARD_MANAGER_H +#define RAM_DISCARD_MANAGER_H + +#include "qemu/typedefs.h" +#include "qom/object.h" +#include "qemu/queue.h" + +#define TYPE_RAM_DISCARD_MANAGER "ram-discard-manager" +typedef struct RamDiscardManagerClass RamDiscardManagerClass; +typedef struct RamDiscardManager RamDiscardManager; +DECLARE_OBJ_CHECKERS(RamDiscardManager, RamDiscardManagerClass, + RAM_DISCARD_MANAGER, TYPE_RAM_DISCARD_MANAGER); + +#define TYPE_RAM_DISCARD_SOURCE "ram-discard-source" +typedef struct RamDiscardSourceClass RamDiscardSourceClass; +typedef struct RamDiscardSource RamDiscardSource; +DECLARE_OBJ_CHECKERS(RamDiscardSource, RamDiscardSourceClass, + RAM_DISCARD_SOURCE, TYPE_RAM_DISCARD_SOURCE); + +typedef struct RamDiscardListener RamDiscardListener; +typedef int (*NotifyRamPopulate)(RamDiscardListener *rdl, + MemoryRegionSection *section); +typedef void (*NotifyRamDiscard)(RamDiscardListener *rdl, + MemoryRegionSection *section); + +struct RamDiscardListener { + /* + * @notify_populate: + * + * Notification that previously discarded memory is about to get popul= ated. + * Listeners are able to object. If any listener objects, already + * successfully notified listeners are notified about a discard again. + * + * @rdl: the #RamDiscardListener getting notified + * @section: the #MemoryRegionSection to get populated. The section + * is aligned within the memory region to the minimum granul= arity + * unless it would exceed the registered section. + * + * Returns 0 on success. If the notification is rejected by the listen= er, + * an error is returned. + */ + NotifyRamPopulate notify_populate; + + /* + * @notify_discard: + * + * Notification that previously populated memory was discarded success= fully + * and listeners should drop all references to such memory and prevent + * new population (e.g., unmap). + * + * @rdl: the #RamDiscardListener getting notified + * @section: the #MemoryRegionSection to get discarded. The section + * is aligned within the memory region to the minimum granul= arity + * unless it would exceed the registered section. + */ + NotifyRamDiscard notify_discard; + + MemoryRegionSection *section; + QLIST_ENTRY(RamDiscardListener) next; +}; + +static inline void ram_discard_listener_init(RamDiscardListener *rdl, + NotifyRamPopulate populate_fn, + NotifyRamDiscard discard_fn) +{ + rdl->notify_populate =3D populate_fn; + rdl->notify_discard =3D discard_fn; +} + +/** + * typedef ReplayRamDiscardState: + * + * The callback handler for #RamDiscardSourceClass.replay_populated/ + * #RamDiscardSourceClass.replay_discarded to invoke on populated/discarded + * parts. + * + * @section: the #MemoryRegionSection of populated/discarded part + * @opaque: pointer to forward to the callback + * + * Returns 0 on success, or a negative error if failed. + */ +typedef int (*ReplayRamDiscardState)(MemoryRegionSection *section, + void *opaque); + +/* + * RamDiscardSourceClass: + * + * A #RamDiscardSource provides information about which parts of a specific + * RAM #MemoryRegion are currently populated (accessible) vs discarded. + * + * This is an interface that state providers (like virtio-mem or + * RamBlockAttributes) implement to provide discard state information. A + * #RamDiscardManager wraps sources and manages listener registrations and + * notifications. + */ +struct RamDiscardSourceClass { + /* private */ + InterfaceClass parent_class; + + /* public */ + + /** + * @get_min_granularity: + * + * Get the minimum granularity in which listeners will get notified + * about changes within the #MemoryRegion via the #RamDiscardSource. + * + * @rds: the #RamDiscardSource + * @mr: the #MemoryRegion + * + * Returns the minimum granularity. + */ + uint64_t (*get_min_granularity)(const RamDiscardSource *rds, + const MemoryRegion *mr); + + /** + * @is_populated: + * + * Check whether the given #MemoryRegionSection is completely populated + * (i.e., no parts are currently discarded) via the #RamDiscardSource. + * There are no alignment requirements. + * + * @rds: the #RamDiscardSource + * @section: the #MemoryRegionSection + * + * Returns whether the given range is completely populated. + */ + bool (*is_populated)(const RamDiscardSource *rds, + const MemoryRegionSection *section); + + /** + * @replay_populated: + * + * Call the #ReplayRamDiscardState callback for all populated parts wi= thin + * the #MemoryRegionSection via the #RamDiscardSource. + * + * In case any call fails, no further calls are made. + * + * @rds: the #RamDiscardSource + * @section: the #MemoryRegionSection + * @replay_fn: the #ReplayRamDiscardState callback + * @opaque: pointer to forward to the callback + * + * Returns 0 on success, or a negative error if any notification faile= d. + */ + int (*replay_populated)(const RamDiscardSource *rds, + MemoryRegionSection *section, + ReplayRamDiscardState replay_fn, void *opaque); + + /** + * @replay_discarded: + * + * Call the #ReplayRamDiscardState callback for all discarded parts wi= thin + * the #MemoryRegionSection via the #RamDiscardSource. + * + * @rds: the #RamDiscardSource + * @section: the #MemoryRegionSection + * @replay_fn: the #ReplayRamDiscardState callback + * @opaque: pointer to forward to the callback + * + * Returns 0 on success, or a negative error if any notification faile= d. + */ + int (*replay_discarded)(const RamDiscardSource *rds, + MemoryRegionSection *section, + ReplayRamDiscardState replay_fn, void *opaque); +}; + +/** + * RamDiscardManager: + * + * A #RamDiscardManager coordinates which parts of specific RAM #MemoryReg= ion + * regions are currently populated to be used/accessed by the VM, notifying + * after parts were discarded (freeing up memory) and before parts will be + * populated (consuming memory), to be used/accessed by the VM. + * + * A #RamDiscardManager can only be set for a RAM #MemoryRegion while the + * #MemoryRegion isn't mapped into an address space yet (either directly + * or via an alias); it cannot change while the #MemoryRegion is + * mapped into an address space. + * + * The #RamDiscardManager is intended to be used by technologies that are + * incompatible with discarding of RAM (e.g., VFIO, which may pin all + * memory inside a #MemoryRegion), and require proper coordination to only + * map the currently populated parts, to hinder parts that are expected to + * remain discarded from silently getting populated and consuming memory. + * Technologies that support discarding of RAM don't have to bother and can + * simply map the whole #MemoryRegion. + * + * An example #RamDiscardSource is virtio-mem, which logically (un)plugs + * memory within an assigned RAM #MemoryRegion, coordinated with the VM. + * Logically unplugging memory consists of discarding RAM. The VM agreed t= o not + * access unplugged (discarded) memory - especially via DMA. virtio-mem wi= ll + * properly coordinate with listeners before memory is plugged (populated), + * and after memory is unplugged (discarded). + * + * Listeners are called in multiples of the minimum granularity (unless it + * would exceed the registered range) and changes are aligned to the minim= um + * granularity within the #MemoryRegion. Listeners have to prepare for mem= ory + * becoming discarded in a different granularity than it was populated and= the + * other way around. + */ +struct RamDiscardManager { + Object parent; + + RamDiscardSource *rds; + MemoryRegion *mr; + QLIST_HEAD(, RamDiscardListener) rdl_list; +}; + +RamDiscardManager *ram_discard_manager_new(MemoryRegion *mr, + RamDiscardSource *rds); + +uint64_t ram_discard_manager_get_min_granularity(const RamDiscardManager *= rdm, + const MemoryRegion *mr); + +bool ram_discard_manager_is_populated(const RamDiscardManager *rdm, + const MemoryRegionSection *section); + +/** + * ram_discard_manager_replay_populated: + * + * A wrapper to call the #RamDiscardSourceClass.replay_populated callback + * of the #RamDiscardSource sources. + * + * @rdm: the #RamDiscardManager + * @section: the #MemoryRegionSection + * @replay_fn: the #ReplayRamDiscardState callback + * @opaque: pointer to forward to the callback + * + * Returns 0 on success, or a negative error if any notification failed. + */ +int ram_discard_manager_replay_populated(const RamDiscardManager *rdm, + MemoryRegionSection *section, + ReplayRamDiscardState replay_fn, + void *opaque); + +/** + * ram_discard_manager_replay_discarded: + * + * A wrapper to call the #RamDiscardSourceClass.replay_discarded callback + * of the #RamDiscardSource sources. + * + * @rdm: the #RamDiscardManager + * @section: the #MemoryRegionSection + * @replay_fn: the #ReplayRamDiscardState callback + * @opaque: pointer to forward to the callback + * + * Returns 0 on success, or a negative error if any notification failed. + */ +int ram_discard_manager_replay_discarded(const RamDiscardManager *rdm, + MemoryRegionSection *section, + ReplayRamDiscardState replay_fn, + void *opaque); + +void ram_discard_manager_register_listener(RamDiscardManager *rdm, + RamDiscardListener *rdl, + MemoryRegionSection *section); + +void ram_discard_manager_unregister_listener(RamDiscardManager *rdm, + RamDiscardListener *rdl); + +/* + * Note: later refactoring should take the source into account and the man= ager + * should be able to aggregate multiple sources. + */ +int ram_discard_manager_notify_populate(RamDiscardManager *rdm, + uint64_t offset, uint64_t size); + +/* + * Note: later refactoring should take the source into account and the man= ager + * should be able to aggregate multiple sources. + */ +void ram_discard_manager_notify_discard(RamDiscardManager *rdm, + uint64_t offset, uint64_t size); + +/* + * Note: later refactoring should take the source into account and the man= ager + * should be able to aggregate multiple sources. + */ +void ram_discard_manager_notify_discard_all(RamDiscardManager *rdm); + +/* + * Replay populated sections to all registered listeners. + * + * Note: later refactoring should take the source into account and the man= ager + * should be able to aggregate multiple sources. + */ +int ram_discard_manager_replay_populated_to_listeners(RamDiscardManager *r= dm); + +#endif /* RAM_DISCARD_MANAGER_H */ diff --git a/system/memory.c b/system/memory.c index 52946c5e5d..5a598ca58c 100644 --- a/system/memory.c +++ b/system/memory.c @@ -2069,17 +2069,6 @@ RamDiscardManager *memory_region_get_ram_discard_man= ager(MemoryRegion *mr) return mr->rdm; } =20 -static RamDiscardManager *ram_discard_manager_new(MemoryRegion *mr, - RamDiscardSource *rds) -{ - RamDiscardManager *rdm =3D RAM_DISCARD_MANAGER(object_new(TYPE_RAM_DIS= CARD_MANAGER)); - - rdm->rds =3D rds; - rdm->mr =3D mr; - QLIST_INIT(&rdm->rdl_list); - return rdm; -} - int memory_region_add_ram_discard_source(MemoryRegion *mr, RamDiscardSource *source) { @@ -2101,200 +2090,6 @@ void memory_region_del_ram_discard_source(MemoryReg= ion *mr, mr->rdm =3D NULL; } =20 -static uint64_t ram_discard_source_get_min_granularity(const RamDiscardSou= rce *rds, - const MemoryRegion = *mr) -{ - RamDiscardSourceClass *rdsc =3D RAM_DISCARD_SOURCE_GET_CLASS(rds); - - g_assert(rdsc->get_min_granularity); - return rdsc->get_min_granularity(rds, mr); -} - -static bool ram_discard_source_is_populated(const RamDiscardSource *rds, - const MemoryRegionSection *sec= tion) -{ - RamDiscardSourceClass *rdsc =3D RAM_DISCARD_SOURCE_GET_CLASS(rds); - - g_assert(rdsc->is_populated); - return rdsc->is_populated(rds, section); -} - -static int ram_discard_source_replay_populated(const RamDiscardSource *rds, - MemoryRegionSection *sectio= n, - ReplayRamDiscardState repla= y_fn, - void *opaque) -{ - RamDiscardSourceClass *rdsc =3D RAM_DISCARD_SOURCE_GET_CLASS(rds); - - g_assert(rdsc->replay_populated); - return rdsc->replay_populated(rds, section, replay_fn, opaque); -} - -static int ram_discard_source_replay_discarded(const RamDiscardSource *rds, - MemoryRegionSection *sectio= n, - ReplayRamDiscardState repla= y_fn, - void *opaque) -{ - RamDiscardSourceClass *rdsc =3D RAM_DISCARD_SOURCE_GET_CLASS(rds); - - g_assert(rdsc->replay_discarded); - return rdsc->replay_discarded(rds, section, replay_fn, opaque); -} - -uint64_t ram_discard_manager_get_min_granularity(const RamDiscardManager *= rdm, - const MemoryRegion *mr) -{ - return ram_discard_source_get_min_granularity(rdm->rds, mr); -} - -bool ram_discard_manager_is_populated(const RamDiscardManager *rdm, - const MemoryRegionSection *section) -{ - return ram_discard_source_is_populated(rdm->rds, section); -} - -int ram_discard_manager_replay_populated(const RamDiscardManager *rdm, - MemoryRegionSection *section, - ReplayRamDiscardState replay_fn, - void *opaque) -{ - return ram_discard_source_replay_populated(rdm->rds, section, replay_f= n, opaque); -} - -int ram_discard_manager_replay_discarded(const RamDiscardManager *rdm, - MemoryRegionSection *section, - ReplayRamDiscardState replay_fn, - void *opaque) -{ - return ram_discard_source_replay_discarded(rdm->rds, section, replay_f= n, opaque); -} - -static void ram_discard_manager_initfn(Object *obj) -{ - RamDiscardManager *rdm =3D RAM_DISCARD_MANAGER(obj); - - QLIST_INIT(&rdm->rdl_list); -} - -static void ram_discard_manager_finalize(Object *obj) -{ - RamDiscardManager *rdm =3D RAM_DISCARD_MANAGER(obj); - - g_assert(QLIST_EMPTY(&rdm->rdl_list)); -} - -int ram_discard_manager_notify_populate(RamDiscardManager *rdm, - uint64_t offset, uint64_t size) -{ - RamDiscardListener *rdl, *rdl2; - int ret =3D 0; - - QLIST_FOREACH(rdl, &rdm->rdl_list, next) { - MemoryRegionSection tmp =3D *rdl->section; - - if (!memory_region_section_intersect_range(&tmp, offset, size)) { - continue; - } - ret =3D rdl->notify_populate(rdl, &tmp); - if (ret) { - break; - } - } - - if (ret) { - /* Notify all already-notified listeners about discard. */ - QLIST_FOREACH(rdl2, &rdm->rdl_list, next) { - MemoryRegionSection tmp =3D *rdl2->section; - - if (rdl2 =3D=3D rdl) { - break; - } - if (!memory_region_section_intersect_range(&tmp, offset, size)= ) { - continue; - } - rdl2->notify_discard(rdl2, &tmp); - } - } - return ret; -} - -void ram_discard_manager_notify_discard(RamDiscardManager *rdm, - uint64_t offset, uint64_t size) -{ - RamDiscardListener *rdl; - - QLIST_FOREACH(rdl, &rdm->rdl_list, next) { - MemoryRegionSection tmp =3D *rdl->section; - - if (!memory_region_section_intersect_range(&tmp, offset, size)) { - continue; - } - rdl->notify_discard(rdl, &tmp); - } -} - -void ram_discard_manager_notify_discard_all(RamDiscardManager *rdm) -{ - RamDiscardListener *rdl; - - QLIST_FOREACH(rdl, &rdm->rdl_list, next) { - rdl->notify_discard(rdl, rdl->section); - } -} - -static int rdm_populate_cb(MemoryRegionSection *section, void *opaque) -{ - RamDiscardListener *rdl =3D opaque; - - return rdl->notify_populate(rdl, section); -} - -void ram_discard_manager_register_listener(RamDiscardManager *rdm, - RamDiscardListener *rdl, - MemoryRegionSection *section) -{ - int ret; - - g_assert(section->mr =3D=3D rdm->mr); - - rdl->section =3D memory_region_section_new_copy(section); - QLIST_INSERT_HEAD(&rdm->rdl_list, rdl, next); - - ret =3D ram_discard_source_replay_populated(rdm->rds, rdl->section, - rdm_populate_cb, rdl); - if (ret) { - error_report("%s: Replaying populated ranges failed: %s", __func__, - strerror(-ret)); - } -} - -void ram_discard_manager_unregister_listener(RamDiscardManager *rdm, - RamDiscardListener *rdl) -{ - g_assert(rdl->section); - g_assert(rdl->section->mr =3D=3D rdm->mr); - - rdl->notify_discard(rdl, rdl->section); - memory_region_section_free_copy(rdl->section); - rdl->section =3D NULL; - QLIST_REMOVE(rdl, next); -} - -int ram_discard_manager_replay_populated_to_listeners(RamDiscardManager *r= dm) -{ - RamDiscardListener *rdl; - int ret =3D 0; - - QLIST_FOREACH(rdl, &rdm->rdl_list, next) { - ret =3D ram_discard_source_replay_populated(rdm->rds, rdl->section, - rdm_populate_cb, rdl); - if (ret) { - break; - } - } - return ret; -} - /* Called with rcu_read_lock held. */ MemoryRegion *memory_translate_iotlb(IOMMUTLBEntry *iotlb, hwaddr *xlat_p, Error **errp) @@ -3924,26 +3719,10 @@ static const TypeInfo iommu_memory_region_info =3D { .abstract =3D true, }; =20 -static const TypeInfo ram_discard_manager_info =3D { - .parent =3D TYPE_OBJECT, - .name =3D TYPE_RAM_DISCARD_MANAGER, - .instance_size =3D sizeof(RamDiscardManager), - .instance_init =3D ram_discard_manager_initfn, - .instance_finalize =3D ram_discard_manager_finalize, -}; - -static const TypeInfo ram_discard_source_info =3D { - .parent =3D TYPE_INTERFACE, - .name =3D TYPE_RAM_DISCARD_SOURCE, - .class_size =3D sizeof(RamDiscardSourceClass), -}; - static void memory_register_types(void) { type_register_static(&memory_region_info); type_register_static(&iommu_memory_region_info); - type_register_static(&ram_discard_manager_info); - type_register_static(&ram_discard_source_info); } =20 type_init(memory_register_types) diff --git a/system/ram-discard-manager.c b/system/ram-discard-manager.c new file mode 100644 index 0000000000..3d8c85617d --- /dev/null +++ b/system/ram-discard-manager.c @@ -0,0 +1,240 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * RAM Discard Manager + * + * Copyright Red Hat, Inc. 2026 + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "system/memory.h" + +static uint64_t ram_discard_source_get_min_granularity(const RamDiscardSou= rce *rds, + const MemoryRegion = *mr) +{ + RamDiscardSourceClass *rdsc =3D RAM_DISCARD_SOURCE_GET_CLASS(rds); + + g_assert(rdsc->get_min_granularity); + return rdsc->get_min_granularity(rds, mr); +} + +static bool ram_discard_source_is_populated(const RamDiscardSource *rds, + const MemoryRegionSection *sec= tion) +{ + RamDiscardSourceClass *rdsc =3D RAM_DISCARD_SOURCE_GET_CLASS(rds); + + g_assert(rdsc->is_populated); + return rdsc->is_populated(rds, section); +} + +static int ram_discard_source_replay_populated(const RamDiscardSource *rds, + MemoryRegionSection *sectio= n, + ReplayRamDiscardState repla= y_fn, + void *opaque) +{ + RamDiscardSourceClass *rdsc =3D RAM_DISCARD_SOURCE_GET_CLASS(rds); + + g_assert(rdsc->replay_populated); + return rdsc->replay_populated(rds, section, replay_fn, opaque); +} + +static int ram_discard_source_replay_discarded(const RamDiscardSource *rds, + MemoryRegionSection *sectio= n, + ReplayRamDiscardState repla= y_fn, + void *opaque) +{ + RamDiscardSourceClass *rdsc =3D RAM_DISCARD_SOURCE_GET_CLASS(rds); + + g_assert(rdsc->replay_discarded); + return rdsc->replay_discarded(rds, section, replay_fn, opaque); +} + +RamDiscardManager *ram_discard_manager_new(MemoryRegion *mr, + RamDiscardSource *rds) +{ + RamDiscardManager *rdm; + + rdm =3D RAM_DISCARD_MANAGER(object_new(TYPE_RAM_DISCARD_MANAGER)); + rdm->rds =3D rds; + rdm->mr =3D mr; + QLIST_INIT(&rdm->rdl_list); + return rdm; +} + +uint64_t ram_discard_manager_get_min_granularity(const RamDiscardManager *= rdm, + const MemoryRegion *mr) +{ + return ram_discard_source_get_min_granularity(rdm->rds, mr); +} + +bool ram_discard_manager_is_populated(const RamDiscardManager *rdm, + const MemoryRegionSection *section) +{ + return ram_discard_source_is_populated(rdm->rds, section); +} + +int ram_discard_manager_replay_populated(const RamDiscardManager *rdm, + MemoryRegionSection *section, + ReplayRamDiscardState replay_fn, + void *opaque) +{ + return ram_discard_source_replay_populated(rdm->rds, section, + replay_fn, opaque); +} + +int ram_discard_manager_replay_discarded(const RamDiscardManager *rdm, + MemoryRegionSection *section, + ReplayRamDiscardState replay_fn, + void *opaque) +{ + return ram_discard_source_replay_discarded(rdm->rds, section, + replay_fn, opaque); +} + +static void ram_discard_manager_initfn(Object *obj) +{ + RamDiscardManager *rdm =3D RAM_DISCARD_MANAGER(obj); + + QLIST_INIT(&rdm->rdl_list); +} + +static void ram_discard_manager_finalize(Object *obj) +{ + RamDiscardManager *rdm =3D RAM_DISCARD_MANAGER(obj); + + g_assert(QLIST_EMPTY(&rdm->rdl_list)); +} + +int ram_discard_manager_notify_populate(RamDiscardManager *rdm, + uint64_t offset, uint64_t size) +{ + RamDiscardListener *rdl, *rdl2; + int ret =3D 0; + + QLIST_FOREACH(rdl, &rdm->rdl_list, next) { + MemoryRegionSection tmp =3D *rdl->section; + + if (!memory_region_section_intersect_range(&tmp, offset, size)) { + continue; + } + ret =3D rdl->notify_populate(rdl, &tmp); + if (ret) { + break; + } + } + + if (ret) { + /* Notify all already-notified listeners about discard. */ + QLIST_FOREACH(rdl2, &rdm->rdl_list, next) { + MemoryRegionSection tmp =3D *rdl2->section; + + if (rdl2 =3D=3D rdl) { + break; + } + if (!memory_region_section_intersect_range(&tmp, offset, size)= ) { + continue; + } + rdl2->notify_discard(rdl2, &tmp); + } + } + return ret; +} + +void ram_discard_manager_notify_discard(RamDiscardManager *rdm, + uint64_t offset, uint64_t size) +{ + RamDiscardListener *rdl; + + QLIST_FOREACH(rdl, &rdm->rdl_list, next) { + MemoryRegionSection tmp =3D *rdl->section; + + if (!memory_region_section_intersect_range(&tmp, offset, size)) { + continue; + } + rdl->notify_discard(rdl, &tmp); + } +} + +void ram_discard_manager_notify_discard_all(RamDiscardManager *rdm) +{ + RamDiscardListener *rdl; + + QLIST_FOREACH(rdl, &rdm->rdl_list, next) { + rdl->notify_discard(rdl, rdl->section); + } +} + +static int rdm_populate_cb(MemoryRegionSection *section, void *opaque) +{ + RamDiscardListener *rdl =3D opaque; + + return rdl->notify_populate(rdl, section); +} + +void ram_discard_manager_register_listener(RamDiscardManager *rdm, + RamDiscardListener *rdl, + MemoryRegionSection *section) +{ + int ret; + + g_assert(section->mr =3D=3D rdm->mr); + + rdl->section =3D memory_region_section_new_copy(section); + QLIST_INSERT_HEAD(&rdm->rdl_list, rdl, next); + + ret =3D ram_discard_source_replay_populated(rdm->rds, rdl->section, + rdm_populate_cb, rdl); + if (ret) { + error_report("%s: Replaying populated ranges failed: %s", __func__, + strerror(-ret)); + } +} + +void ram_discard_manager_unregister_listener(RamDiscardManager *rdm, + RamDiscardListener *rdl) +{ + g_assert(rdl->section); + g_assert(rdl->section->mr =3D=3D rdm->mr); + + rdl->notify_discard(rdl, rdl->section); + memory_region_section_free_copy(rdl->section); + rdl->section =3D NULL; + QLIST_REMOVE(rdl, next); +} + +int ram_discard_manager_replay_populated_to_listeners(RamDiscardManager *r= dm) +{ + RamDiscardListener *rdl; + int ret =3D 0; + + QLIST_FOREACH(rdl, &rdm->rdl_list, next) { + ret =3D ram_discard_source_replay_populated(rdm->rds, rdl->section, + rdm_populate_cb, rdl); + if (ret) { + break; + } + } + return ret; +} + +static const TypeInfo ram_discard_manager_info =3D { + .parent =3D TYPE_OBJECT, + .name =3D TYPE_RAM_DISCARD_MANAGER, + .instance_size =3D sizeof(RamDiscardManager), + .instance_init =3D ram_discard_manager_initfn, + .instance_finalize =3D ram_discard_manager_finalize, +}; + +static const TypeInfo ram_discard_source_info =3D { + .parent =3D TYPE_INTERFACE, + .name =3D TYPE_RAM_DISCARD_SOURCE, + .class_size =3D sizeof(RamDiscardSourceClass), +}; + +static void ram_discard_manager_register_types(void) +{ + type_register_static(&ram_discard_manager_info); + type_register_static(&ram_discard_source_info); +} + +type_init(ram_discard_manager_register_types) diff --git a/rust/bindings/system-sys/lib.rs b/rust/bindings/system-sys/lib= .rs index 022fe65dd8..30adf683c3 100644 --- a/rust/bindings/system-sys/lib.rs +++ b/rust/bindings/system-sys/lib.rs @@ -20,7 +20,7 @@ =20 use common::Zeroable; use hwcore_sys::{qemu_irq, DeviceClass, DeviceState}; -use qom_sys::{InterfaceClass, Object, ObjectClass}; +use qom_sys::{Object, ObjectClass}; use util_sys::{Error, EventNotifier, QEMUBH}; =20 #[cfg(MESON)] diff --git a/system/meson.build b/system/meson.build index 9cdfe1b3e7..cd3193d170 100644 --- a/system/meson.build +++ b/system/meson.build @@ -14,6 +14,7 @@ system_ss.add(files( 'globals.c', 'ioport.c', 'ram-block-attributes.c', + 'ram-discard-manager.c', 'memory_mapping.c', 'memory.c', 'physmem.c', --=20 2.54.0 From nobody Thu Jun 25 06:56:52 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1782219039; cv=none; d=zohomail.com; s=zohoarc; b=DA2x79zxFsHSkWzzpGZCqx5rBU0Z1oKmBsUHd7NezmAiQUAuqNav1ZkuzFTXPfzWLw41aZ4AJ0B4O4+9SykMzPzzF4ZF9HcS0t/dvq61TNW/7nw25+FFwgAj+5ok7ph++FGq+aOro4F4vl5SIU8MckBLPdxdj9oaLg41QrTOTxA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1782219039; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=sINIeW2UHD4RjknjeKDQWmHp+p5AoJ5q9+hvtuiEzPw=; b=hMhMrRDtODZpHSrE5u1L3LCO4UOS5s8QRo20vN/zzYJmnpNxOZclTdEB0Neg1aRYPalo2taJbLSI/gAnKiw1vHsrM14gFmIrVXmIbQvrLYXheQD9uAHRFyVn+GZtzQV48FxKR5cpcfSoTQhniODBXJPfXsRgmKFrmpFRza6uT7M= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1782219039382313.49496586943155; Tue, 23 Jun 2026 05:50:39 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wc0YX-0004Y3-Jd; Tue, 23 Jun 2026 08:48:45 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YV-0004XF-KV for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:44 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YO-00070w-PC for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:39 -0400 Received: from mail-qt1-f198.google.com (mail-qt1-f198.google.com [209.85.160.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-76-LRFzO-T_MBGLxsEw1EkrHA-1; Tue, 23 Jun 2026 08:48:35 -0400 Received: by mail-qt1-f198.google.com with SMTP id d75a77b69052e-517787172b0so104014721cf.0 for ; Tue, 23 Jun 2026 05:48:34 -0700 (PDT) Received: from x1.com ([174.91.117.157]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51a51106a09sm22288351cf.0.2026.06.23.05.48.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jun 2026 05:48:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782218916; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=sINIeW2UHD4RjknjeKDQWmHp+p5AoJ5q9+hvtuiEzPw=; b=QJR71ybO/CKB/GdJ//vONZs/MX8iHlHR4ZWq37HQzK/xz5hSjAtc1UhouTUwO8HbSYheRA SIqThOYsIC5tf9/38FKAv8HiDiLPxkH4r4VVxY4CfKvXZ2w490Pg/D/NJqbWwmrZ8VnrGc 1Z0auMsletdeh2+CkAHZCxnD96c/XNg= X-MC-Unique: LRFzO-T_MBGLxsEw1EkrHA-1 X-Mimecast-MFC-AGG-ID: LRFzO-T_MBGLxsEw1EkrHA_1782218914 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1782218914; x=1782823714; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=sINIeW2UHD4RjknjeKDQWmHp+p5AoJ5q9+hvtuiEzPw=; b=KDynU0eLBpIAgdjwHt52Sf8xrHRjeEsY3HWGBNntKm7KfQzxFSVTw/HWJ7yvWrLIUx dfYU4bubKF1tQFvBrvANnQ2M79gMrIpG0VYN8HuPJXo6QV8a+03avjhI/77whVnXG/4z cs4qMtjvlBkOvU0vm9q1gArKCE2Ue3YDFBejk6SmUP2kDy68aFfAF3CvX4aVjeO+thd7 EALsN1ptb+YsZg/i175iX9Jmjgt1y8YQgf9dxIrk64szdibEzlZTKqN9dInkVHcL+WqE Y36cX7ZM3Lw4/SIhedNH6nhpAEfFXQJsSrgxNubDa7WR9D84x36FDp5SJOtk4twWsZ7J f3bg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782218914; x=1782823714; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=sINIeW2UHD4RjknjeKDQWmHp+p5AoJ5q9+hvtuiEzPw=; b=b3I2uo2hxLK2cUEi4K82cbH5OtvKZCS01qL6ZVxYFYEXGhwf+rYieYGqlvSbmc8UZv 7xBmh22LPb8Q1vfigGfo6dzhad/gX/56ls1mniU3UNucaIgO8n/ndruY7b0sIwcuoSNd vx1sNuKqIO69W6sBi/JWrE2N6QTXv8lckM4ArT4HhnHVTGJ+V48xqPXXzEm4MXFFLrAM RdkDsDAsKePvETGs4cLLNTL/fab8dmKLppzqNe3oZaME/jBv56G8bUuIz4lCmYimAPM6 rJo0Y/rkNFbggfqGeX9s3Qwkv6P/9z62e2XkMew76ADutubbdf+8lYAUzS4bBmGHVMtB sxow== X-Gm-Message-State: AOJu0YxFKqOqbjA9DpyMLOtDihlSuLcmg4z70TuSim94cn2h8yVfXEyA UzrVDTbfO+LgZAlp4Q0jiaSIB/FdYlA6vC1FzS5CZjXs3Pf99hLqo/gnDwH+n2yYebnpdeFK43X 5AzRPND2xlfMfq6vwFvv9tkVqQrUESjs63oxKy/vogNyG9D0xX57OYJs4rN7rlwDFDyL6PUmYVn BgN4ghYNL7qQdGxPdv7qUWh6rQpa2LrdV11OBL5A== X-Gm-Gg: AfdE7cnx3UR2rilweU1PhW9A1WkQ0O3gcwa0IWrEzROZv2q0ad8T7Tw46uCfIABwmTu 4VudrwsMgJrTNGQI+lj0jRHAb5IYWiqBX0Es6QziJAHIcQyLYg7fTPtvNfoKFOyOestt3Ans+Qi be06o1157s/AGWeTUF2wDHsBF0r5WL0ZE3ka4VQpDljvEiYE993uRnwC22cyolp50p5eS8Ap+qM CxVMKnrkCTiuJRfdWjxzPXLaFiIi0rO/MsdnUZ7Rav5KH7u5ODZY+35FkK4S+T5rPXFhlldTqOs +kVNc0PV6o9si1kvAFBDjaWx74yRVXuz4+C1IBN/AMigcTDu+216COWWS4DZwRTuMfyZN2KapIm jjQ== X-Received: by 2002:a05:622a:2599:b0:517:895f:1935 with SMTP id d75a77b69052e-519e4a54e07mr295732791cf.13.1782218914072; Tue, 23 Jun 2026 05:48:34 -0700 (PDT) X-Received: by 2002:a05:622a:2599:b0:517:895f:1935 with SMTP id d75a77b69052e-519e4a54e07mr295731991cf.13.1782218913422; Tue, 23 Jun 2026 05:48:33 -0700 (PDT) From: Peter Xu To: qemu-devel@nongnu.org Cc: Peter Xu , Fabiano Rosas , Paolo Bonzini , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , "Maciej S. Szmigiero" , "David Hildenbrand (Arm)" Subject: [PULL 10/18] system/memory: constify section arguments Date: Tue, 23 Jun 2026 08:47:51 -0400 Message-ID: <20260623124759.125399-11-peterx@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260623124759.125399-1-peterx@redhat.com> References: <20260623124759.125399-1-peterx@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=peterx@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1782219041880158500 From: Marc-Andr=C3=A9 Lureau The sections shouldn't be modified. Reviewed-by: Peter Xu Reviewed-by: C=C3=A9dric Le Goater Signed-off-by: Marc-Andr=C3=A9 Lureau Reviewed-by: Philippe Mathieu-Daud=C3=A9 Acked-by: Maciej S. Szmigiero # for CPR Acked-by: David Hildenbrand (Arm) Link: https://lore.kernel.org/r/20260604-rdm5-v5-3-5768e6a0943d@redhat.com Signed-off-by: Peter Xu --- include/hw/vfio/vfio-container.h | 2 +- include/hw/vfio/vfio-cpr.h | 2 +- include/system/ram-discard-manager.h | 14 +++++++------- hw/vfio/cpr-legacy.c | 4 ++-- hw/vfio/listener.c | 10 +++++----- hw/virtio/virtio-mem.c | 10 +++++----- migration/ram.c | 6 +++--- system/memory_mapping.c | 4 ++-- system/ram-block-attributes.c | 8 ++++---- system/ram-discard-manager.c | 10 +++++----- 10 files changed, 35 insertions(+), 35 deletions(-) diff --git a/include/hw/vfio/vfio-container.h b/include/hw/vfio/vfio-contai= ner.h index a7d5c5ed67..b2e7f4312c 100644 --- a/include/hw/vfio/vfio-container.h +++ b/include/hw/vfio/vfio-container.h @@ -277,7 +277,7 @@ struct VFIOIOMMUClass { }; =20 VFIORamDiscardListener *vfio_find_ram_discard_listener( - VFIOContainer *bcontainer, MemoryRegionSection *section); + VFIOContainer *bcontainer, const MemoryRegionSection *section); =20 void vfio_container_region_add(VFIOContainer *bcontainer, MemoryRegionSection *section, bool cpr_rema= p); diff --git a/include/hw/vfio/vfio-cpr.h b/include/hw/vfio/vfio-cpr.h index 4606da500a..ecabe0c747 100644 --- a/include/hw/vfio/vfio-cpr.h +++ b/include/hw/vfio/vfio-cpr.h @@ -69,7 +69,7 @@ void vfio_cpr_giommu_remap(struct VFIOContainer *bcontain= er, MemoryRegionSection *section); =20 bool vfio_cpr_ram_discard_replay_populated( - struct VFIOContainer *bcontainer, MemoryRegionSection *section); + struct VFIOContainer *bcontainer, const MemoryRegionSection *section); =20 void vfio_cpr_save_vector_fd(struct VFIOPCIDevice *vdev, const char *name, int nr, int fd); diff --git a/include/system/ram-discard-manager.h b/include/system/ram-disc= ard-manager.h index da55658169..b188e09a30 100644 --- a/include/system/ram-discard-manager.h +++ b/include/system/ram-discard-manager.h @@ -26,9 +26,9 @@ DECLARE_OBJ_CHECKERS(RamDiscardSource, RamDiscardSourceCl= ass, =20 typedef struct RamDiscardListener RamDiscardListener; typedef int (*NotifyRamPopulate)(RamDiscardListener *rdl, - MemoryRegionSection *section); + const MemoryRegionSection *section); typedef void (*NotifyRamDiscard)(RamDiscardListener *rdl, - MemoryRegionSection *section); + const MemoryRegionSection *section); =20 struct RamDiscardListener { /* @@ -86,7 +86,7 @@ static inline void ram_discard_listener_init(RamDiscardLi= stener *rdl, * * Returns 0 on success, or a negative error if failed. */ -typedef int (*ReplayRamDiscardState)(MemoryRegionSection *section, +typedef int (*ReplayRamDiscardState)(const MemoryRegionSection *section, void *opaque); =20 /* @@ -151,7 +151,7 @@ struct RamDiscardSourceClass { * Returns 0 on success, or a negative error if any notification faile= d. */ int (*replay_populated)(const RamDiscardSource *rds, - MemoryRegionSection *section, + const MemoryRegionSection *section, ReplayRamDiscardState replay_fn, void *opaque); =20 /** @@ -168,7 +168,7 @@ struct RamDiscardSourceClass { * Returns 0 on success, or a negative error if any notification faile= d. */ int (*replay_discarded)(const RamDiscardSource *rds, - MemoryRegionSection *section, + const MemoryRegionSection *section, ReplayRamDiscardState replay_fn, void *opaque); }; =20 @@ -237,7 +237,7 @@ bool ram_discard_manager_is_populated(const RamDiscardM= anager *rdm, * Returns 0 on success, or a negative error if any notification failed. */ int ram_discard_manager_replay_populated(const RamDiscardManager *rdm, - MemoryRegionSection *section, + const MemoryRegionSection *sectio= n, ReplayRamDiscardState replay_fn, void *opaque); =20 @@ -255,7 +255,7 @@ int ram_discard_manager_replay_populated(const RamDisca= rdManager *rdm, * Returns 0 on success, or a negative error if any notification failed. */ int ram_discard_manager_replay_discarded(const RamDiscardManager *rdm, - MemoryRegionSection *section, + const MemoryRegionSection *sectio= n, ReplayRamDiscardState replay_fn, void *opaque); =20 diff --git a/hw/vfio/cpr-legacy.c b/hw/vfio/cpr-legacy.c index c431d89973..2d40d8baea 100644 --- a/hw/vfio/cpr-legacy.c +++ b/hw/vfio/cpr-legacy.c @@ -226,7 +226,7 @@ void vfio_cpr_giommu_remap(VFIOContainer *bcontainer, memory_region_iommu_replay(giommu->iommu_mr, &giommu->n); } =20 -static int vfio_cpr_rdm_remap(MemoryRegionSection *section, void *opaque) +static int vfio_cpr_rdm_remap(const MemoryRegionSection *section, void *op= aque) { RamDiscardListener *rdl =3D opaque; =20 @@ -242,7 +242,7 @@ static int vfio_cpr_rdm_remap(MemoryRegionSection *sect= ion, void *opaque) * directly, which calls vfio_legacy_cpr_dma_map. */ bool vfio_cpr_ram_discard_replay_populated(VFIOContainer *bcontainer, - MemoryRegionSection *section) + const MemoryRegionSection *sect= ion) { RamDiscardManager *rdm =3D memory_region_get_ram_discard_manager(secti= on->mr); VFIORamDiscardListener *vrdl =3D diff --git a/hw/vfio/listener.c b/hw/vfio/listener.c index 14cca678ae..109b5d61af 100644 --- a/hw/vfio/listener.c +++ b/hw/vfio/listener.c @@ -201,7 +201,7 @@ out: } =20 static void vfio_ram_discard_notify_discard(RamDiscardListener *rdl, - MemoryRegionSection *section) + const MemoryRegionSection *sec= tion) { VFIORamDiscardListener *vrdl =3D container_of(rdl, VFIORamDiscardListe= ner, listener); @@ -219,7 +219,7 @@ static void vfio_ram_discard_notify_discard(RamDiscardL= istener *rdl, } =20 static int vfio_ram_discard_notify_populate(RamDiscardListener *rdl, - MemoryRegionSection *section) + const MemoryRegionSection *sec= tion) { VFIORamDiscardListener *vrdl =3D container_of(rdl, VFIORamDiscardListe= ner, listener); @@ -461,7 +461,7 @@ static void vfio_device_error_append(VFIODevice *vbased= ev, Error **errp) } =20 VFIORamDiscardListener *vfio_find_ram_discard_listener( - VFIOContainer *bcontainer, MemoryRegionSection *section) + VFIOContainer *bcontainer, const MemoryRegionSection *section) { VFIORamDiscardListener *vrdl; =20 @@ -1149,8 +1149,8 @@ out: } } =20 -static int vfio_ram_discard_query_dirty_bitmap(MemoryRegionSection *sectio= n, - void *opaque) +static int vfio_ram_discard_query_dirty_bitmap(const MemoryRegionSection *= section, + void *opaque) { const hwaddr size =3D int128_get64(section->size); const hwaddr iova =3D section->offset_within_address_space; diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index be149ee944..ec16550320 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -262,7 +262,7 @@ static int virtio_mem_for_each_plugged_range(VirtIOMEM = *vmem, void *arg, typedef int (*virtio_mem_section_cb)(MemoryRegionSection *s, void *arg); =20 static int virtio_mem_for_each_plugged_section(const VirtIOMEM *vmem, - MemoryRegionSection *s, + const MemoryRegionSection *= s, void *arg, virtio_mem_section_cb cb) { @@ -294,7 +294,7 @@ static int virtio_mem_for_each_plugged_section(const Vi= rtIOMEM *vmem, } =20 static int virtio_mem_for_each_unplugged_section(const VirtIOMEM *vmem, - MemoryRegionSection *s, + const MemoryRegionSection= *s, void *arg, virtio_mem_section_cb cb) { @@ -1680,7 +1680,7 @@ static int virtio_mem_rds_replay_cb(MemoryRegionSecti= on *s, void *arg) } =20 static int virtio_mem_rds_replay_populated(const RamDiscardSource *rds, - MemoryRegionSection *s, + const MemoryRegionSection *s, ReplayRamDiscardState replay_fn, void *opaque) { @@ -1692,11 +1692,11 @@ static int virtio_mem_rds_replay_populated(const Ra= mDiscardSource *rds, =20 g_assert(s->mr =3D=3D &vmem->memdev->mr); return virtio_mem_for_each_plugged_section(vmem, s, &data, - virtio_mem_rds_replay_cb); + virtio_mem_rds_replay_cb); } =20 static int virtio_mem_rds_replay_discarded(const RamDiscardSource *rds, - MemoryRegionSection *s, + const MemoryRegionSection *s, ReplayRamDiscardState replay_fn, void *opaque) { diff --git a/migration/ram.c b/migration/ram.c index 6da24d7258..bd519f1931 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -860,7 +860,7 @@ static inline bool migration_bitmap_clear_dirty(RAMStat= e *rs, return ret; } =20 -static int dirty_bitmap_clear_section(MemoryRegionSection *section, +static int dirty_bitmap_clear_section(const MemoryRegionSection *section, void *opaque) { const hwaddr offset =3D section->offset_within_region; @@ -1588,7 +1588,7 @@ static inline void populate_read_range(RAMBlock *bloc= k, ram_addr_t offset, } } =20 -static inline int populate_read_section(MemoryRegionSection *section, +static inline int populate_read_section(const MemoryRegionSection *section, void *opaque) { const hwaddr size =3D int128_get64(section->size); @@ -1663,7 +1663,7 @@ void ram_write_tracking_prepare(void) } } =20 -static inline int uffd_protect_section(MemoryRegionSection *section, +static inline int uffd_protect_section(const MemoryRegionSection *section, void *opaque) { const hwaddr size =3D int128_get64(section->size); diff --git a/system/memory_mapping.c b/system/memory_mapping.c index da708a08ab..cacef504f6 100644 --- a/system/memory_mapping.c +++ b/system/memory_mapping.c @@ -196,7 +196,7 @@ typedef struct GuestPhysListener { } GuestPhysListener; =20 static void guest_phys_block_add_section(GuestPhysListener *g, - MemoryRegionSection *section) + const MemoryRegionSection *sectio= n) { const hwaddr target_start =3D section->offset_within_address_space; const hwaddr target_end =3D target_start + int128_get64(section->size); @@ -248,7 +248,7 @@ static void guest_phys_block_add_section(GuestPhysListe= ner *g, #endif } =20 -static int guest_phys_ram_populate_cb(MemoryRegionSection *section, +static int guest_phys_ram_populate_cb(const MemoryRegionSection *section, void *opaque) { GuestPhysListener *g =3D opaque; diff --git a/system/ram-block-attributes.c b/system/ram-block-attributes.c index a72924eea7..79c7e97d9a 100644 --- a/system/ram-block-attributes.c +++ b/system/ram-block-attributes.c @@ -37,7 +37,7 @@ typedef int (*ram_block_attributes_section_cb)(MemoryRegi= onSection *s, =20 static int ram_block_attributes_for_each_populated_section(const RamBlockAttributes *= attr, - MemoryRegionSection *secti= on, + const MemoryRegionSection = *section, void *arg, ram_block_attributes_secti= on_cb cb) { @@ -78,7 +78,7 @@ ram_block_attributes_for_each_populated_section(const Ram= BlockAttributes *attr, =20 static int ram_block_attributes_for_each_discarded_section(const RamBlockAttributes *= attr, - MemoryRegionSection *secti= on, + const MemoryRegionSection = *section, void *arg, ram_block_attributes_secti= on_cb cb) { @@ -161,7 +161,7 @@ ram_block_attributes_rds_is_populated(const RamDiscardS= ource *rds, =20 static int ram_block_attributes_rds_replay_populated(const RamDiscardSource *rds, - MemoryRegionSection *section, + const MemoryRegionSection *secti= on, ReplayRamDiscardState replay_fn, void *opaque) { @@ -175,7 +175,7 @@ ram_block_attributes_rds_replay_populated(const RamDisc= ardSource *rds, =20 static int ram_block_attributes_rds_replay_discarded(const RamDiscardSource *rds, - MemoryRegionSection *section, + const MemoryRegionSection *secti= on, ReplayRamDiscardState replay_fn, void *opaque) { diff --git a/system/ram-discard-manager.c b/system/ram-discard-manager.c index 3d8c85617d..1c9ff7fda5 100644 --- a/system/ram-discard-manager.c +++ b/system/ram-discard-manager.c @@ -28,7 +28,7 @@ static bool ram_discard_source_is_populated(const RamDisc= ardSource *rds, } =20 static int ram_discard_source_replay_populated(const RamDiscardSource *rds, - MemoryRegionSection *sectio= n, + const MemoryRegionSection *= section, ReplayRamDiscardState repla= y_fn, void *opaque) { @@ -39,7 +39,7 @@ static int ram_discard_source_replay_populated(const RamD= iscardSource *rds, } =20 static int ram_discard_source_replay_discarded(const RamDiscardSource *rds, - MemoryRegionSection *sectio= n, + const MemoryRegionSection *= section, ReplayRamDiscardState repla= y_fn, void *opaque) { @@ -74,7 +74,7 @@ bool ram_discard_manager_is_populated(const RamDiscardMan= ager *rdm, } =20 int ram_discard_manager_replay_populated(const RamDiscardManager *rdm, - MemoryRegionSection *section, + const MemoryRegionSection *sectio= n, ReplayRamDiscardState replay_fn, void *opaque) { @@ -83,7 +83,7 @@ int ram_discard_manager_replay_populated(const RamDiscard= Manager *rdm, } =20 int ram_discard_manager_replay_discarded(const RamDiscardManager *rdm, - MemoryRegionSection *section, + const MemoryRegionSection *sectio= n, ReplayRamDiscardState replay_fn, void *opaque) { @@ -164,7 +164,7 @@ void ram_discard_manager_notify_discard_all(RamDiscardM= anager *rdm) } } =20 -static int rdm_populate_cb(MemoryRegionSection *section, void *opaque) +static int rdm_populate_cb(const MemoryRegionSection *section, void *opaqu= e) { RamDiscardListener *rdl =3D opaque; =20 --=20 2.54.0 From nobody Thu Jun 25 06:56:52 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1782219038; cv=none; d=zohomail.com; s=zohoarc; b=T/CBAdt9V5kNhhHjvsLVgZ5G6zr51mI0ihqKsJxjxCNqNyPFZYYATRpWpnHuRPuk0YdQl/yFVLIVRpGXVbP5wwN/OQMWqpPwO+7NSpsrTfgaTGrc/1xIqoZxdANMT+WjxoEKAhtk6dsIK1onuMs5TL/GFUJfasuoGaXW4ScEv94= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1782219038; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=24x9ENDYcEXyW0GKNdB3tM4NZHVw1V9yuGNfVyt1HX4=; b=OPNc000bKa1a/CIDhAh1l8NsOy6F0GJ3RlmqJJ/gMKs2B1hYJz4jOv8RFG/WK0c/W67WB5sc2Nso5PIgogQwKpLQxnsxKp9kvuya0NzxckOEo/6CHUyxHR0X3czA377Q1xsXjC4euPu1WN+sz/pY/j9HcfvUJatlxLpmPE2AoAQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 17822190386691012.7791694013553; Tue, 23 Jun 2026 05:50:38 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wc0Ya-0004Z6-7H; Tue, 23 Jun 2026 08:48:48 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YY-0004YD-H9 for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:46 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YW-00071N-Kq for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:46 -0400 Received: from mail-qt1-f198.google.com (mail-qt1-f198.google.com [209.85.160.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-665-ASSCnXDhNzuGG9uqK0egWQ-1; Tue, 23 Jun 2026 08:48:36 -0400 Received: by mail-qt1-f198.google.com with SMTP id d75a77b69052e-519e4aaec80so82368041cf.0 for ; Tue, 23 Jun 2026 05:48:35 -0700 (PDT) Received: from x1.com ([174.91.117.157]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51a51106a09sm22288351cf.0.2026.06.23.05.48.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jun 2026 05:48:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782218919; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=24x9ENDYcEXyW0GKNdB3tM4NZHVw1V9yuGNfVyt1HX4=; b=Gx85a84uajaVJTuni+yU8mIzfOUjrTvEMUJiz1T0RwSjd/ROfBij3F3Jdki0UgYrnkX4d1 dybvdtF8Dt+9H+daR4YPtaTDb5OO73xF3bq7IB792DXKHvMlhWBwaKOHHmT4f0qgCL0Qec b5ZSm97vQkLqnZS5H2tEyLyBc5XlZMw= X-MC-Unique: ASSCnXDhNzuGG9uqK0egWQ-1 X-Mimecast-MFC-AGG-ID: ASSCnXDhNzuGG9uqK0egWQ_1782218915 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1782218915; x=1782823715; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=24x9ENDYcEXyW0GKNdB3tM4NZHVw1V9yuGNfVyt1HX4=; b=gYg06P4bF3FqKIS75c77VtAJsfLa256SxRrdfYmCbVNq0WibI9B4L4eYNs72iNE3ll Zd/BGDic+dhb4o4XSVKxYtZ+HYeq09FyIsg4ysHyvrHfjrM2cM/tIfse8kk9kUvIMzI+ xx1y2O53ZMbx1SLTywtcysLCuJS45c4+j9rD1kFT+KjNFeYX6jBx2TE2FaV/mDkeoN2u SHniw6A1u8jjW6R+SBPRXV4fJLQuBke4epyRY9t6KdymePyKx+fARRwjqPIRR0xqoTEp 3gRfuHrqDtusZa3PHKK2v4yllfk1aCX8WRff8v6qE2g7bKAtHJlMyvBuZjoTE3Tf9ZlB 4xKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782218915; x=1782823715; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=24x9ENDYcEXyW0GKNdB3tM4NZHVw1V9yuGNfVyt1HX4=; b=TTkCjTpa5ctXuGEpmnV0N/ig/Cf2oUu7QxMpbWi1sPAbAWZLJFkYca0JaI13eITTtb uEl3Y3BnuG3Lr7rsvrVwEmo5k6zUYPi7tq9fgl24ZrKlnvQ2H7cygqNUm7RBq7FEprA7 UzuOWvnQgrkjVJi2KQmhaiaPzSPAtriMGq9RIdFeno5oysra0+NoQDoSRJTGcEMQVPuy F+iayvAB08PuQmwmvskcGGoJC37Q0RJeTl4iBniIoH6Vlr1pusaMFnF7j+5RyokmY1v1 TqXEsXXrUk0BDl7709DzZ5Ajj+iY7HgZJsbYobyzT/Wgt2+P1XPHwaah6S1qx9F7XUIM jNNQ== X-Gm-Message-State: AOJu0Yw619Wt+5+EJF4Crsc1z48tjD4GjB0A/n+nzL0YIWnC1T7tyj3/ /DNsIcb6JP1Lfn4KUZ26AQc9SlhtK5uPxT8fKki1Ces06Ago1xDnZsZtcPMHqC3ZYY3ryjBdTpX Ef4N47TARC4NMPlVlFT9QiA+ByW643eKxf1UhMxTd3v731SmdmX/ADFeddFjWYGrSa2XXiiJzHf n8c3ANNr76Cjn7d+P68EzYA2lZ3V48CU+VAZ2ikA== X-Gm-Gg: AfdE7ckLNCieSUR9JQazQHPTXVKywMDWiKH0bxSiXKKWgHiFWHcmjRBsJYjSvLA2jtJ fomZISdyoi+eKImw+QXwkRSXr5LEDb7QIlxz9h3dMDbP7bOMXA8g/NRAinLN4l1JoHOJBbWTQEd d6Yyha6i98MKndMzvivc4niyYiUznGTqxWopVhzwfoLLC9Gfk0ykf+1Y9JRFVKA4bA8G84Z4bxO Xigy6hzqqnkiQkKQOonjFxuYle+sZKZCynebTINnaZ6pajkF6KYIcoiZJo3n+sC1iibR+865hkZ 1JJm+ROjditaxqx5owx29gBYnT2yWr0LoosrdGzfw0Xa0vzNlr1Zv6Y2tL/WX7DpjwSNLJturt1 Dkg== X-Received: by 2002:a05:622a:4289:b0:517:9d3f:8f3 with SMTP id d75a77b69052e-519e49158c4mr276850271cf.5.1782218915289; Tue, 23 Jun 2026 05:48:35 -0700 (PDT) X-Received: by 2002:a05:622a:4289:b0:517:9d3f:8f3 with SMTP id d75a77b69052e-519e49158c4mr276849661cf.5.1782218914729; Tue, 23 Jun 2026 05:48:34 -0700 (PDT) From: Peter Xu To: qemu-devel@nongnu.org Cc: Peter Xu , Fabiano Rosas , Paolo Bonzini , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , David Hildenbrand Subject: [PULL 11/18] system/ram-discard-manager: implement replay via is_populated iteration Date: Tue, 23 Jun 2026 08:47:52 -0400 Message-ID: <20260623124759.125399-12-peterx@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260623124759.125399-1-peterx@redhat.com> References: <20260623124759.125399-1-peterx@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=peterx@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1782219039668158500 From: Marc-Andr=C3=A9 Lureau Replace the source-level replay wrappers with a new replay_by_populated_state() helper that iterates the section at min-granularity, calls is_populated() for each chunk, and aggregates consecutive chunks of the same state before invoking the callback. This moves the iteration logic from individual sources into the manager, preparing for multi-source aggregation where the manager must combine state from multiple sources anyway. The replay_populated/replay_discarded vtable entries in RamDiscardSourceClass are no longer called but remain in the interface for now; they will be removed in follow-up commits along with the now-dead source implementations. Reviewed-by: Peter Xu Signed-off-by: Marc-Andr=C3=A9 Lureau Acked-by: David Hildenbrand Link: https://lore.kernel.org/r/20260604-rdm5-v5-4-5768e6a0943d@redhat.com Signed-off-by: Peter Xu --- system/ram-discard-manager.c | 85 ++++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 24 deletions(-) diff --git a/system/ram-discard-manager.c b/system/ram-discard-manager.c index 1c9ff7fda5..a907ddf370 100644 --- a/system/ram-discard-manager.c +++ b/system/ram-discard-manager.c @@ -27,26 +27,65 @@ static bool ram_discard_source_is_populated(const RamDi= scardSource *rds, return rdsc->is_populated(rds, section); } =20 -static int ram_discard_source_replay_populated(const RamDiscardSource *rds, - const MemoryRegionSection *= section, - ReplayRamDiscardState repla= y_fn, - void *opaque) +/* + * Iterate the section at source granularity, aggregating consecutive chun= ks + * with matching populated state, and call replay_fn for each run. + */ +static int replay_by_populated_state(const RamDiscardManager *rdm, + const MemoryRegionSection *section, + bool replay_populated, + ReplayRamDiscardState replay_fn, + void *opaque) { - RamDiscardSourceClass *rdsc =3D RAM_DISCARD_SOURCE_GET_CLASS(rds); + uint64_t granularity, offset, size, end, pos, run_start =3D 0; + bool in_run =3D false; + int ret =3D 0; =20 - g_assert(rdsc->replay_populated); - return rdsc->replay_populated(rds, section, replay_fn, opaque); -} + granularity =3D ram_discard_source_get_min_granularity(rdm->rds, rdm->= mr); + offset =3D section->offset_within_region; + size =3D int128_get64(section->size); + end =3D offset + size; + + /* Align iteration to granularity boundaries */ + pos =3D QEMU_ALIGN_DOWN(offset, granularity); + + for (; pos < end; pos +=3D granularity) { + MemoryRegionSection chunk =3D { + .mr =3D section->mr, + .offset_within_region =3D pos, + .size =3D int128_make64(granularity), + }; + bool populated =3D ram_discard_source_is_populated(rdm->rds, &chun= k); + + if (populated =3D=3D replay_populated) { + if (!in_run) { + run_start =3D pos; + in_run =3D true; + } + } else if (in_run) { + MemoryRegionSection tmp =3D *section; + + if (memory_region_section_intersect_range(&tmp, run_start, + pos - run_start)) { + ret =3D replay_fn(&tmp, opaque); + if (ret) { + return ret; + } + } + in_run =3D false; + } + } =20 -static int ram_discard_source_replay_discarded(const RamDiscardSource *rds, - const MemoryRegionSection *= section, - ReplayRamDiscardState repla= y_fn, - void *opaque) -{ - RamDiscardSourceClass *rdsc =3D RAM_DISCARD_SOURCE_GET_CLASS(rds); + if (in_run) { + MemoryRegionSection tmp =3D *section; =20 - g_assert(rdsc->replay_discarded); - return rdsc->replay_discarded(rds, section, replay_fn, opaque); + if (memory_region_section_intersect_range(&tmp, run_start, + pos - run_start)) { + ret =3D replay_fn(&tmp, opaque); + } + } + + return ret; } =20 RamDiscardManager *ram_discard_manager_new(MemoryRegion *mr, @@ -78,8 +117,7 @@ int ram_discard_manager_replay_populated(const RamDiscar= dManager *rdm, ReplayRamDiscardState replay_fn, void *opaque) { - return ram_discard_source_replay_populated(rdm->rds, section, - replay_fn, opaque); + return replay_by_populated_state(rdm, section, true, replay_fn, opaque= ); } =20 int ram_discard_manager_replay_discarded(const RamDiscardManager *rdm, @@ -87,8 +125,7 @@ int ram_discard_manager_replay_discarded(const RamDiscar= dManager *rdm, ReplayRamDiscardState replay_fn, void *opaque) { - return ram_discard_source_replay_discarded(rdm->rds, section, - replay_fn, opaque); + return replay_by_populated_state(rdm, section, false, replay_fn, opaqu= e); } =20 static void ram_discard_manager_initfn(Object *obj) @@ -182,8 +219,8 @@ void ram_discard_manager_register_listener(RamDiscardMa= nager *rdm, rdl->section =3D memory_region_section_new_copy(section); QLIST_INSERT_HEAD(&rdm->rdl_list, rdl, next); =20 - ret =3D ram_discard_source_replay_populated(rdm->rds, rdl->section, - rdm_populate_cb, rdl); + ret =3D ram_discard_manager_replay_populated(rdm, rdl->section, + rdm_populate_cb, rdl); if (ret) { error_report("%s: Replaying populated ranges failed: %s", __func__, strerror(-ret)); @@ -208,8 +245,8 @@ int ram_discard_manager_replay_populated_to_listeners(R= amDiscardManager *rdm) int ret =3D 0; =20 QLIST_FOREACH(rdl, &rdm->rdl_list, next) { - ret =3D ram_discard_source_replay_populated(rdm->rds, rdl->section, - rdm_populate_cb, rdl); + ret =3D ram_discard_manager_replay_populated(rdm, rdl->section, + rdm_populate_cb, rdl); if (ret) { break; } --=20 2.54.0 From nobody Thu Jun 25 06:56:52 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1782219040; cv=none; d=zohomail.com; s=zohoarc; b=HXqKLvPxxp89s1v6z+t8kxzuajRVwyEMEvOxQK8UWNqrxoTrZ5Pr4T4xxBQZTJj22TYbXE05HtOIZqAoEjmTuKsb/7gra6PCCq2BmYWaDuX+ti/QtdKURPf1GqvQnS3Qq1CGerWp4tFW8kV7izs/JuSco2iZr4cZPHaIPmn5SAM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1782219040; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=GMugfKkzQoQqUMR/78UE4ehQnL4nusRrCbVz2kVTbW0=; b=CGKqf8i+Ei6YtuhqTHp2kO29N205HxI7cBbrNL6wAUkI9LCii0ATodg5Fyhv6kLvxhSKlRC3YiM396un/8e77Ajr/Ynv+a0Rkq+1mItUTRHWmANnqjaQAhL/kB0WbfShuITg0my/7beVPkxBy2DC9DAMFyQ6ZN9opYlgbe8RRqA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1782219040982669.7641823224559; Tue, 23 Jun 2026 05:50:40 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wc0YZ-0004Z1-Sr; Tue, 23 Jun 2026 08:48:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YY-0004YC-E9 for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:46 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YU-00071T-Hy for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:46 -0400 Received: from mail-qt1-f200.google.com (mail-qt1-f200.google.com [209.85.160.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-649-fMc0wzIUNgitub8kt6A8ww-1; Tue, 23 Jun 2026 08:48:38 -0400 Received: by mail-qt1-f200.google.com with SMTP id d75a77b69052e-51a08feb103so63580171cf.2 for ; Tue, 23 Jun 2026 05:48:38 -0700 (PDT) Received: from x1.com ([174.91.117.157]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51a51106a09sm22288351cf.0.2026.06.23.05.48.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jun 2026 05:48:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782218919; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=GMugfKkzQoQqUMR/78UE4ehQnL4nusRrCbVz2kVTbW0=; b=eOD5ufHUCtbWSspLIkG0QcXDdANNtWht1GYVGgCqJf+bU4qY+HJlZIs3nLR1gFzUkk0oM8 0ICI2Q4YFgydxRZlVL36fE1LbwCKH7mh7bv8s+vjhq9tbH5F3gdROqjLOVUPV73rOONhgo ZZb+BlpmCoRBC58XLs2Ssbw+p5gjnRY= X-MC-Unique: fMc0wzIUNgitub8kt6A8ww-1 X-Mimecast-MFC-AGG-ID: fMc0wzIUNgitub8kt6A8ww_1782218918 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1782218918; x=1782823718; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=GMugfKkzQoQqUMR/78UE4ehQnL4nusRrCbVz2kVTbW0=; b=ZXLXFATwFKi+7wNdtK7ZLfoxozz37g0ywLH18Pq6jiuLFcvKfppiszpxMUGOxBvCY0 C3xU9tMQ/7VwY9O88HUKn3fkaI5sYgECYARyj6R8vC0BWtCXEZgGNpf9GRngzx74V5TB WVV3IXjYPNFzoK5wBhgebfDqbOlbTj+MnGcRDGDNmqtRQdjb/hy1LTd6WJTDBDRiWFdR fLc0d2i/0OwZ1T6QTMBVeS6lC1RzXEVh1UYSpi3p2U1kfYcWcCbEnvUG78RxuTFpCAtn jctY8xVQHVlm2KxYm/HBMW9aN/NzhDFDpmlORpqmvpo4Dm31c7QTi4dhWg81Ldte7kWY /C5g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782218918; x=1782823718; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=GMugfKkzQoQqUMR/78UE4ehQnL4nusRrCbVz2kVTbW0=; b=iLKUPmnDbzRrmd9Hf1bhKIxaBbRnll9QwjlBWffI8EjHDgslGmPXiozck+8Fub+h0J xtXwZDYpLY2ywl6CbMqJtT6RSAMzjmGZiOQTpKVt2qNZ49KaStfvW4jI7S59jWFkf0Xz un6BddmnKRtswL/0CKEt196b2/JiQ2Hv2L4vXoDO7TbL55fS6LeVgOus9Chma2u4IAjX OrIG9rvy6PbtxQ3wJKxL2Kg3JSuUNl1Ta9ITLPntINlp55la4kAcJeIhg6CA2HAANThd tScLaQ13T+rqokEzHMdnwabSIE9EW8krzmaMdYZyLT8fX8qTsbhYD7dMcxxVfDZC+cYK 654A== X-Gm-Message-State: AOJu0YwsyFkV676YQBy9esDDPbf/9rzulvFkBzqYaYGBJsE6iKdIw2/T MIkxBgI5hsS8CtSSdH1D3rxc9fH//iUtSVRC2dK0u3x9Q4vN/jpdT4HGI0SPH1km/7x4xl8xltR PPeMNRkrblA2Ma1J+8VMt+TIMfFebY1KMPrYotTiVNeCP7i12CXZn6uEnlEB71AYB+VC154W6nm 6RI7LZZC060fUkJPTscun786o8zRFQCV553gSqaw== X-Gm-Gg: AfdE7ckg0j+J9KpH/Wz+TwShs6gb/gNSB5Rh8Z2V87sUeMYSbS6XmLz6KRtjFMbxpVY d+M38pAnromBZJQPwODsgI7ErEtEleQsew6ISjcZDRQR9H1EfxdoQ1cP2W0JWuGNHqLBqio7oPk RWrOBkmtt8NedDDjkiSuvcDgyeOlkINRYN8nMw/VRvM57Dr4Xu44aW8hxeA12BvFNjR2nkRlVUM 80A06P8zksbm16sn3H+C1vvkXjoBFmwqYoR1kJHMGzqqBDxWzp0bAs0FsF4hOJxEHIE2XLTq7r8 fXEfBxamR6OSKtkMVUKh9lhO5P0BrGzqJZpeUMjmsTTQ0IDwp6pPBSZKwKp1Sph3iDK8vJ9F9t0 a/Q== X-Received: by 2002:ac8:5d0e:0:b0:517:6351:b401 with SMTP id d75a77b69052e-519e4dd3a8bmr276013191cf.44.1782218917826; Tue, 23 Jun 2026 05:48:37 -0700 (PDT) X-Received: by 2002:ac8:5d0e:0:b0:517:6351:b401 with SMTP id d75a77b69052e-519e4dd3a8bmr276012481cf.44.1782218917019; Tue, 23 Jun 2026 05:48:37 -0700 (PDT) From: Peter Xu To: qemu-devel@nongnu.org Cc: Peter Xu , Fabiano Rosas , Paolo Bonzini , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , David Hildenbrand Subject: [PULL 12/18] virtio-mem: remove replay_populated/replay_discarded implementation Date: Tue, 23 Jun 2026 08:47:53 -0400 Message-ID: <20260623124759.125399-13-peterx@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260623124759.125399-1-peterx@redhat.com> References: <20260623124759.125399-1-peterx@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=peterx@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1782219041690158501 From: Marc-Andr=C3=A9 Lureau The replay iteration logic has been moved into the RamDiscardManager, which now iterates at source granularity using is_populated(). The source-level replay_populated/replay_discarded methods and their helpers are no longer called. Remove the now-dead replay methods, the VirtIOMEMReplayData struct, the virtio_mem_for_each_plugged/unplugged_section() helpers (only used by the replay methods), and the virtio_mem_section_cb typedef. Reviewed-by: Peter Xu Acked-by: David Hildenbrand Signed-off-by: Marc-Andr=C3=A9 Lureau Link: https://lore.kernel.org/r/20260604-rdm5-v5-5-5768e6a0943d@redhat.com Signed-off-by: Peter Xu --- hw/virtio/virtio-mem.c | 112 ----------------------------------------- 1 file changed, 112 deletions(-) diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index ec16550320..2b67b2882d 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -259,72 +259,6 @@ static int virtio_mem_for_each_plugged_range(VirtIOMEM= *vmem, void *arg, return ret; } =20 -typedef int (*virtio_mem_section_cb)(MemoryRegionSection *s, void *arg); - -static int virtio_mem_for_each_plugged_section(const VirtIOMEM *vmem, - const MemoryRegionSection *= s, - void *arg, - virtio_mem_section_cb cb) -{ - unsigned long first_bit, last_bit; - uint64_t offset, size; - int ret =3D 0; - - first_bit =3D s->offset_within_region / vmem->block_size; - first_bit =3D find_next_bit(vmem->bitmap, vmem->bitmap_size, first_bit= ); - while (first_bit < vmem->bitmap_size) { - MemoryRegionSection tmp =3D *s; - - offset =3D first_bit * vmem->block_size; - last_bit =3D find_next_zero_bit(vmem->bitmap, vmem->bitmap_size, - first_bit + 1) - 1; - size =3D (last_bit - first_bit + 1) * vmem->block_size; - - if (!memory_region_section_intersect_range(&tmp, offset, size)) { - break; - } - ret =3D cb(&tmp, arg); - if (ret) { - break; - } - first_bit =3D find_next_bit(vmem->bitmap, vmem->bitmap_size, - last_bit + 2); - } - return ret; -} - -static int virtio_mem_for_each_unplugged_section(const VirtIOMEM *vmem, - const MemoryRegionSection= *s, - void *arg, - virtio_mem_section_cb cb) -{ - unsigned long first_bit, last_bit; - uint64_t offset, size; - int ret =3D 0; - - first_bit =3D s->offset_within_region / vmem->block_size; - first_bit =3D find_next_zero_bit(vmem->bitmap, vmem->bitmap_size, firs= t_bit); - while (first_bit < vmem->bitmap_size) { - MemoryRegionSection tmp =3D *s; - - offset =3D first_bit * vmem->block_size; - last_bit =3D find_next_bit(vmem->bitmap, vmem->bitmap_size, - first_bit + 1) - 1; - size =3D (last_bit - first_bit + 1) * vmem->block_size; - - if (!memory_region_section_intersect_range(&tmp, offset, size)) { - break; - } - ret =3D cb(&tmp, arg); - if (ret) { - break; - } - first_bit =3D find_next_zero_bit(vmem->bitmap, vmem->bitmap_size, - last_bit + 2); - } - return ret; -} - static void virtio_mem_notify_unplug(VirtIOMEM *vmem, uint64_t offset, uint64_t size) { @@ -1667,50 +1601,6 @@ static bool virtio_mem_rds_is_populated(const RamDis= cardSource *rds, return virtio_mem_is_range_plugged(vmem, start_gpa, end_gpa - start_gp= a); } =20 -struct VirtIOMEMReplayData { - ReplayRamDiscardState fn; - void *opaque; -}; - -static int virtio_mem_rds_replay_cb(MemoryRegionSection *s, void *arg) -{ - struct VirtIOMEMReplayData *data =3D arg; - - return data->fn(s, data->opaque); -} - -static int virtio_mem_rds_replay_populated(const RamDiscardSource *rds, - const MemoryRegionSection *s, - ReplayRamDiscardState replay_fn, - void *opaque) -{ - const VirtIOMEM *vmem =3D VIRTIO_MEM(rds); - struct VirtIOMEMReplayData data =3D { - .fn =3D replay_fn, - .opaque =3D opaque, - }; - - g_assert(s->mr =3D=3D &vmem->memdev->mr); - return virtio_mem_for_each_plugged_section(vmem, s, &data, - virtio_mem_rds_replay_cb); -} - -static int virtio_mem_rds_replay_discarded(const RamDiscardSource *rds, - const MemoryRegionSection *s, - ReplayRamDiscardState replay_fn, - void *opaque) -{ - const VirtIOMEM *vmem =3D VIRTIO_MEM(rds); - struct VirtIOMEMReplayData data =3D { - .fn =3D replay_fn, - .opaque =3D opaque, - }; - - g_assert(s->mr =3D=3D &vmem->memdev->mr); - return virtio_mem_for_each_unplugged_section(vmem, s, &data, - virtio_mem_rds_replay_cb); -} - static void virtio_mem_unplug_request_check(VirtIOMEM *vmem, Error **errp) { if (vmem->unplugged_inaccessible =3D=3D ON_OFF_AUTO_OFF) { @@ -1766,8 +1656,6 @@ static void virtio_mem_class_init(ObjectClass *klass,= const void *data) =20 rdsc->get_min_granularity =3D virtio_mem_rds_get_min_granularity; rdsc->is_populated =3D virtio_mem_rds_is_populated; - rdsc->replay_populated =3D virtio_mem_rds_replay_populated; - rdsc->replay_discarded =3D virtio_mem_rds_replay_discarded; } =20 static const TypeInfo virtio_mem_info =3D { --=20 2.54.0 From nobody Thu Jun 25 06:56:52 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1782218986; cv=none; d=zohomail.com; s=zohoarc; b=cCTEexTHP+v8AQZeKbbLjH5+tKQ/14t2XCK/s6H/UG8B8lz2xqugF3XZ4qXpDYwf0hSFsGnxnBh9R/+duTUIuxej8blrAMCZsnhbp3RUqC21qzd2ts9f9dLrTbvqPTn06Q0HyhGsNZyxUJtyn3UJbLrOHkWIIg9WpR74dJszOKg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1782218986; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=XnHOf95eEO5Hr/V1VRLg1UJ6geTMs4NXXavyS/3wyUs=; b=TmTjGXYucMBhypas57D7B1LwVq+dVZCDGx+75FzHa1CnJtfwNAwSsokdFczJG742Qr081IDvB+JHtq2Sh9adFE2KG6xAt1jPAYKvBnOVFbX8pBvIOHC+aZzpyDrHgizEuoSjKA2GodI1DG32tGo3MP/vhkDhlkv9rjLunVQ3q9c= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1782218986151633.0578491651952; Tue, 23 Jun 2026 05:49:46 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wc0Yb-0004aB-Lx; Tue, 23 Jun 2026 08:48:49 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0Ya-0004ZA-7K for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:48 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YW-00071r-LH for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:47 -0400 Received: from mail-qt1-f197.google.com (mail-qt1-f197.google.com [209.85.160.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-643-Cg5U7s2EN9mUZcQ0aOIU4g-1; Tue, 23 Jun 2026 08:48:39 -0400 Received: by mail-qt1-f197.google.com with SMTP id d75a77b69052e-517878a92c5so100458451cf.3 for ; Tue, 23 Jun 2026 05:48:39 -0700 (PDT) Received: from x1.com ([174.91.117.157]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51a51106a09sm22288351cf.0.2026.06.23.05.48.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jun 2026 05:48:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782218922; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XnHOf95eEO5Hr/V1VRLg1UJ6geTMs4NXXavyS/3wyUs=; b=HztBtmJvMKO1Dne9HkV3DVwIeQ7Bf5u5N2kmqyMcl6HJVVyXKHmezsBjCcfq8Zheo06UYr u3P5grjpxddoLlShWn0DHFHO4rpRoiuDoPyylwkWML9/u+4R6EtwEMIO3nvpBOKkkK9WpI yBFUVUJj9kd3M9VeM4IkqzhOSX/67Cw= X-MC-Unique: Cg5U7s2EN9mUZcQ0aOIU4g-1 X-Mimecast-MFC-AGG-ID: Cg5U7s2EN9mUZcQ0aOIU4g_1782218919 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1782218919; x=1782823719; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=XnHOf95eEO5Hr/V1VRLg1UJ6geTMs4NXXavyS/3wyUs=; b=ikBNIMJ3lxYIbJrAbm42RkvI9Y0OYV0hOQYwbgH2qcrXyh5Z+JAU0/zXtrBC/S4TQn cuee0O5RCTd8dGRf9pLQK7hUuYrMVvQYkajQA4Jq3FolDEZwsbenKCVTKyUtYYYNADMS LYuCrDfdFLLUZfZzDiVApKn+kJykFJPAWdE7GcfJhe+D4FGsY3y4/cYnneh3iR8Yh6PX 5oJXF/ZLnS1yugbAdWZvZ6tbjepJmXK/IvRd7ZORBaviOA57ZN9/nHqRMmlrq5myBZfe y40zjUQ82aEsehuOKyvZ76qeRR2xBqKrxyxFaZinZsHFQcwV8t0oEOQOINvKYdhfQBdk i2Mg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782218919; x=1782823719; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=XnHOf95eEO5Hr/V1VRLg1UJ6geTMs4NXXavyS/3wyUs=; b=oj7YVhhCEBuQVGt+bQLqY8iVqWpXGKGL47CEr0ZccD6BXVnbjnq7Xj5nZfHHuNYtYu zeOEYy+cp8RYyr02HVPZUECpeJRokjF3Pm0nXaPyeW7vyuxX2vhL/tjoieo21kxsnDsL KaQsXYjHANGZpHRsUWsFYaUh7PCPjCpbzPj4xEA6eS/blSVmhmwBDFTOCVU9e/3VBIYM pbDpHDqMFFvTRI9FgcP4VO86IpMPoVoBTTPKUt/VMlmHO31alSl/s91tz5WCLl3EX/vR BrBHCevnusNY15KghXMx+YVaqyBO4Js/A1Tm3ExfbsgLe/u2u2cGPWXJ7rvaVHI1HIZB XDQA== X-Gm-Message-State: AOJu0YyTUv73oe9++PxVjA6Jxy1yNaVUSq/n27zU1YU+rYRU6Nt5m1zF oYaLFF5orkSUCvMp1Lfz6Qv5cEiv6bXcW4J7tboBlkPNGMuhb0LNehfGxWxr+ymL4xMQEKkaQnP dteijZVSU4AMpxUmBLfRBIQRbaFVu02nyNdfA2p+lwuJeMLOqTnEFlfJKReyB8r6Cz/zhdLut/b G2I472J7jJzsnY1dPatkvxMZejj6Ay+NB+CW9BpA== X-Gm-Gg: AfdE7cm7NUmbo3yAgYQwwleMo9Ofwlgct546QqkeHI3qOxE5CK4v7xa1WUTIyxSkgu0 1INKtjkwMvap7md99kyKj7+MhqD1zdCoPqxXFfacagYaOuiCowJdzwf4aBkBV/fZDMi2fyTTunG 7DjtkNPsowARCGVEC5UY+WT73cFUngUZ6dJzPk4w9ku/CipIrUdVSWXLeK3wVjCPWQjVy9IfLwT mnukkdf97rT+siNOod16wbnlgz5GrzwOCN2voNzajtPJWBJeJ5WhKeROo0d8k5fAIuA/6/cDs0e zbhPYwspILZLmy4OyRWD53mFcLNjw+IB9kKkFKAuG7cvEPyYaLYmZtshnxYLYpWGPqgAIqoESPU sKQ== X-Received: by 2002:a05:622a:7503:b0:519:f423:d3e0 with SMTP id d75a77b69052e-519f99f08f6mr193504571cf.35.1782218918878; Tue, 23 Jun 2026 05:48:38 -0700 (PDT) X-Received: by 2002:a05:622a:7503:b0:519:f423:d3e0 with SMTP id d75a77b69052e-519f99f08f6mr193504081cf.35.1782218918288; Tue, 23 Jun 2026 05:48:38 -0700 (PDT) From: Peter Xu To: qemu-devel@nongnu.org Cc: Peter Xu , Fabiano Rosas , Paolo Bonzini , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , David Hildenbrand Subject: [PULL 13/18] system/ram-discard-manager: drop replay from source interface Date: Tue, 23 Jun 2026 08:47:54 -0400 Message-ID: <20260623124759.125399-14-peterx@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260623124759.125399-1-peterx@redhat.com> References: <20260623124759.125399-1-peterx@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=peterx@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1782218987376158500 From: Marc-Andr=C3=A9 Lureau Remove replay_populated and replay_discarded from RamDiscardSourceClass now that the RamDiscardManager handles replay iteration internally via is_populated. Remove the now-dead replay methods, helpers, and for_each_populated/discarded_section() from ram-block-attributes, which was the last source still carrying this code. Reviewed-by: Peter Xu Acked-by: David Hildenbrand Signed-off-by: Marc-Andr=C3=A9 Lureau Link: https://lore.kernel.org/r/20260604-rdm5-v5-6-5768e6a0943d@redhat.com Signed-off-by: Peter Xu --- include/system/ram-discard-manager.h | 52 +++-------- system/ram-block-attributes.c | 130 --------------------------- 2 files changed, 10 insertions(+), 172 deletions(-) diff --git a/include/system/ram-discard-manager.h b/include/system/ram-disc= ard-manager.h index b188e09a30..b5dbcb4a82 100644 --- a/include/system/ram-discard-manager.h +++ b/include/system/ram-discard-manager.h @@ -77,8 +77,8 @@ static inline void ram_discard_listener_init(RamDiscardLi= stener *rdl, /** * typedef ReplayRamDiscardState: * - * The callback handler for #RamDiscardSourceClass.replay_populated/ - * #RamDiscardSourceClass.replay_discarded to invoke on populated/discarded + * The callback handler used by ram_discard_manager_replay_populated() and + * ram_discard_manager_replay_discarded() to invoke on populated/discarded * parts. * * @section: the #MemoryRegionSection of populated/discarded part @@ -134,42 +134,6 @@ struct RamDiscardSourceClass { */ bool (*is_populated)(const RamDiscardSource *rds, const MemoryRegionSection *section); - - /** - * @replay_populated: - * - * Call the #ReplayRamDiscardState callback for all populated parts wi= thin - * the #MemoryRegionSection via the #RamDiscardSource. - * - * In case any call fails, no further calls are made. - * - * @rds: the #RamDiscardSource - * @section: the #MemoryRegionSection - * @replay_fn: the #ReplayRamDiscardState callback - * @opaque: pointer to forward to the callback - * - * Returns 0 on success, or a negative error if any notification faile= d. - */ - int (*replay_populated)(const RamDiscardSource *rds, - const MemoryRegionSection *section, - ReplayRamDiscardState replay_fn, void *opaque); - - /** - * @replay_discarded: - * - * Call the #ReplayRamDiscardState callback for all discarded parts wi= thin - * the #MemoryRegionSection via the #RamDiscardSource. - * - * @rds: the #RamDiscardSource - * @section: the #MemoryRegionSection - * @replay_fn: the #ReplayRamDiscardState callback - * @opaque: pointer to forward to the callback - * - * Returns 0 on success, or a negative error if any notification faile= d. - */ - int (*replay_discarded)(const RamDiscardSource *rds, - const MemoryRegionSection *section, - ReplayRamDiscardState replay_fn, void *opaque); }; =20 /** @@ -226,8 +190,10 @@ bool ram_discard_manager_is_populated(const RamDiscard= Manager *rdm, /** * ram_discard_manager_replay_populated: * - * A wrapper to call the #RamDiscardSourceClass.replay_populated callback - * of the #RamDiscardSource sources. + * Iterate the given #MemoryRegionSection at minimum granularity, calling + * #RamDiscardSourceClass.is_populated for each chunk, and invoke @replay_= fn + * for each contiguous populated range. In case any call fails, no further + * calls are made. * * @rdm: the #RamDiscardManager * @section: the #MemoryRegionSection @@ -244,8 +210,10 @@ int ram_discard_manager_replay_populated(const RamDisc= ardManager *rdm, /** * ram_discard_manager_replay_discarded: * - * A wrapper to call the #RamDiscardSourceClass.replay_discarded callback - * of the #RamDiscardSource sources. + * Iterate the given #MemoryRegionSection at minimum granularity, calling + * #RamDiscardSourceClass.is_populated for each chunk, and invoke @replay_= fn + * for each contiguous discarded range. In case any call fails, no further + * calls are made. * * @rdm: the #RamDiscardManager * @section: the #MemoryRegionSection diff --git a/system/ram-block-attributes.c b/system/ram-block-attributes.c index 79c7e97d9a..718c7075ce 100644 --- a/system/ram-block-attributes.c +++ b/system/ram-block-attributes.c @@ -32,106 +32,6 @@ ram_block_attributes_get_block_size(void) return qemu_real_host_page_size(); } =20 -typedef int (*ram_block_attributes_section_cb)(MemoryRegionSection *s, - void *arg); - -static int -ram_block_attributes_for_each_populated_section(const RamBlockAttributes *= attr, - const MemoryRegionSection = *section, - void *arg, - ram_block_attributes_secti= on_cb cb) -{ - unsigned long first_bit, last_bit; - uint64_t offset, size; - const size_t block_size =3D ram_block_attributes_get_block_size(); - int ret =3D 0; - - first_bit =3D section->offset_within_region / block_size; - first_bit =3D find_next_bit(attr->bitmap, attr->bitmap_size, - first_bit); - - while (first_bit < attr->bitmap_size) { - MemoryRegionSection tmp =3D *section; - - offset =3D first_bit * block_size; - last_bit =3D find_next_zero_bit(attr->bitmap, attr->bitmap_size, - first_bit + 1) - 1; - size =3D (last_bit - first_bit + 1) * block_size; - - if (!memory_region_section_intersect_range(&tmp, offset, size)) { - break; - } - - ret =3D cb(&tmp, arg); - if (ret) { - error_report("%s: Failed to notify RAM discard listener: %s", - __func__, strerror(-ret)); - break; - } - - first_bit =3D find_next_bit(attr->bitmap, attr->bitmap_size, - last_bit + 2); - } - - return ret; -} - -static int -ram_block_attributes_for_each_discarded_section(const RamBlockAttributes *= attr, - const MemoryRegionSection = *section, - void *arg, - ram_block_attributes_secti= on_cb cb) -{ - unsigned long first_bit, last_bit; - uint64_t offset, size; - const size_t block_size =3D ram_block_attributes_get_block_size(); - int ret =3D 0; - - first_bit =3D section->offset_within_region / block_size; - first_bit =3D find_next_zero_bit(attr->bitmap, attr->bitmap_size, - first_bit); - - while (first_bit < attr->bitmap_size) { - MemoryRegionSection tmp =3D *section; - - offset =3D first_bit * block_size; - last_bit =3D find_next_bit(attr->bitmap, attr->bitmap_size, - first_bit + 1) - 1; - size =3D (last_bit - first_bit + 1) * block_size; - - if (!memory_region_section_intersect_range(&tmp, offset, size)) { - break; - } - - ret =3D cb(&tmp, arg); - if (ret) { - error_report("%s: Failed to notify RAM discard listener: %s", - __func__, strerror(-ret)); - break; - } - - first_bit =3D find_next_zero_bit(attr->bitmap, - attr->bitmap_size, - last_bit + 2); - } - - return ret; -} - - -typedef struct RamBlockAttributesReplayData { - ReplayRamDiscardState fn; - void *opaque; -} RamBlockAttributesReplayData; - -static int ram_block_attributes_rds_replay_cb(MemoryRegionSection *section, - void *arg) -{ - RamBlockAttributesReplayData *data =3D arg; - - return data->fn(section, data->opaque); -} - /* RamDiscardSource interface implementation */ static uint64_t ram_block_attributes_rds_get_min_granularity(const RamDiscardSource *rds, @@ -159,34 +59,6 @@ ram_block_attributes_rds_is_populated(const RamDiscardS= ource *rds, return first_discarded_bit > last_bit; } =20 -static int -ram_block_attributes_rds_replay_populated(const RamDiscardSource *rds, - const MemoryRegionSection *secti= on, - ReplayRamDiscardState replay_fn, - void *opaque) -{ - RamBlockAttributes *attr =3D RAM_BLOCK_ATTRIBUTES(rds); - RamBlockAttributesReplayData data =3D { .fn =3D replay_fn, .opaque =3D= opaque }; - - g_assert(section->mr =3D=3D attr->ram_block->mr); - return ram_block_attributes_for_each_populated_section(attr, section, = &data, - ram_block_attributes_rds_replay_cb); -} - -static int -ram_block_attributes_rds_replay_discarded(const RamDiscardSource *rds, - const MemoryRegionSection *secti= on, - ReplayRamDiscardState replay_fn, - void *opaque) -{ - RamBlockAttributes *attr =3D RAM_BLOCK_ATTRIBUTES(rds); - RamBlockAttributesReplayData data =3D { .fn =3D replay_fn, .opaque =3D= opaque }; - - g_assert(section->mr =3D=3D attr->ram_block->mr); - return ram_block_attributes_for_each_discarded_section(attr, section, = &data, - ram_block_attributes_rds_replay_cb); -} - static bool ram_block_attributes_is_valid_range(RamBlockAttributes *attr, uint64_t off= set, uint64_t size) @@ -346,6 +218,4 @@ static void ram_block_attributes_class_init(ObjectClass= *klass, =20 rdsc->get_min_granularity =3D ram_block_attributes_rds_get_min_granula= rity; rdsc->is_populated =3D ram_block_attributes_rds_is_populated; - rdsc->replay_populated =3D ram_block_attributes_rds_replay_populated; - rdsc->replay_discarded =3D ram_block_attributes_rds_replay_discarded; } --=20 2.54.0 From nobody Thu Jun 25 06:56:52 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1782219048; cv=none; d=zohomail.com; s=zohoarc; b=csGJcWGU/H+uIB1JXuf6O3jm3qOXRL3Jdh1kPtX60gPMIXz9ZuIzi+lRgofuhNdZQKooRu29bp7vD4IlQA6ZTc+fjfYIAh1fXloBujzZ3JK1ZsB6HUWNCuid9kUeqMo5pyesQ+lDc4r4Yo5kKjo30WIzmiSOcZL77VIVNC6v054= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1782219048; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=M1S9Am+qRlQDZIfNOH3kc37vcocVYL9s7hDwmoAwKVQ=; b=ik7sox4x9Zfigzpv7wX8k1He7EDXHGfJXofzx74zMHz6yxp/BWWcwm4f0OgDjJa5Mja/SAdPpFm+B1hC+4v/lOfi4XfJYXe2tJlYEx4+slvj6RlwgR+0Zhg9YDZWzleEkZOsTSMjDami2H+9/IHxO4VFEQBlqNoXv3INjy9Vb2I= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1782219048365213.20855260721817; Tue, 23 Jun 2026 05:50:48 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wc0Yd-0004bA-Ni; Tue, 23 Jun 2026 08:48:51 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0Yb-0004aD-Qr for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:49 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YX-00071z-1x for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:49 -0400 Received: from mail-qt1-f199.google.com (mail-qt1-f199.google.com [209.85.160.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-632-q6NdylNHP3O4KyhHRex6xw-1; Tue, 23 Jun 2026 08:48:43 -0400 Received: by mail-qt1-f199.google.com with SMTP id d75a77b69052e-517c65e497eso106854321cf.2 for ; Tue, 23 Jun 2026 05:48:43 -0700 (PDT) Received: from x1.com ([174.91.117.157]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51a51106a09sm22288351cf.0.2026.06.23.05.48.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jun 2026 05:48:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782218924; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=M1S9Am+qRlQDZIfNOH3kc37vcocVYL9s7hDwmoAwKVQ=; b=BVIyAJ4KeaHo4nRKQizj7cgYYVFNJIQdqxBw59+Q8XLNvtFGEp6NfjAE5UepsxlHv5Leka t1/ap9XhAm+6tJoTXQZzG8INWJBuu4hkrx2r1+QvyMDqVvawrFY/lHdf2GnLTEC57ZB4rd paNGH3C+Yp2rmhrxabGrDOuDdtO3RB4= X-MC-Unique: q6NdylNHP3O4KyhHRex6xw-1 X-Mimecast-MFC-AGG-ID: q6NdylNHP3O4KyhHRex6xw_1782218922 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1782218922; x=1782823722; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=M1S9Am+qRlQDZIfNOH3kc37vcocVYL9s7hDwmoAwKVQ=; b=Mk1bgcZtqiE1jsEGsHtlEr4UrwUeA2Ai6olljYHqj9MkpO/CUOzP62r8WaFid+IN96 Y7XBmeNstb2sd2zxyJPHW3BI2SEwOYUGUp4D2/XIUSTXJB43ix3mTHqXM3VrllLP560U 4Uzv90aj5pDRsSFrRw/VNiazRD7q+Txd8jCLtO7bzcEROkFW3ydDy4Vnj8UKu8yeblwb kxTdV0bHlBPdXkwF7gKS7vB5S7UJfWHDMOZGK6n4wI2DgchqaYQ9NexcEVUb0vDsncR4 cNVECxqi8um41l1zbowJFIcTUjTdMhwmjMcAyc+/RZB/DrF7WrB98Py/oaUf6IeUakel 0wLg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782218922; x=1782823722; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=M1S9Am+qRlQDZIfNOH3kc37vcocVYL9s7hDwmoAwKVQ=; b=JnhBmvZFEh8+/Mr9DJHRikCVi16Pkn7f6320IHGGq+W8bSKsy0jiCz/NU5lYZVe7K9 W+XWtgReY0/yJLE9mV6RfLt3X8+mQYObHFfanr2BjONRqehx0PcTBgkSA5J7Te5qyZ/a POCh6pqeRV0YTVzfvtUXa8ogAXqJLcgMFrxZK8f9jxALvfwG8FIbom2n/75lyw41fSPc oN+AD7Xsl2PO2vqUqbJSN6yh2JD0F1GZsMF/jz2zKed+mCEzHNDG/sJ6woxO27sqeLHl lpfV4BHxnP+81tJJDzoOi2r8PnRrzcvj/GDV+0CzE5IECHIjHSDzlAaoQCpc8+zUCHYm qzpw== X-Gm-Message-State: AOJu0Yy9xDAUqrYlqcnCXlPgRxd+ujyqatd8ZSoMwZAg++x/aFK0m+C1 JByJydoL9ToQpMe71GzzyNiGn/2aLV4Qvdjj4YEzrFVfdPxbC5ToiLr5aGkJE7gXCh9wCTTRGZe W6laM8Z+NvPUf7NlL0FDYCuBj6PXQHG1L+t2QY42FtZp8ZtetUNesNeLIDDSo5L6wJfryHMqNrX 2Pl/Tj2FaUMwpQOEY8nU/MRW758adVBUBh9oj26w== X-Gm-Gg: AfdE7cnA3O256g14kt0EVEDzlSCP/mlXxMTAKtSY/dy0VGh0w+xaNAKmoIlkMVqzm7z 9+++eAJvGgYvLT5ufhnDoK2XLS7jm0m4Kx6uJ66EATFF/LoTE/IDAZRSscGyy9MrtR5M9zUWyho /NSG2nUaMkKapWkoc1VNCBJ6AGmbFEoKQPTs0KeKuMqF79UExs/Ot4GiSCNuSSqUie5tjb8nLtA ftd574SnmrW9gwBFmBGfdV8rbebITCw2tQNdstIMCMCbn+b0zM/yqBc1uibKaO7UpngkGpgFWrH M2pdhyLL5m7JGmHfzbgfm0lB16mxG0azJ0zczP0RgmSb1HtQMoMFZwL8HrtOg5I8kEoUJy42GJF uAg== X-Received: by 2002:a05:622a:389:b0:516:df62:bdd2 with SMTP id d75a77b69052e-51a06b2b24cmr221726191cf.55.1782218921907; Tue, 23 Jun 2026 05:48:41 -0700 (PDT) X-Received: by 2002:a05:622a:389:b0:516:df62:bdd2 with SMTP id d75a77b69052e-51a06b2b24cmr221725501cf.55.1782218921111; Tue, 23 Jun 2026 05:48:41 -0700 (PDT) From: Peter Xu To: qemu-devel@nongnu.org Cc: Peter Xu , Fabiano Rosas , Paolo Bonzini , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Subject: [PULL 14/18] system/memory: implement RamDiscardManager multi-source aggregation Date: Tue, 23 Jun 2026 08:47:55 -0400 Message-ID: <20260623124759.125399-15-peterx@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260623124759.125399-1-peterx@redhat.com> References: <20260623124759.125399-1-peterx@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=peterx@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1782219049824158500 From: Marc-Andr=C3=A9 Lureau Refactor RamDiscardManager to aggregate multiple RamDiscardSource instances. This enables scenarios where multiple components (e.g., virtio-mem and RamBlockAttributes) can coordinate memory discard state for the same memory region. The aggregation uses: - Populated: ALL sources populated - Discarded: ANY source discarded When a source is added with existing listeners, they are notified about regions that become discarded. When a source is removed, listeners are notified about regions that become populated. Reviewed-by: Peter Xu Signed-off-by: Marc-Andr=C3=A9 Lureau Link: https://lore.kernel.org/r/20260604-rdm5-v5-7-5768e6a0943d@redhat.com Signed-off-by: Peter Xu --- include/system/memory.h | 4 +- include/system/ram-discard-manager.h | 141 +++++++-- hw/virtio/virtio-mem.c | 8 +- system/memory.c | 17 +- system/ram-block-attributes.c | 6 +- system/ram-discard-manager.c | 427 ++++++++++++++++++++++++--- 6 files changed, 518 insertions(+), 85 deletions(-) diff --git a/include/system/memory.h b/include/system/memory.h index 4a700cb657..47a0e06fbf 100644 --- a/include/system/memory.h +++ b/include/system/memory.h @@ -2261,8 +2261,10 @@ int memory_region_add_ram_discard_source(MemoryRegio= n *mr, RamDiscardSource *sou * * @mr: the #MemoryRegion * @source: #RamDiscardSource to remove + * + * Returns: 0 on success, or a negative error code on failure. */ -void memory_region_del_ram_discard_source(MemoryRegion *mr, RamDiscardSour= ce *source); +int memory_region_del_ram_discard_source(MemoryRegion *mr, RamDiscardSourc= e *source); =20 /** * memory_region_find: translate an address/size relative to a diff --git a/include/system/ram-discard-manager.h b/include/system/ram-disc= ard-manager.h index b5dbcb4a82..05d3d31b55 100644 --- a/include/system/ram-discard-manager.h +++ b/include/system/ram-discard-manager.h @@ -170,30 +170,96 @@ struct RamDiscardSourceClass { * becoming discarded in a different granularity than it was populated and= the * other way around. */ + +typedef struct RamDiscardSourceEntry RamDiscardSourceEntry; + +struct RamDiscardSourceEntry { + RamDiscardSource *rds; + QLIST_ENTRY(RamDiscardSourceEntry) next; +}; + struct RamDiscardManager { Object parent; =20 - RamDiscardSource *rds; MemoryRegion *mr; + QLIST_HEAD(, RamDiscardSourceEntry) source_list; + uint64_t min_granularity; QLIST_HEAD(, RamDiscardListener) rdl_list; }; =20 -RamDiscardManager *ram_discard_manager_new(MemoryRegion *mr, - RamDiscardSource *rds); +RamDiscardManager *ram_discard_manager_new(MemoryRegion *mr); + +/** + * ram_discard_manager_add_source: + * + * Register a #RamDiscardSource with the #RamDiscardManager. The manager + * aggregates state from all registered sources using AND semantics: a reg= ion + * is considered populated only if ALL sources report it as populated. + * + * If listeners are already registered, they will be notified about any + * regions that become discarded due to adding this source. Specifically, + * for each region that the new source reports as discarded, if all other + * sources reported it as populated, listeners receive a discard notificat= ion. + * + * If any listener rejects the notification (returns an error), previously + * notified listeners are rolled back with populate notifications and the + * source is not added. + * + * @rdm: the #RamDiscardManager + * @source: the #RamDiscardSource to add + * + * Returns: 0 on success, -EBUSY if @source is already registered, or a + * negative error code if a listener rejected the state change. + */ +int ram_discard_manager_add_source(RamDiscardManager *rdm, + RamDiscardSource *source); + +/** + * ram_discard_manager_del_source: + * + * Unregister a #RamDiscardSource from the #RamDiscardManager. + * + * If listeners are already registered, they will be notified about any + * regions that become populated due to removing this source. Specifically, + * for each region that the removed source reported as discarded, if all + * remaining sources report it as populated, listeners receive a populate + * notification. + * + * If any listener rejects the notification (returns an error), previously + * notified listeners are rolled back with discard notifications and the + * source is not removed. + * + * @rdm: the #RamDiscardManager + * @source: the #RamDiscardSource to remove + * + * Returns: 0 on success, -ENOENT if @source is not registered, or a + * negative error code if a listener rejected the state change. + */ +int ram_discard_manager_del_source(RamDiscardManager *rdm, + RamDiscardSource *source); + =20 uint64_t ram_discard_manager_get_min_granularity(const RamDiscardManager *= rdm, const MemoryRegion *mr); =20 +/** + * ram_discard_manager_is_populated: + * + * Check if the given memory region section is populated. + * If the manager has no sources, it is considered populated. + * + * @rdm: the #RamDiscardManager + * @section: the #MemoryRegionSection to check + * + * Returns: true if the section is populated, false otherwise. + */ bool ram_discard_manager_is_populated(const RamDiscardManager *rdm, const MemoryRegionSection *section); =20 /** * ram_discard_manager_replay_populated: * - * Iterate the given #MemoryRegionSection at minimum granularity, calling - * #RamDiscardSourceClass.is_populated for each chunk, and invoke @replay_= fn - * for each contiguous populated range. In case any call fails, no further - * calls are made. + * Call @replay_fn on regions that are populated in all sources. * * @rdm: the #RamDiscardManager * @section: the #MemoryRegionSection @@ -210,10 +276,7 @@ int ram_discard_manager_replay_populated(const RamDisc= ardManager *rdm, /** * ram_discard_manager_replay_discarded: * - * Iterate the given #MemoryRegionSection at minimum granularity, calling - * #RamDiscardSourceClass.is_populated for each chunk, and invoke @replay_= fn - * for each contiguous discarded range. In case any call fails, no further - * calls are made. + * Call @replay_fn on regions that are discarded in any sources. * * @rdm: the #RamDiscardManager * @section: the #MemoryRegionSection @@ -234,31 +297,61 @@ void ram_discard_manager_register_listener(RamDiscard= Manager *rdm, void ram_discard_manager_unregister_listener(RamDiscardManager *rdm, RamDiscardListener *rdl); =20 -/* - * Note: later refactoring should take the source into account and the man= ager - * should be able to aggregate multiple sources. +/** + * ram_discard_manager_notify_populate: + * + * Notify listeners that a region is about to be populated by a source. + * For multi-source aggregation, only notifies when all sources agree + * the region is populated (intersection). + * + * @rdm: the #RamDiscardManager + * @source: the #RamDiscardSource that is populating + * @offset: offset within the memory region + * @size: size of the region being populated + * + * Returns 0 on success, or a negative error if any listener rejects. */ int ram_discard_manager_notify_populate(RamDiscardManager *rdm, + RamDiscardSource *source, uint64_t offset, uint64_t size); =20 -/* - * Note: later refactoring should take the source into account and the man= ager - * should be able to aggregate multiple sources. +/** + * ram_discard_manager_notify_discard: + * + * Notify listeners that a region has been discarded by a source. + * For multi-source aggregation, always notifies immediately + * (union semantics - any source discarding makes region discarded). + * + * @rdm: the #RamDiscardManager + * @source: the #RamDiscardSource that is discarding + * @offset: offset within the memory region + * @size: size of the region being discarded */ void ram_discard_manager_notify_discard(RamDiscardManager *rdm, + RamDiscardSource *source, uint64_t offset, uint64_t size); =20 -/* - * Note: later refactoring should take the source into account and the man= ager - * should be able to aggregate multiple sources. +/** + * ram_discard_manager_notify_discard_all: + * + * Notify listeners that all regions have been discarded by a source. + * + * @rdm: the #RamDiscardManager + * @source: the #RamDiscardSource that is discarding */ -void ram_discard_manager_notify_discard_all(RamDiscardManager *rdm); +void ram_discard_manager_notify_discard_all(RamDiscardManager *rdm, + RamDiscardSource *source); =20 -/* +/** + * ram_discard_manager_replay_populated_to_listeners: + * * Replay populated sections to all registered listeners. + * For multi-source aggregation, only replays regions where all sources + * are populated (intersection). * - * Note: later refactoring should take the source into account and the man= ager - * should be able to aggregate multiple sources. + * @rdm: the #RamDiscardManager + * + * Returns 0 on success, or a negative error if any notification failed. */ int ram_discard_manager_replay_populated_to_listeners(RamDiscardManager *r= dm); =20 diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index 2b67b2882d..35e03ed759 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -264,7 +264,8 @@ static void virtio_mem_notify_unplug(VirtIOMEM *vmem, u= int64_t offset, { RamDiscardManager *rdm =3D memory_region_get_ram_discard_manager(&vmem= ->memdev->mr); =20 - ram_discard_manager_notify_discard(rdm, offset, size); + ram_discard_manager_notify_discard(rdm, RAM_DISCARD_SOURCE(vmem), + offset, size); } =20 static int virtio_mem_notify_plug(VirtIOMEM *vmem, uint64_t offset, @@ -272,7 +273,8 @@ static int virtio_mem_notify_plug(VirtIOMEM *vmem, uint= 64_t offset, { RamDiscardManager *rdm =3D memory_region_get_ram_discard_manager(&vmem= ->memdev->mr); =20 - return ram_discard_manager_notify_populate(rdm, offset, size); + return ram_discard_manager_notify_populate(rdm, RAM_DISCARD_SOURCE(vme= m), + offset, size); } =20 static void virtio_mem_notify_unplug_all(VirtIOMEM *vmem) @@ -283,7 +285,7 @@ static void virtio_mem_notify_unplug_all(VirtIOMEM *vme= m) return; } =20 - ram_discard_manager_notify_discard_all(rdm); + ram_discard_manager_notify_discard_all(rdm, RAM_DISCARD_SOURCE(vmem)); } =20 static bool virtio_mem_is_range_plugged(const VirtIOMEM *vmem, diff --git a/system/memory.c b/system/memory.c index 5a598ca58c..119fee0d34 100644 --- a/system/memory.c +++ b/system/memory.c @@ -2073,21 +2073,22 @@ int memory_region_add_ram_discard_source(MemoryRegi= on *mr, RamDiscardSource *source) { g_assert(memory_region_is_ram(mr)); - if (mr->rdm) { - return -EBUSY; + + if (!mr->rdm) { + mr->rdm =3D ram_discard_manager_new(mr); } =20 - mr->rdm =3D ram_discard_manager_new(mr, RAM_DISCARD_SOURCE(source)); - return 0; + return ram_discard_manager_add_source(mr->rdm, source); } =20 -void memory_region_del_ram_discard_source(MemoryRegion *mr, +int memory_region_del_ram_discard_source(MemoryRegion *mr, RamDiscardSource *source) { - g_assert(mr->rdm->rds =3D=3D source); + g_assert(mr->rdm); + + return ram_discard_manager_del_source(mr->rdm, source); =20 - object_unref(mr->rdm); - mr->rdm =3D NULL; + /* if there is no source and no listener left, we could free rdm */ } =20 /* Called with rcu_read_lock held. */ diff --git a/system/ram-block-attributes.c b/system/ram-block-attributes.c index 718c7075ce..59ec7a28eb 100644 --- a/system/ram-block-attributes.c +++ b/system/ram-block-attributes.c @@ -90,7 +90,8 @@ ram_block_attributes_notify_discard(RamBlockAttributes *a= ttr, { RamDiscardManager *rdm =3D memory_region_get_ram_discard_manager(attr-= >ram_block->mr); =20 - ram_discard_manager_notify_discard(rdm, offset, size); + ram_discard_manager_notify_discard(rdm, RAM_DISCARD_SOURCE(attr), + offset, size); } =20 static int @@ -99,7 +100,8 @@ ram_block_attributes_notify_populate(RamBlockAttributes = *attr, { RamDiscardManager *rdm =3D memory_region_get_ram_discard_manager(attr-= >ram_block->mr); =20 - return ram_discard_manager_notify_populate(rdm, offset, size); + return ram_discard_manager_notify_populate(rdm, RAM_DISCARD_SOURCE(att= r), + offset, size); } =20 int ram_block_attributes_state_change(RamBlockAttributes *attr, diff --git a/system/ram-discard-manager.c b/system/ram-discard-manager.c index a907ddf370..7da91bf648 100644 --- a/system/ram-discard-manager.c +++ b/system/ram-discard-manager.c @@ -7,6 +7,7 @@ =20 #include "qemu/osdep.h" #include "qemu/error-report.h" +#include "qemu/queue.h" #include "system/memory.h" =20 static uint64_t ram_discard_source_get_min_granularity(const RamDiscardSou= rce *rds, @@ -28,20 +29,21 @@ static bool ram_discard_source_is_populated(const RamDi= scardSource *rds, } =20 /* - * Iterate the section at source granularity, aggregating consecutive chun= ks - * with matching populated state, and call replay_fn for each run. + * Iterate a single source's populated or discarded regions and call + * replay_fn for each contiguous run. */ -static int replay_by_populated_state(const RamDiscardManager *rdm, - const MemoryRegionSection *section, - bool replay_populated, - ReplayRamDiscardState replay_fn, - void *opaque) +static int replay_source_by_state(const RamDiscardSource *source, + const MemoryRegion *mr, + const MemoryRegionSection *section, + bool replay_populated, + ReplayRamDiscardState replay_fn, + void *opaque) { uint64_t granularity, offset, size, end, pos, run_start =3D 0; bool in_run =3D false; int ret =3D 0; =20 - granularity =3D ram_discard_source_get_min_granularity(rdm->rds, rdm->= mr); + granularity =3D ram_discard_source_get_min_granularity(source, mr); offset =3D section->offset_within_region; size =3D int128_get64(section->size); end =3D offset + size; @@ -55,7 +57,7 @@ static int replay_by_populated_state(const RamDiscardMana= ger *rdm, .offset_within_region =3D pos, .size =3D int128_make64(granularity), }; - bool populated =3D ram_discard_source_is_populated(rdm->rds, &chun= k); + bool populated =3D ram_discard_source_is_populated(source, &chunk); =20 if (populated =3D=3D replay_populated) { if (!in_run) { @@ -88,28 +90,338 @@ static int replay_by_populated_state(const RamDiscardM= anager *rdm, return ret; } =20 -RamDiscardManager *ram_discard_manager_new(MemoryRegion *mr, - RamDiscardSource *rds) +RamDiscardManager *ram_discard_manager_new(MemoryRegion *mr) { RamDiscardManager *rdm; =20 rdm =3D RAM_DISCARD_MANAGER(object_new(TYPE_RAM_DISCARD_MANAGER)); - rdm->rds =3D rds; rdm->mr =3D mr; - QLIST_INIT(&rdm->rdl_list); return rdm; } =20 +static void ram_discard_manager_update_granularity(RamDiscardManager *rdm) +{ + RamDiscardSourceEntry *entry; + uint64_t granularity =3D 0; + + QLIST_FOREACH(entry, &rdm->source_list, next) { + uint64_t src_granularity; + + src_granularity =3D + ram_discard_source_get_min_granularity(entry->rds, rdm->mr); + g_assert(src_granularity !=3D 0); + if (granularity =3D=3D 0) { + granularity =3D src_granularity; + } else { + granularity =3D MIN(granularity, src_granularity); + } + } + rdm->min_granularity =3D granularity; +} + +static RamDiscardSourceEntry * +ram_discard_manager_find_source(RamDiscardManager *rdm, RamDiscardSource *= rds) +{ + RamDiscardSourceEntry *entry; + + QLIST_FOREACH(entry, &rdm->source_list, next) { + if (entry->rds =3D=3D rds) { + return entry; + } + } + return NULL; +} + +static int rdl_populate_cb(const MemoryRegionSection *section, void *opaqu= e) +{ + RamDiscardListener *rdl =3D opaque; + MemoryRegionSection tmp =3D *rdl->section; + + g_assert(section->mr =3D=3D rdl->section->mr); + + if (!memory_region_section_intersect_range(&tmp, + section->offset_within_regi= on, + int128_get64(section->size)= )) { + return 0; + } + + return rdl->notify_populate(rdl, &tmp); +} + +static int rdl_discard_cb(const MemoryRegionSection *section, void *opaque) +{ + RamDiscardListener *rdl =3D opaque; + MemoryRegionSection tmp =3D *rdl->section; + + g_assert(section->mr =3D=3D rdl->section->mr); + + if (!memory_region_section_intersect_range(&tmp, + section->offset_within_regi= on, + int128_get64(section->size)= )) { + return 0; + } + + rdl->notify_discard(rdl, &tmp); + return 0; +} + +static bool rdm_is_all_populated_skip(const RamDiscardManager *rdm, + const MemoryRegionSection *section, + const RamDiscardSource *skip_source) +{ + RamDiscardSourceEntry *entry; + + QLIST_FOREACH(entry, &rdm->source_list, next) { + if (skip_source && entry->rds =3D=3D skip_source) { + continue; + } + if (!ram_discard_source_is_populated(entry->rds, section)) { + return false; + } + } + return true; +} + +typedef struct SourceNotifyCtx { + RamDiscardManager *rdm; + RamDiscardListener *rdl; + RamDiscardSource *source; /* added or removed */ +} SourceNotifyCtx; + +/* + * Unified helper to replay regions based on populated state. + * If replay_populated is true: replay regions where ALL sources are popul= ated. + * If replay_populated is false: replay regions where ANY source is discar= ded. + */ +static int replay_by_populated_state(const RamDiscardManager *rdm, + const MemoryRegionSection *section, + const RamDiscardSource *skip_source, + bool replay_populated, + ReplayRamDiscardState replay_fn, + void *user_opaque) +{ + uint64_t granularity =3D rdm->min_granularity; + uint64_t offset, end_offset; + uint64_t run_start =3D 0; + bool in_run =3D false; + int ret =3D 0; + + if (QLIST_EMPTY(&rdm->source_list)) { + if (replay_populated) { + return replay_fn(section, user_opaque); + } + return 0; + } + + g_assert(granularity !=3D 0); + + offset =3D section->offset_within_region; + end_offset =3D offset + int128_get64(section->size); + + while (offset < end_offset) { + MemoryRegionSection subsection =3D { + .mr =3D section->mr, + .offset_within_region =3D offset, + .size =3D int128_make64(MIN(granularity, end_offset - offset)), + }; + bool all_populated; + bool included; + + all_populated =3D rdm_is_all_populated_skip(rdm, &subsection, + skip_source); + included =3D replay_populated ? all_populated : !all_populated; + + if (included) { + if (!in_run) { + run_start =3D offset; + in_run =3D true; + } + } else { + if (in_run) { + MemoryRegionSection run_section =3D { + .mr =3D section->mr, + .offset_within_region =3D run_start, + .size =3D int128_make64(offset - run_start), + }; + ret =3D replay_fn(&run_section, user_opaque); + if (ret) { + return ret; + } + in_run =3D false; + } + } + if (granularity > end_offset - offset) { + break; + } + offset +=3D granularity; + } + + if (in_run) { + MemoryRegionSection run_section =3D { + .mr =3D section->mr, + .offset_within_region =3D run_start, + .size =3D int128_make64(end_offset - run_start), + }; + ret =3D replay_fn(&run_section, user_opaque); + } + + return ret; +} + +static int add_source_check_discard_cb(const MemoryRegionSection *section, + void *opaque) +{ + SourceNotifyCtx *ctx =3D opaque; + + return replay_by_populated_state(ctx->rdm, section, ctx->source, true, + rdl_discard_cb, ctx->rdl); +} + +static int del_source_check_populate_cb(const MemoryRegionSection *section, + void *opaque) +{ + SourceNotifyCtx *ctx =3D opaque; + + return replay_by_populated_state(ctx->rdm, section, ctx->source, true, + rdl_populate_cb, ctx->rdl); +} + +int ram_discard_manager_add_source(RamDiscardManager *rdm, + RamDiscardSource *source) +{ + RamDiscardSourceEntry *entry; + RamDiscardListener *rdl, *rdl2; + int ret =3D 0; + + if (ram_discard_manager_find_source(rdm, source)) { + return -EBUSY; + } + + /* + * If there are existing listeners, notify them about regions that + * become discarded due to adding this source. Only notify for regions + * that were previously populated (all other sources agreed). + */ + QLIST_FOREACH(rdl, &rdm->rdl_list, next) { + SourceNotifyCtx ctx =3D { + .rdm =3D rdm, + .rdl =3D rdl, + /* no need to set source */ + }; + ret =3D replay_source_by_state(source, rdm->mr, rdl->section, + false, + add_source_check_discard_cb, &ctx); + if (ret) { + break; + } + } + if (ret) { + QLIST_FOREACH(rdl2, &rdm->rdl_list, next) { + SourceNotifyCtx ctx =3D { + .rdm =3D rdm, + .rdl =3D rdl2, + }; + replay_source_by_state(source, rdm->mr, rdl2->section, + false, + del_source_check_populate_cb, + &ctx); + if (rdl =3D=3D rdl2) { + break; + } + } + + return ret; + } + + entry =3D g_new0(RamDiscardSourceEntry, 1); + entry->rds =3D source; + QLIST_INSERT_HEAD(&rdm->source_list, entry, next); + + ram_discard_manager_update_granularity(rdm); + + return ret; +} + +int ram_discard_manager_del_source(RamDiscardManager *rdm, + RamDiscardSource *source) +{ + RamDiscardSourceEntry *entry; + RamDiscardListener *rdl, *rdl2; + int ret =3D 0; + + entry =3D ram_discard_manager_find_source(rdm, source); + if (!entry) { + return -ENOENT; + } + + /* + * If there are existing listeners, check if any regions become + * populated due to removing this source. + */ + QLIST_FOREACH(rdl, &rdm->rdl_list, next) { + SourceNotifyCtx ctx =3D { + .rdm =3D rdm, + .rdl =3D rdl, + .source =3D source, + }; + /* + * From the previously discarded regions, check if any + * regions become populated. + */ + ret =3D replay_source_by_state(source, rdm->mr, rdl->section, + false, + del_source_check_populate_cb, + &ctx); + if (ret) { + break; + } + } + if (ret) { + QLIST_FOREACH(rdl2, &rdm->rdl_list, next) { + SourceNotifyCtx ctx =3D { + .rdm =3D rdm, + .rdl =3D rdl2, + .source =3D source, + }; + replay_source_by_state(source, rdm->mr, rdl2->section, + false, + add_source_check_discard_cb, + &ctx); + if (rdl =3D=3D rdl2) { + break; + } + } + + return ret; + } + + QLIST_REMOVE(entry, next); + g_free(entry); + ram_discard_manager_update_granularity(rdm); + return ret; +} + uint64_t ram_discard_manager_get_min_granularity(const RamDiscardManager *= rdm, const MemoryRegion *mr) { - return ram_discard_source_get_min_granularity(rdm->rds, mr); + g_assert(mr =3D=3D rdm->mr); + return rdm->min_granularity; } =20 +/* + * Aggregated query: returns true only if ALL sources report populated (AN= D). + */ bool ram_discard_manager_is_populated(const RamDiscardManager *rdm, const MemoryRegionSection *section) { - return ram_discard_source_is_populated(rdm->rds, section); + RamDiscardSourceEntry *entry; + + QLIST_FOREACH(entry, &rdm->source_list, next) { + if (!ram_discard_source_is_populated(entry->rds, section)) { + return false; + } + } + return true; } =20 int ram_discard_manager_replay_populated(const RamDiscardManager *rdm, @@ -117,7 +429,8 @@ int ram_discard_manager_replay_populated(const RamDisca= rdManager *rdm, ReplayRamDiscardState replay_fn, void *opaque) { - return replay_by_populated_state(rdm, section, true, replay_fn, opaque= ); + return replay_by_populated_state(rdm, section, NULL, true, + replay_fn, opaque); } =20 int ram_discard_manager_replay_discarded(const RamDiscardManager *rdm, @@ -125,14 +438,17 @@ int ram_discard_manager_replay_discarded(const RamDis= cardManager *rdm, ReplayRamDiscardState replay_fn, void *opaque) { - return replay_by_populated_state(rdm, section, false, replay_fn, opaqu= e); + return replay_by_populated_state(rdm, section, NULL, false, + replay_fn, opaque); } =20 static void ram_discard_manager_initfn(Object *obj) { RamDiscardManager *rdm =3D RAM_DISCARD_MANAGER(obj); =20 + QLIST_INIT(&rdm->source_list); QLIST_INIT(&rdm->rdl_list); + rdm->min_granularity =3D 0; } =20 static void ram_discard_manager_finalize(Object *obj) @@ -140,74 +456,91 @@ static void ram_discard_manager_finalize(Object *obj) RamDiscardManager *rdm =3D RAM_DISCARD_MANAGER(obj); =20 g_assert(QLIST_EMPTY(&rdm->rdl_list)); + g_assert(QLIST_EMPTY(&rdm->source_list)); } =20 int ram_discard_manager_notify_populate(RamDiscardManager *rdm, + RamDiscardSource *source, uint64_t offset, uint64_t size) { RamDiscardListener *rdl, *rdl2; + MemoryRegionSection section =3D { + .mr =3D rdm->mr, + .offset_within_region =3D offset, + .size =3D int128_make64(size), + }; int ret =3D 0; =20 - QLIST_FOREACH(rdl, &rdm->rdl_list, next) { - MemoryRegionSection tmp =3D *rdl->section; + g_assert(ram_discard_manager_find_source(rdm, source)); =20 - if (!memory_region_section_intersect_range(&tmp, offset, size)) { - continue; - } - ret =3D rdl->notify_populate(rdl, &tmp); + /* + * Only notify about regions that are populated in ALL sources. + * Skip the calling source: it has implicitly declared itself populated + * for this range but may not have updated its bitmap yet. + */ + QLIST_FOREACH(rdl, &rdm->rdl_list, next) { + ret =3D replay_by_populated_state(rdm, §ion, source, true, + rdl_populate_cb, rdl); if (ret) { break; } } =20 if (ret) { - /* Notify all already-notified listeners about discard. */ + /* + * Rollback: notify discard for listeners we already notified, + * including the failing listener which may have been partially + * notified. Listeners must handle discard notifications for + * regions they didn't receive populate notifications for. + */ QLIST_FOREACH(rdl2, &rdm->rdl_list, next) { - MemoryRegionSection tmp =3D *rdl2->section; - + replay_by_populated_state(rdm, §ion, source, true, + rdl_discard_cb, rdl2); if (rdl2 =3D=3D rdl) { break; } - if (!memory_region_section_intersect_range(&tmp, offset, size)= ) { - continue; - } - rdl2->notify_discard(rdl2, &tmp); } } return ret; } =20 void ram_discard_manager_notify_discard(RamDiscardManager *rdm, + RamDiscardSource *source, uint64_t offset, uint64_t size) { RamDiscardListener *rdl; - + MemoryRegionSection section =3D { + .mr =3D rdm->mr, + .offset_within_region =3D offset, + .size =3D int128_make64(size), + }; + + g_assert(ram_discard_manager_find_source(rdm, source)); + + /* + * Only notify about ranges that were aggregately populated before this + * source's discard. Since the source has already updated its state, + * we use replay_by_populated_state with this source skipped - it will + * replay only the ranges where all OTHER sources are populated. + */ QLIST_FOREACH(rdl, &rdm->rdl_list, next) { - MemoryRegionSection tmp =3D *rdl->section; - - if (!memory_region_section_intersect_range(&tmp, offset, size)) { - continue; - } - rdl->notify_discard(rdl, &tmp); + replay_by_populated_state(rdm, §ion, source, true, + rdl_discard_cb, rdl); } } =20 -void ram_discard_manager_notify_discard_all(RamDiscardManager *rdm) +void ram_discard_manager_notify_discard_all(RamDiscardManager *rdm, + RamDiscardSource *source) { RamDiscardListener *rdl; =20 + g_assert(ram_discard_manager_find_source(rdm, source)); + QLIST_FOREACH(rdl, &rdm->rdl_list, next) { rdl->notify_discard(rdl, rdl->section); } } =20 -static int rdm_populate_cb(const MemoryRegionSection *section, void *opaqu= e) -{ - RamDiscardListener *rdl =3D opaque; - - return rdl->notify_populate(rdl, section); -} - void ram_discard_manager_register_listener(RamDiscardManager *rdm, RamDiscardListener *rdl, MemoryRegionSection *section) @@ -220,7 +553,7 @@ void ram_discard_manager_register_listener(RamDiscardMa= nager *rdm, QLIST_INSERT_HEAD(&rdm->rdl_list, rdl, next); =20 ret =3D ram_discard_manager_replay_populated(rdm, rdl->section, - rdm_populate_cb, rdl); + rdl_populate_cb, rdl); if (ret) { error_report("%s: Replaying populated ranges failed: %s", __func__, strerror(-ret)); @@ -246,7 +579,7 @@ int ram_discard_manager_replay_populated_to_listeners(R= amDiscardManager *rdm) =20 QLIST_FOREACH(rdl, &rdm->rdl_list, next) { ret =3D ram_discard_manager_replay_populated(rdm, rdl->section, - rdm_populate_cb, rdl); + rdl_populate_cb, rdl); if (ret) { break; } --=20 2.54.0 From nobody Thu Jun 25 06:56:52 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1782219027; cv=none; d=zohomail.com; s=zohoarc; b=PhC+No+6aqSDvIm1SIzJtSDPQgogzbWJi7PBxbgWzeP9qn0MZLyYzwxWZkbltfti/SoX+VcDUoDe1RIXs0xuBx0XsthkoDfNWOF1o0oyC4CDQVlef736mvWvXrekCySQmKQ2n6tBXGREcu5hKbLOafs+q6EybId1rJ87dApyb3A= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1782219027; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=mZZ5ZaBX0C10PgcNf3Ut2LEa7FLXeBfT5W3Q2HnKEVA=; b=SlWMAjDF5WRt46RcDmmdxzibnENIponJMSqkYezhE2xq1kFAa9hmucprQVjBv6ofAZiM/6NE/VMiJ/zZOiD1m0yeGeAJLb3ZKeNOh1Yv4x7IZ/gfPOmFtvkROkwal7G47FqXvRnfk2S0ezLHOpB/BJ6ph5sd2bk2CRLyPXzg8XQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1782219027784121.61973881825622; Tue, 23 Jun 2026 05:50:27 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wc0Yb-0004a3-A4; Tue, 23 Jun 2026 08:48:49 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YZ-0004Z2-Vs for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:47 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YX-00072K-Mv for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:47 -0400 Received: from mail-qt1-f200.google.com (mail-qt1-f200.google.com [209.85.160.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-617-QtUX3Fb7OwGJ16SZshrWww-1; Tue, 23 Jun 2026 08:48:44 -0400 Received: by mail-qt1-f200.google.com with SMTP id d75a77b69052e-5195760750bso108328461cf.0 for ; Tue, 23 Jun 2026 05:48:43 -0700 (PDT) Received: from x1.com ([174.91.117.157]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51a51106a09sm22288351cf.0.2026.06.23.05.48.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jun 2026 05:48:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782218925; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mZZ5ZaBX0C10PgcNf3Ut2LEa7FLXeBfT5W3Q2HnKEVA=; b=TYJQ+V2PNDrTdpiF2yCasAfRMpUrtwd8GNIVm6K61OIbhB+WnMdYkjHLxfk6kyqOlj7vo7 1zxavMPiyrdejrCcu6m1AJSu3Lzxva77pz9eQ/zm7pdYTDgy+qwHdPOJ1E4EZsslCgHNDD xvbuipjafAHrB6wwwqJvv72srC1QzSQ= X-MC-Unique: QtUX3Fb7OwGJ16SZshrWww-1 X-Mimecast-MFC-AGG-ID: QtUX3Fb7OwGJ16SZshrWww_1782218923 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1782218923; x=1782823723; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=mZZ5ZaBX0C10PgcNf3Ut2LEa7FLXeBfT5W3Q2HnKEVA=; b=s31PDra9uY8z5UTLL1Dux7/BIzqfeXpww9UNj+mJJX2fLjmbFDpBPm2SeL7ttO8Axx XuMADgDBv59IT3j6LWowv4CrEtKLxviApvtUxUAxkCCQ4Fhy07Fpu74Fa5HfM/vZAX4h 6i7IxiT4E7POilmYDe/ENNYjib1VmlAazGC2iRvPYMgJe3SMnYMXHpKUO5yqStB/RJKi 3p/2/l6hqDIr8jp4bpbey97J1Wfs1lKMkTL1cPK4llxda+GwTVwoAeimpTE/YYlwjgaq 7mG+XPDv8y7eq1a2a3eavGw6e4ggDmj98p4Vru+F800teK+L5O/BuwZnp1Yg33v4iRPJ erEA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782218923; x=1782823723; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=mZZ5ZaBX0C10PgcNf3Ut2LEa7FLXeBfT5W3Q2HnKEVA=; b=kAx78LvIAcfp3OE/cmpVWjL+le8RMkQUMAlPd6OmfNy1AzgqoKrevVVK9iabVDIvJU AyW3glYeEDr+qlRFAavXY+7Pm+8MLf4XjwjCXF/zlLitqXGpTM8pn1qyxdj2MvIFljA7 Qyc4iT8m3zUjaAbWQJT8eyD45YBpwUrf3MYx/dFbR2vpTmbf+CqIZ+7xCtE+F64bUb3V Ws63mydEDrvDdFiEqnVZU93qvfKlL3HsypZIq9NEqKB8mPb1OvTwT+ThcPmQMIavQqLn ACON/27SzxHlawVNQJMnfOPKu02lmekOeLayCWW9ZbCqvVnHkE8rTLZX//U5UuxpvmRE fGUQ== X-Gm-Message-State: AOJu0Yw85+d5crySeQ7qpB7Ia3PEZwfWBuJ+N9fgL7QajQgakdl0dcH1 lDsh1mFoydSFICJVIxvmAL7K9JY6J8rEZbzqMvopk0TK7IwVGJMLbIatYoVBF060SIcxFE/PTjR hW8j56GFTIo4j0z0sxI4NUQPwcUZLtzdR01Ty0HCuvTTZ6T3DrAsc6d/rd5pCTzRwMfPDql+O2M QQFRIhBlB/4iZJupe/Nbmh4wr7nwxvsj69DAFiBw== X-Gm-Gg: AfdE7clgT+4n4omlKZIqiFOySsMi/fLlPKv2iB0XLsxY3ayzqpITaKU7ofTw18T1PcV tl0wRXfqwArf1EYv1/sg+3MqG5POj0kvLANiRFE5XvThRz2T9fJc4DQxctz4nSrcU+DFTpYu58i xd+BPutjsx2qBVu4zMgoAuHeXhZCLTxDEAUMfzC8PBgIvGtJEBnaoub0NU4734foreZCL68GJxo 7d1zKMgPB2XIBBLbe3Ka8RvbhLkWBCmDfEQ42ZWJGnLMrHKp7kuuG9pQ0mM9sBRxUgyvMbt5aLP tP/IhF8wD4VCyiYAnEtTmuhaQpRGH1Qr1/QPr6Y6fG0RKLV+PMmrjuSiL6s7UhXsKLhjTuWJhbn TNw== X-Received: by 2002:a05:622a:1a8a:b0:516:e6f3:c1f with SMTP id d75a77b69052e-51a55b21c1amr33095221cf.47.1782218923240; Tue, 23 Jun 2026 05:48:43 -0700 (PDT) X-Received: by 2002:a05:622a:1a8a:b0:516:e6f3:c1f with SMTP id d75a77b69052e-51a55b21c1amr33094631cf.47.1782218922526; Tue, 23 Jun 2026 05:48:42 -0700 (PDT) From: Peter Xu To: qemu-devel@nongnu.org Cc: Peter Xu , Fabiano Rosas , Paolo Bonzini , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Subject: [PULL 15/18] system/physmem: destroy ram block attributes before RCU-deferred reclaim Date: Tue, 23 Jun 2026 08:47:56 -0400 Message-ID: <20260623124759.125399-16-peterx@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260623124759.125399-1-peterx@redhat.com> References: <20260623124759.125399-1-peterx@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=peterx@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1782219029775158500 From: Marc-Andr=C3=A9 Lureau ram_block_attributes_destroy() was called from reclaim_ramblock(), which runs as an RCU callback deferred by call_rcu(). However,when the RamDiscardManager is finalized, it will assert that its source_list is empty in the next commit. Since the RCU callback hasn't run yet, the source added by ram_block_attributes_create() is still attached. Move ram_block_attributes_destroy() into qemu_ram_free() so the source is removed synchronously. This is safe because qemu_ram_free() during shutdown runs after pause_all_vcpus(), so no vCPU thread can concurrently access the attributes via kvm_convert_memory(). Reviewed-by: Peter Xu Signed-off-by: Marc-Andr=C3=A9 Lureau Link: https://lore.kernel.org/r/20260604-rdm5-v5-8-5768e6a0943d@redhat.com [peterx: rebase on top of qemu_ram_free() change] Signed-off-by: Peter Xu --- system/physmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/physmem.c b/system/physmem.c index db8ad84ab6..c4bfb57625 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -2582,7 +2582,6 @@ static void reclaim_ramblock(RAMBlock *block) } =20 if (block->guest_memfd >=3D 0) { - ram_block_attributes_destroy(block->attributes); close(block->guest_memfd); ram_block_coordinated_discard_require(false); } @@ -2610,6 +2609,7 @@ void qemu_ram_free(RAMBlock *block) qatomic_set(&ram_list.mru_block, NULL); /* Write list before version */ qatomic_store_release(&ram_list.version, ram_list.version + 1); + g_clear_pointer(&block->attributes, ram_block_attributes_destroy); call_rcu(block, reclaim_ramblock, rcu); qemu_mutex_unlock_ramlist(); } --=20 2.54.0 From nobody Thu Jun 25 06:56:52 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1782219045; cv=none; d=zohomail.com; s=zohoarc; b=V8WKiMF67+LnJxKK2wAoYxmBZdgaFik4R1W5XrNPMIXkSOEAJTRxvoOl0GpykqQh1tNPOeu59YNxmQNXPY2LePEAQWdHjdWWHyYezpSZFPwWyXmtSCbRUulqRUspjnqjTyKyMutrPt0vDDeY7/YPZfKW18BYkCS9pvGgQ4Xd7jI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1782219045; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=o6j9IIN1re0pi/37Fxh9v0POSNlaYsqAG3daLdzi7VU=; b=WljiTvLh1LMVd3xTeEjNnqcSuDGDVkeEVjHbxWJ+KhAgPe6led1MN7SNof0WdMPqDS5fh1wgfmHJ4no1g780zMCbWU4DHsRiDMrOzTpMOzJHPs42BBZPqzqD3sDT8splqFJMXFBooZGdL3tLVyX76CMaacfShUnVZJfkqT/YHhc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1782219044991348.4818083947864; Tue, 23 Jun 2026 05:50:44 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wc0Yd-0004av-3i; Tue, 23 Jun 2026 08:48:51 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0Yb-0004a4-An for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:49 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0YZ-00073B-MB for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:49 -0400 Received: from mail-qt1-f198.google.com (mail-qt1-f198.google.com [209.85.160.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-187-MkINQp9QOGSc9JK3RO5DuQ-1; Tue, 23 Jun 2026 08:48:45 -0400 Received: by mail-qt1-f198.google.com with SMTP id d75a77b69052e-51a19f736a1so57297571cf.2 for ; Tue, 23 Jun 2026 05:48:45 -0700 (PDT) Received: from x1.com ([174.91.117.157]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51a51106a09sm22288351cf.0.2026.06.23.05.48.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jun 2026 05:48:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782218927; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=o6j9IIN1re0pi/37Fxh9v0POSNlaYsqAG3daLdzi7VU=; b=Cnfh5sncQRjStSbWzDZdEpVjwyDQkgtS+trxf8SLJgYDlhPpkhJc5Vagfbp4EFwVvc2snr QfQvoQlZr5oODfMaFL4RRpy672QTXctnHLSdQS9Z5lxuh9/Ax6FObhC9DXq3l47n2BIykc tbpZtMGts50NxikrIsFFlBEDZ0/Uyjo= X-MC-Unique: MkINQp9QOGSc9JK3RO5DuQ-1 X-Mimecast-MFC-AGG-ID: MkINQp9QOGSc9JK3RO5DuQ_1782218925 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1782218925; x=1782823725; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=o6j9IIN1re0pi/37Fxh9v0POSNlaYsqAG3daLdzi7VU=; b=smVxq8fQQWpYE0+azqHnHLlVFIzTx1lc2x4WEPtlEDUPQX0b6d7FYdPOq+5HbxA6J3 yQklDojYZBfEtdxs54zOKY6Kb2SGpmro76lGzNXtmSAaAdC4NB45gdKeE4ThT2iQlAY4 v0DeRHI/byR54HIe8vYZ6O8q8edc6Em12Dfol1vifD6MyJfkrPVwUwQipr/IhzMp8er6 4DcOcs57kCxNGlL+QeWqYVd/7Rzt9wOw7Ht6Ulrrhejex9p7RyWd9q3PU+S6xg7HkENI 1ozfcqBTjO20i3piKg5JkQsFPv94/lwGREDENQl6oz23a7aWWsFezcxI7BnB3vgeJ99p I4dA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782218925; x=1782823725; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=o6j9IIN1re0pi/37Fxh9v0POSNlaYsqAG3daLdzi7VU=; b=blE8MtSXDcIwlLQUt0wjjPMa2m2lbTvSgQzalSAeQWt6R+do3WfVmxiYMU1UmHdSXA 0eVYX5qyjsvSc28bJ+0hguXvbmFJbk8JFxbH9ehhLu5fEnwPJUcpOFq+ep+/zZrPbl5z CiSY5a4FQIlMbIXqi1VqGMiyuuIrQmRFUOFr1V8HWy7r/jlTN8KBthtPUtMfY5oQl2/j j6RBhSQL+JHaRihc3b58YLN4A3zT1TMUgyjKobdV78xPQ7CX3PoqkKBtZYfDU37zmMCQ 7YN7HVCCZ/ydVBmG0EjtNaT7s3+KkkAJvfXW+GW+OFeSi7MYWwAJOX89whqJ2qaEZXNo +uKQ== X-Gm-Message-State: AOJu0YxKcGM159mHJp5yfA7acmPItzFnBAeqznXodGpGmtdQb3UQEMTs 9xNJCWvzB66DJpZTo6WCKxFxW2/KoMYjtnOHQjEdIO7fVmtej7UYtJypW+ZrmZBWPf3oqoFDwnq 6UAVESG8gHA2XvDeuii3GKRdqqtX2uEXvt8PeZsyQGI2qgOjJmbP0XXuvZ+AaV8rpPtOuzDwVVH X5dq0+KYZSKRAlvB63Ybb+gpDDF3LXw2F7ivED3A== X-Gm-Gg: AfdE7cn2oCqhXU9mQ01Mze2IfSLBnVcC15cG143AXN/3zUy3T+uo8RGXp1o+tICUc9r OLbqkBXGwI0weJFa43gxtaIb7OAfQ6iJjA3j55zTbQSl95SBrHaxFKp7YQkzsru3pMJLOi3rxAz +DJ/gdaIC4bDuSjeuDUMCuXqtlFIPPSTtRmFjZ0/BgAJ0JCTTQzdiEkcPC7Ak7mMxU1ByfzxK4s sXTJ60ZWr/u8dw6tjCLyWsN2r6nTl+GMZJcuUQYqo/ClK0GRsbW/pIjQ+z8nRe1Ejin8Zf7Z08L QcDVOjgZEel8EAlsxxaEB+8WKShQinr/CCWpHFHbenPG5ZuFb4b7/LHq2V1ZVY7ksECVjTJUBVQ wkQ== X-Received: by 2002:a05:622a:ca:b0:516:d73d:2a34 with SMTP id d75a77b69052e-51a545b4a4amr43467631cf.5.1782218924779; Tue, 23 Jun 2026 05:48:44 -0700 (PDT) X-Received: by 2002:a05:622a:ca:b0:516:d73d:2a34 with SMTP id d75a77b69052e-51a545b4a4amr43466991cf.5.1782218924043; Tue, 23 Jun 2026 05:48:44 -0700 (PDT) From: Peter Xu To: qemu-devel@nongnu.org Cc: Peter Xu , Fabiano Rosas , Paolo Bonzini , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Subject: [PULL 16/18] system/memory: add RamDiscardManager reference counting and cleanup Date: Tue, 23 Jun 2026 08:47:57 -0400 Message-ID: <20260623124759.125399-17-peterx@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260623124759.125399-1-peterx@redhat.com> References: <20260623124759.125399-1-peterx@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=peterx@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1782219045678158500 From: Marc-Andr=C3=A9 Lureau Listeners now hold a reference to the RamDiscardManager, ensuring it stays alive while listeners are registered. The RDM is eagerly freed when the last source and listener are removed, and also unreffed during MemoryRegion finalization as a safety net. This completes the TODO left in the previous commit and prevents both use-after-free and memory leaks of the RamDiscardManager. Reviewed-by: Peter Xu Signed-off-by: Marc-Andr=C3=A9 Lureau Link: https://lore.kernel.org/r/20260604-rdm5-v5-9-5768e6a0943d@redhat.com Signed-off-by: Peter Xu --- system/memory.c | 14 +++++++++++--- system/ram-discard-manager.c | 2 ++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/system/memory.c b/system/memory.c index 119fee0d34..5fc36708ec 100644 --- a/system/memory.c +++ b/system/memory.c @@ -1771,6 +1771,7 @@ static void memory_region_finalize(Object *obj) memory_region_clear_coalescing(mr); g_free((char *)mr->name); g_free(mr->ioeventfds); + object_unref(mr->rdm); } =20 Object *memory_region_owner(const MemoryRegion *mr) @@ -2084,11 +2085,18 @@ int memory_region_add_ram_discard_source(MemoryRegi= on *mr, int memory_region_del_ram_discard_source(MemoryRegion *mr, RamDiscardSource *source) { + int ret; g_assert(mr->rdm); =20 - return ram_discard_manager_del_source(mr->rdm, source); - - /* if there is no source and no listener left, we could free rdm */ + ret =3D ram_discard_manager_del_source(mr->rdm, source); + if (ret !=3D 0) { + return ret; + } + if (QLIST_EMPTY(&mr->rdm->source_list) && QLIST_EMPTY(&mr->rdm->rdl_li= st)) { + object_unref(mr->rdm); + mr->rdm =3D NULL; + } + return 0; } =20 /* Called with rcu_read_lock held. */ diff --git a/system/ram-discard-manager.c b/system/ram-discard-manager.c index 7da91bf648..4e8816e5a2 100644 --- a/system/ram-discard-manager.c +++ b/system/ram-discard-manager.c @@ -549,6 +549,7 @@ void ram_discard_manager_register_listener(RamDiscardMa= nager *rdm, =20 g_assert(section->mr =3D=3D rdm->mr); =20 + object_ref(rdm); rdl->section =3D memory_region_section_new_copy(section); QLIST_INSERT_HEAD(&rdm->rdl_list, rdl, next); =20 @@ -570,6 +571,7 @@ void ram_discard_manager_unregister_listener(RamDiscard= Manager *rdm, memory_region_section_free_copy(rdl->section); rdl->section =3D NULL; QLIST_REMOVE(rdl, next); + object_unref(rdm); } =20 int ram_discard_manager_replay_populated_to_listeners(RamDiscardManager *r= dm) --=20 2.54.0 From nobody Thu Jun 25 06:56:52 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1782219035; cv=none; d=zohomail.com; s=zohoarc; b=kHhHRDHIeLQcjUEXj/uy8S1WFJem9jzpJ/ibWj116sZesFl0btHpLGQPMejt31MFg4Avjyz3ETAyJ0SIWk4OhcUBSOHB5JKd94xOswjt1rIrgj5uxAs2sr3B/OWYrbBU4ci76p3iyDsYVkv1BoZvkfJHGHkp/13KutzZNL08aWo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1782219035; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=8zucj8BcjAP5BVRrvJeIpgpudrfOlWRpjPEN4hlYkKs=; b=cuTX8KRPSgGFQF8bVhXsFKAb/taitz8IeN3noEWS2bbaH8lv9Hv2EMpvFLDbZijqHqBhs5toI2Bqlktkv1W3iLkKnDCW9hAafCxkTJa1CLUrkSQGY/MKj4ux7e9jYl1w51Dtr1xnnJS0T+VfX0CYHsUPpCJr7IkrDK4WJGRaZS0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1782219035361976.9737157767254; Tue, 23 Jun 2026 05:50:35 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wc0Yl-0004cb-DC; Tue, 23 Jun 2026 08:48:59 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0Yi-0004c3-Iy for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:56 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0Yd-00074P-Ku for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:56 -0400 Received: from mail-qt1-f199.google.com (mail-qt1-f199.google.com [209.85.160.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-600-GyLCiIKNPTOdE6D3JEUerg-1; Tue, 23 Jun 2026 08:48:48 -0400 Received: by mail-qt1-f199.google.com with SMTP id d75a77b69052e-5177b8def69so105773221cf.2 for ; Tue, 23 Jun 2026 05:48:47 -0700 (PDT) Received: from x1.com ([174.91.117.157]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51a51106a09sm22288351cf.0.2026.06.23.05.48.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jun 2026 05:48:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782218931; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=8zucj8BcjAP5BVRrvJeIpgpudrfOlWRpjPEN4hlYkKs=; b=H+kx5m565aSSxx7B3ZBKyIgbPujwhmIbmJxL1NbgwX9vAJbGM6h7RkyLx0YgxhI21f/aVP xcSK0X8n7tyaQ7G18F9V/g0adn+2E3iXIAV9Fj0xK0muU+Ji6W7TcdbiNqc23ye16rma4c RljEDPnnfWB6/vXg78nQhS9puHIZUOU= X-MC-Unique: GyLCiIKNPTOdE6D3JEUerg-1 X-Mimecast-MFC-AGG-ID: GyLCiIKNPTOdE6D3JEUerg_1782218927 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1782218927; x=1782823727; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=8zucj8BcjAP5BVRrvJeIpgpudrfOlWRpjPEN4hlYkKs=; b=K4jVXFqtKbgHMUtVygHeGm/X0DuseL6lReTDIRAkBtJfD0bfr3/Lk4BddlokQBg7SK bbBBy6tV5uwvV2/jegDFdrpIDhLM55JChf8xsNATkHh9SmJlKdoZouuiIku2U/85uTxE WwVY2alqXe1LzK4lThZnx2wM6MWPSM4+H0niO2hplwr975/yOfsAeOhVY7JA8KCI90xZ gt/J8JmklXy1bgFXksJxJGFCOm3hLbmZyI14ENtIdgrmkJf1/SJfz/4AldAGla904SVI wjj4PnQ/gaJMEfoZ+1hXc27zkLfIxccgQ1H1frALKtyUrCcRwUOHx7FktH1zmGoMlviB ghWw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782218927; x=1782823727; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=8zucj8BcjAP5BVRrvJeIpgpudrfOlWRpjPEN4hlYkKs=; b=h57CFMnCaxVNSvzm8kv7MbupJtliJKVZ6gWtYaiKNtG1uXc32+Q62pC+yTNkZDNltg iSmNgK7KAXVL3EFOO+5FYwgrhSylhEY9bEGeQUr3V5HgTa0u6S0ONllu2N3Pvf729U1d 7lgfqbDbB+eBsYVJZZhvOlspYLnOAxIN8NxXtmr8bKu0nc7zVP7miRYcXca3AhYwfbF4 JboDCcBucJl2WKGtA4KBscVSWJtWbwMyV+f+tsd28tw+hT1ZSVuHvPVAILNfl+m0x4gP uQYbjqwkkYXqx6IlsPN/gJ7X7795vM4PAJoyawgLEX0WMbAe9SMHYEBGdDlxc6kfjZ2n Vn5w== X-Gm-Message-State: AOJu0YylTx01OC5rFvPCxfO8SWHeoYW38lieLc5M+PDKj+GJBJ7d0tXZ 63M+/0oVMVb0Kw5OLE3wqcDOW1rQJm9nSnTbB8b+yFOv7YDgKcIWuzFnosPmzhURaChvUx39fJg npDA7ND/CUgZd7mQDtz/J6Nw3+6kMh4waXZGnih2pe7j4RliKGhjDRHO3Q4pzu+cTSy7MVYRSML NlCZBDWVBDz+oDE1TzFlKeYulSUBbCFcMT3ZcxnA== X-Gm-Gg: AfdE7cl/k5VNssNaWXnyxhzkpnYbxNeQRf1qCss8hjDTATOIXT9wJcD6y0+v6iSfMpW 6tL/Bi+qsb0CmqYmc0lMf5GBd/9HGDzmmZXNmya+y+ZjA6u3viJko5Bn4vRjCWhLtNVi/JmWAJx pqUiTtBstUgqO+p0nMMyOi9ObrV2ICp7rHodZnKz4gHADP9ip0sM14i8wn/wxs6kbL5VCBRdrol n9csHtUkudpMaYX96cIrVzCq/c7HZgFVsYDhUjKPVrQPSIRdliKzxDUvBmircGFuES05szfz3hl VToQPV0dJ8vpjEshpmbzJBahfqxtbDFC9MB48Qx0W54gxcLrK5cFv3clMjLPqSCpLMIkArkKRuK GKg== X-Received: by 2002:a05:622a:5986:b0:519:efea:cf41 with SMTP id d75a77b69052e-51a55ace970mr32459861cf.28.1782218926562; Tue, 23 Jun 2026 05:48:46 -0700 (PDT) X-Received: by 2002:a05:622a:5986:b0:519:efea:cf41 with SMTP id d75a77b69052e-51a55ace970mr32458831cf.28.1782218925589; Tue, 23 Jun 2026 05:48:45 -0700 (PDT) From: Peter Xu To: qemu-devel@nongnu.org Cc: Peter Xu , Fabiano Rosas , Paolo Bonzini , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Subject: [PULL 17/18] tests: add unit tests for RamDiscardManager multi-source aggregation Date: Tue, 23 Jun 2026 08:47:58 -0400 Message-ID: <20260623124759.125399-18-peterx@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260623124759.125399-1-peterx@redhat.com> References: <20260623124759.125399-1-peterx@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=peterx@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1782219035751158500 From: Marc-Andr=C3=A9 Lureau Add various unit tests for the RamDiscardManager multi-source aggregation functionality. The test uses a TestRamDiscardSource QOM object that tracks populated state via a bitmap, similar to RamBlockAttributes implementation. Signed-off-by: Marc-Andr=C3=A9 Lureau Link: https://lore.kernel.org/r/20260604-rdm5-v5-10-5768e6a0943d@redhat.com Signed-off-by: Peter Xu --- MAINTAINERS | 2 + tests/unit/test-ram-discard-manager-stubs.c | 48 + tests/unit/test-ram-discard-manager.c | 1235 +++++++++++++++++++ tests/unit/meson.build | 8 +- 4 files changed, 1292 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test-ram-discard-manager-stubs.c create mode 100644 tests/unit/test-ram-discard-manager.c diff --git a/MAINTAINERS b/MAINTAINERS index 18b659a44c..fc6d035d4c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3363,6 +3363,8 @@ F: system/memory-internal.h F: system/ram-block-attributes.c F: system/ram-discard-manager.c F: scripts/coccinelle/memory-region-housekeeping.cocci +F: tests/unit/test-ram-discard-manager.c +F: tests/unit/test-ram-discard-manager-stubs.c =20 Memory devices M: David Hildenbrand diff --git a/tests/unit/test-ram-discard-manager-stubs.c b/tests/unit/test-= ram-discard-manager-stubs.c new file mode 100644 index 0000000000..74b126fd3f --- /dev/null +++ b/tests/unit/test-ram-discard-manager-stubs.c @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "qemu/osdep.h" +#include "qom/object.h" +#include "glib.h" +#include "system/memory.h" + +RamDiscardManager *memory_region_get_ram_discard_manager(MemoryRegion *mr) +{ + return mr->rdm; +} + +int memory_region_add_ram_discard_source(MemoryRegion *mr, + RamDiscardSource *source) +{ + if (!mr->rdm) { + mr->rdm =3D ram_discard_manager_new(mr); + } + return ram_discard_manager_add_source(mr->rdm, source); +} + +int memory_region_del_ram_discard_source(MemoryRegion *mr, + RamDiscardSource *source) +{ + RamDiscardManager *rdm =3D mr->rdm; + + if (!rdm) { + return 0; + } + + return ram_discard_manager_del_source(rdm, source); +} + +uint64_t memory_region_size(const MemoryRegion *mr) +{ + return int128_get64(mr->size); +} + +MemoryRegionSection *memory_region_section_new_copy(MemoryRegionSection *s) +{ + MemoryRegionSection *copy =3D g_new(MemoryRegionSection, 1); + *copy =3D *s; + return copy; +} + +void memory_region_section_free_copy(MemoryRegionSection *s) +{ + g_free(s); +} diff --git a/tests/unit/test-ram-discard-manager.c b/tests/unit/test-ram-di= scard-manager.c new file mode 100644 index 0000000000..3d39a1e94b --- /dev/null +++ b/tests/unit/test-ram-discard-manager.c @@ -0,0 +1,1235 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "qemu/osdep.h" +#include "qemu/bitmap.h" +#include "qemu/module.h" +#include "qemu/main-loop.h" +#include "qapi/error.h" +#include "qom/object.h" +#include "qom/qom-qobject.h" +#include "glib.h" +#include "system/memory.h" + +#define TYPE_TEST_RAM_DISCARD_SOURCE "test-ram-discard-source" + +OBJECT_DECLARE_SIMPLE_TYPE(TestRamDiscardSource, TEST_RAM_DISCARD_SOURCE) + +struct TestRamDiscardSource { + Object parent; + + MemoryRegion *mr; + uint64_t granularity; + unsigned long *bitmap; + uint64_t bitmap_size; +}; + +static uint64_t test_rds_get_min_granularity(const RamDiscardSource *rds, + const MemoryRegion *mr) +{ + TestRamDiscardSource *src =3D TEST_RAM_DISCARD_SOURCE(rds); + + g_assert(mr =3D=3D src->mr); + return src->granularity; +} + +static bool test_rds_is_populated(const RamDiscardSource *rds, + const MemoryRegionSection *section) +{ + TestRamDiscardSource *src =3D TEST_RAM_DISCARD_SOURCE(rds); + uint64_t offset =3D section->offset_within_region; + uint64_t size =3D int128_get64(section->size); + uint64_t first_bit =3D offset / src->granularity; + uint64_t last_bit =3D (offset + size - 1) / src->granularity; + unsigned long found; + + g_assert(section->mr =3D=3D src->mr); + + /* Check if any bit in range is zero (discarded) */ + found =3D find_next_zero_bit(src->bitmap, last_bit + 1, first_bit); + return found > last_bit; +} + +static void test_rds_class_init(ObjectClass *klass, const void *data) +{ + RamDiscardSourceClass *rdsc =3D RAM_DISCARD_SOURCE_CLASS(klass); + + rdsc->get_min_granularity =3D test_rds_get_min_granularity; + rdsc->is_populated =3D test_rds_is_populated; +} + +static const TypeInfo test_rds_info =3D { + .name =3D TYPE_TEST_RAM_DISCARD_SOURCE, + .parent =3D TYPE_OBJECT, + .instance_size =3D sizeof(TestRamDiscardSource), + .class_init =3D test_rds_class_init, + .interfaces =3D (const InterfaceInfo[]) { + { TYPE_RAM_DISCARD_SOURCE }, + { } + }, +}; + +static TestRamDiscardSource *test_source_new(MemoryRegion *mr, + uint64_t granularity) +{ + TestRamDiscardSource *src; + uint64_t region_size =3D memory_region_size(mr); + + src =3D TEST_RAM_DISCARD_SOURCE(object_new(TYPE_TEST_RAM_DISCARD_SOURC= E)); + src->mr =3D mr; + src->granularity =3D granularity; + src->bitmap_size =3D DIV_ROUND_UP(region_size, granularity); + src->bitmap =3D bitmap_new(src->bitmap_size); + + return src; +} + +static void test_source_free(TestRamDiscardSource *src) +{ + g_free(src->bitmap); + object_unref(OBJECT(src)); +} + +static void test_source_populate(TestRamDiscardSource *src, + uint64_t offset, uint64_t size) +{ + uint64_t first_bit =3D offset / src->granularity; + uint64_t nbits =3D size / src->granularity; + + bitmap_set(src->bitmap, first_bit, nbits); +} + +static void test_source_discard(TestRamDiscardSource *src, + uint64_t offset, uint64_t size) +{ + uint64_t first_bit =3D offset / src->granularity; + uint64_t nbits =3D size / src->granularity; + + bitmap_clear(src->bitmap, first_bit, nbits); +} + +typedef struct TestListener { + RamDiscardListener rdl; + int populate_count; + int discard_count; + uint64_t last_populate_offset; + uint64_t last_populate_size; + uint64_t last_discard_offset; + uint64_t last_discard_size; + int fail_on_populate; /* Return error on Nth populate */ + int populate_call_num; +} TestListener; + +static int test_listener_populate(RamDiscardListener *rdl, + const MemoryRegionSection *section) +{ + TestListener *tl =3D container_of(rdl, TestListener, rdl); + + tl->populate_call_num++; + if (tl->fail_on_populate > 0 && + tl->populate_call_num >=3D tl->fail_on_populate) { + return -ENOMEM; + } + + tl->populate_count++; + tl->last_populate_offset =3D section->offset_within_region; + tl->last_populate_size =3D int128_get64(section->size); + return 0; +} + +static void test_listener_discard(RamDiscardListener *rdl, + const MemoryRegionSection *section) +{ + TestListener *tl =3D container_of(rdl, TestListener, rdl); + + tl->discard_count++; + tl->last_discard_offset =3D section->offset_within_region; + tl->last_discard_size =3D int128_get64(section->size); +} + +static void test_listener_init(TestListener *tl) +{ + ram_discard_listener_init(&tl->rdl, + test_listener_populate, + test_listener_discard); +} + +#define TEST_REGION_SIZE (16 * 1024 * 1024) /* 16 MB */ +#define GRANULARITY_4K (4 * 1024) +#define GRANULARITY_2M (2 * 1024 * 1024) + +static MemoryRegion *test_mr; + +static void test_setup(void) +{ + test_mr =3D g_new0(MemoryRegion, 1); + test_mr->size =3D int128_make64(TEST_REGION_SIZE); + test_mr->ram =3D true; +} + +static void test_teardown(void) +{ + g_clear_pointer(&test_mr->rdm, object_unref); + object_unparent(OBJECT(test_mr)); + g_free(test_mr); + test_mr =3D NULL; +} + +static void test_single_source_basic(void) +{ + TestRamDiscardSource *src; + RamDiscardManager *rdm; + MemoryRegionSection section; + int ret; + + test_setup(); + + src =3D test_source_new(test_mr, GRANULARITY_4K); + rdm =3D memory_region_get_ram_discard_manager(test_mr); + g_assert_null(rdm); + + /* Add source */ + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src)); + g_assert_cmpint(ret, =3D=3D, 0); + + rdm =3D memory_region_get_ram_discard_manager(test_mr); + g_assert_nonnull(rdm); + + g_assert_cmpuint(ram_discard_manager_get_min_granularity(rdm, test_mr), + =3D=3D, GRANULARITY_4K); + + /* Initially all discarded */ + section.mr =3D test_mr; + section.offset_within_region =3D 0; + section.size =3D int128_make64(GRANULARITY_4K); + g_assert_false(ram_discard_manager_is_populated(rdm, §ion)); + + /* Populate a range in source */ + test_source_populate(src, 0, GRANULARITY_4K * 4); + + /* Now should be populated */ + g_assert_true(ram_discard_manager_is_populated(rdm, §ion)); + + /* Check larger section */ + section.size =3D int128_make64(GRANULARITY_4K * 4); + g_assert_true(ram_discard_manager_is_populated(rdm, §ion)); + + /* Check section that spans populated and discarded */ + section.size =3D int128_make64(GRANULARITY_4K * 8); + g_assert_false(ram_discard_manager_is_populated(rdm, §ion)); + + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src)); + + g_assert_true(ram_discard_manager_is_populated(rdm, §ion)); + + test_source_free(src); + test_teardown(); +} + +static void test_single_source_listener(void) +{ + TestRamDiscardSource *src; + RamDiscardManager *rdm; + MemoryRegionSection section; + TestListener tl =3D { 0, }; + int ret; + + test_setup(); + + src =3D test_source_new(test_mr, GRANULARITY_4K); + + /* Populate some ranges before adding listener */ + test_source_populate(src, 0, GRANULARITY_4K * 4); + test_source_populate(src, GRANULARITY_4K * 8, GRANULARITY_4K * 4); + + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src)); + g_assert_cmpint(ret, =3D=3D, 0); + rdm =3D memory_region_get_ram_discard_manager(test_mr); + g_assert_nonnull(rdm); + + /* Register listener */ + test_listener_init(&tl); + section.mr =3D test_mr; + section.offset_within_region =3D 0; + section.size =3D int128_make64(TEST_REGION_SIZE); + + ram_discard_manager_register_listener(rdm, &tl.rdl, §ion); + + /* Should have been notified about populated regions */ + g_assert_cmpint(tl.populate_count, =3D=3D, 2); + + /* Notify populate for new range */ + tl.populate_count =3D 0; + test_source_populate(src, GRANULARITY_4K * 16, GRANULARITY_4K * 2); + ret =3D ram_discard_manager_notify_populate(rdm, RAM_DISCARD_SOURCE(sr= c), + GRANULARITY_4K * 16, + GRANULARITY_4K * 2); + g_assert_cmpint(ret, =3D=3D, 0); + g_assert_cmpint(tl.populate_count, =3D=3D, 1); + g_assert_cmpuint(tl.last_populate_offset, =3D=3D, GRANULARITY_4K * 16); + g_assert_cmpuint(tl.last_populate_size, =3D=3D, GRANULARITY_4K * 2); + + /* Notify discard */ + tl.discard_count =3D 0; + test_source_discard(src, 0, GRANULARITY_4K * 4); + ram_discard_manager_notify_discard(rdm, RAM_DISCARD_SOURCE(src), + 0, GRANULARITY_4K * 4); + g_assert_cmpint(tl.discard_count, =3D=3D, 1); + g_assert_cmpuint(tl.last_discard_offset, =3D=3D, 0); + g_assert_cmpuint(tl.last_discard_size, =3D=3D, GRANULARITY_4K * 4); + + /* Unregister listener */ + ram_discard_manager_unregister_listener(rdm, &tl.rdl); + + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src)); + test_source_free(src); + test_teardown(); +} + +static void test_two_sources_same_granularity(void) +{ + TestRamDiscardSource *src1, *src2; + RamDiscardManager *rdm; + MemoryRegionSection section; + int ret; + + test_setup(); + + src1 =3D test_source_new(test_mr, GRANULARITY_4K); + src2 =3D test_source_new(test_mr, GRANULARITY_4K); + + /* Add first source */ + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src1)); + g_assert_cmpint(ret, =3D=3D, 0); + + /* Add second source */ + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src2)); + g_assert_cmpint(ret, =3D=3D, 0); + + rdm =3D memory_region_get_ram_discard_manager(test_mr); + g_assert_nonnull(rdm); + + /* Check granularity */ + g_assert_cmpuint(ram_discard_manager_get_min_granularity(rdm, test_mr), + =3D=3D, GRANULARITY_4K); + + section.mr =3D test_mr; + section.offset_within_region =3D 0; + section.size =3D int128_make64(GRANULARITY_4K); + + /* Both discarded -> aggregated discarded */ + g_assert_false(ram_discard_manager_is_populated(rdm, §ion)); + + /* Populate in src1 only */ + test_source_populate(src1, 0, GRANULARITY_4K); + g_assert_false(ram_discard_manager_is_populated(rdm, §ion)); + + /* Populate in src2 only */ + test_source_discard(src1, 0, GRANULARITY_4K); + test_source_populate(src2, 0, GRANULARITY_4K); + g_assert_false(ram_discard_manager_is_populated(rdm, §ion)); + + /* Populate in both -> aggregated populated */ + test_source_populate(src1, 0, GRANULARITY_4K); + g_assert_true(ram_discard_manager_is_populated(rdm, §ion)); + + /* Remove sources */ + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src2)= ); + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src1)= ); + + test_source_free(src2); + test_source_free(src1); + test_teardown(); +} + +/* + * Test: Two sources with different granularities (4K and 2M). + * The aggregated granularity should be GCD(4K, 2M) =3D 4K. + */ +static void test_two_sources_different_granularity(void) +{ + TestRamDiscardSource *src_4k, *src_2m; + RamDiscardManager *rdm; + MemoryRegionSection section; + int ret; + + test_setup(); + + src_4k =3D test_source_new(test_mr, GRANULARITY_4K); + src_2m =3D test_source_new(test_mr, GRANULARITY_2M); + + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src_4k)); + g_assert_cmpint(ret, =3D=3D, 0); + + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src_2m)); + g_assert_cmpint(ret, =3D=3D, 0); + + rdm =3D memory_region_get_ram_discard_manager(test_mr); + + g_assert_cmpuint(ram_discard_manager_get_min_granularity(rdm, test_mr), + =3D=3D, GRANULARITY_4K); + + section.mr =3D test_mr; + section.offset_within_region =3D 0; + section.size =3D int128_make64(GRANULARITY_4K); + + /* Both discarded */ + g_assert_false(ram_discard_manager_is_populated(rdm, §ion)); + + /* Populate 4K in src_4k, but src_2m still discarded the whole 2M bloc= k */ + test_source_populate(src_4k, 0, GRANULARITY_4K); + g_assert_false(ram_discard_manager_is_populated(rdm, §ion)); + + /* Populate 2M in src_2m (which includes the 4K block) */ + test_source_populate(src_2m, 0, GRANULARITY_2M); + g_assert_true(ram_discard_manager_is_populated(rdm, §ion)); + + /* Check a 4K block at offset 4K (populated in src_2m but not in src_4= k) */ + section.offset_within_region =3D GRANULARITY_4K; + g_assert_false(ram_discard_manager_is_populated(rdm, §ion)); + + /* Populate it in src_4k */ + test_source_populate(src_4k, GRANULARITY_4K, GRANULARITY_4K); + g_assert_true(ram_discard_manager_is_populated(rdm, §ion)); + + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src_2= m)); + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src_4= k)); + + test_source_free(src_2m); + test_source_free(src_4k); + test_teardown(); +} + +/* + * Test: Notification with two sources. + * Populate notification should only fire when all sources are populated. + */ +static void test_two_sources_notification(void) +{ + TestRamDiscardSource *src1, *src2; + RamDiscardManager *rdm; + MemoryRegionSection section; + TestListener tl =3D { 0, }; + int ret; + + test_setup(); + + src1 =3D test_source_new(test_mr, GRANULARITY_4K); + src2 =3D test_source_new(test_mr, GRANULARITY_4K); + + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src1)); + g_assert_cmpint(ret, =3D=3D, 0); + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src2)); + g_assert_cmpint(ret, =3D=3D, 0); + + rdm =3D memory_region_get_ram_discard_manager(test_mr); + + /* Register listener */ + test_listener_init(&tl); + section.mr =3D test_mr; + section.offset_within_region =3D 0; + section.size =3D int128_make64(TEST_REGION_SIZE); + ram_discard_manager_register_listener(rdm, &tl.rdl, §ion); + + /* No populate notifications yet (all discarded) */ + g_assert_cmpint(tl.populate_count, =3D=3D, 0); + + /* Populate in src1 only - no notification (src2 still discarded) */ + test_source_populate(src1, 0, GRANULARITY_4K * 4); + ret =3D ram_discard_manager_notify_populate(rdm, RAM_DISCARD_SOURCE(sr= c1), + 0, GRANULARITY_4K * 4); + g_assert_cmpint(ret, =3D=3D, 0); + g_assert_cmpint(tl.populate_count, =3D=3D, 0); + + /* Populate same range in src2 - now should notify */ + test_source_populate(src2, 0, GRANULARITY_4K * 4); + ret =3D ram_discard_manager_notify_populate(rdm, RAM_DISCARD_SOURCE(sr= c2), + 0, GRANULARITY_4K * 4); + g_assert_cmpint(ret, =3D=3D, 0); + g_assert_cmpint(tl.populate_count, =3D=3D, 1); + + /* Discard from src1 - should notify discard immediately */ + tl.discard_count =3D 0; + test_source_discard(src1, 0, GRANULARITY_4K * 2); + ram_discard_manager_notify_discard(rdm, RAM_DISCARD_SOURCE(src1), + 0, GRANULARITY_4K * 2); + g_assert_cmpint(tl.discard_count, =3D=3D, 1); + + ram_discard_manager_unregister_listener(rdm, &tl.rdl); + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src2)= ); + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src1)= ); + + test_source_free(src2); + test_source_free(src1); + test_teardown(); +} + +/* + * Test: Adding source with existing listener. + * When a new source is added, listeners should be notified about + * regions that become discarded. + */ +static void test_add_source_with_listener(void) +{ + TestRamDiscardSource *src1, *src2; + RamDiscardManager *rdm; + MemoryRegionSection section; + TestListener tl =3D { 0, }; + int ret; + + test_setup(); + + src1 =3D test_source_new(test_mr, GRANULARITY_4K); + src2 =3D test_source_new(test_mr, GRANULARITY_4K); + + /* Populate some range in src1 */ + test_source_populate(src1, 0, GRANULARITY_4K * 8); + + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src1)); + g_assert_cmpint(ret, =3D=3D, 0); + rdm =3D memory_region_get_ram_discard_manager(test_mr); + + /* Register listener */ + test_listener_init(&tl); + section.mr =3D test_mr; + section.offset_within_region =3D 0; + section.size =3D int128_make64(TEST_REGION_SIZE); + ram_discard_manager_register_listener(rdm, &tl.rdl, §ion); + + /* Should have been notified about populated region */ + g_assert_cmpint(tl.populate_count, =3D=3D, 1); + g_assert_cmpint(tl.last_populate_offset, =3D=3D, 0); + g_assert_cmpint(tl.last_populate_size, =3D=3D, GRANULARITY_4K * 8); + + /* src2 has part of the region populated, part discarded */ + /* src2 has 0-4 populated, 4-8 discarded */ + test_source_populate(src2, 0, GRANULARITY_4K * 4); + + /* Add src2 - listener should be notified about newly discarded region= s */ + tl.discard_count =3D 0; + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src2)); + g_assert_cmpint(ret, =3D=3D, 0); + + /* + * The range 4K*4 to 4K*8 was populated in src1 but discarded in src2, + * so it becomes aggregated-discarded. Listener should be notified. + * Only this range should trigger a discard notification - regions bey= ond + * 4K*8 were already discarded in src1, so adding src2 doesn't change = them. + */ + g_assert_cmpint(tl.discard_count, =3D=3D, 1); + g_assert_cmpint(tl.last_discard_offset, =3D=3D, GRANULARITY_4K * 4); + g_assert_cmpint(tl.last_discard_size, =3D=3D, GRANULARITY_4K * 4); + + ram_discard_manager_unregister_listener(rdm, &tl.rdl); + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src2)= ); + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src1)= ); + + test_source_free(src2); + test_source_free(src1); + test_teardown(); +} + +/* + * Test: Removing source with existing listener. + * When a source is removed, listeners should be notified about + * regions that become populated. + */ +static void test_remove_source_with_listener(void) +{ + TestRamDiscardSource *src1, *src2; + RamDiscardManager *rdm; + MemoryRegionSection section; + TestListener tl =3D { 0, }; + int ret; + + test_setup(); + + src1 =3D test_source_new(test_mr, GRANULARITY_4K); + src2 =3D test_source_new(test_mr, GRANULARITY_4K); + + /* src1: all of first 8 blocks populated */ + test_source_populate(src1, 0, GRANULARITY_4K * 8); + /* src2: only first 4 blocks populated */ + test_source_populate(src2, 0, GRANULARITY_4K * 4); + + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src1)); + g_assert_cmpint(ret, =3D=3D, 0); + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src2)); + g_assert_cmpint(ret, =3D=3D, 0); + + rdm =3D memory_region_get_ram_discard_manager(test_mr); + + /* Register listener */ + test_listener_init(&tl); + section.mr =3D test_mr; + section.offset_within_region =3D 0; + section.size =3D int128_make64(TEST_REGION_SIZE); + ram_discard_manager_register_listener(rdm, &tl.rdl, §ion); + + /* Only first 4 blocks are aggregated-populated */ + g_assert_cmpint(tl.populate_count, =3D=3D, 1); + g_assert_cmpuint(tl.last_populate_size, =3D=3D, GRANULARITY_4K * 4); + + /* Remove src2 - blocks 4-8 should become populated */ + tl.populate_count =3D 0; + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src2)= ); + + /* Listener should be notified about newly populated region (4K*4 to 4= K*8) */ + g_assert_cmpint(tl.populate_count, >=3D, 1); + + ram_discard_manager_unregister_listener(rdm, &tl.rdl); + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src1)= ); + + test_source_free(src2); + test_source_free(src1); + test_teardown(); +} + +/* + * Test: Add a source, register a listener, remove the source, then add it= back. + * This checks the transition from 0 sources (all populated) to 1 source + * (partially discarded) with an active listener. + */ +static void test_readd_source_with_listener(void) +{ + TestRamDiscardSource *src; + RamDiscardManager *rdm; + MemoryRegionSection section; + TestListener tl =3D { 0, }; + int ret; + + test_setup(); + + src =3D test_source_new(test_mr, GRANULARITY_4K); + + /* Populate some range in src */ + test_source_populate(src, 0, GRANULARITY_4K * 8); + + /* 1. Add source */ + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src)); + g_assert_cmpint(ret, =3D=3D, 0); + rdm =3D memory_region_get_ram_discard_manager(test_mr); + + /* 2. Register listener */ + test_listener_init(&tl); + section.mr =3D test_mr; + section.offset_within_region =3D 0; + section.size =3D int128_make64(TEST_REGION_SIZE); + ram_discard_manager_register_listener(rdm, &tl.rdl, §ion); + + /* Listener notified about populated region (0 - 32K) */ + g_assert_cmpint(tl.populate_count, =3D=3D, 1); + g_assert_cmpuint(tl.last_populate_size, =3D=3D, GRANULARITY_4K * 8); + + /* 3. Remove source */ + tl.populate_count =3D 0; + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src)); + + /* + * With 0 sources, everything is populated. + * The range that was discarded in src (from 32K to end) becomes popul= ated. + */ + g_assert_cmpint(tl.populate_count, =3D=3D, 1); + g_assert_cmpuint(tl.last_populate_offset, =3D=3D, GRANULARITY_4K * 8); + g_assert_cmpuint(tl.last_populate_size, =3D=3D, TEST_REGION_SIZE - GRA= NULARITY_4K * 8); + + /* 4. Add source back */ + tl.discard_count =3D 0; + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src)); + g_assert_cmpint(ret, =3D=3D, 0); + + /* + * Now we have 1 source again. The range (32K to end) is discarded aga= in. + * Listener should be notified about this discard. + */ + g_assert_cmpint(tl.discard_count, =3D=3D, 1); + g_assert_cmpuint(tl.last_discard_offset, =3D=3D, GRANULARITY_4K * 8); + g_assert_cmpuint(tl.last_discard_size, =3D=3D, TEST_REGION_SIZE - GRAN= ULARITY_4K * 8); + + ram_discard_manager_unregister_listener(rdm, &tl.rdl); + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src)); + test_source_free(src); + test_teardown(); +} + +/* + * Test: Duplicate source registration should fail. + */ +static void test_duplicate_source(void) +{ + TestRamDiscardSource *src; + int ret; + + test_setup(); + + src =3D test_source_new(test_mr, GRANULARITY_4K); + + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src)); + g_assert_cmpint(ret, =3D=3D, 0); + + /* Adding same source again should fail */ + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src)); + g_assert_cmpint(ret, =3D=3D, -EBUSY); + + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src)); + test_source_free(src); + test_teardown(); +} + +/* + * Test: Populate notification rollback on listener error. + */ +static void test_populate_rollback(void) +{ + TestRamDiscardSource *src; + RamDiscardManager *rdm; + MemoryRegionSection section; + TestListener tl1 =3D { 0, }, tl2 =3D { 0, }; + int ret; + + test_setup(); + + src =3D test_source_new(test_mr, GRANULARITY_4K); + + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src)); + g_assert_cmpint(ret, =3D=3D, 0); + rdm =3D memory_region_get_ram_discard_manager(test_mr); + + /* Register two listeners */ + test_listener_init(&tl1); + test_listener_init(&tl2); + tl2.fail_on_populate =3D 1; /* Second listener fails on first populat= e */ + + section.mr =3D test_mr; + section.offset_within_region =3D 0; + section.size =3D int128_make64(TEST_REGION_SIZE); + + /* + * Register tl2 first so it's visited second (QLIST_INSERT_HEAD revers= es + * registration order). This ensures tl1 receives populate before tl2 + * fails. + */ + ram_discard_manager_register_listener(rdm, &tl2.rdl, §ion); + ram_discard_manager_register_listener(rdm, &tl1.rdl, §ion); + + /* Try to populate - should fail and roll back */ + test_source_populate(src, 0, GRANULARITY_4K); + ret =3D ram_discard_manager_notify_populate(rdm, RAM_DISCARD_SOURCE(sr= c), + 0, GRANULARITY_4K); + g_assert_cmpint(ret, =3D=3D, -ENOMEM); + + /* First listener should have received populate then discard (rollback= ) */ + g_assert_cmpint(tl1.populate_count, =3D=3D, 1); + g_assert_cmpint(tl1.discard_count, =3D=3D, 1); + + ram_discard_manager_unregister_listener(rdm, &tl1.rdl); + ram_discard_manager_unregister_listener(rdm, &tl2.rdl); + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src)); + test_source_free(src); + test_teardown(); +} + +/* + * Test: Replay populated with two sources (intersection). + */ +static void test_replay_populated_intersection(void) +{ + TestRamDiscardSource *src1, *src2; + RamDiscardManager *rdm; + MemoryRegionSection section; + TestListener tl =3D { 0, }; + int ret; + + test_setup(); + + src1 =3D test_source_new(test_mr, GRANULARITY_4K); + src2 =3D test_source_new(test_mr, GRANULARITY_4K); + + /* + * src1: blocks 0-7 populated + * src2: blocks 4-11 populated + * Intersection: blocks 4-7 + */ + test_source_populate(src1, 0, GRANULARITY_4K * 8); + test_source_populate(src2, GRANULARITY_4K * 4, GRANULARITY_4K * 8); + + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src1)); + g_assert_cmpint(ret, =3D=3D, 0); + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src2)); + g_assert_cmpint(ret, =3D=3D, 0); + + rdm =3D memory_region_get_ram_discard_manager(test_mr); + + /* Register listener - should only get notified about intersection */ + test_listener_init(&tl); + section.mr =3D test_mr; + section.offset_within_region =3D 0; + section.size =3D int128_make64(TEST_REGION_SIZE); + ram_discard_manager_register_listener(rdm, &tl.rdl, §ion); + + /* Should have been notified about blocks 4-7 (intersection) */ + g_assert_cmpint(tl.populate_count, =3D=3D, 1); + g_assert_cmpuint(tl.last_populate_offset, =3D=3D, GRANULARITY_4K * 4); + g_assert_cmpuint(tl.last_populate_size, =3D=3D, GRANULARITY_4K * 4); + + ram_discard_manager_unregister_listener(rdm, &tl.rdl); + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src2)= ); + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src1)= ); + + test_source_free(src2); + test_source_free(src1); + test_teardown(); +} + +/* + * Test: Empty region (no sources). + */ +static void test_no_sources(void) +{ + test_setup(); + + /* No sources - should have no manager */ + g_assert_null(memory_region_get_ram_discard_manager(test_mr)); + g_assert_false(memory_region_has_ram_discard_manager(test_mr)); + + test_teardown(); +} + +static void test_redundant_discard(void) +{ + TestRamDiscardSource *src1, *src2; + RamDiscardManager *rdm; + MemoryRegionSection section; + TestListener tl =3D { 0, }; + int ret; + + test_setup(); + + src1 =3D test_source_new(test_mr, GRANULARITY_4K); + src2 =3D test_source_new(test_mr, GRANULARITY_4K); + + /* Add sources */ + ret =3D memory_region_add_ram_discard_source(test_mr, RAM_DISCARD_SOUR= CE(src1)); + g_assert_cmpint(ret, =3D=3D, 0); + ret =3D memory_region_add_ram_discard_source(test_mr, RAM_DISCARD_SOUR= CE(src2)); + g_assert_cmpint(ret, =3D=3D, 0); + + rdm =3D memory_region_get_ram_discard_manager(test_mr); + + /* Register listener */ + test_listener_init(&tl); + section.mr =3D test_mr; + section.offset_within_region =3D 0; + section.size =3D int128_make64(TEST_REGION_SIZE); + ram_discard_manager_register_listener(rdm, &tl.rdl, §ion); + + /* Populate intersection (0-4K) in both sources */ + test_source_populate(src1, 0, GRANULARITY_4K); + test_source_populate(src2, 0, GRANULARITY_4K); + + /* Notify populate src1 - should trigger listener populate */ + ret =3D ram_discard_manager_notify_populate(rdm, RAM_DISCARD_SOURCE(sr= c1), + 0, GRANULARITY_4K); + g_assert_cmpint(ret, =3D=3D, 0); + g_assert_cmpint(tl.populate_count, =3D=3D, 1); + + /* Now Discard src1 -> Aggregate Discarded */ + tl.discard_count =3D 0; + test_source_discard(src1, 0, GRANULARITY_4K); + ram_discard_manager_notify_discard(rdm, RAM_DISCARD_SOURCE(src1), 0, G= RANULARITY_4K); + g_assert_cmpint(tl.discard_count, =3D=3D, 1); + + /* Now Discard src2 -> Aggregate Discarded (Already Discarded!) */ + /* Listener should NOT receive another discard notification for the sa= me range. */ + test_source_discard(src2, 0, GRANULARITY_4K); + ram_discard_manager_notify_discard(rdm, RAM_DISCARD_SOURCE(src2), 0, G= RANULARITY_4K); + + g_assert_cmpint(tl.discard_count, =3D=3D, 1); + + ram_discard_manager_unregister_listener(rdm, &tl.rdl); + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src2)= ); + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src1)= ); + + test_source_free(src2); + test_source_free(src1); + test_teardown(); +} + +/* + * Test: Listener with partial section coverage. + * Listener should only receive notifications for its registered range. + */ +static void test_partial_listener_section(void) +{ + TestRamDiscardSource *src; + RamDiscardManager *rdm; + MemoryRegionSection section; + TestListener tl =3D { 0, }; + int ret; + + test_setup(); + + src =3D test_source_new(test_mr, GRANULARITY_4K); + + /* Populate blocks 0-7 */ + test_source_populate(src, 0, GRANULARITY_4K * 8); + + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src)); + g_assert_cmpint(ret, =3D=3D, 0); + rdm =3D memory_region_get_ram_discard_manager(test_mr); + + /* Register listener for only blocks 2-5 (not the full region) */ + test_listener_init(&tl); + section.mr =3D test_mr; + section.offset_within_region =3D GRANULARITY_4K * 2; + section.size =3D int128_make64(GRANULARITY_4K * 4); + ram_discard_manager_register_listener(rdm, &tl.rdl, §ion); + + /* Should be notified only about blocks 2-5 (intersection) */ + g_assert_cmpint(tl.populate_count, =3D=3D, 1); + g_assert_cmpuint(tl.last_populate_offset, =3D=3D, GRANULARITY_4K * 2); + g_assert_cmpuint(tl.last_populate_size, =3D=3D, GRANULARITY_4K * 4); + + /* Discard block 0 - outside listener's section, no notification */ + tl.discard_count =3D 0; + test_source_discard(src, 0, GRANULARITY_4K); + ram_discard_manager_notify_discard(rdm, RAM_DISCARD_SOURCE(src), + 0, GRANULARITY_4K); + g_assert_cmpint(tl.discard_count, =3D=3D, 0); + + /* Discard block 3 - inside listener's section */ + test_source_discard(src, GRANULARITY_4K * 3, GRANULARITY_4K); + ram_discard_manager_notify_discard(rdm, RAM_DISCARD_SOURCE(src), + GRANULARITY_4K * 3, GRANULARITY_4K); + g_assert_cmpint(tl.discard_count, =3D=3D, 1); + g_assert_cmpuint(tl.last_discard_offset, =3D=3D, GRANULARITY_4K * 3); + + /* Discard spanning boundary (blocks 5-6) - only block 5 in section */ + tl.discard_count =3D 0; + test_source_discard(src, GRANULARITY_4K * 5, GRANULARITY_4K * 2); + ram_discard_manager_notify_discard(rdm, RAM_DISCARD_SOURCE(src), + GRANULARITY_4K * 5, GRANULARITY_4K = * 2); + g_assert_cmpint(tl.discard_count, =3D=3D, 1); + g_assert_cmpuint(tl.last_discard_offset, =3D=3D, GRANULARITY_4K * 5); + g_assert_cmpuint(tl.last_discard_size, =3D=3D, GRANULARITY_4K); + + ram_discard_manager_unregister_listener(rdm, &tl.rdl); + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src)); + test_source_free(src); + test_teardown(); +} + +/* + * Test: Multiple listeners with different (non-overlapping) sections. + */ +static void test_multiple_listeners_different_sections(void) +{ + TestRamDiscardSource *src; + RamDiscardManager *rdm; + MemoryRegionSection section1, section2; + TestListener tl1 =3D { 0, }, tl2 =3D { 0, }; + int ret; + + test_setup(); + + src =3D test_source_new(test_mr, GRANULARITY_4K); + + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src)); + g_assert_cmpint(ret, =3D=3D, 0); + rdm =3D memory_region_get_ram_discard_manager(test_mr); + + /* Listener 1: blocks 0-3 */ + test_listener_init(&tl1); + section1.mr =3D test_mr; + section1.offset_within_region =3D 0; + section1.size =3D int128_make64(GRANULARITY_4K * 4); + ram_discard_manager_register_listener(rdm, &tl1.rdl, §ion1); + + /* Listener 2: blocks 8-11 */ + test_listener_init(&tl2); + section2.mr =3D test_mr; + section2.offset_within_region =3D GRANULARITY_4K * 8; + section2.size =3D int128_make64(GRANULARITY_4K * 4); + ram_discard_manager_register_listener(rdm, &tl2.rdl, §ion2); + + /* Initially all discarded - no populate notifications */ + g_assert_cmpint(tl1.populate_count, =3D=3D, 0); + g_assert_cmpint(tl2.populate_count, =3D=3D, 0); + + /* Populate blocks 0-3 - only tl1 should be notified */ + test_source_populate(src, 0, GRANULARITY_4K * 4); + ret =3D ram_discard_manager_notify_populate(rdm, RAM_DISCARD_SOURCE(sr= c), + 0, GRANULARITY_4K * 4); + g_assert_cmpint(ret, =3D=3D, 0); + g_assert_cmpint(tl1.populate_count, =3D=3D, 1); + g_assert_cmpint(tl2.populate_count, =3D=3D, 0); + + /* Populate blocks 8-11 - only tl2 should be notified */ + test_source_populate(src, GRANULARITY_4K * 8, GRANULARITY_4K * 4); + ret =3D ram_discard_manager_notify_populate(rdm, RAM_DISCARD_SOURCE(sr= c), + GRANULARITY_4K * 8, + GRANULARITY_4K * 4); + g_assert_cmpint(ret, =3D=3D, 0); + g_assert_cmpint(tl1.populate_count, =3D=3D, 1); + g_assert_cmpint(tl2.populate_count, =3D=3D, 1); + + /* Populate blocks 4-7 (gap) - neither listener should be notified */ + test_source_populate(src, GRANULARITY_4K * 4, GRANULARITY_4K * 4); + ret =3D ram_discard_manager_notify_populate(rdm, RAM_DISCARD_SOURCE(sr= c), + GRANULARITY_4K * 4, + GRANULARITY_4K * 4); + g_assert_cmpint(ret, =3D=3D, 0); + g_assert_cmpint(tl1.populate_count, =3D=3D, 1); + g_assert_cmpint(tl2.populate_count, =3D=3D, 1); + + ram_discard_manager_unregister_listener(rdm, &tl2.rdl); + ram_discard_manager_unregister_listener(rdm, &tl1.rdl); + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src)); + test_source_free(src); + test_teardown(); +} + +/* + * Test: Multiple listeners with overlapping sections. + */ +static void test_overlapping_listener_sections(void) +{ + TestRamDiscardSource *src; + RamDiscardManager *rdm; + MemoryRegionSection section1, section2; + TestListener tl1 =3D { 0, }, tl2 =3D { 0, }; + int ret; + + test_setup(); + + src =3D test_source_new(test_mr, GRANULARITY_4K); + + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src)); + g_assert_cmpint(ret, =3D=3D, 0); + rdm =3D memory_region_get_ram_discard_manager(test_mr); + + /* Listener 1: blocks 0-7 */ + test_listener_init(&tl1); + section1.mr =3D test_mr; + section1.offset_within_region =3D 0; + section1.size =3D int128_make64(GRANULARITY_4K * 8); + ram_discard_manager_register_listener(rdm, &tl1.rdl, §ion1); + + /* Listener 2: blocks 4-11 (overlaps with tl1 on blocks 4-7) */ + test_listener_init(&tl2); + section2.mr =3D test_mr; + section2.offset_within_region =3D GRANULARITY_4K * 4; + section2.size =3D int128_make64(GRANULARITY_4K * 8); + ram_discard_manager_register_listener(rdm, &tl2.rdl, §ion2); + + /* Populate blocks 4-7 (overlap region) - both should be notified */ + test_source_populate(src, GRANULARITY_4K * 4, GRANULARITY_4K * 4); + ret =3D ram_discard_manager_notify_populate(rdm, RAM_DISCARD_SOURCE(sr= c), + GRANULARITY_4K * 4, + GRANULARITY_4K * 4); + g_assert_cmpint(ret, =3D=3D, 0); + g_assert_cmpint(tl1.populate_count, =3D=3D, 1); + g_assert_cmpint(tl2.populate_count, =3D=3D, 1); + + /* Populate blocks 0-3 - only tl1 */ + test_source_populate(src, 0, GRANULARITY_4K * 4); + ret =3D ram_discard_manager_notify_populate(rdm, RAM_DISCARD_SOURCE(sr= c), + 0, GRANULARITY_4K * 4); + g_assert_cmpint(ret, =3D=3D, 0); + g_assert_cmpint(tl1.populate_count, =3D=3D, 2); + g_assert_cmpint(tl2.populate_count, =3D=3D, 1); + + /* Populate blocks 8-11 - only tl2 */ + test_source_populate(src, GRANULARITY_4K * 8, GRANULARITY_4K * 4); + ret =3D ram_discard_manager_notify_populate(rdm, RAM_DISCARD_SOURCE(sr= c), + GRANULARITY_4K * 8, + GRANULARITY_4K * 4); + g_assert_cmpint(ret, =3D=3D, 0); + g_assert_cmpint(tl1.populate_count, =3D=3D, 2); + g_assert_cmpint(tl2.populate_count, =3D=3D, 2); + + ram_discard_manager_unregister_listener(rdm, &tl2.rdl); + ram_discard_manager_unregister_listener(rdm, &tl1.rdl); + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src)); + test_source_free(src); + test_teardown(); +} + +/* + * Test: Listener at exact memory region boundaries. + */ +static void test_boundary_section(void) +{ + TestRamDiscardSource *src; + RamDiscardManager *rdm; + MemoryRegionSection section; + TestListener tl =3D { 0, }; + uint64_t last_offset; + int ret; + + test_setup(); + + src =3D test_source_new(test_mr, GRANULARITY_4K); + + /* Populate last 4 blocks of the region */ + last_offset =3D TEST_REGION_SIZE - GRANULARITY_4K * 4; + test_source_populate(src, last_offset, GRANULARITY_4K * 4); + + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src)); + g_assert_cmpint(ret, =3D=3D, 0); + rdm =3D memory_region_get_ram_discard_manager(test_mr); + + /* Register listener for exactly the last 4 blocks */ + test_listener_init(&tl); + section.mr =3D test_mr; + section.offset_within_region =3D last_offset; + section.size =3D int128_make64(GRANULARITY_4K * 4); + ram_discard_manager_register_listener(rdm, &tl.rdl, §ion); + + /* Should receive notification for the populated range */ + g_assert_cmpint(tl.populate_count, =3D=3D, 1); + g_assert_cmpuint(tl.last_populate_offset, =3D=3D, last_offset); + g_assert_cmpuint(tl.last_populate_size, =3D=3D, GRANULARITY_4K * 4); + + /* Discard exactly at boundary */ + tl.discard_count =3D 0; + test_source_discard(src, last_offset, GRANULARITY_4K * 4); + ram_discard_manager_notify_discard(rdm, RAM_DISCARD_SOURCE(src), + last_offset, GRANULARITY_4K * 4); + g_assert_cmpint(tl.discard_count, =3D=3D, 1); + + ram_discard_manager_unregister_listener(rdm, &tl.rdl); + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src)); + test_source_free(src); + test_teardown(); +} + +static int count_discarded_blocks(const MemoryRegionSection *section, + void *opaque) +{ + int *count =3D opaque; + *count +=3D int128_get64(section->size) / GRANULARITY_4K; + return 0; +} + +/* + * Test: replay_discarded with two sources (union semantics). + */ +static void test_replay_discarded(void) +{ + TestRamDiscardSource *src1, *src2; + RamDiscardManager *rdm; + MemoryRegionSection section; + int count =3D 0; + int ret; + + test_setup(); + + src1 =3D test_source_new(test_mr, GRANULARITY_4K); + src2 =3D test_source_new(test_mr, GRANULARITY_4K); + + /* + * src1: blocks 0-3 populated, rest discarded + * src2: blocks 2-5 populated, rest discarded + * Aggregated populated: blocks 2-3 (intersection) + * Aggregated discarded: blocks 0-1, 4-5, 6+ (union of discarded) + */ + test_source_populate(src1, 0, GRANULARITY_4K * 4); + test_source_populate(src2, GRANULARITY_4K * 2, GRANULARITY_4K * 4); + + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src1)); + g_assert_cmpint(ret, =3D=3D, 0); + ret =3D memory_region_add_ram_discard_source(test_mr, + RAM_DISCARD_SOURCE(src2)); + g_assert_cmpint(ret, =3D=3D, 0); + + rdm =3D memory_region_get_ram_discard_manager(test_mr); + + section.mr =3D test_mr; + section.offset_within_region =3D 0; + section.size =3D int128_make64(GRANULARITY_4K * 8); + + /* Count discarded blocks */ + ret =3D ram_discard_manager_replay_discarded(rdm, §ion, + count_discarded_blocks, &co= unt); + + g_assert_cmpint(ret, =3D=3D, 0); + /* Discarded: blocks 0-1 (2), blocks 4-5 (2), blocks 6-7 (2) =3D 6 blo= cks */ + g_assert_cmpint(count, =3D=3D, 6); + + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src2)= ); + memory_region_del_ram_discard_source(test_mr, RAM_DISCARD_SOURCE(src1)= ); + + test_source_free(src2); + test_source_free(src1); + test_teardown(); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + module_call_init(MODULE_INIT_QOM); + type_register_static(&test_rds_info); + + g_test_add_func("/ram-discard-manager/single-source/basic", + test_single_source_basic); + g_test_add_func("/ram-discard-manager/single-source/listener", + test_single_source_listener); + g_test_add_func("/ram-discard-manager/two-sources/same-granularity", + test_two_sources_same_granularity); + g_test_add_func("/ram-discard-manager/two-sources/different-granularit= y", + test_two_sources_different_granularity); + g_test_add_func("/ram-discard-manager/two-sources/notification", + test_two_sources_notification); + g_test_add_func("/ram-discard-manager/dynamic/add-source-with-listener= ", + test_add_source_with_listener); + g_test_add_func("/ram-discard-manager/dynamic/remove-source-with-liste= ner", + test_remove_source_with_listener); + g_test_add_func("/ram-discard-manager/dynamic/readd-source-with-listen= er", + test_readd_source_with_listener); + g_test_add_func("/ram-discard-manager/edge/duplicate-source", + test_duplicate_source); + g_test_add_func("/ram-discard-manager/edge/populate-rollback", + test_populate_rollback); + g_test_add_func("/ram-discard-manager/edge/replay-intersection", + test_replay_populated_intersection); + g_test_add_func("/ram-discard-manager/edge/no-sources", + test_no_sources); + g_test_add_func("/ram-discard-manager/multi-source/redundant-discard", + test_redundant_discard); + g_test_add_func("/ram-discard-manager/listener/partial-section", + test_partial_listener_section); + g_test_add_func("/ram-discard-manager/listener/multiple-different", + test_multiple_listeners_different_sections); + g_test_add_func("/ram-discard-manager/listener/overlapping", + test_overlapping_listener_sections); + g_test_add_func("/ram-discard-manager/edge/boundary-section", + test_boundary_section); + g_test_add_func("/ram-discard-manager/multi-source/replay-discarded", + test_replay_discarded); + + return g_test_run(); +} diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 01cc540a45..5ba6b1a230 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -138,7 +138,13 @@ if have_system 'test-bufferiszero': [], 'test-smp-parse': [qom, meson.project_source_root() / 'hw/core/machine= -smp.c'], 'test-vmstate': [migration, io], - 'test-yank': ['socket-helpers.c', qom, io, chardev] + 'test-yank': ['socket-helpers.c', qom, io, chardev], + 'test-ram-discard-manager': [ + 'test-ram-discard-manager.c', + 'test-ram-discard-manager-stubs.c', + meson.project_source_root() / 'system/ram-discard-manager.c', + genh, qemuutil, qom + ], } if config_host_data.get('CONFIG_INOTIFY1') tests +=3D {'test-util-filemonitor': []} --=20 2.54.0 From nobody Thu Jun 25 06:56:52 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1782218990; cv=none; d=zohomail.com; s=zohoarc; b=mmqxuQSVMNIQoILnCpNSOKbqx4YzmvMtL67bQFxOTGdzRQOxGM8+TXXH+/qAQWoU/D8K7rlBEvde3vUL/UbVdjXAKJYZRqLcfyQNssWNUCH6UB5Lwiy5OqaZMM4iGamxgHwt8T2yoba4jkuOEkD4a3W8396qjBIWaNuoGBMNb8Q= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1782218990; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=BUCTGAMfUlfjvkSgaEmGOjoXM8k4zTSG2Wny9ifuO80=; b=VmCYD5RDQl4V+RFYovyh3/9SB/3+wjtqk19q39HdiV45Bx3rn3X7XW4ouh1gzxl9trq/BWD94FreAI/onlSZBUDF+4iq2dCV4uKoUuUwxrf7oTbxwRheZowp3gXl0jYZRIHMk8hix+4U8F5SaaLbSJOSSXqi96bSdfQ79Z3Yo9I= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1782218990592837.1756725417794; Tue, 23 Jun 2026 05:49:50 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wc0Yg-0004br-LG; Tue, 23 Jun 2026 08:48:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0Ye-0004bD-81 for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:52 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wc0Yc-00074E-BG for qemu-devel@nongnu.org; Tue, 23 Jun 2026 08:48:52 -0400 Received: from mail-qt1-f199.google.com (mail-qt1-f199.google.com [209.85.160.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-163-WUlwqUWAOJWavE_hE5FcEw-1; Tue, 23 Jun 2026 08:48:48 -0400 Received: by mail-qt1-f199.google.com with SMTP id d75a77b69052e-51a5212cf77so15995311cf.2 for ; Tue, 23 Jun 2026 05:48:48 -0700 (PDT) Received: from x1.com ([174.91.117.157]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51a51106a09sm22288351cf.0.2026.06.23.05.48.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jun 2026 05:48:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782218929; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=BUCTGAMfUlfjvkSgaEmGOjoXM8k4zTSG2Wny9ifuO80=; b=MNg8U5vhFj3VdgoRfrljYLGl3F1VEBn9IrJA5JEY4LvBHSgLub0Fa6b8n3FbMrE0SWeeHm agjPHWIL8hNc/aQ0qnhaUVhVrGXnK4MFXtYcYB2b8ELtwnS171WAU8QNmlud/Br14wP6Hw jKKfClZqi/0qSMznbNegB3IWS9lH0SQ= X-MC-Unique: WUlwqUWAOJWavE_hE5FcEw-1 X-Mimecast-MFC-AGG-ID: WUlwqUWAOJWavE_hE5FcEw_1782218928 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1782218928; x=1782823728; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=BUCTGAMfUlfjvkSgaEmGOjoXM8k4zTSG2Wny9ifuO80=; b=LkZH2n2ycC4yuNekqDBmiuf7euGicvjDohmfChq6dAn8QeNbuhfA8cmujuq1zmqSQe mjUa1LPKFUf3LT6ySLN2fl5zC2vsEeIqN30rnbMjEnyaKiIZXXD/bkU0HSQmuuOxdfEx XhN/gYBu1zjlPAnsAxGGl6Ssz3wnpRwheFKlrvtxnPvQcuACgLL2xfB34IukfTEiXM6Q +ywjqORhpCqvYRNCnDyGgCA1qYj/yzHRY6foYK6Gem4spymZUlvD9SuRghDq6W1z4VId 2trXohT6YIpZvXk9H8IQcdClpfxf0ld6H/xyMchsRCbDTzgQtzKe7lCxf8cvhkqOHpMr HNKg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782218928; x=1782823728; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=BUCTGAMfUlfjvkSgaEmGOjoXM8k4zTSG2Wny9ifuO80=; b=UKy4fXg37zmGRSV8kPmTsOeXqdcy62KrupnPpyzxj6pV/ms5zFObgbXvHeS4SRIaNl uwg48HxdiNrx23ua1CwFy6beXfTmPaHp4mRZ546E/gB0hImFhwfl7J2K5d5UeEy/XInu Zlq+e4AdLtabuYJbtd6dRsy3LiB+WLhbr2REOQ79Wwm85t088j0pFfpTyJcjuT094DgQ 0rdYXBFOoR8z8Z9yFRAdYyo/P/9u0VD1zjqcu45DAaxXc0O2A/cNteYAo6brtt+UxauC 0ARZRed5sFwC1kPsih+vVYyA6MJk8fr4TcHfSIM7jdhumvyJ0CN2tLS5drIbLacHOXZx 5kPQ== X-Gm-Message-State: AOJu0Yx9BhClLKx+H0ZeXRuag+7ZXMSH6qAWLR5Q7MvAV9xdytd/BvP1 K24OvggXtBVBPJgLuER8iBC+DFp5g39W/dFwdKcvtaQ5S/0c4FnIb43P2z6dgV2P6ayWMwQJ+pO QpVCFxHPqz60a/JjEMf8ZPQs9vRBgf4nhHUrz0mdK7Yak140LxT7XtXvmFmbv02MRklezgDZIRE XUCXoUKJIhd8m3Mat8QXsneL3zncTKeFDCyk1snw== X-Gm-Gg: AfdE7clvRuLoQ5P4VQgAO4Ydu1iMbnaAoivrqkQPuAlYD3TEaFkT/W6YrUgb0Te2jhd Lax+6PX+OjfQfAgnggvRPPqPPbGwF0gw2yi8TJgAoutgHDuvAHljSfKdDxLYw0XZ3++jF9MDk+k bLnghaiGg8zzUAPtvaJWaRSAbmrQcBSBgv9GNonWP7Wovkdj+fPqu16Hfa7XgvUH5pl0nBb09yn OuHNflRfnSDLZVVbg6GfCHEx8xKN5JLjE5GK36d6iyuYoBRHl6MXvXjt41HdDdsoYnF8w+BHL51 v0CJUPOk5poth3OjFBhrzKGOye39FFbSnagkanfibGaPq/RRltqw5H5D7fIpfVfVpzVNso33Y99 61g== X-Received: by 2002:a05:622a:228a:b0:519:5680:1b5 with SMTP id d75a77b69052e-519e4a55277mr288279471cf.21.1782218927495; Tue, 23 Jun 2026 05:48:47 -0700 (PDT) X-Received: by 2002:a05:622a:228a:b0:519:5680:1b5 with SMTP id d75a77b69052e-519e4a55277mr288278991cf.21.1782218926853; Tue, 23 Jun 2026 05:48:46 -0700 (PDT) From: Peter Xu To: qemu-devel@nongnu.org Cc: Peter Xu , Fabiano Rosas , Paolo Bonzini , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Xiaoyao Li Subject: [PULL 18/18] system/physmem: make ram_block_discard_range() handle guest_memfd Date: Tue, 23 Jun 2026 08:47:59 -0400 Message-ID: <20260623124759.125399-19-peterx@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260623124759.125399-1-peterx@redhat.com> References: <20260623124759.125399-1-peterx@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=peterx@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1782218991370158501 From: Marc-Andr=C3=A9 Lureau Most callers of ram_block_discard_range() want to discard both the shared and guest_memfd backing. Only kvm_convert_memory() intentionally discards a single plane during private/shared conversions. Rename the current implementation to ram_block_discard_shared_range() and make ram_block_discard_range() a composite that also discards guest_memfd when present (rb->guest_memfd >=3D 0). This ensures callers like virtio-mem, virtio-balloon, hv-balloon, migration.. reclaim private pages on discard. Update kvm_convert_memory() to use the plane-specific ram_block_discard_shared_range() since it only needs to discard the shared backing when converting to private. Likewise, after TDVF image copy, use ram_block_discard_shared_range(). Reviewed-by: Peter Xu Reviewed-by: Xiaoyao Li Signed-off-by: Marc-Andr=C3=A9 Lureau Link: https://lore.kernel.org/r/20260604-rdm5-v5-11-5768e6a0943d@redhat.com Signed-off-by: Peter Xu --- include/system/ramblock.h | 3 ++- accel/kvm/kvm-all.c | 2 +- system/physmem.c | 25 +++++++++++++++++++++---- target/i386/kvm/tdx.c | 2 +- system/trace-events | 2 +- 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/include/system/ramblock.h b/include/system/ramblock.h index 2b38718fe5..f0639287bf 100644 --- a/include/system/ramblock.h +++ b/include/system/ramblock.h @@ -103,7 +103,8 @@ struct RamBlockAttributes { =20 /* @offset: the offset within the RAMBlock */ int ram_block_discard_range(RAMBlock *rb, uint64_t offset, size_t length); -/* @offset: the offset within the RAMBlock */ +int ram_block_discard_shared_range(RAMBlock *rb, uint64_t offset, + size_t length); int ram_block_discard_guest_memfd_range(RAMBlock *rb, uint64_t offset, size_t length); =20 diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index f4f0e64fbd..8ddfbaff46 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -3422,7 +3422,7 @@ int kvm_convert_memory(hwaddr start, hwaddr size, boo= l to_private) */ goto out_unref; } - ret =3D ram_block_discard_range(rb, offset, size); + ret =3D ram_block_discard_shared_range(rb, offset, size); } else { ret =3D ram_block_discard_guest_memfd_range(rb, offset, size); } diff --git a/system/physmem.c b/system/physmem.c index c4bfb57625..c21ea92915 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -4093,7 +4093,7 @@ int qemu_ram_foreach_block(RAMBlockIterFunc func, voi= d *opaque) * Returns: 0 on success, none-0 on failure * */ -int ram_block_discard_range(RAMBlock *rb, uint64_t offset, size_t length) +int ram_block_discard_shared_range(RAMBlock *rb, uint64_t offset, size_t l= ength) { int ret =3D -1; =20 @@ -4142,7 +4142,7 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t of= fset, size_t length) * have a MAP_PRIVATE mapping, possibly messing with other * MAP_PRIVATE/MAP_SHARED mappings. There is no easy way to * change that behavior whithout violating the promised - * semantics of ram_block_discard_range(). + * semantics of ram_block_discard_shared_range(). * * Only warn, because it works as long as nobody else uses that * file. @@ -4198,8 +4198,9 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t of= fset, size_t length) goto err; #endif } - trace_ram_block_discard_range(rb->idstr, host_startaddr, length, - need_madvise, need_fallocate, ret); + trace_ram_block_discard_shared_range(rb->idstr, host_startaddr, le= ngth, + need_madvise, need_fallocate, + ret); } else { error_report("%s: Overrun block '%s' (%" PRIu64 "/%zx/" RAM_ADDR_F= MT")", __func__, rb->idstr, offset, length, rb->max_length); @@ -4209,6 +4210,22 @@ err: return ret; } =20 +int ram_block_discard_range(RAMBlock *rb, uint64_t offset, size_t length) +{ + int ret; + + ret =3D ram_block_discard_shared_range(rb, offset, length); + if (ret) { + return ret; + } + + if (rb->guest_memfd >=3D 0) { + ret =3D ram_block_discard_guest_memfd_range(rb, offset, length); + } + + return ret; +} + int ram_block_discard_guest_memfd_range(RAMBlock *rb, uint64_t offset, size_t length) { diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index df46fce769..dfad469112 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -385,7 +385,7 @@ static void tdx_finalize_vm(Notifier *notifier, void *u= nused) * KVM_MEMORY_MAPPING. It becomes useless. */ ram_block =3D tdx_guest->tdvf_mr->ram_block; - ram_block_discard_range(ram_block, 0, ram_block->max_length); + ram_block_discard_shared_range(ram_block, 0, ram_block->max_length); =20 tdx_vm_ioctl(KVM_TDX_FINALIZE_VM, 0, NULL, &error_fatal); CONFIDENTIAL_GUEST_SUPPORT(tdx_guest)->ready =3D true; diff --git a/system/trace-events b/system/trace-events index e6e1b61279..51b4a4679a 100644 --- a/system/trace-events +++ b/system/trace-events @@ -32,7 +32,7 @@ global_dirty_changed(unsigned int bitmask) "bitmask 0x%"P= RIx32 address_space_map(void *as, uint64_t addr, uint64_t len, bool is_write, ui= nt32_t attrs) "as:%p addr 0x%"PRIx64":%"PRIx64" write:%d attrs:0x%x" find_ram_offset(uint64_t size, uint64_t offset) "size: 0x%" PRIx64 " @ 0x%= " PRIx64 find_ram_offset_loop(uint64_t size, uint64_t candidate, uint64_t offset, u= int64_t next, uint64_t mingap) "trying size: 0x%" PRIx64 " @ 0x%" PRIx64 ",= offset: 0x%" PRIx64" next: 0x%" PRIx64 " mingap: 0x%" PRIx64 -ram_block_discard_range(const char *rbname, void *hva, size_t length, bool= need_madvise, bool need_fallocate, int ret) "%s@%p + 0x%zx: madvise: %d fa= llocate: %d ret: %d" +ram_block_discard_shared_range(const char *rbname, void *hva, size_t lengt= h, bool need_madvise, bool need_fallocate, int ret) "%s@%p + 0x%zx: madvise= : %d fallocate: %d ret: %d" qemu_ram_alloc_shared(const char *name, size_t size, size_t max_size, int = fd, void *host) "%s size %zu max_size %zu fd %d host %p" =20 subpage_register(void *subpage, uint32_t start, uint32_t end, int idx, int= eidx, uint16_t section) "subpage %p start 0x%08x end 0x%08x idx 0x%08x eid= x 0x%08x section %u" --=20 2.54.0