From nobody Wed Jan 8 20:00:08 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1734434235577279.5951670871236; Tue, 17 Dec 2024 03:17:15 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 996) id 7235315B5; Tue, 17 Dec 2024 06:17:14 -0500 (EST) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id 5BC6615EB; Tue, 17 Dec 2024 06:15:34 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 996) id E63F01559; Tue, 17 Dec 2024 06:15:29 -0500 (EST) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id A80DF15D8 for ; Tue, 17 Dec 2024 06:15:18 -0500 (EST) Received: from mx-prod-mc-01.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-454-kKyqhYCPNEeokzAPY_6uvQ-1; Tue, 17 Dec 2024 06:15:14 -0500 Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.40]) (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-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id DB77A1955F41 for ; Tue, 17 Dec 2024 11:15:13 +0000 (UTC) Received: from toolbox.redhat.com (unknown [10.42.28.136]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id B728019560AD; Tue, 17 Dec 2024 11:15:12 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-1.7 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=3.4.4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1734434118; 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=k4aQ0xan46bIko1X9TNEqsCkXTIrxvvChDBdGFkYgHo=; b=bMsHu97KGAvDGqdHJFFn/0Wwki9YpyYdNXKkoEbs8nvsOLltil8Gp97bAiznFkPxR63nAE c4hmMZtQQTSUIWNn3usDsqIIrWHnRp6ZxOTXiIR+YhXajBCNlQrY/lLGqzUlxfQ+sVR3eq 71reQT+sRNz3GxZGYjAxX9Ysc2S53D4= X-MC-Unique: kKyqhYCPNEeokzAPY_6uvQ-1 X-Mimecast-MFC-AGG-ID: kKyqhYCPNEeokzAPY_6uvQ From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: devel@lists.libvirt.org Cc: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Subject: [PATCH 1/3] util: introduce object for holding a system inhibitor lock Date: Tue, 17 Dec 2024 11:15:07 +0000 Message-ID: <20241217111509.3779007-2-berrange@redhat.com> In-Reply-To: <20241217111509.3779007-1-berrange@redhat.com> References: <20241217111509.3779007-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.40 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: QsS8oBAfvYWo1br-ZGfmMQyL7Duku6EnYdxssbH07xA_1734434114 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: TKJUBTS2UTB4BLQI53GHSFJYOY7MS3FM X-Message-ID-Hash: TKJUBTS2UTB4BLQI53GHSFJYOY7MS3FM X-MailFrom: berrange@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1734434236800116600 Content-Type: text/plain; charset="utf-8" The system inhibitor locks are currently handled by code in the virNetDaemon class. The driver code invokes a callback provided by the daemon when it wants to start or end inhibition. When the first inhibition is started, the daemon will call out to logind to apply it system wide. This has many flaws * A single message is registered with logind regardless of what driver holds the inhibition * An inhibition of daemon shutdown can't be acquired without also inhibiting system shutdown * Config of the inhibitions cannot be tailored by the driver The new virInhibitor object addresses these: * The object directly manages an inhibition with logind privately to the driver, enabling custom messages to be set. * It is possible to acquire an inhibition locally to the daemon without forwarding it to logind. Signed-off-by: Daniel P. Berrang=C3=A9 --- po/POTFILES | 1 + src/libvirt_private.syms | 7 ++ src/util/meson.build | 1 + src/util/virinhibitor.c | 214 +++++++++++++++++++++++++++++++++++++++ src/util/virinhibitor.h | 58 +++++++++++ 5 files changed, 281 insertions(+) create mode 100644 src/util/virinhibitor.c create mode 100644 src/util/virinhibitor.h diff --git a/po/POTFILES b/po/POTFILES index 3514aa3dca..c71e439fe3 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -293,6 +293,7 @@ src/util/virhostcpu.c src/util/virhostmem.c src/util/virhostuptime.c src/util/viridentity.c +src/util/virinhibitor.c src/util/virinitctl.c src/util/viriscsi.c src/util/virjson.c diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c931003fad..adc3e3064f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2608,6 +2608,13 @@ virIdentitySetUserName; virIdentitySetX509DName; =20 =20 +# util/virinhibitor.h +virInhibitorFree; +virInhibitorHold; +virInhibitorNew; +virInhibitorRelease; + + # util/virinitctl.h virInitctlFifos; virInitctlSetRunLevel; diff --git a/src/util/meson.build b/src/util/meson.build index 30f71b0227..69ef49139a 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -45,6 +45,7 @@ util_sources =3D [ 'virhostmem.c', 'virhostuptime.c', 'viridentity.c', + 'virinhibitor.c', 'virinitctl.c', 'viriscsi.c', 'virjson.c', diff --git a/src/util/virinhibitor.c b/src/util/virinhibitor.c new file mode 100644 index 0000000000..647bdc9fbb --- /dev/null +++ b/src/util/virinhibitor.c @@ -0,0 +1,214 @@ +/* + * virinhibitor.c: helper APIs for inhibiting host actions + * + * Copyright (C) 2024 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#include + +#include "virinhibitor.h" +#include "virgdbus.h" +#include "virsystemd.h" +#include "virfile.h" +#include "virlog.h" +#include "virenum.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +VIR_LOG_INIT("util.inhibitor"); + +struct _virInhibitor { + GMutex lock; + size_t count; + int fd; + + char *what; + char *who; + char *why; + const char *mode; + + virInhibitorAction action; + void *actionData; +}; + +VIR_ENUM_DECL(virInhibitorMode); + +VIR_ENUM_IMPL(virInhibitorMode, + VIR_INHIBITOR_MODE_LAST, + "block", "delay"); + +#ifdef G_OS_UNIX +/* As per: https://www.freedesktop.org/wiki/Software/systemd/inhibit */ +static int +virInhibitorAcquire(const char *what, + const char *who, + const char *why, + const char *mode, + int *inhibitorFD) +{ + g_autoptr(GVariant) reply =3D NULL; + g_autoptr(GUnixFDList) replyFD =3D NULL; + g_autoptr(GVariant) message =3D NULL; + GDBusConnection *systemBus; + int fd; + int rc; + + VIR_DEBUG("what=3D%s who=3D%s why=3D%s mode=3D%s", + NULLSTR(what), NULLSTR(who), NULLSTR(why), NULLSTR(mode)); + + if (!(systemBus =3D virGDBusGetSystemBus())) { + VIR_DEBUG("system dbus not available, skipping system inhibitor"); + return 0; + } + + if (virSystemdHasLogind() < 0) { + VIR_DEBUG("logind not available, skipping system inhibitor"); + return 0; + } + + message =3D g_variant_new("(ssss)", what, who, why, mode); + + rc =3D virGDBusCallMethodWithFD(systemBus, + &reply, + G_VARIANT_TYPE("(h)"), + &replyFD, + NULL, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "Inhibit", + message, + NULL); + + if (rc < 0) + return -1; + + if (g_unix_fd_list_get_length(replyFD) <=3D 0) { + VIR_DEBUG("Missing inhibitor FD in logind reply"); + return -1; + } + + fd =3D g_unix_fd_list_get(replyFD, 0, NULL); + if (fd < 0) { + VIR_DEBUG("Unable to get inhibitor FD from logind reply"); + return -1; + } + + *inhibitorFD =3D fd; + VIR_DEBUG("Got inhibitor FD %d", fd); + return 0; +} +#endif + + +static char * +virInhibitorWhatFormat(virInhibitorWhat what) +{ + const char *whatstr[] =3D { + "sleep", + "shutdown", + "idle", + "handle-power-key", + "handle-suspend-key", + "handle-hibernate-key", + "handle-lid-switch", + }; + GString *str =3D g_string_new(""); + size_t i; + + for (i =3D 0; i < G_N_ELEMENTS(whatstr); i++) { + if (what & (1 << i)) { + if (str->len) + g_string_append(str, ":"); + g_string_append(str, whatstr[i]); + } + } + + return g_string_free(str, FALSE); +} + + +virInhibitor *virInhibitorNew(virInhibitorWhat what, + const char *who, + const char *why, + virInhibitorMode mode, + virInhibitorAction action, + void *actionData) +{ + virInhibitor *inhibitor =3D g_new0(virInhibitor, 1); + + inhibitor->fd =3D -1; + inhibitor->what =3D virInhibitorWhatFormat(what); + inhibitor->who =3D g_strdup(who); + inhibitor->why =3D g_strdup(why); + inhibitor->mode =3D virInhibitorModeTypeToString(mode); + inhibitor->action =3D action; + inhibitor->actionData =3D actionData; + + return inhibitor; +} + +void virInhibitorHold(virInhibitor *inhibitor) +{ + g_mutex_lock(&inhibitor->lock); + + if (inhibitor->count =3D=3D 0) { + if (inhibitor->action) { + inhibitor->action(true, inhibitor->actionData); + } +#ifdef G_OS_UNIX + if (virInhibitorAcquire( + inhibitor->what, inhibitor->who, inhibitor->why, + inhibitor->mode, &inhibitor->fd) < 0) { + VIR_ERROR(_("Failed to acquire inhibitor: %1$s"), + virGetLastErrorMessage()); + virResetLastError(); + } +#else + VIR_DEBUG("No inhibitor implementation on non-UNIX platforms"); +#endif + } + inhibitor->count++; + g_mutex_unlock(&inhibitor->lock); +} + + +void virInhibitorRelease(virInhibitor *inhibitor) +{ + g_mutex_lock(&inhibitor->lock); + inhibitor->count--; + if (inhibitor->count =3D=3D 0) { + VIR_FORCE_CLOSE(inhibitor->fd); + if (inhibitor->action) { + inhibitor->action(false, inhibitor->actionData); + } + } + g_mutex_unlock(&inhibitor->lock); +} + + +void virInhibitorFree(virInhibitor *inhibitor) +{ + if (!inhibitor) + return; + + g_free(inhibitor->what); + g_free(inhibitor->who); + g_free(inhibitor->why); + VIR_FORCE_CLOSE(inhibitor->fd); + g_free(inhibitor); +} diff --git a/src/util/virinhibitor.h b/src/util/virinhibitor.h new file mode 100644 index 0000000000..0a1c445d41 --- /dev/null +++ b/src/util/virinhibitor.h @@ -0,0 +1,58 @@ +/* + * virinhibitor.h: helper APIs for inhibiting host actions + * + * Copyright (C) 2024 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#pragma once + +#include "internal.h" + +typedef struct _virInhibitor virInhibitor; + +typedef enum { + VIR_INHIBITOR_WHAT_NONE =3D 0, + VIR_INHIBITOR_WHAT_SLEEP =3D (1 << 1), + VIR_INHIBITOR_WHAT_SHUTDOWN =3D (1 << 2), + VIR_INHIBITOR_WHAT_IDLE =3D (1 << 3), + VIR_INHIBITOR_WHAT_POWER_KEY =3D (1 << 4), + VIR_INHIBITOR_WHAT_SUSPEND_KEY =3D (1 << 5), + VIR_INHIBITOR_WHAT_HIBERNATE_KEY =3D (1 << 6), + VIR_INHIBITOR_WHAT_LID_SWITCH =3D (1 << 7), +} virInhibitorWhat; + +typedef enum { + VIR_INHIBITOR_MODE_BLOCK, + VIR_INHIBITOR_MODE_DELAY, + + VIR_INHIBITOR_MODE_LAST +} virInhibitorMode; + +typedef void (*virInhibitorAction)(bool inhibited, + void *opaque); + +virInhibitor *virInhibitorNew(virInhibitorWhat what, + const char *who, + const char *why, + virInhibitorMode mode, + virInhibitorAction action, + void *actionData); + +void virInhibitorHold(virInhibitor *inhibitor); +void virInhibitorRelease(virInhibitor *inhibitor); + +void virInhibitorFree(virInhibitor *inhibitor); --=20 2.46.0