|
|
Log in / Subscribe / Register

LWN.net Weekly Edition for August 20, 2026

Welcome to the LWN.net Weekly Edition for August 20, 2026

This edition contains the following feature content:

This week's edition also includes these inner pages:

  • Brief items: Brief news items from throughout the community.
  • Announcements: Newsletters, conferences, security updates, patches, and more.

Please enjoy this week's edition, and, as always, thank you for supporting LWN.net.

Comments (none posted)

Debian weighs eight options in vote on LLM usage

By Joe Brockmeier
August 19, 2026

The Debian Project is voting on the usage of large language models (LLMs) to make contributions to the project. The first proposal, sent in late July by Matthias Geiger, would expressly forbid any contributions to Debian that are created by or with the assistance of LLMs. That kicked off a firestorm of discussion and a flood of alternate proposals. Debian developers are now voting on eight proposals in total that range from banning LLM-assisted contributions to explicitly approving them, as well as the standard "none of the above" option that would leave Debian with no agreed policy.

Debian and AI

While other distributions, such as Fedora and Gentoo, have settled their policies regarding AI-assisted contributions, Debian has held off on making a decision—though not for a lack of discussion. The topic has come up several times over the years without any resolution.

In 2024, Tiago Bortoletto Vaz worried that Debian was "already facing negative consequences" due to the use of AI-generated content and wanted to gather input from Debian developers ahead of a possible general resolution (GR) on the topic. The discussion led him to conclude that the project was "far from consensus on an official Debian position" regarding the use of generative AI, and he did not pursue a GR.

In February 2026, Lucas Nussbaum opened another discussion on the topic by proposing that Debian allow AI-assisted contributions. He said that people who admit to using AI were being attacked by "a group of people that vehemently rejects AI", and he wanted to find a middle ground for Debian to move forward. The resulting discussion was, in his words, "generally civilized and interesting", and he thought that a GR might not be needed after all.

It's time

Last month, Geiger decided that one is needed after all. He said that it is "time for Debian to make a statement regarding generative AI and LLM usage". He opted to skip ahead to officially submitting his GR proposal, rather than testing the waters as others had done, because the topic had already been discussed in detail. Once the dam broke, a flood of proposals followed. In total, there are eight proposals for Debian's developers to consider, summarized below, plus "none of the above".

  1. No LLM contributions to Debian via Social Contract. Geiger's option: it would amend Debian's Social Contract to expressly forbid any contributions to Debian created with the use of LLMs or other generative-AI tools. It does not apply to upstream projects that use LLMs or AI-related software (thus, packaging an application for AI-related development would be unaffected).
  2. Allow AI-assisted contributions with conditions. Nussbaum's option: it expressly allows AI-assisted contributions as long as the contributor follows a set of conditions, including assuming full responsibility for technical merit, security, license compliance, etc. It also requests, but does not require, disclosure if "a significant portion of a contribution is generated or substantially assisted by a tool". The form of disclosure is left to the contributor.
  3. Reject LLMs as far as practical, update code of conduct. Proposed by Ian Jackson, this option would amend Debian's code of conduct to forbid the use of LLMs to create "messages to humans" such as bug reports, emails, discussions on Salsa, and even blog posts aggregated on Planet Debian. It requests that contributors "avoid the use of LLMs in their Debian work", but concedes that a complete ban on LLM output is impractical.
  4. Accept AI contributions for Debian-specific work. This option, proposed by Pierre-Elliott Bécue, expressly allows contributions created with or by generative-AI tools, with a set of conditions placing responsibility on the submitter.
  5. Responsible use of generative AI. Under Marc Haber's option, Debian would issue a statement describing its position as neither endorsing or prohibiting the use of generative-AI tools in Debian, and says that use of such tools "is neither exempt from nor subject to special rules beyond the standards already expected of Debian contributors".
  6. A cautious approach to generative AI. Proposed by Tobias Frost: if adopted, the project would issue a statement describing its position on generative AI as encouraging contributors to "avoid the use of generative AI where practical and to prefer human authorship, collaboration, and technical understanding over AI-generated output". However, it does not forbid the use of generative AI, and affirms that the project trusts its developers to uphold Debian's "high quality values".
  7. Debian is created by humans. This proposal, put forward by Gard Spreemann, was inspired by the GCC project's AI policy and the rust-lang/rust policy from the Rust language team. It disallows output of generative-AI tools as direct contributions, but allows contributors to use such tools "as an [assistive] tool to explore, research, analyze, critique, etc."
  8. Avoid the use of LLM: climate destruction is a deal breaker. Holger Levsen's option would have Debian issue a position statement against LLMs on environmental grounds as well as "significant ethical, legal, technical, and social concerns". However, it acknowledges LLM usage can be "hard if not impossible to detect". Therefore, it is a position statement only: there would be no prohibition of LLM usage for Debian contributions.

Debian uses the Condorcet method for voting to find the majority-preferred option, so voters will rank their choices in order of preference rather than needing to choose only one. Because Geiger's option would modify the Social Contract it requires a three-to-one majority to pass.

Discussion

It is difficult these days, if not impossible, to participate in open-source projects without being immersed in the debates about LLM usage. The positions and arguments deployed in Debian's discussion will likely be familiar to most readers. For example, regarding code copyright, Geiger argued that there is "huge uncertainty" about the copyright status of LLM outputs. He failed to see how LLM-generated code could comply with the Debian Free Software Guidelines (DFSG): "If you let a function be generated where you can't be 100% if you don't have any license obligations due to the training data".

Others were not persuaded that LLMs posed a risk to Debian or violated the DFSG. Russ Allbery pointed out that many of Debian's upstream projects, including the kernel, "have decided that none of these concerns matter and they're going to ignore all licensing issues around LLM output". The ship had sailed, he said. Ted Ts'o said that he was "perfectly happy to certify that I believe there is no copyright issue". He argued there was no more copyright uncertainty around LLM output than humans who might write code after searching for examples on Stack Overflow.

Simon Richter said that he expected the US legal system would decide that LLM outputs were "unrelated to training data and not copyrightable". However, he reached that conclusion not based on its legal merits, but because "the expensive lawyers" would be working against a finding that LLM output was not distributable due to copyright problems.

The topic of quality, or lack thereof, was also explored at length. Bécue's first draft of a ballot option, which became "Accept AI contributions for Debian-specific work", originally included specific prohibitions against using an AI assistant to push commits or upload packages. Nussbaum complained that this added arbitrary restrictions against personal workflows. He asked what the problem was with asking a local agent to commit and push to a branch.

In the ensuing back-and-forth, Bécue said that he used LLMs daily, but believed that "the more automated and fast-paced a tool is, the more safety nets are required". He was not arguing that humans don't do low-quality work, but he wanted to prevent automated systems pushing a higher volume of it. Haber responded that people should be able to use LLMs to do low-quality work if they were going to do so anyway:

But why should we not let us be assisted in doing crap if we're going to do crap anyway? Bad people are going to do AI assisted crap, good people are going to produce less crap if they are allowed to use assistance of their choice.

Bécue said that would lead to producing "10 times the crap 10 times faster, which has a significant impact and produces more strain" on the project. In another message, he said that most of the people he knew using generative AI "read less than half the code it writes" and warned that they were already having difficulty in trying to write code on their own.

Matthias Urlichs, however, did not share Bécue's concerns about quality. He said that his own packaging had improved a lot since he started letting an LLM do it, and he doubted that Debian would see 100 times more crap:

Conversely, I can immediately think of a couple of use cases where LLMs would add some tangible value. Like, chasing down reproducible-build failures. Or filter [Intent to Package bugs] for existing software that already does what the new package wants to add. Or help scan packages in the NEW queue. Or help keep our clones of Rust, Go, Python and/or Node packages up to date – which frankly is one of the more tedious and un-rewarding jobs in Debian.

Compilers and calculators

Ts'o commented on the concerns about people who depend on LLMs forgetting how to code. He acknowledged that calculators led to a decline in the number of people who could do math in their heads, and that compilers had definitely led to fewer people who were good at writing assembly language. "But I think it's more about people being less proficient at certain skills that are no longer as important, and less about some more general claim about 'cognitive decline'."

Adrian Bunk brought up the debhelper tool for building Debian packages as an example closer to home for Debian. He said that there was now a clear lack of knowledge among Debian developers about the internals of building Debian packages, which meant that they were "often lost how to debug and fix issues in their packages". Bunk and Ts'o submitted these examples of skill loss as arguments for, not against, the use of LLMs.

However, Bécue remained unconvinced. He replied to Ts'o that his calculator comparison "has some merit, but is not a good one anyway". He worried that people would turn to LLMs without having first developed their ability to think critically about the problems, which left them "both vulnerable to a rug pull, but also to be fed garbage without ever realizing it".

