From nobody Tue Feb 10 23:13:20 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; 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=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1602449248; cv=none; d=zohomail.com; s=zohoarc; b=V87r1Kz/9FJiLWnavoG6G53vBzTcSaSnE3LTINr8SNsZAoJtIMknJDvAlX3p+xvYmlyl5U920yHseadS+pc1/RBvJyP/IHTvKZQkpJqSsBXNg9J32ZmDsR6fw8q07C90TT/Q48xMCiiMZsi6PSyUwyQY0jdFgmXruQRSUMI49BM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1602449248; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=tBSHczW2Lzk3cLtx36KBC74qLkYR3CoBuZtx44+ZG+w=; b=BLTyg2QK641MyTZtpItXapbkMYl04JfQjw4javbBOl0PgDcfX2AKuiKdlG+GGyFUeaxhXe/pMcpTMC+JwAM9XqMvmwvK7VFGuIi38yeYl0NkzToH6xOnT+zVKY0/YsZYK6REgFO6UMRpwzchSWylhVfaDiBtZLI/9SLH8E4I2oc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; 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=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 160244924842293.96399455643962; Sun, 11 Oct 2020 13:47:28 -0700 (PDT) Received: from localhost ([::1]:54738 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kRiFa-0007E5-1U for importer@patchew.org; Sun, 11 Oct 2020 16:47:26 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:57866) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kRi67-0002TA-9S for qemu-devel@nongnu.org; Sun, 11 Oct 2020 16:37:39 -0400 Received: from us-smtp-delivery-124.mimecast.com ([63.128.21.124]:36044) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.90_1) (envelope-from ) id 1kRi64-0005b7-W3 for qemu-devel@nongnu.org; Sun, 11 Oct 2020 16:37:38 -0400 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-316-gFLx1wC3M2CNkhiBFWngew-1; Sun, 11 Oct 2020 16:37:33 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id D847A185A0DD for ; Sun, 11 Oct 2020 20:37:32 +0000 (UTC) Received: from localhost (unknown [10.36.110.19]) by smtp.corp.redhat.com (Postfix) with ESMTP id 98FCD100239A; Sun, 11 Oct 2020 20:37:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1602448656; 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=tBSHczW2Lzk3cLtx36KBC74qLkYR3CoBuZtx44+ZG+w=; b=O5vB2qgoN/MEZLtnbrHFo0OT0/Qt/bwJ2JEtyy2Zuav4/kudXfs5kZWzAGGZfiHcE05NIR 08QianhJD3s7Qd12MopFyNswhiqsGDdhBLErTm+/nnHSmXMGVpz1EtReXb9Fkw3GNVTvpf kn54fuLJS6Kyel/0nD+GuUDVXaEYk7c= X-MC-Unique: gFLx1wC3M2CNkhiBFWngew-1 From: marcandre.lureau@redhat.com To: qemu-devel@nongnu.org Subject: [PoCv2 13/15] qga: implement {get,set}-vcpus in Rust Date: Mon, 12 Oct 2020 00:35:11 +0400 Message-Id: <20201011203513.1621355-14-marcandre.lureau@redhat.com> In-Reply-To: <20201011203513.1621355-1-marcandre.lureau@redhat.com> References: <20201011203513.1621355-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=marcandre.lureau@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com 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=lists.gnu.org; Received-SPF: pass client-ip=63.128.21.124; envelope-from=marcandre.lureau@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/11 16:23:51 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.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, PDS_OTHER_BAD_TLD=1.999, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=-1, RCVD_IN_MSPIKE_WL=-0.01, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: pbonzini@redhat.com, berrange@redhat.com, armbru@redhat.com, stefanha@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) From: Marc-Andr=C3=A9 Lureau This is a rewrite of the C version (using the nix & winapi crates). The main difference is that Rust doesn't let you mix const/mut logic, the way transfer_vcpu in C does. The Rust version does introduce some duplication, but is also more strict and can prevent mistakes. Signed-off-by: Marc-Andr=C3=A9 Lureau --- qga/Cargo.toml | 6 ++ qga/commands-posix.c | 159 ------------------------------------------ qga/commands-win32.c | 76 -------------------- qga/commands.c | 14 ++++ qga/qmp/mod.rs | 18 +++++ qga/qmp/vcpus.rs | 161 +++++++++++++++++++++++++++++++++++++++++++ tests/test-qga.c | 2 + 7 files changed, 201 insertions(+), 235 deletions(-) create mode 100644 qga/qmp/vcpus.rs diff --git a/qga/Cargo.toml b/qga/Cargo.toml index 63a419255d..bb86fc543d 100644 --- a/qga/Cargo.toml +++ b/qga/Cargo.toml @@ -9,6 +9,12 @@ common =3D { path =3D "../rust/common" } libc =3D "^0.2.76" hostname =3D "^0.3.1" =20 +[target."cfg(unix)".dependencies] +nix =3D "^0.18.0" + +[target."cfg(windows)".dependencies] +winapi =3D { version =3D "^0.3.9", features =3D ["sysinfoapi", "winnt"] } + [lib] path =3D "lib.rs" crate-type =3D ["staticlib"] diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 3bffee99d4..2c2c97fbca 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -2092,165 +2092,6 @@ error: return NULL; } =20 -#define SYSCONF_EXACT(name, errp) sysconf_exact((name), #name, (errp)) - -static long sysconf_exact(int name, const char *name_str, Error **errp) -{ - long ret; - - errno =3D 0; - ret =3D sysconf(name); - if (ret =3D=3D -1) { - if (errno =3D=3D 0) { - error_setg(errp, "sysconf(%s): value indefinite", name_str); - } else { - error_setg_errno(errp, errno, "sysconf(%s)", name_str); - } - } - return ret; -} - -/* Transfer online/offline status between @vcpu and the guest system. - * - * On input either @errp or *@errp must be NULL. - * - * In system-to-@vcpu direction, the following @vcpu fields are accessed: - * - R: vcpu->logical_id - * - W: vcpu->online - * - W: vcpu->can_offline - * - * In @vcpu-to-system direction, the following @vcpu fields are accessed: - * - R: vcpu->logical_id - * - R: vcpu->online - * - * Written members remain unmodified on error. - */ -static void transfer_vcpu(GuestLogicalProcessor *vcpu, bool sys2vcpu, - char *dirpath, Error **errp) -{ - int fd; - int res; - int dirfd; - static const char fn[] =3D "online"; - - dirfd =3D open(dirpath, O_RDONLY | O_DIRECTORY); - if (dirfd =3D=3D -1) { - error_setg_errno(errp, errno, "open(\"%s\")", dirpath); - return; - } - - fd =3D openat(dirfd, fn, sys2vcpu ? O_RDONLY : O_RDWR); - if (fd =3D=3D -1) { - if (errno !=3D ENOENT) { - error_setg_errno(errp, errno, "open(\"%s/%s\")", dirpath, fn); - } else if (sys2vcpu) { - vcpu->online =3D true; - vcpu->can_offline =3D false; - } else if (!vcpu->online) { - error_setg(errp, "logical processor #%" PRId64 " can't be " - "offlined", vcpu->logical_id); - } /* otherwise pretend successful re-onlining */ - } else { - unsigned char status; - - res =3D pread(fd, &status, 1, 0); - if (res =3D=3D -1) { - error_setg_errno(errp, errno, "pread(\"%s/%s\")", dirpath, fn); - } else if (res =3D=3D 0) { - error_setg(errp, "pread(\"%s/%s\"): unexpected EOF", dirpath, - fn); - } else if (sys2vcpu) { - vcpu->online =3D (status !=3D '0'); - vcpu->can_offline =3D true; - } else if (vcpu->online !=3D (status !=3D '0')) { - status =3D '0' + vcpu->online; - if (pwrite(fd, &status, 1, 0) =3D=3D -1) { - error_setg_errno(errp, errno, "pwrite(\"%s/%s\")", dirpath, - fn); - } - } /* otherwise pretend successful re-(on|off)-lining */ - - res =3D close(fd); - g_assert(res =3D=3D 0); - } - - res =3D close(dirfd); - g_assert(res =3D=3D 0); -} - -GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp) -{ - int64_t current; - GuestLogicalProcessorList *head, **link; - long sc_max; - Error *local_err =3D NULL; - - current =3D 0; - head =3D NULL; - link =3D &head; - sc_max =3D SYSCONF_EXACT(_SC_NPROCESSORS_CONF, &local_err); - - while (local_err =3D=3D NULL && current < sc_max) { - GuestLogicalProcessor *vcpu; - GuestLogicalProcessorList *entry; - int64_t id =3D current++; - char *path =3D g_strdup_printf("/sys/devices/system/cpu/cpu%" PRId= 64 "/", - id); - - if (g_file_test(path, G_FILE_TEST_EXISTS)) { - vcpu =3D g_malloc0(sizeof *vcpu); - vcpu->logical_id =3D id; - vcpu->has_can_offline =3D true; /* lolspeak ftw */ - transfer_vcpu(vcpu, true, path, &local_err); - entry =3D g_malloc0(sizeof *entry); - entry->value =3D vcpu; - *link =3D entry; - link =3D &entry->next; - } - g_free(path); - } - - if (local_err =3D=3D NULL) { - /* there's no guest with zero VCPUs */ - g_assert(head !=3D NULL); - return head; - } - - qapi_free_GuestLogicalProcessorList(head); - error_propagate(errp, local_err); - return NULL; -} - -int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp) -{ - int64_t processed; - Error *local_err =3D NULL; - - processed =3D 0; - while (vcpus !=3D NULL) { - char *path =3D g_strdup_printf("/sys/devices/system/cpu/cpu%" PRId= 64 "/", - vcpus->value->logical_id); - - transfer_vcpu(vcpus->value, false, path, &local_err); - g_free(path); - if (local_err !=3D NULL) { - break; - } - ++processed; - vcpus =3D vcpus->next; - } - - if (local_err !=3D NULL) { - if (processed =3D=3D 0) { - error_propagate(errp, local_err); - } else { - error_free(local_err); - } - } - - return processed; -} - void qmp_guest_set_user_password(const char *username, const char *password, bool crypted, diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 0c3c05484f..1e140b68a6 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -1740,82 +1740,6 @@ void qmp_guest_set_time(bool has_time, int64_t time_= ns, Error **errp) } } =20 -GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp) -{ - PSYSTEM_LOGICAL_PROCESSOR_INFORMATION pslpi, ptr; - DWORD length; - GuestLogicalProcessorList *head, **link; - Error *local_err =3D NULL; - int64_t current; - - ptr =3D pslpi =3D NULL; - length =3D 0; - current =3D 0; - head =3D NULL; - link =3D &head; - - if ((GetLogicalProcessorInformation(pslpi, &length) =3D=3D FALSE) && - (GetLastError() =3D=3D ERROR_INSUFFICIENT_BUFFER) && - (length > sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION))) { - ptr =3D pslpi =3D g_malloc0(length); - if (GetLogicalProcessorInformation(pslpi, &length) =3D=3D FALSE) { - error_setg(&local_err, "Failed to get processor information: %= d", - (int)GetLastError()); - } - } else { - error_setg(&local_err, - "Failed to get processor information buffer length: %d", - (int)GetLastError()); - } - - while ((local_err =3D=3D NULL) && (length > 0)) { - if (pslpi->Relationship =3D=3D RelationProcessorCore) { - ULONG_PTR cpu_bits =3D pslpi->ProcessorMask; - - while (cpu_bits > 0) { - if (!!(cpu_bits & 1)) { - GuestLogicalProcessor *vcpu; - GuestLogicalProcessorList *entry; - - vcpu =3D g_malloc0(sizeof *vcpu); - vcpu->logical_id =3D current++; - vcpu->online =3D true; - vcpu->has_can_offline =3D true; - - entry =3D g_malloc0(sizeof *entry); - entry->value =3D vcpu; - - *link =3D entry; - link =3D &entry->next; - } - cpu_bits >>=3D 1; - } - } - length -=3D sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); - pslpi++; /* next entry */ - } - - g_free(ptr); - - if (local_err =3D=3D NULL) { - if (head !=3D NULL) { - return head; - } - /* there's no guest with zero VCPUs */ - error_setg(&local_err, "Guest reported zero VCPUs"); - } - - qapi_free_GuestLogicalProcessorList(head); - error_propagate(errp, local_err); - return NULL; -} - -int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp) -{ - error_setg(errp, QERR_UNSUPPORTED); - return -1; -} - static gchar * get_net_error_message(gint error) { diff --git a/qga/commands.c b/qga/commands.c index 15478a16e7..a5f8e32ece 100644 --- a/qga/commands.c +++ b/qga/commands.c @@ -577,3 +577,17 @@ GuestFileRead *qmp_guest_file_read(int64_t handle, boo= l has_count, =20 return read_data; } + +#ifndef CONFIG_WITH_RUST +GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp) +{ + error_setg(errp, QERR_UNSUPPORTED); + return NULL; +} + +int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp) +{ + error_setg(errp, QERR_UNSUPPORTED); + return 0; +} +#endif diff --git a/qga/qmp/mod.rs b/qga/qmp/mod.rs index e855aa4bd7..7c4d30c7de 100644 --- a/qga/qmp/mod.rs +++ b/qga/qmp/mod.rs @@ -41,3 +41,21 @@ mod hostname; extern "C" fn qmp_guest_get_host_name(errp: *mut *mut sys::Error) -> *mut = qapi_sys::GuestHostName { qmp!(hostname::get(), errp) } + +mod vcpus; + +#[no_mangle] +extern "C" fn qmp_guest_get_vcpus( + errp: *mut *mut sys::Error, +) -> *mut qapi_sys::GuestLogicalProcessorList { + qmp!(vcpus::get(), errp) +} + +#[no_mangle] +extern "C" fn qmp_guest_set_vcpus( + vcpus: *const qapi_sys::GuestLogicalProcessorList, + errp: *mut *mut sys::Error, +) -> libc::c_longlong { + let vcpus =3D unsafe { from_qemu_none(qapi::NewPtr(vcpus)) }; + qmp!(vcpus::set(vcpus), errp, -1) +} diff --git a/qga/qmp/vcpus.rs b/qga/qmp/vcpus.rs new file mode 100644 index 0000000000..f86838355e --- /dev/null +++ b/qga/qmp/vcpus.rs @@ -0,0 +1,161 @@ +#[cfg(unix)] +use std::fs::OpenOptions; +#[cfg(unix)] +use std::io::ErrorKind; +#[cfg(unix)] +use std::os::unix::fs::FileExt; + +#[cfg(windows)] +use winapi::um::{sysinfoapi, winnt}; + +use crate::*; + +#[cfg(target_os =3D "linux")] +fn get_sysfs_cpu_path(id: i64) -> String { + format!("/sys/devices/system/cpu/cpu{}", id) +} + +#[cfg(target_os =3D "linux")] +fn set_vcpu(vcpu: &qapi::GuestLogicalProcessor) -> Result<()> { + let path =3D get_sysfs_cpu_path(vcpu.logical_id); + std::fs::metadata(&path)?; + + let path =3D format!("{}/online", path); + match OpenOptions::new().read(true).write(true).open(&path) { + Ok(file) =3D> { + let mut buf =3D [0u8; 1]; + file.read_exact_at(&mut buf, 0)?; + let online =3D buf[0] !=3D 0; + if vcpu.online !=3D online { + buf[0] =3D if vcpu.online { b'1' } else { b'0' }; + file.write_all_at(&buf, 0)?; + } + } + Err(e) =3D> { + if e.kind() !=3D ErrorKind::NotFound { + return Err(e.into()); + } else if !vcpu.online { + return err!(format!( + "logical processor #{} can't be offlined", + vcpu.logical_id + )); + } + } + } + + Ok(()) +} + +#[cfg(not(target_os =3D "linux"))] +fn set_vcpu(_vcpu: &qapi::GuestLogicalProcessor) -> Result<()> { + err!("unimplemented") +} + +pub(crate) fn set(vcpus: Vec) -> Result { + let mut processed =3D 0; + + for vcpu in &vcpus { + if let Err(e) =3D set_vcpu(vcpu) { + if processed !=3D 0 { + break; + } + return Err(e); + } + + processed +=3D 1; + } + + Ok(processed) +} + +#[cfg(target_os =3D "linux")] +pub(crate) fn get() -> Result> { + use nix::unistd::sysconf; + + let mut vcpus =3D vec![]; + let nproc_conf =3D match sysconf(unsafe { std::mem::transmute(libc::_S= C_NPROCESSORS_CONF) })? { + Some(nproc) =3D> nproc, + None =3D> { + return err!("Indefinite number of processors."); + } + }; + + for logical_id in 0..nproc_conf { + let path =3D get_sysfs_cpu_path(logical_id); + if std::fs::metadata(&path).is_err() { + continue; + } + + let path =3D format!("{}/online", path); + let (online, can_offline) =3D match OpenOptions::new().read(true).= open(&path) { + Ok(file) =3D> { + let mut buf =3D [0u8; 1]; + file.read_exact_at(&mut buf, 0)?; + (buf[0] !=3D 0, Some(true)) + } + Err(e) =3D> { + if e.kind() !=3D ErrorKind::NotFound { + return Err(e.into()); + } + (true, Some(false)) + } + }; + + vcpus.push(qapi::GuestLogicalProcessor { + logical_id, + online, + can_offline, + }); + } + + Ok(vcpus) +} + +#[cfg(target_os =3D "windows")] +fn get_logical_processor_info() -> Result> { + unsafe { + let mut needed_size =3D 0; + sysinfoapi::GetLogicalProcessorInformation(std::ptr::null_mut(), &= mut needed_size); + let struct_size =3D std::mem::size_of::() as u32; + if needed_size =3D=3D 0 || needed_size < struct_size || needed_siz= e % struct_size !=3D 0 { + return err!("Failed to get processor information"); + } + + let nstruct =3D needed_size / struct_size; + let mut buf =3D Vec::with_capacity(nstruct as usize); + let result =3D sysinfoapi::GetLogicalProcessorInformation(buf.as_m= ut_ptr(), &mut needed_size); + if result =3D=3D 0 { + return err!("Failed to get processor information"); + } + + let nstruct =3D needed_size / struct_size; + buf.set_len(nstruct as usize); + Ok(buf) + } +} + +#[cfg(target_os =3D "windows")] +pub(crate) fn get() -> Result> { + let mut vcpus =3D vec![]; + + get_logical_processor_info()?.iter().map(|info| { + for _ in 0..info.ProcessorMask.count_ones() { + vcpus.push(qapi::GuestLogicalProcessor { + logical_id: vcpus.len() as i64, + online: true, + can_offline: Some(false), + }); + } + }); + + if vcpus.is_empty() { + return err!("Guest reported zero VCPUs"); + } + + Ok(vcpus) +} + +#[cfg(not(any(target_os =3D "linux", target_os =3D "windows")))] +pub(crate) fn get() -> Result> { + err!("unimplemented") +} diff --git a/tests/test-qga.c b/tests/test-qga.c index 6190e93e0e..ff1807531c 100644 --- a/tests/test-qga.c +++ b/tests/test-qga.c @@ -307,6 +307,7 @@ static void test_qga_info(gconstpointer fix) =20 static void test_qga_get_vcpus(gconstpointer fix) { +#ifdef CONFIG_WITH_RUST const TestFixture *fixture =3D fix; QDict *ret; QList *list; @@ -323,6 +324,7 @@ static void test_qga_get_vcpus(gconstpointer fix) g_assert(qdict_haskey(qobject_to(QDict, entry->value), "logical-id")); =20 qobject_unref(ret); +#endif } =20 static void test_qga_get_fsinfo(gconstpointer fix) --=20 2.28.0