From nobody Wed Jun 24 21:41:35 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 38.145.34.151 as permitted sender) client-ip=38.145.34.151; 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 38.145.34.151 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass(p=reject dis=none) header.from=lists.libvirt.org ARC-Seal: i=1; a=rsa-sha256; t=1782160870; cv=none; d=zohomail.com; s=zohoarc; b=AwXVm1RKgrRPnfCKS25K382UF4Tm7bgUVzwZSfderAbrsVdSX0pW0yQY4msCNTO2/fOHOG7l6yhci+YEdvqJ83twcDMnfF0Rm84TcNPKea9VMuMYRZsaeBDPRWyRT3Z/hyCfry4JNSMYngYnixZ9Snt/Gm/1SX0P3CbRjg5MY8Y= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1782160870; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:Subject:Subject:To:To:Message-Id; bh=aS4Bpwas1zz4KuFuJP65A9+cGynEAhGCuC/IkBiZ/Y4=; b=MsQyEFh5tyPb21qv5MllsFtn9wsQGWqsTMSHsjxsjaDThE3Nzr/GBvnvEQOXJ7QK1B3MY1VR4VZPDjNrYCkbnulS9IZL6I4pJZ/BNPKMlxfHLX4UVm3GNSq5Xi0cAXXM73PYXiLzzLLInysc9fVqbG4KvRXseu1Tz4aEVT0S5wo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 38.145.34.151 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [38.145.34.151]) by mx.zohomail.com with SMTPS id 1782160870232164.8983496350072; Mon, 22 Jun 2026 13:41:10 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 993) id EE08E41CE4; Mon, 22 Jun 2026 16:41:08 -0400 (EDT) Received: from [172.19.199.7] (unknown [10.16.107.18]) by lists.libvirt.org (Postfix) with ESMTP id 4F31F41D5F; Mon, 22 Jun 2026 16:39:49 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 993) id BE2C241C3D; Mon, 22 Jun 2026 16:39:40 -0400 (EDT) Received: from mail-wm1-x32b.google.com (mail-wm1-x32b.google.com [IPv6:2a00:1450:4864:20::32b]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 2283841C3A for ; Mon, 22 Jun 2026 16:39:39 -0400 (EDT) Received: by mail-wm1-x32b.google.com with SMTP id 5b1f17b1804b1-490ac357c55so52617965e9.1 for ; Mon, 22 Jun 2026 13:39:39 -0700 (PDT) Received: from localhost ([69.51.117.128]) by smtp.gmail.com with UTF8SMTPSA id 586e51a60fabf-4472efb37fesm7057066fac.10.2026.06.22.13.39.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 22 Jun 2026 13:39:35 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=4.0.1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=google; t=1782160777; x=1782765577; darn=lists.libvirt.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=aS4Bpwas1zz4KuFuJP65A9+cGynEAhGCuC/IkBiZ/Y4=; b=SZGS86wyrLTvNidrvfCPFYmpX7NTyd6vRzIShN/tt6p4GhYu8IySe20+1LhjwFvSjp PJEX079MeZjSZ+G7wUqNT4BRjHpOSoF+itkVuIq3zA/IBf7YpQxBbTZ1pmdjAFXbQQ0a OoC9nnTKveRMufn4jNb2cAVFuwuBnvJYFM5jtUZ6H+HsJmWbsAIT80i7YWq/9VmYmZJT bK3FZ7C2DeLAJaeDDxWpjgISzLdjr6F7bpctZebmkU+MZMEPCPninST8YK6z0S5y63Jg sdmJ4xREu6scL+XlRNG/gCc12tOUt+A9ArQ2qL9zGmoGgMc1Czs85bXZnuzNlcpggxAc ePNA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782160777; x=1782765577; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=aS4Bpwas1zz4KuFuJP65A9+cGynEAhGCuC/IkBiZ/Y4=; b=QMYjY8pkYmQe6uKvcKSZ1Y9hnIcMbMeTyT1pF8pC7X6zAxAosPseE75ZCI86QBwG4q 9ok1wcCSIlRZIoEdYnF6OhXiWDfbVdoGOGuCBaShYyn0ZOxoN449Rpnio6UgO/h8YMx0 PGPWlWFhDxY9xEzGix95LJq34EkLUbk//iGz8cz3ksTsBBKFoxBv6okboQRXHWX+kctk 9TVFUIF1Fwh4jLGd186aScupiYgMSCkP6fRT9bNuoKg4ITNbs+VP8lBIwgqxPqz1tSV5 9ghByssi8PMMz4AL1ZlIwBIhjW650wc5uLKjW+hf1P3znDYtjt5b8nDjm2X4gWxuP25W t16w== X-Gm-Message-State: AOJu0Yz2gULJXGjfT/6amHhwhAbOxfD7eckHxc/2ZNKS5K1xdNOK8RVc oIJKLgHy35YWB92Nydjjg4KpbGNo0BvAUywAtLiOaSFx/6IuVHZw3Ehxv8l3uYKrulpTj6cVBb2 zbQkbtcqNIA== X-Gm-Gg: AfdE7clZxTGzU0sBQHk5dgE1qKQD+I1V6AGBzj6+aevKTdBicj/rSYSdUv23YpKkcaH yscE4mHCZRvRR/w4m4YBh7i69CvKdqloOaZnHiHGF4cuH9Vq223/bbQWOF1MTNkE8w2/hn7Rs9R Nh6EP3W+XrMU0SAZiqMyECQp/vaRuxdsq05Xd/oosxFFCUnXcWA4Mjuxt9pc+mqZsQFSpq/mGfl msV1yRHVovi4C7a7dSP27IaGSrXDQbS6ukEr4zkeptJoNxFkcwt3Ie5eKoJkwQP/Rq0PT6jt2Kb +o1ED545PNLRe3TMkI4cNFwmwQ7Plqjt0wcOepGfp8wfX2EH4XUlvQKIH48Mx6uLFOG/nr2Om5j JBvnw6j3fXq3EpRqdEjkBmuB984gmQlZBmaw/gdfHuUWAexc8u+uUZeWE0lcm05Rc5xHMMtJKBG cV9+E= X-Received: by 2002:a05:600c:8b2b:b0:490:c2a3:23cf with SMTP id 5b1f17b1804b1-49240e7b294mr282780185e9.34.1782160777600; Mon, 22 Jun 2026 13:39:37 -0700 (PDT) To: devel@lists.libvirt.org Subject: [RFC] sanlock: Add option to check ownership of disk leases Date: Mon, 22 Jun 2026 14:38:00 -0600 Message-ID: <20260622203934.845906-1-jfehlig@suse.com> X-Mailer: git-send-email 2.51.0 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Message-ID-Hash: WR65GREPUY6SRE6NJQHDXXGNK5LFIMVL X-Message-ID-Hash: WR65GREPUY6SRE6NJQHDXXGNK5LFIMVL X-MailFrom: jfehlig@suse.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: cfontana@suse.de X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Jim Fehlig via Devel Reply-To: Jim Fehlig X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1782160873038158500 Content-Type: text/plain; charset="utf-8" From: Jim Fehlig In a clustered environment it may be desirable to provision disk leases for use by a specific domain. This patch adds a 'check_disk_lease_owner' option to the sanlock driver to check that leases are owned by the domain attempting to acquire them. sanlock's Lock Value Block (LVB) is used to store the owning domain UUID within the lease. When a domain is started and attempts to acquire its leases, the sanlock driver will ensure its UUID matches the UUID recorded in the leases. Any mismatches will cause lease acquisition and domain startup to fail. The 'check_disk_lease_owner' option is disabled by default. When enabled, it can be used with auto_disk_leases or leases managed by an external application. Signed-off-by: Jim Fehlig --- Inspired by Claudio, implemented by Jim :-) src/locking/libvirt_sanlock.aug | 1 + src/locking/lock_driver_sanlock.c | 78 ++++++++++++++++++++++++- src/locking/sanlock.conf | 23 ++++++++ src/locking/test_libvirt_sanlock.aug.in | 1 + 4 files changed, 102 insertions(+), 1 deletion(-) diff --git a/src/locking/libvirt_sanlock.aug b/src/locking/libvirt_sanlock.= aug index 62d0672952..af6c25755f 100644 --- a/src/locking/libvirt_sanlock.aug +++ b/src/locking/libvirt_sanlock.aug @@ -25,6 +25,7 @@ module Libvirt_sanlock =3D | int_entry "io_timeout" | str_entry "user" | str_entry "group" + | bool_entry "check_disk_lease_owner" let comment =3D [ label "#comment" . del /#[ \t]*/ "# " . store /([^ \= t\n][^\n]*)?/ . del /\n/ "\n" ] let empty =3D [ label "#empty" . eol ] =20 diff --git a/src/locking/lock_driver_sanlock.c b/src/locking/lock_driver_sa= nlock.c index a07f3652c1..7ed1081cbd 100644 --- a/src/locking/lock_driver_sanlock.c +++ b/src/locking/lock_driver_sanlock.c @@ -67,6 +67,7 @@ struct _virLockManagerSanlockDriver { unsigned int hostID; bool autoDiskLease; char *autoDiskLeasePath; + bool checkDiskLeaseOwner; unsigned int io_timeout; =20 /* under which permissions does sanlock run */ @@ -147,6 +148,10 @@ virLockManagerSanlockLoadConfig(virLockManagerSanlockD= river *driver, if (virConfGetValueBool(conf, "require_lease_for_disks", &driver->requ= ireLeaseForDisks) < 0) return -1; =20 + if (virConfGetValueBool(conf, "check_disk_lease_owner", + &driver->checkDiskLeaseOwner) < 0) + return -1; + if (virConfGetValueUInt(conf, "io_timeout", &driver->io_timeout) < 0) return -1; =20 @@ -839,6 +844,73 @@ virLockManagerSanlockRegisterKillscript(int sock, return 0; } =20 +static int virLockManagerSanlockCheckOwner(virLockManagerSanlockDriver *dr= iver, + virLockManagerSanlockPrivate *p= riv) +{ + char lvb[VIR_UUID_STRING_BUFLEN] =3D {0}; + char vm_uuidstr[VIR_UUID_STRING_BUFLEN]; + int rv; + size_t i; + + if (!driver->checkDiskLeaseOwner) + return 0; + + virUUIDFormat(priv->vm_uuid, vm_uuidstr); + + for (i =3D 0; i < priv->res_count; i++) { + memset(lvb, 0, sizeof(lvb)); + + rv =3D sanlock_get_lvb(0, priv->res_args[i], lvb, sizeof(lvb)); + if (rv < 0) { + /* Failed to read LVB, treat as "legacy" lease + * without ownership tracking and skip the check. + */ + VIR_DEBUG("Failed to read LVB, skipping ownership check"); + continue; + } + + if (lvb[0] =3D=3D '\0') { + VIR_DEBUG("Writing VM UUID to empty LVB"); + /* Empty LVB: this lease does not yet have an owner recorded. = Write + * the domain's UUID so that subsequent acquire attempts by ot= her + * domains will be rejected. This handles the auto_disk_leases= case + * where lease files are created by libvirt. rather + */ + if ((rv =3D sanlock_set_lvb(0, priv->res_args[i], vm_uuidstr, + sizeof(vm_uuidstr))) < 0) { + char *err =3D NULL; + if (virLockManagerSanlockError(rv, &err)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to set LVB for lease %1$s: %2= $s"), + priv->res_args[i]->disks[0].path, NULLS= TR(err)); + VIR_FREE(err); + } else { + virReportSystemError(-rv, + _("Failed to set LVB for lease %1= $s"), + priv->res_args[i]->disks[0].path); + } + return -1; + } + continue; + } + + VIR_DEBUG("Comparing LVB UUID '%s' to VM UUID '%s'", lvb, vm_uuids= tr); + if (STRNEQ(lvb, vm_uuidstr)) { + /* + * LVB contains a different domain UUID. This lease + * was provisioned for another domain and must not + * be acquired by this one. + */ + virReportError(VIR_ERR_RESOURCE_BUSY, + _("Disk lease %1$s is already assigned to domai= n %2$s, not %3$s"), + priv->res_args[i]->disks[0].path, lvb, vm_uuids= tr); + return -1; + } + } + return 0; +} + + static int virLockManagerSanlockAcquire(virLockManager *lock, const char *state, unsigned int flags, @@ -934,7 +1006,8 @@ static int virLockManagerSanlockAcquire(virLockManager= *lock, =20 if (!(flags & VIR_LOCK_MANAGER_ACQUIRE_REGISTER_ONLY)) { VIR_DEBUG("Acquiring object %u", priv->res_count); - if ((rv =3D sanlock_acquire(sock, priv->vm_pid, 0, + if ((rv =3D sanlock_acquire(sock, priv->vm_pid, + driver->checkDiskLeaseOwner ? SANLK_ACQU= IRE_LVB : 0, priv->res_count, priv->res_args, opt)) < 0) { char *err =3D NULL; @@ -949,6 +1022,9 @@ static int virLockManagerSanlockAcquire(virLockManager= *lock, } goto error; } + + if (virLockManagerSanlockCheckOwner(driver, priv) < 0) + goto error; } =20 VIR_FREE(opt); diff --git a/src/locking/sanlock.conf b/src/locking/sanlock.conf index 3c356bef9c..e7d6938e84 100644 --- a/src/locking/sanlock.conf +++ b/src/locking/sanlock.conf @@ -67,3 +67,26 @@ # access them. Accepted values are described in qemu.conf. #user =3D "root" #group =3D "root" + +# +# Flag to enable verifying if disk leases have been provisioned +# for domains attempting to acquire them. This is accomplished +# using sanlock's Lock Value Block (LVB), a 512 byte application +# specific block in the lease lockspace where the domain's UUID +# can be stored when the lease is created. When libvirt starts a +# domain, the sanlock driver will check for a valid and matching +# UUID in the LVB of all leases. This prevents a lease that was +# provisioned for one domain from accidentally being used by a +# different domain. +# +# When enabled, if a lease file has an empty LVB, the UUID of the +# acquiring domain is written into the LVB automatically, so that +# subsequent lease acquisition attempts by other domains will be +# rejected. This behavior accommodates the auto_disk_leases case, +# where leases are created by libvirt. If leases are managed by +# an external application, it must write the domain UUID into the +# LVB during lease creation. +# +# Defaults to disabled. +# +#check_disk_lease_owner =3D 0 diff --git a/src/locking/test_libvirt_sanlock.aug.in b/src/locking/test_lib= virt_sanlock.aug.in index 5eabb6726d..e468a2cdcd 100644 --- a/src/locking/test_libvirt_sanlock.aug.in +++ b/src/locking/test_libvirt_sanlock.aug.in @@ -9,3 +9,4 @@ module Test_libvirt_sanlock =3D { "io_timeout" =3D "0" } { "user" =3D "root" } { "group" =3D "root" } +{ "check_disk_lease_owner" =3D "0" } --=20 2.51.0