Environmental impact

The environmental impact of LLMs was a dominant theme in the discussion. Bas Wijnen said he could not understand how others could agree that LLMs "destroy our ecosystem" but conclude that it is not a deal-breaker when considering their use. The only response he had seen on that point was that "other activities are also bad (some even worse) for the climate", which he did not see as a reasonable argument.

All of our users live on this planet, so protecting that planet is a matter of life and death for them. In other words, caring about something as big as climate change during our Debian work is not (as was suggested elsewhere in the discussion) a violation of the social contract. On the contrary, I would argue that the social contract requires us to care about climate change and prevent it as much as we can.

Nussbaum replied that he was not dismissing the topic of climate change, but claimed that singling out LLMs "sounds like AI-bashing, not like a well-reasoned discussion about the impact on climate change". He said that Debian could reduce its environmental impact in other ways, such as building fewer packages, stopping large-scale QA efforts that require many rebuilds, and suggested ways Debian could reduce its "travel-induced CO2" by changing how DebConf is organized. "Why would Debian encourage me to travel to India, South Korea, Argentina or Japan for Debconf, but at the same time, decide that it is unacceptable to use AI assistance"?

In a postscript to a message about free-as-in beer LLMs, Ts'o suggested that the concerns about environmental impact were merely "an excuse to justify a position that someone has already has made for other reasons". Didier 'OdyX' Raboud responded that Ts'o's type of argument was "either ill-advised, or in bad faith". His concern was not with ecological impact on a per-query basis, but with the effect of the LLM industry overall:

AI companies are not a mandatory feature of our societies. We don't have to allow AI companies to destroy books to train LLMs [0]. We don't have to allow building datacenters to put strain on local electricity or water networks, or increase the local temperature. In a summer with massive drought and fires burning through Europe and North America, with (public) funding desperately missing in firefighting, climate action, etc, deciding to invest 30 B€ in AI Gigafactories [1] _is_ a choice that we "as a species" are making, and one that I don't think is right at all.

It is unclear whether the dozens of messages exchanged between Debian developers have used more, or less, energy than asking an LLM for help building a package; it is, however, clear that few, if any, minds were changed during the discussion.

Vote

Debian has dealt with divisive decisions before, of course. For instance, the project struggled with the question of choosing a default init system for some time before it was decided by the Debian Technical Committee in February 2014; The topic reared its head again as a GR in October 2014, the outcome of which was that a GR was not required.

The init debate—in the form of "init-system diversity" was rekindled in 2018, and voted on as a GR at the end of 2019. Ultimately, Debian chose systemd with support for exploring other alternatives. While the init debates brought out strong feelings, and words, it does not seem to have dealt great harm to Debian in the long run.

Considering the number of options, and the fact that several are similar in nature, it is difficult to guess which of the proposals is likely to win. If history is any guide, though, the likely outcome is that the project will dust itself off and get back to work after the vote—though the topic may well bubble up again before all is said and done.

The voting period began on August 15, and will run through August 28. While there were quite a few people participating in the discussion, there were far fewer developers who weighed in than likely voters; according to the tally sheet for the vote, more than 130 developers have cast their ballot already out of more than 1,000 eligible voters.

Whatever option wins, one hopes that the project is better for it in the long run.

Comments (148 posted)

Representing Python paths using pathlib

By Jake Edge
August 19, 2026

PyCon US

At the outset of his PyCon US 2026 talk, Trey Hunner said that his goal was for attendees to stop representing filesystem paths as strings and to use pathlib instead. That's kind of a tall order, at least for longtime Python users, since string-based paths have been pervasive—and mostly work. It is that "mostly" part that makes Hunner want to see things change, of course, so he set out to describe a lesser-known corner of the language and to try to change some minds.

Hunner introduced himself as a Python trainer for development teams; he also runs Python Morsels, which is a "weekly skill-building service" for developers of all skill levels. Beyond that, he publishes a newsletter with a weekly Python tip.

Strings and paths

[Trey Hunner]

For most of Python's history, paths have been represented as regular strings, which works and will continue working forever, but there are problems with doing so. Over ten years ago, Python 3.4 introduced pathlib based on PEP 428 ("The pathlib module – object-oriented filesystem paths") in order to clean things up. There are multiple problems he would be describing for string paths: the standard-library alternatives to pathlib are difficult to find and awkward to use, while string paths can lead to bugs and distinguishing paths from other strings can be hard to do.

He turned the clock back to 2016, when many users were still on Python 2.7, to look at what existed in the standard library to work with file paths. There were four modules, os, os.path, glob, and shutil, "that we might have reached for" to deal with paths. shutil has "a bunch of high-level file-related stuff, including seven different functions for copying files and directories". By comparison, glob is simpler, with just glob() and iglob() for doing shell-like pattern matching for path names. os.path is used for "manipulating file paths", including splitting, joining, and querying them.

The story with the os module is more complicated, he said. In his opinion, Python has two "junk drawers" in its standard library: os and sys. os is for things related to the computer and operating system, while sys contains "junk" related to the Python interpreter itself. os has lots of functions for working with paths and files, as well as many that are for other purposes. He briefly listed off more than a dozen file- or path-related functions, but then showed seven slides listing all of the other functions in os—probably around 200 in all (slides, use arrow keys to advance). His point was that it was not easy to find path functions in os, not to mention the others scattered in os.path, glob, and shutil.

But, if paths are just strings, he asked, why can't the string-manipulation functions be used instead of those in os.path? He showed three versions of some code for a Django project that set a variable to the path of the file directory's sibling templates directory. The first:

    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    TEMPLATES_DIR = os.path.join(BASE_DIR, "templates")
and the second:
    BASE_DIR = os.path.abspath(__file__).rsplit("/", maxsplit=2)[0]
    TEMPLATES_DIR = BASE_DIR  + "/templates"
Both need to have imported os.path, naturally. The second works, but is somewhat less readable perhaps; it also suffers from a portability problem, in that Windows uses "\" as its path separator, so it may not work on that kind of path. Importing os allows using os.sep, but even that is not all that readable, he said:
    BASE_DIR = os.path.abspath(__file__).rsplit(os.sep, maxsplit=2)[0]
    TEMPLATES_DIR = BASE_DIR  + os.sep + "templates"
The readability and maintainability of the latter two examples is why the utility functions in os.path were added, he said. Meanwhile, depending on where various parts of the path came from, there may be a mixture of forward and backward slashes in it, which actually works on Windows, but looks pretty strange, he said. (It does not, however, work at all on Linux.)

There is another problem with paths as strings, which is something Hunner calls "stringly typed code". Data that is passed as strings, when a better type exists is stringly typed. He gave an example (which apparently was from last year):

    target = "2025-09-25"

    if target[:4] == "2025":
        print("That's this year")
That works, but it assumes that the string is actually a date in the proper format. Using a datetime object instead leads to a little more code but provides a guarantee that the string is actually a valid date; otherwise strptime() would raise ValueError:
    from datetime import datetime

    user_input = "2025-09-25"
    target = datetime.strptime(user_input, "%Y-%m-%d").date()

    if target.year == 2025:
        print("That's this year")

Hunner argued that using strings to represent paths is stringly typed as well. Returning to his earlier example, he showed how a Path object can change that:

    from pathlib import Path

    BASE_DIR = Path(__file__).resolve().parent.parent
    TEMPLATES_DIR = BASE_DIR / "templates"
As Hunner described later in the talk, the resolve() method turns a Path into an absolute path and the parent attribute resolves to the path of the parent directory. The slash ("/") operator is used to join two paths.

For code that uses type annotations, a Path object provides another benefit: a type checker can spot problems where strings and paths are being confused in the code. Being able to distinguish those uses makes it easier to reason about the code and to catch bugs in it as well.

Meanwhile, the Path version is easier to read than the os.path version he showed earlier:

    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    TEMPLATES_DIR = os.path.join(BASE_DIR, "templates")
In order to understand that first line, he has to read it from right to left, getting the absolute path of the file using abspath(), its parent directory (dirname()), and the parent of that. It uses nested calls, while the Path version chains calls and attributes in a way that reads much more naturally, at least to him.

He showed some examples where Path alternatives are easier to read and use, including replacing the classic with block for reading a file with a one-liner:

    with open("config.txt", mode="rt") as file:
        content = file.read()

    # one line replacement using Path
    content = Path("config.txt").read_text()
Making a directory using the os module means either using mkdir() or makedirs() depending on whether the intermediate directories should be created. For a Path object, the mkdir() method has a parents flag that can be used to create intermediate directories. Likewise, for copying files, the Path object has the copy() and copy_into() methods that were added in Python 3.14; prior to that, four separate functions from shutil could have been used (copyfile(), copy(), copy2(), or copytree()). "I can't tell which of these you need because I don't remember which one does which."

