From nobody Sun Mar 22 14:12:45 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=bytedance.com ARC-Seal: i=1; a=rsa-sha256; t=1773920403; cv=none; d=zohomail.com; s=zohoarc; b=fyOkw35YXOGbU0CkS99JOMZoNMsK8LULKXh+4rHSz1O/YkR1ZJuCAmsySk695OugwkHGuvK1xWi65als8XJinR28hdUep9M+5eGIeZbeseApKnFuYtm92tnFCzqUpvp5kXaYyiajHy4LXRLiyKChWwBlE+EfY2uKDvEgWmy/7sA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1773920403; 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=G7AZ4K1LApZ83qpc7CCQiivvbVea9ymgYf/d/4iWmjM=; b=TKQgxYi7q1y44wRetEzifPdCtkqqVgh17SSEqvNci0koNL/VGpJsrJf0EU/yjM0w5K8jM/bS/N+LqY6Y8fLAlozKmNw2zHARyEOIRAmisScm0goU2KzT6h+9ur1t2S5EfcRmOejWw1zv8KfTbXBxN70Anze5zm5Pu2FGzNi9EaA= 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 1773920403589876.6145882290455; Thu, 19 Mar 2026 04:40:03 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1w3BiX-0007JI-Dd; Thu, 19 Mar 2026 07:39:09 -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 1w3BiU-0007Ik-G6 for qemu-devel@nongnu.org; Thu, 19 Mar 2026 07:39:06 -0400 Received: from va-1-115.ptr.blmpb.com ([209.127.230.115]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1w3BiR-0004bb-Sn for qemu-devel@nongnu.org; Thu, 19 Mar 2026 07:39:06 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=2212171451; d=bytedance.com; t=1773920337; h=from:subject: mime-version:from:date:message-id:subject:to:cc:reply-to:content-type: mime-version:in-reply-to:message-id; bh=G7AZ4K1LApZ83qpc7CCQiivvbVea9ymgYf/d/4iWmjM=; b=Jp9Gsz6GP3NynVO96NhxFEMFFE7ynQpb4UA5QeQJF0oan7I6qlQHQo2VafOcXtU+yHTCcG nnE40+tFfL6bAbZfhoTlHhyZydzG8+0EZ88pkow7pDbiMwWCrpqRYine6+hJN+aHgJU3q8 J9E4AtLFScInyZ8V1xbKxS8WLfC/FEi/PrffjZcT5hyN52QIUtyQkX/eGvBh+qsr+3ueeG LrhVCPPMB58+Ai6UHUkJCTCnVR4HH61aMGyILXTM0Wxzidov52EfG+jFRILHjiXS0fS9tM ifQmNzR0InophUZVgDWkLI/DU/WKmKA2mM+DO+xniNdWPiPTY4sDyyRcaoge8g== To: Subject: [RFC v2 1/2] migration: Support ghash migration In-Reply-To: <20260319113830.53867-1-hongmianquan@bytedance.com> Mime-Version: 1.0 Cc: , , , , "hongmianquan" X-Lms-Return-Path: X-Mailer: git-send-email 2.32.1 (Apple Git-133) Content-Transfer-Encoding: quoted-printable From: "hongmianquan" Date: Thu, 19 Mar 2026 19:38:29 +0800 Message-Id: <20260319113830.53867-2-hongmianquan@bytedance.com> X-Original-From: hongmianquan References: <20260319113830.53867-1-hongmianquan@bytedance.com> 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=209.127.230.115; envelope-from=hongmianquan@bytedance.com; helo=va-1-115.ptr.blmpb.com X-Spam_score_int: -3 X-Spam_score: -0.4 X-Spam_bar: / X-Spam_report: (-0.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.819, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.903, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no 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 @bytedance.com) X-ZM-MESSAGEID: 1773920406617158500 Content-Type: text/plain; charset="utf-8" Refer to commit 9a85e4b8f672016adbf7b7d5beaab2a99b9b5615 to support for GHashTable migration. A custom save/restore is implemented. Each item is made of a key and a data. Currently, only pointer-type keys and values are supported. On the get() path, ghashtable must be allocated using the proper key compare, key destroy and value destroy. This must be handled beforehand, for example in a pre_load method. Signed-off-by: hongmianquan --- include/migration/vmstate.h | 22 ++++++ migration/trace-events | 5 ++ migration/vmstate-types.c | 147 ++++++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 89f9f49d20..cd7893c66a 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -265,6 +265,7 @@ extern const VMStateInfo vmstate_info_bitmap; extern const VMStateInfo vmstate_info_qtailq; extern const VMStateInfo vmstate_info_gtree; extern const VMStateInfo vmstate_info_qlist; +extern const VMStateInfo vmstate_info_ghash; =20 #define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0) /* @@ -882,6 +883,27 @@ extern const VMStateInfo vmstate_info_qlist; .start =3D offsetof(_type, _next), = \ } =20 +/* + * For migrating a GHashTable whose key is a pointer to _key_type and the + * value, a pointer to _val_type + * The target hashtable must have been properly initialized + * _vmsd: Start address of the 2 element array containing the data vmsd + * and the key vmsd, in that order + * _key_type: type of the key + * _val_type: type of the value + */ +#define VMSTATE_GHASH_V(_field, _state, _version, _vmsd, = \ + _key_type, _val_type) = \ +{ = \ + .name =3D (stringify(_field)), = \ + .version_id =3D (_version), = \ + .vmsd =3D (_vmsd), = \ + .info =3D &vmstate_info_ghash, = \ + .start =3D sizeof(_key_type), = \ + .size =3D sizeof(_val_type), = \ + .offset =3D offsetof(_state, _field), = \ +} + /* _f : field name _f_n : num of elements field_name _n : num of elements diff --git a/migration/trace-events b/migration/trace-events index 90629f828f..f00f4c3e74 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -86,6 +86,11 @@ get_qlist_end(const char *field_name, const char *vmsd_n= ame) "%s(%s)" put_qlist(const char *field_name, const char *vmsd_name, int version_id) "= %s(%s v%d)" put_qlist_end(const char *field_name, const char *vmsd_name) "%s(%s)" =20 +get_ghash(const char *field_name, const char *key_vmsd_name, const char *v= al_vmsd_name, uint32_t nnodes) "%s(%s/%s) nnodes=3D%d" +get_ghash_end(const char *field_name, const char *key_vmsd_name, const cha= r *val_vmsd_name, int ret) "%s(%s/%s) %d" +put_ghash(const char *field_name, const char *key_vmsd_name, const char *v= al_vmsd_name, uint32_t nnodes) "%s(%s/%s) nnodes=3D%d" +put_ghash_end(const char *field_name, const char *key_vmsd_name, const cha= r *val_vmsd_name, int ret) "%s(%s/%s) %d" + # qemu-file.c qemu_file_fclose(void) "" qemu_file_put_fd(const char *name, int fd, int ret) "ioc %s, fd %d -> stat= us %d" diff --git a/migration/vmstate-types.c b/migration/vmstate-types.c index 89cb211472..e6c3573789 100644 --- a/migration/vmstate-types.c +++ b/migration/vmstate-types.c @@ -942,3 +942,150 @@ const VMStateInfo vmstate_info_qlist =3D { .get =3D get_qlist, .put =3D put_qlist, }; + +struct put_ghash_data { + QEMUFile *f; + const VMStateDescription *key_vmsd; + const VMStateDescription *val_vmsd; + JSONWriter *vmdesc; + int ret; +}; + +static gboolean put_ghash_elem(gpointer key, gpointer value, gpointer data) +{ + struct put_ghash_data *capsule =3D (struct put_ghash_data *)data; + QEMUFile *f =3D capsule->f; + int ret; + Error *local_err =3D NULL; + + qemu_put_byte(f, true); + + /* put the key */ + ret =3D vmstate_save_state(f, capsule->key_vmsd, key, + capsule->vmdesc, &local_err); + if (ret) { + error_report_err(local_err); + capsule->ret =3D ret; + return false; + } + + /* put the data */ + ret =3D vmstate_save_state(f, capsule->val_vmsd, value, + capsule->vmdesc, &local_err); + if (ret) { + error_report_err(local_err); + capsule->ret =3D ret; + return false; + } + return true; +} + +static int put_ghash(QEMUFile *f, void *pv, size_t unused_size, + const VMStateField *field, JSONWriter *vmdesc) +{ + const VMStateDescription *key_vmsd =3D &field->vmsd[1]; + const VMStateDescription *val_vmsd =3D &field->vmsd[0]; + struct put_ghash_data capsule =3D { + .f =3D f, + .key_vmsd =3D key_vmsd, + .val_vmsd =3D val_vmsd, + .vmdesc =3D vmdesc, + .ret =3D 0}; + GHashTable **pval =3D pv; + GHashTable *hash =3D *pval; + GHashTableIter iter; + gpointer key, value; + uint32_t nnodes =3D g_hash_table_size(hash); + int ret; + + trace_put_ghash(field->name, key_vmsd->name, val_vmsd->name, nnodes); + qemu_put_be32(f, nnodes); + g_hash_table_iter_init(&iter, hash); + while (g_hash_table_iter_next(&iter, &key, &value)) { + if (!put_ghash_elem(key, value, (gpointer)&capsule)) { + break; + } + } + qemu_put_byte(f, false); + ret =3D capsule.ret; + if (ret) { + error_report("%s : failed to save ghash (%d)", field->name, ret); + } + trace_put_ghash_end(field->name, key_vmsd->name, val_vmsd->name, ret); + return ret; +} + +static int get_ghash(QEMUFile *f, void *pv, size_t unused_size, + const VMStateField *field) +{ + const VMStateDescription *key_vmsd =3D &field->vmsd[1]; + const VMStateDescription *val_vmsd =3D &field->vmsd[0]; + int version_id =3D field->version_id; + size_t key_size =3D field->start; + size_t val_size =3D field->size; + int nnodes, count =3D 0; + GHashTable **pval =3D pv; + GHashTable *hash =3D *pval; + void *key, *val; + int ret =3D 0; + Error *local_err =3D NULL; + + if (version_id > key_vmsd->version_id) { + error_report("%s %s", key_vmsd->name, "too new"); + return -EINVAL; + } + if (version_id < key_vmsd->minimum_version_id) { + error_report("%s %s", key_vmsd->name, "too old"); + return -EINVAL; + } + if (version_id > val_vmsd->version_id) { + error_report("%s %s", val_vmsd->name, "too new"); + return -EINVAL; + } + if (version_id < val_vmsd->minimum_version_id) { + error_report("%s %s", val_vmsd->name, "too old"); + return -EINVAL; + } + + nnodes =3D qemu_get_be32(f); + trace_get_ghash(field->name, key_vmsd->name, val_vmsd->name, nnodes); + + while (qemu_get_byte(f)) { + if ((++count) > nnodes) { + ret =3D -EINVAL; + break; + } + key =3D g_malloc0(key_size); + ret =3D vmstate_load_state(f, key_vmsd, key, version_id, &local_er= r); + if (ret) { + error_report_err(local_err); + goto key_error; + } + val =3D g_malloc0(val_size); + ret =3D vmstate_load_state(f, val_vmsd, val, version_id, &local_er= r); + if (ret) { + error_report_err(local_err); + goto val_error; + } + g_hash_table_insert(hash, key, val); + } + if (count !=3D nnodes) { + error_report("%s inconsistent stream when loading the ghash", + field->name); + return -EINVAL; + } + trace_get_ghash_end(field->name, key_vmsd->name, val_vmsd->name, ret); + return ret; +val_error: + g_free(val); +key_error: + g_free(key); + trace_get_ghash_end(field->name, key_vmsd->name, val_vmsd->name, ret); + return ret; +} + +const VMStateInfo vmstate_info_ghash =3D { + .name =3D "ghash", + .get =3D get_ghash, + .put =3D put_ghash, +}; --=20 2.32.1 (Apple Git-133) From nobody Sun Mar 22 14:12:45 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=bytedance.com ARC-Seal: i=1; a=rsa-sha256; t=1773920399; cv=none; d=zohomail.com; s=zohoarc; b=nDihe80K2pigmKKVPuey1lir69uhqhQ7wLZD2X8bnAweur7Hhnvt9uQ25Vhgd7dk1lvAMd7DgIXODWFRA9Lrc18H63r6uB+9XT/zsZEYWNeCiVpDSN9JJoRNk+ZE7onFAHuB19Yt+n/QFJrlw4GAEWw5j2+73bMZo6rBqlEbeoo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1773920399; 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=TveFI/sDZqiQ3mrpO0u1dXilS/98mgQUpWeqgtqotqQ=; b=WfvRY5htJYvqI6O42LYTnRp6yHI1u4qvGsyhDgFGUxF8a9LOfTwqKL7j3I4KCFkg+oGbfDA7jBwQ41zlgEIFLVY1y0twi8/0/iJuYFcfcP0VimkHpGfY2vbiLT5yda3h2DomyrUS/MWzWCl5coTSJ8NhYUUC+cwIwfHVCvayaQc= 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 1773920399225611.6686287156842; Thu, 19 Mar 2026 04:39:59 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1w3Bif-0007K6-7h; Thu, 19 Mar 2026 07:39:17 -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 1w3Bib-0007Js-RO for qemu-devel@nongnu.org; Thu, 19 Mar 2026 07:39:14 -0400 Received: from va-1-112.ptr.blmpb.com ([209.127.230.112]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1w3Bia-0004cR-2d for qemu-devel@nongnu.org; Thu, 19 Mar 2026 07:39:13 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=2212171451; d=bytedance.com; t=1773920346; h=from:subject: mime-version:from:date:message-id:subject:to:cc:reply-to:content-type: mime-version:in-reply-to:message-id; bh=TveFI/sDZqiQ3mrpO0u1dXilS/98mgQUpWeqgtqotqQ=; b=ENXfe4z0cQx7yKjeFM2ayRbgBztO75YaAJzRVZiUfHZq52JeXuunVfrkoCG6cYC4GAwGIH nufwaOwV3z51LCFshFqkYqmHNeuHTd6SJcgOWui0aRICew23+HhMkC+fl6o996zuF5nxhZ y8fwRIX7kAmjJ32EWMWX/oFlVfsk8u0L3ZU/afUvVgMee94FNbmCejxl6HZuT/EHbsWVY4 XPRk5SyTMMzer2dlRiiFW8MDtFdyX8n4PRgq6equUXL3iYtxJLtPcN6rlcYkrwBItg5xg2 qc0qSXXC/zQ4IJp+wO6wi6hVSJ4403VzKdoNxoex9TMApjanJoc9KTaMW3bngw== Cc: , , , , "hongmianquan" From: "hongmianquan" Subject: [RFC v2 2/2] cpr: use hashtable for cpr fds Mime-Version: 1.0 In-Reply-To: <20260319113830.53867-1-hongmianquan@bytedance.com> To: References: <20260319113830.53867-1-hongmianquan@bytedance.com> X-Mailer: git-send-email 2.32.1 (Apple Git-133) Date: Thu, 19 Mar 2026 19:38:30 +0800 Message-Id: <20260319113830.53867-3-hongmianquan@bytedance.com> X-Lms-Return-Path: X-Original-From: hongmianquan 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=lists.gnu.org; Received-SPF: pass client-ip=209.127.230.112; envelope-from=hongmianquan@bytedance.com; helo=va-1-112.ptr.blmpb.com X-Spam_score_int: -3 X-Spam_score: -0.4 X-Spam_bar: / X-Spam_report: (-0.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.819, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.903, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no 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 @bytedance.com) X-ZM-MESSAGEID: 1773920403568154100 Content-Type: text/plain; charset="utf-8" Use a hashtable to store cpr fds to reduce the time consumption of `cpr_find_fd` in scenarios with a large number of fds, which relies on the migration support for GHashTable implemented earlier. The time complexity for `cpr_find_fd` is reduced from O(N) to O(1). To demonstrate the performance improvement, we tested the total time consumed by `cpr_find_fd` (called N times for N fds) under our real-world business scenarios with different numbers of file descriptors. The results are measured in nanoseconds: | Number of FDs | Total time with QLIST (ns) | Total time with GHashTable (= ns) | |---------------|----------------------------|-----------------------------= ----| | 540 | 936,753 | 393,358 = | | 2,870 | 24,102,342 | 2,212,113 = | | 7,530 | 152,715,916 | 5,474,310 = | As shown in the data, the lookup time grows exponentially with the QLIST as the number of fds increases. With the GHashTable, the time consumption remains linear (O(1) per lookup), significantly reducing the downtime during the CPR process. Signed-off-by: hongmianquan --- include/migration/cpr.h | 4 +- migration/cpr.c | 129 ++++++++++++++++++++++++++++------------ system/vl.c | 2 + 3 files changed, 95 insertions(+), 40 deletions(-) diff --git a/include/migration/cpr.h b/include/migration/cpr.h index 5850fd1788..858b251bb5 100644 --- a/include/migration/cpr.h +++ b/include/migration/cpr.h @@ -18,16 +18,16 @@ #define QEMU_CPR_FILE_VERSION 0x00000001 #define CPR_STATE "CprState" =20 -typedef QLIST_HEAD(CprFdList, CprFd) CprFdList; typedef QLIST_HEAD(CprVFIODeviceList, CprVFIODevice) CprVFIODeviceList; =20 typedef struct CprState { - CprFdList fds; + GHashTable *fds; CprVFIODeviceList vfio_devices; } CprState; =20 extern CprState cpr_state; =20 +void cpr_state_init(void); void cpr_save_fd(const char *name, int id, int fd); void cpr_delete_fd(const char *name, int id); int cpr_find_fd(const char *name, int id); diff --git a/migration/cpr.c b/migration/cpr.c index a0b37007f5..cfdddb5043 100644 --- a/migration/cpr.c +++ b/migration/cpr.c @@ -27,59 +27,101 @@ CprState cpr_state; =20 /*************************************************************************= ***/ =20 -typedef struct CprFd { +typedef struct CprFdKey { char *name; unsigned int namelen; int id; +} CprFdKey; + +typedef struct CprFdVal { int fd; - QLIST_ENTRY(CprFd) next; -} CprFd; +} CprFdVal; + +#define VMSTATE_FDS_KEY \ +{ \ + .name =3D "cpr-fd-key", \ + .version_id =3D 1, \ + .minimum_version_id =3D 1, \ + .fields =3D (const VMStateField[]) { \ + VMSTATE_UINT32(namelen, CprFdKey), \ + VMSTATE_VBUFFER_ALLOC_UINT32(name, CprFdKey, 0, NULL, namelen), \ + VMSTATE_INT32(id, CprFdKey), \ + VMSTATE_END_OF_LIST() \ + } \ +} =20 -static const VMStateDescription vmstate_cpr_fd =3D { - .name =3D "cpr fd", - .version_id =3D 1, - .minimum_version_id =3D 1, - .fields =3D (VMStateField[]) { - VMSTATE_UINT32(namelen, CprFd), - VMSTATE_VBUFFER_ALLOC_UINT32(name, CprFd, 0, NULL, namelen), - VMSTATE_INT32(id, CprFd), - VMSTATE_FD(fd, CprFd), - VMSTATE_END_OF_LIST() - } +#define VMSTATE_FDS_VAL \ +{ \ + .name =3D "cpr-fd-value", \ + .version_id =3D 1, \ + .minimum_version_id =3D 1, \ + .fields =3D (const VMStateField[]) { \ + VMSTATE_FD(fd, CprFdVal), \ + VMSTATE_END_OF_LIST() \ + } \ +} + +static const VMStateDescription vmstate_fds_hashtable[2] =3D { + VMSTATE_FDS_VAL, /* value */ + VMSTATE_FDS_KEY /* key */ }; =20 +static guint cpr_fd_key_hash(gconstpointer v) +{ + const CprFdKey *key =3D v; + return g_str_hash(key->name) ^ key->id; +} + +static gboolean cpr_fd_key_equal(gconstpointer a, gconstpointer b) +{ + const CprFdKey *key_a =3D a; + const CprFdKey *key_b =3D b; + return !strcmp(key_a->name, key_b->name) && key_a->id =3D=3D key_b->id; +} + +static void cpr_destroy_fd_key(gpointer data) +{ + CprFdKey *k =3D (CprFdKey *) data; + g_free(k->name); + g_free(k); +} + +void cpr_state_init(void) +{ + CprState *s =3D &cpr_state; + + s->fds =3D g_hash_table_new_full(cpr_fd_key_hash, cpr_fd_key_equal, + cpr_destroy_fd_key, g_free); +} + void cpr_save_fd(const char *name, int id, int fd) { - CprFd *elem =3D g_new0(CprFd, 1); + CprFdKey *key =3D g_new0(CprFdKey, 1); + CprFdVal *val =3D g_new0(CprFdVal, 1); =20 trace_cpr_save_fd(name, id, fd); - elem->name =3D g_strdup(name); - elem->namelen =3D strlen(name) + 1; - elem->id =3D id; - elem->fd =3D fd; - QLIST_INSERT_HEAD(&cpr_state.fds, elem, next); + key->name =3D g_strdup(name); + key->namelen =3D strlen(name) + 1; + key->id =3D id; + val->fd =3D fd; + g_hash_table_insert(cpr_state.fds, key, val); } =20 -static CprFd *find_fd(CprFdList *head, const char *name, int id) +static CprFdVal *find_fd(CprFdKey *key) { - CprFd *elem; - - QLIST_FOREACH(elem, head, next) { - if (!strcmp(elem->name, name) && elem->id =3D=3D id) { - return elem; - } - } - return NULL; + return g_hash_table_lookup(cpr_state.fds, key); } =20 void cpr_delete_fd(const char *name, int id) { - CprFd *elem =3D find_fd(&cpr_state.fds, name, id); + CprFdKey key =3D { + .name =3D (char *)name, + .id =3D id, + }; + CprFdVal *elem =3D find_fd(&key); =20 if (elem) { - QLIST_REMOVE(elem, next); - g_free(elem->name); - g_free(elem); + g_hash_table_remove(cpr_state.fds, &key); } =20 trace_cpr_delete_fd(name, id); @@ -87,7 +129,11 @@ void cpr_delete_fd(const char *name, int id) =20 int cpr_find_fd(const char *name, int id) { - CprFd *elem =3D find_fd(&cpr_state.fds, name, id); + CprFdKey key =3D { + .name =3D (char *)name, + .id =3D id, + }; + CprFdVal *elem =3D find_fd(&key); int fd =3D elem ? elem->fd : -1; =20 trace_cpr_find_fd(name, id, fd); @@ -96,7 +142,11 @@ int cpr_find_fd(const char *name, int id) =20 void cpr_resave_fd(const char *name, int id, int fd) { - CprFd *elem =3D find_fd(&cpr_state.fds, name, id); + CprFdKey key =3D { + .name =3D (char *)name, + .id =3D id, + }; + CprFdVal *elem =3D find_fd(&key); int old_fd =3D elem ? elem->fd : -1; =20 if (old_fd < 0) { @@ -125,9 +175,11 @@ int cpr_open_fd(const char *path, int flags, const cha= r *name, int id, =20 bool cpr_walk_fd(cpr_walk_fd_cb cb) { - CprFd *elem; + GHashTableIter iter; + CprFdVal *elem; =20 - QLIST_FOREACH(elem, &cpr_state.fds, next) { + g_hash_table_iter_init(&iter, cpr_state.fds); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&elem)) { g_assert(elem->fd >=3D 0); if (!cb(elem->fd)) { return false; @@ -142,7 +194,8 @@ static const VMStateDescription vmstate_cpr_state =3D { .version_id =3D 1, .minimum_version_id =3D 1, .fields =3D (VMStateField[]) { - VMSTATE_QLIST_V(fds, CprState, 1, vmstate_cpr_fd, CprFd, next), + VMSTATE_GHASH_V(fds, CprState, 1, vmstate_fds_hashtable, + CprFdKey, CprFdVal), VMSTATE_END_OF_LIST() }, .subsections =3D (const VMStateDescription * const []) { diff --git a/system/vl.c b/system/vl.c index 3e341142a0..da42de87db 100644 --- a/system/vl.c +++ b/system/vl.c @@ -2894,6 +2894,8 @@ void qemu_init(int argc, char **argv) =20 qemu_init_subsystems(); =20 + cpr_state_init(); + /* first pass of option parsing */ optind =3D 1; while (optind < argc) { --=20 2.32.1 (Apple Git-133)