From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [IPv6:2a0f:8001:1:32::40]) by lore.proxmox.com (Postfix) with ESMTPS id B27231FF0ED for ; Sat, 24 Oct 2026 06:59:04 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 3A53421649; Sat, 24 Oct 2026 06:59:04 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; t=1792817930; cv=none; d=google.com; s=arc-20260327; b=T01eaW51nhQ0HzPi0mncAUz478Xwhbu8HzVZkHRTKxi3WU9+beRGvDnIEJuqTA/trw bOb2sE802lt+/kSAMIWbZPDKDujgd7wuGmVf6YkAAdHaz9garkDyzzOh95rrh7LF4BNk a78uT8UO4OeBRmlKUxEd3g4P4zRst6zhb0i3thwtxpVEmicb3XUBzqn87gvPJQ18l98i BeKtcP1gObKu2Bqq0GioaDDvTZ0EDuD6rX+b+naVK3NexJDRdJbB1DZJgiGsvTDVOVId TZgd7Iz1E1qo42oOfzJCOy/hIidYsxBGaI76ucDkmfeow8Qc7lviLr6NNGM/Xtopnseu cdEw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=content-transfer-encoding:to:subject:message-id:date:references :in-reply-to:from:mime-version:dkim-signature; bh=0Ic8IgDT/uFhIq4mSWo/UR1myutqJmHhTRADGyXupjo=; fh=qUdnlOw4HMavIAa4vJfUpEe/QUA6LBLHlg5B+iT7exQ=; b=rAnmmngd0BGDr3jo/EkLKSdkcNTWO189E9yZivXLLh6IYThfntxOUkNlG072rI6YRH RrrcD+mUdWr+ogN3/V7CEyXTlSb8xUwMvUDGtRN0iqeiSAOtwXTsM2dwrsxL1uIrUhIt 6qcA5peST00WfNoJWn0u4stJlxaVL0S9pNLn5fk4kGaq7dx5Tp3JnPugNB2s5ZkR/Yig DrddLvVh5ug6jdDeDMWdVSk5IGjA2WEwTbYcRIhAxqBX+Bhk4qaz+r8NTN1+v9SSU2VN m9kdkjy15UC1gEMAN+4qy1d83KX86pT2FZETYJ1J7q+jshwbFQY/O9BcYbPbup41tpK/ R19g==; darn=lists.proxmox.com ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1792817930; x=1793422730; darn=lists.proxmox.com; h=content-transfer-encoding:content-type:to:subject:message-id:date :references:in-reply-to:from:mime-version:from:to:cc:subject:date :message-id:reply-to:content-type; bh=0Ic8IgDT/uFhIq4mSWo/UR1myutqJmHhTRADGyXupjo=; b=hZXoVwwYdPAWQbSN+GEE/nF61zl1jsiokrYugNmkgItu/MbDBN3EH4Fhu7P1888883 WZ7nGsCFtz1L+k/mGFJ6y4CNuyWU+RD0P8Xerz8JwLEyFieL6nOXPonGpT1E9NwsgXTZ YvwY8yD1mu817mX8CE2zHD1BidE3lLt1SZjdgNT+b4spVbL1iEI7OcG68hmBHcVcqzMI ZFcZiyQaJeQNPSPFsBACngAvoT/u6zmgsidBpz53Zm/uItnMPO5cU6PUE3bET7jPK21u 3raphhmrjsnPmxCu3d5iQlDb8azE0W1NkbT/7f6ai20PNFjJILFJDII0IrrtDU3HQg+Q 91JA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1792817930; x=1793422730; h=content-transfer-encoding:content-type:to:subject:message-id:date :references:in-reply-to:from:mime-version:x-gm-gg:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to:content-type; bh=0Ic8IgDT/uFhIq4mSWo/UR1myutqJmHhTRADGyXupjo=; b=TlgVKY6pFW4qAXTd9+9BKPU24LYIp8rY+GmSvZFkHoewxZFcOJIkCS9f1Pc+X2LIgp oeHA9tUOTYQGG6yTrb/rBEASKzYmtBXz/3glI9zHhyV1iUeQz3S/SzBIJa7/dIRCbNX5 trMkaXz7xcILhkC47wqGDFWhqtgjCVh95IJ0d+zdz7D+jFermyTiRRlmBx7Eeaf/ofGd Jd7Q3s/bdhLm33bvpE3uSkEPvqBReblMmcVU394fMmLW8yBATjCOzNhS1wMUxF5Vsvht QofXxfSKGG10Y6n+gmjgHjDhyz48+72oQGLG84iR+Exw9GNwTCGBx3SayRif7FHCHIp8 w4Jg== X-Gm-Message-State: AFq9FYILp2/XUWqe4n2920hyISnl+9WsYSVZk5G08WMmnQXvj9xeeh6+ rNqZK+clnxLRwntkMLsW6+dbQJpgjUQYTnrO9/D2oGY2aY5jh9fZ9in5zfV2mZBJZ7LuO7A0INL gL7QX1FbB3wWx3rpt8xSnudfQPM/eXc9UWw== X-Gm-Gg: AYBFou1zbbalnSNjO7cxqJnBy7Z3shWoJGTwsWfOIqxlBbMBzYiP8UjLlCCIyH1zGiW x5EYa6jJqnuZNt56+C7zs93+tioTlWLxid49I2z96iISxQbwUliRW7pAQ8qkczgm82vyVqSpKgo GGWr8+kIOkDVcsJ1h+ZmvCz1Xudp/mVW/VmCaBGbIO0ftsMg8J7WhKG65+Mg1/2taKCs2/4ibOe ZZ+/eF3PSpSI4SrnAoQowIcbkEK58p07COp7rJaxCBA8mZbrcKp/sySRXLzvF1jROSzHiapSzRa jvVXik4yHnsXYP2GsSiN2xfTi+0tezj9JGwlE2i/4xe8Sq4wKxc0r5oLcOf3qcKEs+PZAJzNGZF 12sxpMXGbuGUSNkN/6DkxZwbhWCFDAoB0DMHfg2Ff14PtmhnQQEVKq1E= X-Received: by 2002:a05:6402:1d4c:b0:6b1:e8e1:a3cd with SMTP id 4fb4d7f45d1cf-6b44300fca7mr1290440a12.35.1792817930014; Fri, 23 Oct 2026 21:58:50 -0700 (PDT) MIME-Version: 1.0 From: =?UTF-8?B?57WQ5Y+L?= In-Reply-To: References: Date: Fri, 23 Oct 2026 21:58:49 -0700 X-Gm-Features: AclHuK9-nLVnFvB7VmxFVM4-TIENIZmuOzy58jNikSxQ_338HvRvGt3ZjpSoRv0 Message-ID: Subject: [PATCH pve-kernel 1/2] d/scripts: correctly compare namespaced ABI exports To: pve-devel@lists.proxmox.com Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-SPAM-LEVEL: Spam detection results: 0 AWL -0.900 Adjusted score from AWL reputation of From: address DKIM_SIGNED 0.1 Message has a DKIM or DK signature, not necessarily valid DKIM_VALID -0.1 Message has at least one valid DKIM or DK signature DKIM_VALID_AU -0.1 Message has a valid DKIM or DK signature from author's domain DKIM_VALID_EF -0.1 Message has a valid DKIM or DK signature from envelope-from domain DMARC_PASS -0.1 DMARC pass policy FREEMAIL_FROM 0.001 Sender email is commonly abused enduser mail provider KAM_STOCKGEN 1.5 Email Contains Generic Pump & Dump Stock Tip POISEN_SPAM_PILL 0.1 Meta: its spam POISEN_SPAM_PILL_1 0.1 random spam to be learned in bayes POISEN_SPAM_PILL_3 0.1 random spam to be learned in bayes RCVD_IN_DNSWL_NONE -0.0001 Sender listed at https://www.dnswl.org/, no trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: IFF5KBLETURZETPBX5DMB7HSV4LCHWJT X-Message-ID-Hash: IFF5KBLETURZETPBX5DMB7HSV4LCHWJT X-MailFrom: miagetegorann@gmail.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: abi-generate emits a different field order for namespaced exports. Parse both layouts explicitly so the module name does not become part of the symbol name. Otherwise, building hv_vmbus into vmlinux falsely reports three existing namespaced exports as missing. Compare the actual export type and namespace, preserving hash and missing symbol checks and symbol/module blacklists. Reject added or changed namespace requirements, malformed entries and duplicate symbols. Fix the export-type diagnostic's printf argument separator. Add 12 ABI regression tests, including end-to-end abi-generate output, relocation, hash changes, GPL restrictions, namespaces and skip handling. Document the check and test command, and ignore Python bytecode caches. All 12 tests pass under WSL2 Ubuntu 24.04. Rechecking the existing 7.0.14-26-pve build artifacts with SKIPABI=3D0 preserves all 32,726 symbols= , their CRCs and export types, with only the expected 47 VMBus relocations. Signed-off-by: =E7=B5=90=E5=8F=8B --- .gitignore | 1 + README | 8 ++ debian/scripts/abi-check | 56 ++++++++++--- debian/tests/test_abi_check.py | 140 +++++++++++++++++++++++++++++++++ 4 files changed, 192 insertions(+), 13 deletions(-) create mode 100644 debian/tests/test_abi_check.py diff --git a/.gitignore b/.gitignore index 295de11..aa1d4e1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ *.deb *.dsc *.prepared +__pycache__/ /abi-tmp* /config*.org /proxmox-kernel-[0-9]*/ diff --git a/README b/README index 9dd855a..00564c8 100644 --- a/README +++ b/README @@ -167,6 +167,14 @@ variable in the Makefile, rebuilding the packages and running 'make abiupdate' (the 'abiupdate' target in 'Makefile' contains the steps for consistently updating the repository). +The ABI check reads both ordinary and namespaced exports. Moving an export +between a module and vmlinux is reported without failing the check. Missin= g +symbols, hash changes and stricter export or namespace requirements fail i= t +unless an applicable blacklist or the ABI skip mode permits them. + +Run the ABI checker regression tests on a Debian build host with +'python3 -B -m unittest discover -s debian/tests -v'. + The source package-name is proxmox-kernel-MAJ.MIN, the version of the pack= age defaults to MAJ.MIN.PATCH-KREL - but this can be adapted to contain a suff= ix for test-packages (e.g. ~test01). The version in the Makefile needs to be = equal diff --git a/debian/scripts/abi-check b/debian/scripts/abi-check index 9987d04..ff000c3 100755 --- a/debian/scripts/abi-check +++ b/debian/scripts/abi-check @@ -89,17 +89,35 @@ sub is_ignored($$) { return 0; } +# abi-generate emits four fields for ordinary exports, and five fields for +# namespaced exports (namespace, type, hash, symbol, module). In the latte= r +# format the trailing module must not become part of the symbol name. +sub parse_symbol { + my ($line, $file, $number) =3D @_; + chomp $line; + $line =3D~ s/\r$//; + + if ($line =3D~ /^(EXPORT_SYMBOL(?:_[A-Z0-9_]+)?)\s+(\S+)\s+(0x[0-9a-f]+)\s+(\S+)$/) { + return ($4, $1, $2, $3, ''); + } + if ($line =3D~ /^(\S+)\s+(EXPORT_SYMBOL(?:_[A-Z0-9_]+)?)\s+(0x[0-9a-f]+)\s+(\S+)\s+(\S+)$/= ) { + return ($4, $2, $5, $3, $1); + } + die "EE: $file:$number: malformed ABI entry: '$line'\n"; +} + # Read new syms first print " Reading new symbols ($abistr)..."; $count =3D 0; open(my $NEW_FH, '<', $abinew) or die "Could not open $abinew - $!"; while (<$NEW_FH>) { - chomp; - m/^(\S+)\s(.+)\s(0x[0-9a-f]+)\s(.+)$/; - $symbols{$4}{'type'} =3D $1; - $symbols{$4}{'loc'} =3D $2; - $symbols{$4}{'hash'} =3D $3; - $module_syms{$2} =3D 0; + my ($sym, $type, $loc, $hash, $namespace) =3D parse_symbol($_, $abinew= , $.); + die "EE: $abinew:$.: duplicate symbol '$sym'\n" if defined($symbols{$sym}{'type'}); + $symbols{$sym}{'type'} =3D $type; + $symbols{$sym}{'loc'} =3D $loc; + $symbols{$sym}{'hash'} =3D $hash; + $symbols{$sym}{'namespace'} =3D $namespace; + $module_syms{$loc} =3D 0; $count++; } close($NEW_FH); @@ -110,11 +128,12 @@ print " Reading old symbols..."; $count =3D 0; open(my $OLD_FH, '<', $abiold) or die "Could not open $abiold - $!"; while (<$OLD_FH>) { - chomp; - m/^(\S+)\s(.+)\s(0x[0-9a-f]+)\s(.+)$/; - $symbols{$4}{'old_type'} =3D $1; - $symbols{$4}{'old_loc'} =3D $2; - $symbols{$4}{'old_hash'} =3D $3; + my ($sym, $type, $loc, $hash, $namespace) =3D parse_symbol($_, $abiold= , $.); + die "EE: $abiold:$.: duplicate symbol '$sym'\n" if defined($symbols{$sym}{'old_type'}); + $symbols{$sym}{'old_type'} =3D $type; + $symbols{$sym}{'old_loc'} =3D $loc; + $symbols{$sym}{'old_hash'} =3D $hash; + $symbols{$sym}{'old_namespace'} =3D $namespace; $count++; } close($OLD_FH); @@ -158,6 +177,7 @@ $count =3D 0; my $moved =3D 0; my $changed_type =3D 0; my $changed_hash =3D 0; +my $changed_namespace =3D 0; for my $sym (keys(%symbols)) { if (!defined($symbols{$sym}{'old_type'}) or !defined($symbols{$sym}{'type'})) { next; @@ -172,12 +192,21 @@ for my $sym (keys(%symbols)) { # Changes to export type are only bad if new type isn't # EXPORT_SYMBOL. Changing things to GPL are bad. if ($symbols{$sym}{'type'} ne $symbols{$sym}{'old_type'}) { - printf(" TYPE : %-40s : %s =3D> %s%s\n", $sym, $symbols{$sym}{'old_typ= e'}. + printf(" TYPE : %-40s : %s =3D> %s%s\n", $sym, $symbols{$sym}{'old_typ= e'}, $symbols{$sym}{'type'}, is_ignored($symbols{$sym}{'loc'}, $sym) ? " (ignored)" : ""); $changed_type++ if $symbols{$sym}{'type'} ne "EXPORT_SYMBOL" and !is_ignored($symbols{$sym}{'loc'}, $sym); } + # Adding or changing a namespace requires consumers to change their imports. + # Removing a namespace relaxes that requirement and is compatible. + if ($symbols{$sym}{'namespace'} ne $symbols{$sym}{'old_namespace'}) { + printf(" NS : %-40s : %s =3D> %s%s\n", $sym, + $symbols{$sym}{'old_namespace'} || '(none)', $symbols{$sym}{'namespace'} || '(none)', + is_ignored($symbols{$sym}{'loc'}, $sym) ? " (ignored)" : ""); + $changed_namespace++ if $symbols{$sym}{'namespace'} ne '' && !is_ignored($symbols{$sym}{'loc'}, $sym); + } + # Changes to the hash are always bad if ($symbols{$sym}{'hash'} ne $symbols{$sym}{'old_hash'}) { printf(" HASH : %-40s : %s =3D> %s%s\n", $sym, $symbols{$sym}{'old_has= h'}, @@ -191,8 +220,9 @@ for my $sym (keys(%symbols)) { print "WW: $moved symbols changed location\n" if $moved; print "$EE $changed_type symbols changed export type and weren't ignored\n" if $changed_type; print "$EE $changed_hash symbols changed hash and weren't ignored\n" if $changed_hash; +print "$EE $changed_namespace symbols changed namespace and weren't ignored\n" if $changed_namespace; -$errors++ if $changed_hash or $changed_type; +$errors++ if $changed_hash or $changed_type or $changed_namespace; if ($changed_hash) { print "II: Module hash change summary...\n"; for my $mod (sort { $module_syms{$b} <=3D> $module_syms{$a} } keys %module_syms) { diff --git a/debian/tests/test_abi_check.py b/debian/tests/test_abi_check.p= y new file mode 100644 index 0000000..928c64a --- /dev/null +++ b/debian/tests/test_abi_check.py @@ -0,0 +1,140 @@ +#!/usr/bin/python3 + +"""Check ABI compatibility using both formats emitted by abi-generate.""" + +from pathlib import Path +import subprocess +import tempfile +import unittest + + +ROOT =3D Path(__file__).resolve().parents[2] +CHECKER =3D ROOT / "debian/scripts/abi-check" +GENERATOR =3D ROOT / "debian/scripts/abi-generate" + + +class AbiCheckTests(unittest.TestCase): + def setUp(self): + temporary =3D tempfile.TemporaryDirectory(prefix=3D"kernel-abi-tes= t-") + self.addCleanup(temporary.cleanup) + self.directory =3D Path(temporary.name) + + def check(self, old, new, *, skip=3DFalse, blacklist=3D""): + (self.directory / "abi-prev-test").write_text(old) + (self.directory / "abi-test").write_text(new) + (self.directory / "abi-blacklist").write_text(blacklist) + return subprocess.run( + ["perl", str(CHECKER), "abi-test", "abi-prev-test", str(int(skip))], + cwd=3Dself.directory, text=3DTrue, stdout=3Dsubprocess.PIPE, + stderr=3Dsubprocess.STDOUT, check=3DFalse, + ) + + def test_namespaced_and_ordinary_exports_can_move_to_vmlinux(self): + old =3D ( + "EXPORT_SYMBOL drivers/hv/hv_vmbus 0x12345678\tvmbus_open\n" + "module:mshv_vtl EXPORT_SYMBOL_GPL 0x853b6fd2\thv_post_message\tdrivers/hv/hv_vmbus\n" + ) + result =3D self.check(old, old.replace("drivers/hv/hv_vmbus", "vml= inux")) + self.assertEqual(result.returncode, 0, result.stdout) + self.assertIn("2 symbols changed location", result.stdout) + self.assertIn("found 0 missing symbols", result.stdout) + self.assertIn("found 0 new symbols", result.stdout) + + def test_namespaced_hash_change_is_an_error(self): + old =3D "DMA_BUF EXPORT_SYMBOL_GPL 0x12345678\tdma_buf_get\tvmlinu= x\n" + result =3D self.check(old, old.replace("0x12345678", "0x87654321")= ) + self.assertNotEqual(result.returncode, 0, result.stdout) + self.assertIn("1 symbols changed hash", result.stdout) + self.assertRegex(result.stdout, r"vmlinux\s+: 1") + + def test_namespaced_export_restriction_is_an_error(self): + old =3D "DMA_BUF EXPORT_SYMBOL 0x12345678\tdma_buf_get\tvmlinux\n" + result =3D self.check(old, old.replace("EXPORT_SYMBOL ", "EXPORT_SYMBOL_GPL ")) + self.assertNotEqual(result.returncode, 0, result.stdout) + self.assertIn("EXPORT_SYMBOL =3D> EXPORT_SYMBOL_GPL", result.stdou= t) + self.assertIn("1 symbols changed export type", result.stdout) + + def test_ordinary_exports_keep_hash_and_type_checks(self): + old =3D "EXPORT_SYMBOL vmlinux 0x12345678\tordinary\n" + for new in ( + old.replace("0x12345678", "0x87654321"), + old.replace("EXPORT_SYMBOL ", "EXPORT_SYMBOL_GPL "), + ): + with self.subTest(new=3Dnew): + result =3D self.check(old, new) + self.assertNotEqual(result.returncode, 0, result.stdout) + + def test_namespace_added_or_changed_requires_consumer_changes(self): + new =3D "DMA_BUF EXPORT_SYMBOL 0x12345678\tdma_buf_get\tvmlinux\n" + for old in ( + "EXPORT_SYMBOL vmlinux 0x12345678\tdma_buf_get\n", + new.replace("DMA_BUF", "OLD_NAMESPACE"), + ): + with self.subTest(old=3Dold): + result =3D self.check(old, new) + self.assertNotEqual(result.returncode, 0, result.stdout) + self.assertIn("1 symbols changed namespace", result.stdout= ) + + def test_namespace_and_gpl_restrictions_can_be_removed(self): + old =3D "DMA_BUF EXPORT_SYMBOL_GPL 0x12345678\tdma_buf_get\tvmlinu= x\n" + new =3D "EXPORT_SYMBOL vmlinux 0x12345678\tdma_buf_get\n" + result =3D self.check(old, new) + self.assertEqual(result.returncode, 0, result.stdout) + self.assertIn("DMA_BUF =3D> (none)", result.stdout) + + def test_namespaced_symbol_and_module_blacklists_still_apply(self): + old =3D "DMA_BUF EXPORT_SYMBOL 0x12345678\tdma_buf_get\tvmlinux\n" + new =3D old.replace("0x12345678", "0x87654321").replace("DMA_BUF", "NEW_NAMESPACE") + for blacklist in ("dma_buf_get\n", "M: vmlinux\n"): + with self.subTest(blacklist=3Dblacklist): + changed =3D self.check(old, new, blacklist=3Dblacklist) + self.assertEqual(changed.returncode, 0, changed.stdout) + missing =3D self.check(old, "", blacklist=3Dblacklist) + self.assertEqual(missing.returncode, 0, missing.stdout) + + def test_missing_namespaced_symbol_is_still_an_error(self): + old =3D "DMA_BUF EXPORT_SYMBOL 0x12345678\tdma_buf_get\tvmlinux\n" + result =3D self.check(old, "") + self.assertNotEqual(result.returncode, 0, result.stdout) + self.assertIn("found 1 missing symbols", result.stdout) + + def test_skip_flag_still_reports_abi_errors(self): + old =3D "DMA_BUF EXPORT_SYMBOL_GPL 0x12345678\tdma_buf_get\tvmlinu= x\n" + result =3D self.check(old, old.replace("0x12345678", "0x87654321"), skip=3DTrue) + self.assertEqual(result.returncode, 0, result.stdout) + self.assertIn("WW: 1 symbols changed hash", result.stdout) + + def test_malformed_entries_are_rejected_even_when_skipped(self): + valid =3D "EXPORT_SYMBOL vmlinux 0x12345678\tordinary\n" + for old, new in ((valid, valid + "broken\n"), (valid + "broken\n", valid)): + with self.subTest(old=3Dold, new=3Dnew): + result =3D self.check(old, new, skip=3DTrue) + self.assertNotEqual(result.returncode, 0, result.stdout) + self.assertIn("malformed ABI entry", result.stdout) + + def test_duplicate_entries_are_rejected(self): + valid =3D "EXPORT_SYMBOL vmlinux 0x12345678\tordinary\n" + for old, new in ((valid, valid * 2), (valid * 2, valid)): + with self.subTest(old=3Dold, new=3Dnew): + result =3D self.check(old, new) + self.assertNotEqual(result.returncode, 0, result.stdout) + self.assertIn("duplicate symbol 'ordinary'", result.stdout= ) + + def test_real_generator_output_preserves_namespaced_relocations(self): + symvers =3D ( + "0x12345678\tvmbus_open\tdrivers/hv/hv_vmbus\tEXPORT_SYMBOL\t\= n" + "0x853b6fd2\thv_post_message\tdrivers/hv/hv_vmbus\tEXPORT_SYMB= OL_GPL\tmodule:mshv_vtl\n" + ) + for name, content in (("abi-prev-test", symvers), ("abi-test", symvers.replace("drivers/hv/hv_vmbus", "vmlinux"))): + source =3D self.directory / "Module.symvers" + source.write_text(content) + subprocess.run(["bash", str(GENERATOR), str(source), str(self.directory / name)], check=3DTrue) + old =3D (self.directory / "abi-prev-test").read_text() + new =3D (self.directory / "abi-test").read_text() + result =3D self.check(old, new) + self.assertEqual(result.returncode, 0, result.stdout) + self.assertIn("2 symbols changed location", result.stdout) + + +if __name__ =3D=3D "__main__": + unittest.main() --=20 2.56.0.windows.1 On Fri, 23 Oct 2026 21:58:41 -0700, =E7=B5=90=E5=8F=8B wrote: > This series restores built-in VMBus support for the Proxmox VE installer > in Hyper-V Generation 2 guests. Linux 6.18 split HYPERV_VMBUS out of HYPE= RV; > the existing HYPERV=3Dy override therefore no longer makes hv_vmbus built= in. > The installer takes one snapshot of sysfs modalias paths, so the VMBus > storage children must be enumerated before that snapshot. > > Patch 1 fixes the ABI parser first: three namespaced VMBus exports would > otherwise be reported as missing when moved from hv_vmbus into vmlinux. > Patch 2 enables HYPERV_VMBUS=3Dy. Config-override cleanup and general bui= ld > validation changes are kept in a separate follow-up series. > > Validation of this exact two-commit submission: > - Generated patches apply with git am --whitespace=3Derror-all, with th= e > same resulting tree. Perl syntax and all 12 ABI regression tests pass= . > - Clean complete amd64 make deb succeeds for the fixed and modular > control builds in Debian trixie with rustc 1.94.1 and pahole 1.30. > CONFIG_RUST and BTF are enabled. Both have the same existing lintian > perf-bench man-page warning; no build or lintian errors. > - Strict fresh-build ABI checks (SKIPABI=3D0, empty blacklist) preserve= all > 32,726 symbols, CRCs, export types and namespaces. The fixed build ha= s > only the expected 47 VMBus provider moves into vmlinux. > - Gen2 A/B test: the fresh modular control reproduces ISO-not-found; > the fixed ISO auto-discovers storage on three cold boots, completes > installation, and passes three installed disk-only cold boots. > /init is unchanged and hv_storvsc is not manually preloaded. > - The installed image hash matches the build artifact. Storage I/O, > persistent data across cold boots, SSH/network, ZFS module loading > and PVE services pass on Gen2 and non-Hyper-V QEMU/KVM. > - QEMU/KVM also passes complete installation, two installed cold boots > and installation of the newly built headers and perf packages. > - Hyper-V Gen1 passes complete BIOS installation, two installed cold > boots, persistent disk I/O, networking and ZFS module loading. > - arm64: full native-emulated Debian package build and minimal QEMU > initramfs boot, virtio ext4 I/O and networking pass. > > Validation limits: > - No arm64 Hyper-V host was available. arm64 QEMU tests do not cover > Hyper-V on arm64 or a complete Proxmox VE arm64 installation. > - arm64 QEMU directly boots the verified packaged EFI zboot payload; > the EFI firmware entry path is not tested. There is no previous arm64 > ABI or firmware baseline in this repository, so those comparisons > were skipped by the standard build rules. > - Hyper-V tests used unsigned test kernels with Secure Boot disabled. > > Base: current pve-kernel master at 78f3d3e2f3ce28c51b80919bc3fc35a399ddb3= c7. > Bug: https://bugzilla.proxmox.com/show_bug.cgi?id=3D8027 > > =E7=B5=90=E5=8F=8B (2): > d/scripts: correctly compare namespaced ABI exports > fix #8027: config: enable CONFIG_HYPERV_VMBUS > > .gitignore | 1 + > README | 13 +++ > debian/rules.d/config-common.opts | 1 + > debian/scripts/abi-check | 56 +++++++++--- > debian/tests/test_abi_check.py | 140 ++++++++++++++++++++++++++++++ > 5 files changed, 198 insertions(+), 13 deletions(-) > create mode 100644 debian/tests/test_abi_check.py > > > base-commit: 78f3d3e2f3ce28c51b80919bc3fc35a399ddb3c7 > -- > 2.56.0.windows.1