Using pathlib

The pathlib module contains one main thing, Hunner said: the Path object. The Path() constructor takes a string representation of a path and returns a Path object, which will either be a PosixPath or a WindowsPath depending on the underlying operating system. Those two types support all of the same operations and just differ in the way they normalize paths; users should not have to care.

There are a little over two dozen useful methods that can be called on Path objects, six attributes (e.g. name), and two class methods (Path.cwd() for the current working directory and Path.home() for a user's home directory). There are more than 70 attributes and methods, overall, but he only rarely uses the others.

When pathlib was first introduced, users often needed to convert Path objects to strings in order to use them (e.g. open(str(path), ...), but over time more and more of the Python builtins and standard-library modules have added support. "Pretty much every utility in Python that accepts a file path will also accept a Path object", he said. He listed six separate examples and noted that even functions and methods that are explicitly designed to take path strings will also work with Path objects. So, legacy code that still uses the older functions (e.g. os.path.join() or os.mkdir()) will still work correctly when passed a Path object. Beyond that, most third-party packages, such as Django, pandas, and pytest, will accept Path objects. If a third-party package does not accept Path objects, it is probably a bug that should be reported, Hunner said.

The way to start using pathlib is to simply start passing the strings that specify paths to the Path() constructor:

    >>> from pathlib import Path
    >>> notes_path = Path("Documents/notes.txt")
For portability, the forward slash should be used to separate names in string literals, but a WindowsPath will normalize any backslash-separated names as needed.

A Path object can be used to do various things, such as joining it to a file name. That can be done with the joinpath() method or by using the slash operator:

    >>> from pathlib import Path
    >>> home = Path.home()
    >>> path1 = home.joinpath(".config.toml")
    >>> path2 = home / ".config.toml"
The slash operator looked odd to him when he first saw it, but it has grown on him and he now finds it pretty readable. In addition, the constructor accepts multiple arguments (either strings or other Path objects) and joins them together, so:
    >>> path3 = Path(home, ".config.toml")
    >>> path3
    PosixPath('/home/trey/.config.toml')
    >>> path1 == path2 == path3
    True
All three mechanisms are equivalent and none is clearly better than the others, but he said that the third approach is typically only used when it is not known whether the components are strings or Path objects.

Hunner said that he finds the os.path functions to be "unfortunately named", with squished-together, often shortened words, while the equivalents in pathlib are better thought-out. For example, he prefers path.name over using os.path.basename(path) and the same goes for path.parent over os.path.dirname(path). Even more compelling is using path.suffix over os.path.splitext(path)[1]. He noted that there are cheat sheets for pathlib in an article that he wrote and in the Python pathlib documentation.

Inheriting and extending

Since Python 3.12, classes can extend the functionality of pathlib.Path via inheritance. So, for example, a custom Path class could be created that has a method to change directories:

    import os
    import pathlib

    class BetterPath(pathlib.Path):
        def chdir(self):
            os.chdir(self)
Inheriting from Path is not likely to be common, but when it is done, any attributes used by the new class, perhaps for storing metadata, can be propagated to derivative Path objects (e.g. parent) by overriding the with_segments() method in the subclass.

Back in 2016, PEP 519 ("Adding a file system path protocol") was accepted for inclusion into Python 3.6. It described what was needed for an object to be considered "path-like", so it would be accepted anywhere a path string or Path object was expected. Effectively, it explained what kind of quack was needed in order for duck typing to determine that the duck should be treated as a path. It turns out that a class only needs to implement a single method, __fspath__(), which returns a string or bytes representation of the path-like object, in order to quack correctly.

Path-like objects that follow the path protocol will be accepted by open() and other builtins and standard-library functions. In addition, PEP 519 enables third-party path libraries. He thinks that pathlib is great, "but if you don't like it, there's a whole ecosystem of path-like objects beyond just pathlib". He showed a "very silly example" of a path-like class, which did not inherit from Path, that worked with open() and would work anywhere else where a Path can be passed.

Common mistakes

Next he described some of the mistakes that new Path users make. The first is something of a historical accident. When the feature was introduced in Python 3.4, the usual way to open a file using a path was the open() method for Path. When Python 3.6 was released with PEP 519, there was no need to use that method because the open() builtin started accepting path-like objects. Since it is simply historical at this point, he thinks that the open() method for Path should be avoided; "not everyone agrees with that advice, but I'm on the stage so I get to say this", Hunner said to laughter.

Another common mistake is to convert Path objects to strings unnecessarily. For displaying or logging a path, using an f-string implicitly converts the object to a string:

    >>> print(f"Reading: {path}")
    Reading: example.txt
There is no need to do an explicit string conversion of the object for open() or any of the other functions that accept path-like objects. "If you think that you need to convert a path to a string, you probably don't."

Lastly, the flexibility of the Path() constructor means that multiple strings can be joined into a single path by passing them to the constructor. There is no need to create a Path object for one piece and use joinpath() or the slash operator to construct the final path.

There is a persistent, but he thinks mostly unwarranted, complaint: pathlib is slow. "It is true that pathlib can be slower for some operations, but readability is sometimes worth a small performance penalty." He compared the performance of os.walk() with Path.walk() on 400,000 files. The two were roughly the same at just under one second (0.91s for os.walk() versus 0.85s), but he noted that Path.walk() returns strings rather than Path objects. Converting those strings to Path objects made the test take 2.22s.

Most path operations are not done in tight loops, so the penalty of that may not really matter much, he said. Path objects provide more readability, which is also important. "Optimize only when it really matters."

He concluded by noting that pathlib is not simply a different API, it is, instead, an acknowledgment that file paths are "important enough to warrant their own data type". It is meant to make handling path operations easy by representing them properly in the language.

[I would like to thank the Linux Foundation, LWN's travel sponsor, for its assistance with my trip to Long Beach, CA for PyCon US.]

Comments (15 posted)

Bootstrappable builds: how and why

By Jake Edge
August 17, 2026

FOSSY

This year's edition of the Free and Open Source Software Yearly conference, better known as "FOSSY", moved north to the beautiful (and enormous) campus of the University of British Columbia (UBC) in Vancouver, Canada from its home for the three previous editions: Portland, Oregon, in the US. There were many different types of talks at FOSSY, from deeply technical kernel-track topics, through talks on legal and community issues, to the "FOSS in Daily Life" talks. In the "Toolchains and Other Development Tools" track, Timothy Sample gave a presentation about bootstrappable builds, which is somewhat less well-known than its cousin, reproducible builds, though LWN did look at the topic just over two years ago. In short, a bootstrappable build is one that starts with a tiny program that can build another slightly larger program, which can build yet another, and so on, until the entirety of a modern Linux user space is built from a small seed. Ultimately, it results in code with a completely understood origin—unlike a typical Linux user space today.

He began by asking attendees whether they had heard of bootstrappable builds and whether they were generally familiar with the idea; he seemed impressed that the majority knew the term and that roughly half of the audience knew more than that. He said that he embarked on the path toward bootstrappable builds almost ten years ago when he started using GNU Guix (which he pronounced "geeks"—surprising me). At that time, if you were using Guix, you were contributing to it, he said with a chuckle. Guix is a "functional package manager" that is similar to (and inspired by) Nix.

[Timothy Sample]

For both Guix and Nix, all of the software in the system is represented in a "derivation graph", which describes how to build each of its programs. There are various inputs required in order to be able to build a particular program, which are specified in the graph. The way to build each of the inputs (and, of course, the inputs to the inputs and so on) is also represented in the graph. "There's hundreds and hundreds of nodes in modern software, which is terrifyingly complex."

He gave the example of a Python program. It, obviously, requires Python in order to run, but Python is a C program, so a C compiler is needed. That C compiler is written in some language, so a compiler for that language will be needed. And so on. Guix collects all of that into the graph, which is an object that can be looked at and explored. "So you start wondering who compiles my compiler's compiler compiler and where does it stop?"

For a system like Debian, it stops at a C compiler binary that someone has uploaded to the repositories. For Guix, the original stopping point was a 250MB statically linked blob of GNU user-space programs. The answer to where all of that code came from is not entirely clear, of course, which was unsatisfying to Guix developers. That blob could be built reproducibly, which is good, Sample said, but does not solve the entire problem.

Bootstrappable

The basic idea behind bootstrappable builds is to create a system that can be built without relying on pre-built artifacts. "Can we go from zero to the modern day without having to just assume the existence of these already-built-for-us artifacts?" The classic recipe for yogurt requires some yogurt to start the process, which is like how we normally build a C compiler today—we start with an existing C compiler binary. You might think about making sourdough bread with your grandmother's starter brought over from the old country; "we're basically making C compilers with Dennis Ritchie's starter carried over from Bell Labs".

It is not just C, of course, as it is true for most languages. It is something of a point of pride for languages to "self host" by writing the compiler and other tools in the language itself. It is natural for the language developers to do that, because obviously their language is the best, but it leaves something of a chicken-and-egg problem behind. Bootstrappable builds is an effort to move beyond that and to build these tools "from scratch".

Reproducible builds allow people to "have more confidence that the binary you are using, which is actually executing on the computer, corresponds to the source code". A user can receive a binary that purports to come from a set of source code files, but how can they be sure that it does? With a reproducible build, they can create the binary themselves and check to ensure that it is bit-for-bit the same as what they were given.

Bootstrappable builds do exactly the same thing, but they handle a different failure mode. If a reproducible build fails to verify, that's because the person who built the binary is lying or mistaken about where it came from. Bootstrappable builds can prevent the kinds of problems that Ken Thompson described in his famous Turing Award lecture: Reflections on Trusting Trust.

An example that Thompson gave in that lecture asked where in a C compiler you can find the definition of "\n", Sample said. Looking in the source code of the compiler will not show a definition, it will simply provide the circular definition that "\n" is "\n"; the conversion of "\n" to ASCII ten is embodied in the C compiler binary itself. Thompson continued his lecture by noting that something rather more dangerous, such as a backdoor for the login program, could also be hidden in the compiler in the same way.

It is not just C compilers, or even just compilers, that can have this sort of flaw; any self-hosting program can potentially fall prey to it. Programs of this sort can remove details from the source code and have them persist in binary form. As he was preparing for the talk, a colleague pointed him at a recent paper ("Trusting-Trust Attack against an Entire Linux Distribution through Binary Manipulation") that showed an actual attack of this sort. The researchers inserted a backdoor into the strip program on NixOS, which is run on nearly every binary that is built on the system. "They were able to backdoor basically every single program on the system in a way that's completely invisible from source-code analysis." That is the kind of attack that bootstrappable builds is meant to thwart.

While the security angle is the largest benefit of bootstrappable builds, Sample said that there are software-freedom aspects too. Being able to read the source code is useful, but knowing that the source code corresponds to the running program is important as well. There is also a sense of pride that many programmers have in making their code clear and understandable. Ensuring that the code can be inspected and that all of its details exist in some available body of source code is part of that.

The best way to handle bootstrapping is proactively, he said. Before a compiler is self-hosted, it is normally written in some other language; preserving that code and maintaining it alongside the self-hosted version provides a means to ensure that nothing is hidden in the binary. That is what the GNU Guile project does; it is a version of Scheme that is used by Guix and various other projects. Guile still has a C implementation of the language available to use for bootstrapping the compiler. GNU Make has a makefile, of course, but it also has a shell script in case no make is available. "We recognize that we're a fundamental build tool and that there should be another on-ramp here."

For tools that only support a self-hosted build, there are some techniques that he and others in the bootstrappable-builds community use to circumvent that lack. The first is an "archaeological dig", which uses the history of the project to find a non-self-hosted version; that version is built using the tools from that era. "Then you move through history, version after version [...] until you get to the modern tool." Sometimes some of the version steps can be skipped, but overall it is a slow process. "In some ways, it just sort of kicks the can down the road; technically, you do have all of the source code", but asking someone to look at, say, 12 different versions of a tool is rather daunting; it would be nice for there to just be one version to verify.

An audience member asked if this was like using the OCaml version of the Rust compiler to bootstrap to current Rust; Sample said that it was, except that the OCaml Rust compiler is no longer available. Another attendee noted that the Plan 9 C compiler that was used to build the Go programming language is still available, as is the earlier Plan 9 C compiler that built that C compiler. Those kinds of build chains are normal for Guix, Sample said. For Rust, it currently starts with the C++-based mrustc to build Rust version 1.54 or 1.56; modern Rust is 1.97 and nearly every version in between must be built, which is quite slow. When rebuilding a Guix system, Sample said, "it's very depressing when you hit this chain of Rust compiles"; an attendee said it took them three days to build that on their Arm laptop.

The end result of those chains is not all that nice because of the number of steps that need to be verified. An alternative is to "purpose-build a new tool for bringing something up", which is exactly what mrustc is. The result is nicer, with a single code base to inspect, but "it takes forever" to develop a bespoke tool of that sort. He has done some of that and the result is unsatisfying at some level because the tool simply exists to enable another tool to be bootstrapped. Beyond that, the tool will require maintenance to keep up with the target tool, but it is not particularly exciting work that might attract other developers.

The most successful bootstrappable builds use a combination of the two approaches. As with Rust and mrustc, they go back in time to a simpler version that can be built with an alternative bespoke tool, then move forward to the present-day version. In fact, mrustc can now build Rust 1.90, but that has not been integrated into Guix yet; he plans to do so in the near future.

Projects

He returned to Guix and its seed, which is only around 256 bytes these days, rather than the 250MB blob. It consists of a program called hex0, which can "build up through many many layers and eventually gets to GCC 2, GCC 4, and modern GCC, and modern Guile and all these tools". While that's "super cool", there are a lot of caveats; the biggest is that a statically linked Guile is still used "to do a bunch of stuff". That is "absolutely cheating", he said, but there are plans to fix that, which he is working on, but it is going to take some time to achieve.

The other thing that often disappoints people is that there is no answer for how to bootstrap the kernel. Guix assumes there is a kernel; "it'll bootstrap all of userland from nothing, but the kernel is outside of the scope of this discussion".

A related project is live-bootstrap, which works with Guix and uses many of the same tools and approaches; live-bootstrap moves more quickly than Guix, however, and has explored bootstrapping kernels using the Fiwix kernel. Live-bootstrap regenerates any of the machine-created files that might accompany a source release (e.g. configure) as well; it is "very admirable how thoroughgoing they are", but the "downside is it's extremely complicated".

To demonstrate that, he put up the 182-step process to bootstrap the system. It lists tools that need to be built in the order needed to arrive at a base Linux system. It starts with hex0, builds various different tools, including multiple C compilers of increasing complexity, many versions of Perl in order to bootstrap Automake and Autoconf, and so on. It does not include tools like Rust and Go; "it's just the modern GNU/Linux base system".

"It's great that they've done that work, it's pretty wild and complicated, and it would be nice to improve that", Sample said.

The hex0 program provides a way to turn a string of hexadecimal text into a binary with those bytes. Normally, that is used to build hex1 and hex2, which are also hexadecimal converters adding single-character labels (hex1) and more complete labels that allow fancier addressing modes (hex2). Using those, M0 can be built, which allows using assembly mnemonics, rather than hex opcodes.

Sample said that he had omitted a few steps but that eventually M2-Planet can be built, which "is almost like C"; code can be compiled, but sometimes certain C features will be missing so it will need to be rewritten to avoid them. At that point, everything switches over to use GNU Mes, which is a Scheme interpreter written in the M2-Planet dialect of C. Mes has a C library (Meslibc) and a C compiler written in Scheme (MesCC). Those allow building the Tiny C Compiler (TCC), which "is a simple C compiler but much more complete than MesCC". Modern development tools can then be built using TCC.

Germ

That is the path taken by both Guix and live-bootstrap. "It works, [...] but everything is super complicated." He is working on a different approach, called Germ (or Germ Lisp), which is introduced in a blog post on his site. In that post, he pointed out that the existing mechanism goes from C to Scheme and back to C, all to end up in Guix, which is Scheme-based. But, he recognized, that "a primitive Lisp interpreter is not much more complicated than a primitive assembler."

He works on Mes and likes it; "sometimes I get paid to work on Mes, Mes is great". But he is also writing a Mes replacement, which is not all that uncommon. There are Mes replacements being written in Haskell and ML, for example; everyone who looks at the problem immediately wants to write the replacement in Forth, he said. Bootstrapping Forth via a hex monitor is an obvious use of the language, but most developers do not want write the rest of the code in Forth, he thinks; "I would rather read the binary". From the audience, Keith Packard said: "Assembly is easier to write than Forth."

Scheme folks are different, Sample said, and are willing to write code in that language. The intent of Germ is jump over all of the intermediate steps and have a Scheme interpreter from the start. "It just says: 'Scheme, go!', well it has two stages, but almost 'Scheme, go!'." It is how Mes was designed originally, he said; it took some shortcuts that allowed it to succeed early, "but now it's getting stuck".

Germ is about 2.25KB; he wanted it to be 2KB, but missed that goal by a little. It is a binary that "can run almost-Scheme"; it is just enough Scheme that it can run an assembler written in Scheme. That assembler is used to build the second stage, which is "kind of just like a Scheme interpreter". It has contiguous bytes and vectors, features for I/O and working with the kernel, and it will almost run unmodified Guix build scripts (there are still a few dangling items to fully make that work). It uses MesCC to compile C code and has a Scheme shell that he wrote years ago for handling shell scripts; "eventually it'll run awk scripts and sed scripts".

Sample said that attendees might be expecting a demo at that point in his talk, but that he had been giving one throughout, as his slides were running on his laptop using Germ. He added an interface to SDL, provided a "draw pixel" function for Germ, and loaded in the font information. As was guessed by an audience member (winning the 1000-nerd-point prize), the font he used was from the original Symbolics Lisp machine.

He took a brief tour of the Germ code, showing the Scheme-based assembly (like that in memory.scm), while noting that he maintains a regular assembly version (memory.s) in parallel. There is a practical side to that choice, as well, since by using a real assembler "you get debugging symbols and everything, with the other one you most certainly don't", he said with a laugh.

Overall, Germ hits his goals well. It quickly rises to a high level of abstraction that exactly fits the Guix use case. All of the Guix build scripts are written in Scheme; Guix avoids using shell scripts for the most part.

It's conceptually simple. Now I know not everyone loves Lisp or Scheme—somehow it's controversial—but regular old, plain Scheme has got to be better than this tower of bespoke assemblers and compilers for languages that don't quite exist.

That statement was met with some laughter from the audience as might be guessed—Lisp/Scheme are controversial and somewhat divisive, after all. The biggest problem that Germ faces is not surprising, he said: performance. He is writing a Scheme in the same way that the original Lisp interpreters were written in the 1950s, using assembly language. "I can't bring to bear all of the modern techniques because writing in assembly is hard and keeping things small is hard."

Germ is "faster than Mes, technically", at least on a micro-benchmark of making function calls. But whenever a real program is being run, Mes is much faster because nearly everything in Germ runs in Scheme (e.g. loops). For a comparison, it takes about 100 seconds for Mes to compile itself on his desktop, or 60 seconds if the experimental bytecode compiler is used. Compiling Mes on Germ, with a bunch of optimizations that he is testing enabled, takes around 140-150 seconds. The problem with that is that Mes is "unbearably slow", so being worse than Mes is something of a non-starter.

In addition, Germ is less portable than Mes, which can run on Arm and RISC-V, while Germ is x86_64-only at this point. Another problem Germ faces is that "people just hate parens", which is irrational, but he can relate because he was one of the haters until he ran into Guix. Scheme is a relatively easy language to implement, though, and, since it meshes well with Guix, makes a lot of sense for bootstrapping.

Future

Looking ahead, he would like to integrate Germ with Guix "in a way that's exciting for everyone". Currently, Guix depends on %bootstrap-guile, which is the statically linked Guile binary, but Germ could potentially replace that; it could also be replaced with Mes, but either way would be a nice step forward.

He would also like to work on the performance of Germ; moving some of the looping constructs into the assembly code is some low-hanging fruit. "That feels like band-aids", however, and he wonders if he should simply write a compiler; there is a need for a compiler backend for C, so maybe the two could be combined. He has some starting work toward a RISC-V port that he would like to finish as well.

He ended the talk there, but there was lively Q&A session after that. Packard asked how much of Scheme was implemented in Germ; was it R5RS compliant, for example? Sample said that it is a Guile Scheme, but does not have extras like the Guile Object Oriented Programming System (GOOPS); it is effectively an R7RS Scheme, but he took some shortcuts like removing floating-point numbers since he does not need them.

Mark Wielaard asked how many of the 182 steps were removed by this work. Sample said that in his "dreaming mind", Germ would serve as a wedge that others would use to create Scheme-based shortcuts to remove some of the long chains of builds (e.g. Perl and autoconf) and reduce the problem further. He acknowledged Wielaard's estimate of more than 80 steps still remaining; Wielaard pointed out that someone could sabotage step 73 and it is likely that it would go unnoticed. Sample agreed that it was a known flaw in the approach, but that the number of steps was being reduced to slowly improve the ability to verify everything.

The seed could be smaller than the 2.25KB if he wanted, an attendee said. He agreed and noted that he could simply use hex0 to load the first stage of Germ, but "I don't want to play games, I want to actually get results". He did not want to start any fights and respected those who use hex0, but it feels a bit like cheating to him.

The final question was whether Germ had a read-eval-print loop (REPL); the answer was yes, of course, since he had been displaying his slides using it. He showed the REPL and his use of the (next-slide) and (prev-slide) functions; he also demonstrated that it gives a backtrace on errors. "I program in this all the time, it can't be driving me crazy; it has to have a few creature comforts." He took some shortcuts (e.g. no floating-point numbers), but it has some extras too, such as delimited continuations.

He closed by noting that Germ has "the fanciest macros", including a working syntax-case form. He had to implement that himself, since, ironically, there is no bootstrappable syntax-case—it is written using syntax-case.

[I would like to thank the Linux Foundation, LWN's travel sponsor, for helping with my travel expenses to Vancouver for FOSSY.]

Comments (15 posted)

Fedora prepares for the end of AF_ALG

By Joe Brockmeier
August 18, 2026

The Linux kernel's user-space interface (AF_ALG) to the Crypto API has been linked to a number of recent high-profile security problems, including Copy Fail and successor vulnerabilities. It was deprecated earlier this year. Eric Biggers, and other kernel developers, have been working to remove it from the kernel. With that in mind, the Fedora Project is planning to restrict use of AF_ALG in the next Fedora release in the hopes of nudging remaining users of the API to prepare for its eventual removal.

Goodbye AF_ALG

Allowing user space programs to request crypto operations from the kernel was both popular and controversial when AF_ALG was added by crypto subsystem maintainer Herbert Xu in 2010. Xu designed AF_ALG to allow user-space programs access to hardware cryptographic accelerators in order to provide performance gains.

Some, however, were unconvinced that this was a good idea. Christoph Hellwig, for example, said that it was computationally intensive code that had "no business in kernel space unless absolutely required (e.g. for kernel consumers)". He added that CPUs were gaining "proper instructions" for cryptography, which made providing a user-space API even less useful.

In hindsight, it turns out that adding AF_ALG was a bad idea—but not, necessarily, for the reasons that its critics expressed at the time. The reason that kernel developers are now working to get rid of AF_ALG is that it has proven to be not only unnecessary, but a regular source of kernel vulnerabilities as well, as Biggers pointed out in his patch documenting the deprecation of AF_ALG.

AF_ALG is almost completely unnecessary, and it exposes a massive attack surface that hasn't been standing up to modern vulnerability discovery tools. [...]

This isn't sustainable, especially as LLMs have accelerated the rate the vulnerabilities are coming in. The effort that is being put into this thing is vastly disproportional to the few programs that actually use it, and those programs would be better served by userspace code anyway.

The time has clearly come to rid the kernel of AF_ALG, but kernel developers have to be cautious about ripping it out to avoid disrupting user-space programs that have come to rely on it.

One of the popular user-space programs that makes use of AF_ALG is the cryptsetup utility, which is used to set up disk encryption, such as LUKS volumes, using dm-crypt. The project pointed out that AF_ALG had been deprecated in its release notes for cryptsetup 2.8.7.

The release notes state that cryptsetup would be able to use a user-space crypto library in lieu of AF_ALG if it was not present, though some methods would require root access. Users were warned that the absence of AF_ALG "could cause severe compatibility issues if the required algorithm (or encryption mode) is not implemented in the userspace library". The Serpent and Twofish ciphers are specifically mentioned as missing from several user-space libraries.

Christoph Anton Mitterer had spotted the warning when cryptosetup 2.8.7-rc1 was published. He raised his hand on the linux-crypto mailing list, on July 8, to ask about potential fallout from the deprecation of AF_ALG. Mitterer said that he did use those ciphers and "it would really be quite unfortunate if sooner or later I couldn't use them". He asked if anything was being done to ensure that those would remain available.

Biggers replied that Mitterer might have gotten the wrong impression from the cryptsetup release notes. The things that had been removed from AF_ALG so far, zero-copy and async-execution support, should have no impact on cryptsetup. "There are indeed more people turning off AF_ALG in their kernels now; however, general-purpose distros aren't doing that." That statement was true in July, but it will not be true much longer.

General purpose distributions are doing that

Justin Forbes and Peter Robinson put forward the "Disable in Kernel Crypto Userspace API (Phase 1)" change proposal for Fedora 45, which was announced by Aoife Moloney on July 22. The proposal notes that AF_ALG is deprecated in the kernel "with some parts of it being actively removed early in the 7.2 cycle" due to security risks. It recommends restricting AF_ALG's use in the Fedora 45 release "so we can do a controlled ending of support". Change proposals are expected to identify the impact that a change would have on the distribution—the proposal says that there are not many Fedora packages that are known users of AF_ALG, "so the impact should be minimal".

The proposal does identify a few known users of AF_ALG in Fedora, however: cryptsetup, the iNet Wireless Daemon (iwd), and the Linux kernel crypto API user-space interface library (libkcapi), which is used by dracut. It says that those users are unaffected by the change, though there may be third-party packages that use AF_ALG. In that case, it makes sense to identify them now so that they can be modified before AF_ALG goes away entirely.

The first phase uses the upstream patches due to land shortly, likely in 7.3, to limit the use of the API to the known apps and restricts the use. This allows Fedora to identify unknown users and gracefully deal with them before the active demise of the interface upstream providing users a more graceful process rather than universally pulling the rug without any notice.

The upstream patch being referred to is not identified, but it seems to be the one posted by Biggers on June 22, and applied by Xu on July 5. Biggers added a sysctl knob, af_alg_restrict, with three possible settings for AF_ALG: a zero for unrestricted, one for limited functionality, or two for completely disabled.

Beginning with Linux 7.3 the default value will be set to 1: that will enable a limited algorithm allowlist for unprivileged processes such as iwd, bluez, and iproute2, and a longer one for privileged processes. He said that "common use cases such as iwd and bluez [Bluetooth] are taken into account already", and he had verified that iwd still worked with the new default setting.

The contingency plan for the Fedora change proposal is to re-enable AF_ALG before Fedora 45 is released if it is found to cause too many problems. The presumption is that Fedora users will not notice.

Discussion

During the discussion on the Fedora devel mailing list, Ondrej Kozina said that he did not understand why the change was needed, given that AF_ALG was already being removed from the kernel.

Robinson replied that there were a few reasons for the change. One was to communicate the coming removal of AF_ALG so that Fedora users were aware; the other was to ensure that the breaking change was made on a release boundary rather than in the middle of a release cycle, since Fedora 45 will ship with the 7.2 kernel and then move to the 7.3 kernel once it is released. "We don't want the upstream patches heading to 7.3 to suddenly break users [systems] mid-release when upstream yanks whatever rug they choose whenever they choose. It doesn't make for a good user experience does it?"

That did not quite satisfy Kozina, who argued against turning off AF_ALG without a replacement. He complained, for example, that cryptsetup would require users to have CAP_SYS_ADMIN for use with some of the ciphers, and that Fedora would have limited support for TrueCrypt and VeraCrypt containers. Robinson pointed out that many of the use cases identified by Kozina were not present in Fedora itself. "I believe these would only be used if a user when out of their way to use those, generally via a manual install process." He reiterated that AF_ALG is going away "whether we like it or not" and the idea was to get Fedora users ready ahead of time.

Barry Scott said that he had a LUKS 2 vault on a Raspberry Pi 4 he had configured "with advice from the *internet*" using a cipher that would be affected by the AF_ALG restrictions. "Clearly I will have to migrate to a supported cipher before upgrading to f45." Robinson observed that "the internet wasn't entirely correct", and said that Scott would need to migrate to a different cipher "before long", but not for Fedora 45.

Ian McInerney wondered what this meant for Fedora 44, which was released in April. "Since this change is targeted at F45 and kernel 7.2, does this mean that F44 will not get kernel 7.2 released to it and stay on kernel 7.1?" Forbes replied that he had a method for adding or removing patches for specific Fedora releases, so Fedora 44 would still get 7.2 without the AF_ALG restriction patch.

The Fedora Engineering Steering Committee (FESCo) discussed the change in a ticket and voted to approve the change with five in favor of the change, and no votes against. The beta release for Fedora 45 is scheduled for September 15. It will be interesting to see whether restricting AF_ALG causes many problems for Fedora users, or if its phase out will be relatively uneventful.

Comments (5 posted)

128-Bit page tables for Arm

By Jonathan Corbet
August 13, 2026
The size of a processor's page-table entries directly limits how much physical memory that processor is able to access. Back in the 32-bit days, that limit was 4GB, an amount of memory that once seemed nearly infinite, but which would now struggle to hold a basic AI-enabled "hello world" app. The expansion to 64 bits on most popular architectures would seem to have removed those limits now; some Arm systems, for example, can use 56 of those bits to access up to 72PB of memory. So it might be surprising that the Arm architecture is evolving to support even larger page-table entries (PTEs). This patch set from Anshuman Khandual adds support for 128-bit PTEs, but who will benefit from this capability is not entirely clear.

The information of most interest in a PTE is a physical address — the address of the actual memory for bottom-level entries, or the address of the next table for higher levels. Not all of the bits in the PTE hold that address, though; if nothing else, the lowest bits, which correspond to the offset within the page in a virtual address, can be used for other purposes. Our article "On pages and folios" describes PTE entries in some detail; this diagram, showing how a 64-bit PTE might be divided, is taken from that article:

[Simple address
structure]

On a modern, 64-bit Arm system configured for 56-bit addresses and 4096-byte pages, a maximum of 44 bits of the PTE can be used to represent the physical address of a page in memory, while 12 bits are available for housekeeping purposes.

Expanding a PTE to 128 bits obviously makes it possible to store more information in that entry, but at a cost: doubling the size of PTEs will, clearly, double the size of the page tables. For some workloads, page tables already occupy more memory than users would like; every page occupied by a page table is unavailable for use by the system's workloads. Since one page can only hold half as many PTEs as before, there are implications for huge pages; a 2MB PMD-level huge page on a 64-bit-PTE system drops to 1MB when PTEs grow to 128 bits, and PUD-level huge pages shrink from 1GB to 256MB — a factor of four, since there are two levels of page tables that are eliminated for those pages. The sizes of multi-size transparent huge pages that can be coalesced for faster translation lookaside buffer (TLB) access also drop by similar factors. For workloads that are heavily dependent on huge pages for performance, those reductions could prove painful.

Given that there are clear costs involved with going to larger PTE sizes, one would expect that there would be gains in other areas; otherwise, there would be little point in making the change. To understand those gains, it is worth looking more closely at the new format. The details of what 128-bit Arm PTEs look like can be seen on this page; the bottom-level PTE format looks like this:

[128-bit PTE format]

One thing that jumps out immediately is that the address portion of the PTE, stretching from bits 12 to 55, is only 44 bits in length. Add in the 12 offset bits, and the maximum address size is 56 bits, the same that is currently possible with 64-bit PTEs. So expanding the range of physical memory that can be addressed is not an immediate goal of this change. That said, it is worth noting all of the reserved bits — the bits shown in gray and without labels. There are 35 reserved bits above the most-significant address bit, leaving quite a bit of room for future expansion of the address field.

There are ten bits of the PTE that are not interpreted by the hardware at all; they are reserved for software use. That is double the five bits that are available on Arm systems with 64-bit PTEs. Five extra bits may not seem like a lot, but the kernel should eventually be able to make good use of them for memory management.

Bits 109 and 110 are the "skip level" (SKL) field. This field, which is present at all page-table levels, controls how the page-table-traversal process works. On most systems, the page-table hierarchy is rigid, with the expected number of levels (usually between three and five) always present. The one exception is for huge pages, where one or more levels are removed at the end of the search. Consider the PMD, which sits one level above the final page-table level; one entry in the PMD points to an entire page of PTEs, and covers (typically) 2MB of address space. By setting a bit in the PMD entry, though, the kernel can indicate that the entire 2MB has been assigned in a single page — a PMD-level huge page.

The SKL field generalizes this mechanism somewhat; it can indicate that the following step in the lookup process is a huge page, even if it is another level in the page-table hierarchy rather than the final step. That feature would appear to open the door to using huge pages for the page tables themselves, which would have the potential of speeding address translation and reducing TLB use.

The kernel changes required to support 128-bit PTEs are relatively small, consisting mostly of a set of macro definitions describing where the various fields and bits are. The most disruptive part has to do with page-table manipulation. When working through entries at various levels of the page-table hierarchy, it is important to read them atomically, so that the entire entry is coherent. That reading is done with READ_ONCE() in current kernels, but READ_ONCE() depends on atomic operations, and Arm CPUs do not have 128-bit atomic operations. Similar concerns apply to the modification of PTEs as well. The patch series wraps these accesses with a new pair of functions (ptval_get() and ptval_set()) that default to READ_ONCE() and WRITE_ONCE(), but which can be overridden by the architecture if need be. For Arm systems built for 128-bit PTEs, those functions are implemented with atomic ldp and stp (load-pair and set-pair) instructions.

In the current implementation, at least, the kernel must be specifically built for 128-bit PTEs, and kernels built that way will be unable to boot on CPUs that do not support that PTE size. That will make life harder for distributors; they have strong incentives to keep the number of kernels they build to a minimum. Fixing this problem will almost certainly involve a fair amount of boot-time code patching, but that may be required before distributors will consider enabling support for the larger PTEs.

This series has been through a few RFC iterations and appears to be stabilizing somewhat. Of course, relatively few people have hardware that supports 128-bit PTEs, so the amount of in-the-field testing of this work is necessarily limited. By the time that hardware becomes more widely available, though, Linux may well be ready to support it. But, in the short term, it is not at all clear that many systems will benefit from making use of this feature.

Comments (8 posted)

BPF, continuous testing, and stable kernels

By Daroc Alden
August 14, 2026

LSFMM+BPF

Ihor Solodrai and Shung-Hsi Yu wrapped up the BPF track at the 2026 Linux Storage, Filesystem, Memory-Management, and BPF Summit with a pair of sessions related to testing. Solodrai spoke about what has changed for BPF's continuous-integration (CI) testing. Yu spoke about what may be needed to test BPF updates in stable kernels more thoroughly. The BPF subsystem's CI tests are in a good place, they said; even so, Solodrai and Yu have a handful of possible avenues toward enabling better test coverage in the future.

BPF CI

Since last year, Solodrai has made several improvements to the BPF-CI infrastructure, which he maintains. He particularly wanted to discuss LLM-powered reviews, additional test workflows, and some updates he has made to the test infrastructure. LLM review is something that Solodrai had been looking into before Sashiko showed that it could work. He ended up producing his own independent implementation of the idea. The BPF-CI infrastructure uses Chris Mason's review prompts, semantic search, the Lore mailing-list archives, and the kernel source tree to produce reviews about BPF changes. The reviews are triggered via GitHub actions — making a pull request to the GitHub mirror of the BPF tree will produce, a while later, a comment on it with a review from the LLM.

At first, Solodrai didn't know whether this sort of thing would be useful. It turns out that "everyone is excited about AI reviews right now", so it does seem to be. Sashiko, with a dedicated development team rather than just Solodrai, is a more powerful tool, so he's considering turning off the BPF-CI-LLM reviews. He intends to keep them for now because they use a different LLM provider (Anthropic, rather than Sashiko's use of Google) and so produce a slightly different flavor of review. He has also been using LLMs to investigate and report on flaky tests, so that he does not need to investigate all of the failures himself.

The conventional test coverage has been expanded too. The user-space portions of the BPF self tests now run with address sanitization (ASAN) enabled. That was supposed to catch bugs in libbpf, but has mostly caught bugs in the tests themselves so far, which is still useful. Veristat, a tool in the kernel tree that measures how long it takes to load BPF programs, is now run on an expanded corpus of programs to catch performance regressions in the verifier.

Previously, the tests only ran against the BPF trees. Now, they also run against linux-next, which should help catch integration problems earlier. The self tests now run using both GCC and Clang. It used to be that they were compiled with both, but only the Clang-compiled tests were run. Now, the output of both compilers is run. That testing is still new and will possibly need more development, but Solodrai expects it to be useful.

The underlying CI-test infrastructure has seen some updates, mostly moving from Ubuntu to Debian, although some Ubuntu hosts remain. The test machines now use GCC 15.x and Clang 21.x, upgraded from GCC 14 and Clang 19. Solodrai wishes that the change in compiler versions was too trivial to mention, but it was a substantial amount of work. Soon, he hopes to upgrade to GCC 16 and Clang 22.

Alongside all of this good news, he does have some continuing complaints. Anthropic, GitHub, the Ubuntu repositories, and even git.kernel.org are all prone to going down. When he began working on CI infrastructure, failures were usually his fault. Now, they're mostly the fault of the external services he depends on, which is frustrating. "Software is less reliable these days — and I wonder what the reason for that is — but if you have influence over any of these companies, please make them more reliable."

He then asked the assembled developers what else should be tested in CI. Amery Hung had suggested to him having a dashboard that shows failures and successes by test case, instead of by build, he said. Everyone else was fairly happy with the state of the test infrastructure, although someone suggested that getting earlier access to the LLM-powered reviews would be nice.

That triggered a long discussion about the differences between the BPF-CI-LLM reviews and Sashiko. One advantage of the former is that it can search the mailing list archives for context; someone suggested bringing that idea to Sashiko developer Roman Gushchin. Even with that difference eliminated, the BPF developers still thought that having multiple independent reviews was helpful for catching subtle problems.

Stable kernels

Stable releases of the Linux kernel are put together using patches manually marked for backporting or picked up by the AUTOSEL patch-selection tool. The problem, Yu explained, is that AUTOSEL does not run the BPF self tests. When determining whether a patch ought to be backported, AUTOSEL checks whether it applies cleanly, but that is not enough to be sure that the verifier continues working as intended.

Last year, Yu proposed to fix this, and Solodrai helped by providing access to the existing self tests, so that Yu could duplicate the setup. Now, he has the self tests running against several different stable trees, and can share what the additional coverage has caught.

Most of the failures are noise, he said, especially from tests that are just wrong for the backported code. For example, just prior to the session he had sent a revert to back out a change that added a new test using a helper that wasn't present in the 6.6 kernel. Sometimes the failures are more subtle; one backported test set the network's maximum transfer unit to ten bytes, which is fine inside a network namespace, but on sufficiently old kernels it was affecting the root namespace, causing many downstream failures.

Build failures are more annoying, but are mostly a case of needing to backport additional patches that were missed. The testing has caught more complicated problems, too. It found a kernel panic caused by mistakenly assuming that a pointer in a struct_ops structure was valid, for example. Still, when Yu began this work he was hoping to catch more real regressions. The most useful way to make sure that regressions are caught is to backport the tests alongside any backported changes, he said.

Daniel Borkmann wanted to know how often Yu was running the tests. He answered that they run in the morning every day so that he can look at them when he wakes up. Borkmann asked whether there was a path to having the stable tests run as part of the main BPF-CI test suite. Yu didn't think that it was impossible, but he did note that he was doing things in a slightly different way — rather than running on every change, his tests just pull whatever is in the stable tree when they run. It's not as fast as watching the mailing list might be, he said, but it still usually lets him finish a complete test run before Greg Kroah-Hartman makes a stable release candidate. He does think that it's useful to have the stable testing separate from the main BPF-CI infrastructure.

Solodrai wanted to know how often Yu had to backport a test or examine a test failure on a stable branch. Yu is currently testing against three stable branches, and he sees something break about once a month. Not a huge amount, but it does need someone to maintain it, Yu said.

There is, of course, more to be done. More self tests should be backported, Yu said, and the testing should probably also include running on different architectures. It may even be possible to run the self tests from the BPF development tree on stable kernels, if a list of known-bad tests could be maintained. Either way, the kernel's BPF code is receiving more automated testing and scrutiny than ever. With so many exciting new features discussed throughout the summit, it's good to know that the tests are keeping pace.

Comments (10 posted)

Development statistics for the 7.2 kernel

By Jonathan Corbet
August 17, 2026
Linus Torvalds released the 7.2 kernel on August 17, after noting that the number of fixes coming in was still "bigger than I would have wished for". In fact, 7.2 was one of the busiest development cycles in the kernel's history, adding nearly 600,000 lines of code. It's time to look at some statistics to get a handle on how the kernel's development community is changing.

There were 16,418 non-merge commits brought into the mainline for the 7.2 release, exceeding the (already busy) 7.1 release; it is, in fact, the second-busiest release in the kernel's history. Only the 6.7 release brought in more commits but, while 6.7 was dominated by the merging of the bcachefs development history, the volume for 7.2 is more broad-based.

These commits were contributed by 2,652 developers, a big increase over the previous record (2,479 in 7.1). If one looks at the history of developer involvement since the beginning of the Git era, the result is:

[Line plot of
	developers per release]

(This plot, like much of the information here, comes from the subscriber-only LWN Kernel Source Database). There has been a clear trend over that entire history: the number of developers contributing to each release increases over time. But the slope of that line has clearly changed.

The most active developers working on 7.2 were:

Most active 7.2 developers
By changesets
Uwe Kleine-König 1510.9%
Rosen Penev 1460.9%
Ian Rogers 1380.8%
Johan Hovold 1330.8%
Arnaldo Carvalho de Melo 1310.8%
Chuck Lever 1290.8%
Eric Dumazet 1210.7%
Ville Syrjälä 1150.7%
Johannes Berg 1120.7%
Krzysztof Kozlowski 1100.7%
Thorsten Blum 1080.7%
Namjae Jeon 1060.6%
Christoph Hellwig 1040.6%
Sean Christopherson 1000.6%
Jakub Kicinski 960.6%
SJ Park 940.6%
Mike Rapoport 910.6%
Dmitry Baryshkov 870.5%
Eric Biggers 860.5%
Rafael J. Wysocki 780.5%
By changed lines
Matthew Stewart 835878.4%
Hawking Zhang 628936.3%
Miguel Ojeda 389793.9%
Ian Rogers 319493.2%
Darren Ye 208432.1%
Ethan Nelson-Moore 168931.7%
Harry Wentland 152331.5%
Uwe Kleine-König 138031.4%
Ingo Molnar 136491.4%
Chuck Lever 101721.0%
Eric Biggers 100671.0%
Jakub Kicinski 94490.9%
Rodrigo Siqueira 77490.8%
Johannes Berg 71100.7%
Arnd Bergmann 70850.7%
Emil Tsalapatis 68100.7%
Vivek Aknurwar 65440.7%
Rob Clark 64900.6%
Sabrina Dubroca 64010.6%
Svyatoslav Ryhel 60720.6%

Uwe Kleine-König [KSDB] was the biggest contributor of commits to the 7.2 release with cleanups through the driver subsystem. Rosen Penev [KSDB] contributed a long list of LLM-authored bug fixes throughout the architecture-specific, driver, networking, and crypto subsystems, among others. Ian Rogers [KSDB] worked extensively on the user-space perf tool, as did Arnaldo Carvalho de Melo [KSDB]. Johan Hovold [KSDB] made numerous improvements, mostly in the SPI and USB subsystems.

Matthew Stewart [KSDB] reached the top of the lines-changed column by following the time-honored tradition of adding more massive, machine-generated amdgpu header files; Hawking Zhang [KSDB] did likewise. Miguel Ojeda [KSDB] brought the Rust zerocopy crate into the kernel source. Darren Ye [KSDB] added the MediaTek mt8196 sound driver.

Just over 8% of the commits in 7.2 carried Tested-by tags, while 48% included Reviewed-by tags. The review tags, in particular, are showing a mild downward trend in recent releases:

[Reviewed-by tags per
release]

Whether that decline reflects an actual decrease in the amount of review taking place is unclear at best. In any case the most active testers and reviews for this cycle were:

Test and review credits in 7.2
Tested-by
Dan Wheeler 1177.0%
Luiz Capitulino 543.2%
James Clark 442.6%
Sarthak Sharma 442.6%
Venkat Rao Bagalkote 321.9%
Tommaso Merciai 271.6%
David Riley 271.6%
Jie Gan 271.6%
Geert Uytterhoeven 251.5%
Arthur Kiyanovski 251.5%
Marek Szyprowski 251.5%
Randy Dunlap 241.4%
Shivaprasad G Bhat 241.4%
Rinitha S 211.3%
Vitaly Prosyak 201.2%
Reviewed-by
Konrad Dybcio 2312.2%
Dmitry Baryshkov 2252.1%
Andy Shevchenko 1751.7%
Geert Uytterhoeven 1711.6%
Krzysztof Kozlowski 1521.5%
Frank Li 1471.4%
Ilpo Järvinen 1451.4%
Christoph Hellwig 1431.4%
Jan Kara 1211.2%
Christian König 1201.1%
Linus Walleij 1161.1%
Alex Deucher 1051.0%
Simon Horman 1021.0%
Jeff Layton 1011.0%
Ido Schimmel 940.9%

Dan Wheeler [KSDB] is, as always, the top tester by virtue of his work with AMD graphics-driver patches. On the review side, Konrad Dybcio [KSDB] added his tag to 231 changes while Dmitry Baryshkov [KSDB] tagged 225; the same two, who both tend to focus on drivers and devicetree files for Qualcomm devices, were at the top of that list for the 7.1 cycle as well.

Work on the 7.2 kernel was supported by 249 employers that we were able to identify; the most active of those were:

Most active 7.2 employers
By changesets
(Unknown)274316.7%
Intel15129.2%
Google11917.3%
Red Hat8735.3%
AMD8135.0%
Qualcomm7674.7%
(None)7434.5%
NVIDIA5353.3%
Meta4412.7%
(Consultant)4292.6%
SUSE3582.2%
Renesas Electronics3282.0%
IBM3071.9%
Kylin2781.7%
NXP Semiconductors2641.6%
Oracle2451.5%
Arm2221.4%
BayLibre2031.2%
Microsoft2011.2%
Bootlin1941.2%
By lines changed
AMD22412122.4%
(Unknown)10386110.4%
Google10256510.3%
Qualcomm590215.9%
Intel536615.4%
Red Hat515595.2%
Meta386353.9%
(None)282182.8%
NVIDIA274172.7%
MediaTek220252.2%
NXP Semiconductors176921.8%
BayLibre159721.6%
Oracle122331.2%
Microsoft117861.2%
Renesas Electronics111031.1%
Linaro102091.0%
(Consultant)93620.9%
IBM92050.9%
Texas Instruments83980.8%
SUSE83500.8%

The most significant change this time around, arguably, is the significant increase in developers with unknown affiliation. This is partially, at least, a reflection of the ongoing flood of new developers entering the kernel community.

New developers and their tools

Each of the previous two kernel releases had set a record for the number of first-time developers contributing changes; 7.2 has broken that record again, with 613 contributors [KSDB] who had not been seen here before. Here, once again, the trend is clear:

[First-time developers by
release]

The most active new developer was Bryam Vargas [KSDB], who contributed 43 commits fixing problems in the input, NVMe, F2FS, AppArmor, Landlock, SELinux, NTFS, WiFi, ATA, SCSI, networking, Ceph, and Thunderbolt subsystems, among others. As has been observed here before, it would be difficult for a seasoned kernel developer to reach deeply into that many subsystems over the course of a single development cycle — at least, if they wanted to understand what they are doing. For a previously unknown developer to do this is surprising at best. Vargas's patches do not carry Assisted-by tags, though, so we are left to believe that this work was done without LLM assistance.

Overall, 1,111 changes in 7.2 (under 7% of the total) carried Assisted-by tags — a significant increase over the 301 seen in 7.1. The real count of LLM-assisted patches in 7.2 must surely be far higher than that, though. Many developers do not supply those tags (often — but not always — out of ignorance of the rules), maintainers rarely ask about LLM use, and at least one maintainer actively strips those tags when applying patches. Accurately tracking commits developed with LLM assistance may turn out not to be possible, but it sometimes feels like the kernel community does not care enough to really try.

The other way in which LLM usage is making itself felt in kernel development is in the area of patch review. There are 252 patches in 7.2 with Reported-by tags crediting the Sashiko review system [KSDB]; 568 commits mention Sashiko in their changelogs. Other LLMs are also clearly being used to find kernel bugs, though, with real effects.

The 7.2 release contains 4,830 commits with Fixes tags, indicating that they fix a bug introduced by a previous commit. To see just how significant an increase is, consider this plot, an updated version of one that has been seen here before (most recently for the 6.17 development cycle):

[Fixes tags for 7.2]

The heavy green line plots how many commits in each release contained Fixes tags, while the heavy brown line is the number of commits that were identified by Fixes tags in subsequent commits. The crossover point is at 5.9, suggesting that, as of that release, the kernel community started fixing more bugs than it introduced. That conclusion will not hold, though; it will take years for all of the post-5.9 bugs to be identified and fixed, and that line will shift as it happens.

The noteworthy part of the plot, though, is at the right-hand side, where the number of commits carrying Fixes tags increases dramatically, after having been roughly level for quite a few releases. That, it seems, is what happens once large numbers of people start turning LLMs toward the task of finding bugs in existing software. This is going to be an interesting trend to watch. The number of bugs cannot be infinite — even in the kernel — so the rate of bug detection and fixing must eventually fall off. The existing bugs will have been fixed, and LLM review will have reduced the number of new bugs introduced. At least, that is the hope.

If that drop-off does not happen, there will be some interesting questions to answer. It seems reasonably clear that the spread of LLMs has enabled people to create kernel patches who would not have been capable of doing so before. If that is true, it is not much of a stretch to conclude that, in many cases, the submitters of these patches do not fully understand what those patches do. Perhaps the LLMs are good enough that this understanding is no longer necessary, but it could also be that we are creating a pile of code that nobody has ever really understood, but which will need to be maintained in the coming years.

The Linux kernel is aimed at production use, not research or experimentation. But there is currently a massive experiment being run on the kernel's development processes and community. This community has absorbed new processes and tools many times over its 35-year history, and will almost certainly find a way to do that this time as well. But that absorption has not always been without turbulence along the way.

Meanwhile, there are nearly 14,000 non-merge changesets sitting in the linux-next repository and poised to be pulled for the 7.3 release; over 1,100 of them contain Assisted-by tags. It would seem that the high level of activity that has characterized recent releases will not be ending anytime soon. As always, keep an eye on LWN as we follow the next development cycle (and those that come after).

Comments (24 posted)

Page editor: Joe Brockmeier

Inside this week's LWN.net Weekly Edition

  • Briefs: Brief news items from throughout the community.
  • Announcements: Newsletters, conferences, security updates, patches, and more.
Next page: Brief items>>

Copyright © 2026, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds