From nobody Sun Dec 14 06:17:10 2025 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=1752239178; cv=none; d=zohomail.com; s=zohoarc; b=DeAaed3Qhd8jIvVexjeuXaAUH1LLHFfqIzWjInl6fjdzyyIdGYntwrEedqFDuAv/by/THchpm/YDv5tOFNR80vvuTYpmYCydr+EGO3DeQxNdX0Tw9XQ/ZTtymiHb1VmFn6apX8H+QeNPgbRRckLdSyJNrCHKiyvnKOhzF4E9itA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1752239178; 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=yv/e9TfGTNAXq5vppeKFNtoeq3WG3Gxymxnt/da3xBQ=; b=VCwjd7weMsp+pIa7lm4Wr1ShB3EkGTop7HZJnSVZKws0ovuOriEGwM2E2vrM9Uh3c6tAt+TTVIWWyw4ZXohNwUJ18g5Xrh2tvwJCy+c7FL5VUqg3yf4RFIH9an36KpSw7YDgmbHYQublEwLUxkb+orEYcaSb3XSs2bdf9iFujJE= 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 lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1752239178596366.86383241463955; Fri, 11 Jul 2025 06:06:18 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uaDR9-0001eG-4H; Fri, 11 Jul 2025 09:05:11 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uaDPI-0000Pp-5p for qemu-devel@nongnu.org; Fri, 11 Jul 2025 09:03:28 -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 1uaDPG-0003hE-6H for qemu-devel@nongnu.org; Fri, 11 Jul 2025 09:03:15 -0400 Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-606-M_7Cpp-BMBORHNtw_xWI-w-1; Fri, 11 Jul 2025 09:03:09 -0400 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id D2B82195609F; Fri, 11 Jul 2025 13:03:07 +0000 (UTC) Received: from gerbillo.redhat.com (unknown [10.44.33.145]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id DDD5619560A3; Fri, 11 Jul 2025 13:03:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752238992; 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=yv/e9TfGTNAXq5vppeKFNtoeq3WG3Gxymxnt/da3xBQ=; b=R0WxqLQCtKqjRVdKrUlFyK5Tf7t2PPKgMcqau7MsxdQLCEE9Cki48u6zM1YmUkI/Vj9Aev dr8NfzIxjbOmnFB58LoeY8JsDC24Yn8QN7yG6tl0sZrZL//6ehH3656SrpM2viNsvA1TW5 OX7iGxRBUn5MZ2V35GZp4hdiy0TV6FI= X-MC-Unique: M_7Cpp-BMBORHNtw_xWI-w-1 X-Mimecast-MFC-AGG-ID: M_7Cpp-BMBORHNtw_xWI-w_1752238988 From: Paolo Abeni To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Dmitry Fleytman , Akihiko Odaki , Jason Wang , Sriram Yagnaraman , "Michael S. Tsirkin" , Stefano Garzarella , Cornelia Huck , Luigi Rizzo , Giuseppe Lettieri , Vincenzo Maffione , Eric Blake , Markus Armbruster , kvm@vger.kernel.org Subject: [PATCH RFC v2 04/13] virtio: serialize extended features state Date: Fri, 11 Jul 2025 15:02:09 +0200 Message-ID: In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 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=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pabeni@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, 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, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=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: 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: 1752239180930116600 Content-Type: text/plain; charset="utf-8" If the driver uses any of the extended features (i.e. above 64), serialize the full features range (128 bits). This is one of the few spots that need explicitly to know and set in stone the extended features array size; add a build bug to prevent breaking the migration should such size change again in the future: more serialization plumbing will be needed. Signed-off-by: Paolo Abeni --- v1 -> v2: - uint128_t -> u64[2] --- hw/virtio/virtio.c | 97 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 11 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 82a285a31d..6a313313dd 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -2954,6 +2954,24 @@ static const VMStateDescription vmstate_virtio_disab= led =3D { } }; =20 +static bool virtio_128bit_features_needed(void *opaque) +{ + VirtIODevice *vdev =3D opaque; + + return virtio_features_use_extended(vdev->host_features_array); +} + +static const VMStateDescription vmstate_virtio_128bit_features =3D { + .name =3D "virtio/128bit_features", + .version_id =3D 1, + .minimum_version_id =3D 1, + .needed =3D &virtio_128bit_features_needed, + .fields =3D (const VMStateField[]) { + VMSTATE_UINT64_ARRAY(guest_features_array, VirtIODevice, 2), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_virtio =3D { .name =3D "virtio", .version_id =3D 1, @@ -2963,6 +2981,7 @@ static const VMStateDescription vmstate_virtio =3D { }, .subsections =3D (const VMStateDescription * const []) { &vmstate_virtio_device_endian, + &vmstate_virtio_128bit_features, &vmstate_virtio_64bit_features, &vmstate_virtio_virtqueues, &vmstate_virtio_ringsize, @@ -3059,23 +3078,30 @@ const VMStateInfo virtio_vmstate_info =3D { .put =3D virtio_device_put, }; =20 -static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val) +static int virtio_set_features_nocheck(VirtIODevice *vdev, const uint64_t = *val) { VirtioDeviceClass *k =3D VIRTIO_DEVICE_GET_CLASS(vdev); - bool bad =3D (val & ~(vdev->host_features)) !=3D 0; + uint64_t tmp[VIRTIO_FEATURES_DWORDS]; + bool bad; + + virtio_features_andnot(tmp, val, vdev->host_features_array); + bad =3D !virtio_features_is_empty(tmp); + + virtio_features_and(tmp, val, vdev->host_features_array); =20 - val &=3D vdev->host_features; if (k->set_features) { - k->set_features(vdev, val); + bad =3D bad || virtio_features_use_extended(tmp); + k->set_features(vdev, tmp[0]); } - vdev->guest_features =3D val; + + virtio_features_copy(vdev->guest_features_array, tmp); return bad ? -1 : 0; } =20 typedef struct VirtioSetFeaturesNocheckData { Coroutine *co; VirtIODevice *vdev; - uint64_t val; + uint64_t val[VIRTIO_FEATURES_DWORDS]; int ret; } VirtioSetFeaturesNocheckData; =20 @@ -3094,12 +3120,41 @@ virtio_set_features_nocheck_maybe_co(VirtIODevice *= vdev, uint64_t val) VirtioSetFeaturesNocheckData data =3D { .co =3D qemu_coroutine_self(), .vdev =3D vdev, - .val =3D val, }; + virtio_features_from_u64(data.val, val); aio_bh_schedule_oneshot(qemu_get_current_aio_context(), virtio_set_features_nocheck_bh, &data); qemu_coroutine_yield(); return data.ret; + } else { + uint64_t features[VIRTIO_FEATURES_DWORDS]; + virtio_features_from_u64(features, val); + return virtio_set_features_nocheck(vdev, features); + } +} + +static void virtio_set_128bit_features_nocheck_bh(void *opaque) +{ + VirtioSetFeaturesNocheckData *data =3D opaque; + + data->ret =3D virtio_set_features_nocheck(data->vdev, data->val); + aio_co_wake(data->co); +} + +static int coroutine_mixed_fn +virtio_set_128bit_features_nocheck_maybe_co(VirtIODevice *vdev, + const uint64_t *val) +{ + if (qemu_in_coroutine()) { + VirtioSetFeaturesNocheckData data =3D { + .co =3D qemu_coroutine_self(), + .vdev =3D vdev, + }; + virtio_features_copy(data.val, val); + aio_bh_schedule_oneshot(qemu_get_current_aio_context(), + virtio_set_128bit_features_nocheck_bh, &da= ta); + qemu_coroutine_yield(); + return data.ret; } else { return virtio_set_features_nocheck(vdev, val); } @@ -3107,6 +3162,7 @@ virtio_set_features_nocheck_maybe_co(VirtIODevice *vd= ev, uint64_t val) =20 int virtio_set_features(VirtIODevice *vdev, uint64_t val) { + uint64_t features[VIRTIO_FEATURES_DWORDS]; int ret; /* * The driver must not attempt to set features after feature negotiati= on @@ -3122,7 +3178,8 @@ int virtio_set_features(VirtIODevice *vdev, uint64_t = val) __func__, vdev->name); } =20 - ret =3D virtio_set_features_nocheck(vdev, val); + virtio_features_from_u64(features, val); + ret =3D virtio_set_features_nocheck(vdev, features); if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { /* VIRTIO_RING_F_EVENT_IDX changes the size of the caches. */ int i; @@ -3145,6 +3202,7 @@ void virtio_reset(void *opaque) { VirtIODevice *vdev =3D opaque; VirtioDeviceClass *k =3D VIRTIO_DEVICE_GET_CLASS(vdev); + uint64_t features[VIRTIO_FEATURES_DWORDS]; int i; =20 virtio_set_status(vdev, 0); @@ -3171,7 +3229,8 @@ void virtio_reset(void *opaque) vdev->start_on_kick =3D false; vdev->started =3D false; vdev->broken =3D false; - virtio_set_features_nocheck(vdev, 0); + virtio_features_clear(features); + virtio_set_features_nocheck(vdev, features); vdev->queue_sel =3D 0; vdev->status =3D 0; vdev->disabled =3D false; @@ -3254,7 +3313,7 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int vers= ion_id) * Note: devices should always test host features in future - don't cr= eate * new dependencies like this. */ - vdev->guest_features =3D features; + virtio_features_from_u64(vdev->guest_features_array, features); =20 config_len =3D qemu_get_be32(f); =20 @@ -3333,7 +3392,23 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int ver= sion_id) vdev->device_endian =3D virtio_default_endian(); } =20 - if (virtio_64bit_features_needed(vdev)) { + /* + * Serialization needs constant size features array. Avoid + * silently breaking migration should the feature space increase + * even more in the (far away) future + */ + QEMU_BUILD_BUG_ON(VIRTIO_FEATURES_DWORDS !=3D 2); + if (virtio_128bit_features_needed(vdev)) { + uint64_t *val =3D vdev->guest_features_array; + + if (virtio_set_128bit_features_nocheck_maybe_co(vdev, val) < 0) { + error_report("Features 0x" VIRTIO_FEATURES_FMT " unsupported. " + "Allowed features: 0x" VIRTIO_FEATURES_FMT, + VIRTIO_FEATURES_PR(val), + VIRTIO_FEATURES_PR(vdev->host_features_array)); + return -1; + } + } else if (virtio_64bit_features_needed(vdev)) { /* * Subsection load filled vdev->guest_features. Run them * through virtio_set_features to sanity-check them against --=20 2.50.0