LWN.net Weekly Edition for September 3, 2026
Welcome to the LWN.net Weekly Edition for September 3, 2026
This edition contains the following feature content:
- A pause for the Python JIT: work has been paused on the JIT since June, after the steering council asked for a PEP to define the work.
- The "rnull" Rust block driver: a blueprint for adding new block devices using Rust.
- Using steal time to moderate CPU demands: a patch set to allow virtual machines to give up vCPUs when contention is high.
- Governing GNOMEs: how the project's technical decision-making is evolving: a look at GNOME's evolving RFC process and other technical-governance progress.
- The rest of the 7.3 merge window: noteworthy changes coming to the next kernel release.
- Securely suspending LUKS-encrypted disks: fixing a regression that allowed disk-encryption keys to remain in memory when a system was put to sleep.
- A note on subscription prices from LWN: LWN's subscription prices are changing for the first time since 2022.
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.
A pause for the Python JIT
In 2024 the Python 3.13 release added an experimental just-in-time (JIT) compiler to optimize the way that CPython executes Python code. Since then, work has proceeded on the JIT, albeit perhaps less formally than some might like. In June, Python's steering council (SC) put out an announcement that no new development on the JIT land (with the exception of bug and security fixes) in Python's main branch, until it accepts a Python Enhancement Proposal (PEP) that would make the case for the JIT as a supported part of CPython. That has led to the creation of PEP 836 ("JIT Go Brrr: The Path to a Supported JIT Compiler for CPython"), which is currently under discussion. As it stands, it seems likely that work on JIT will continue, but when that will happen is less certain.
PEP it up
The Python community uses PEPs to propose new features, serve as a focus for discussion, collect community input, and to serve as a record of decisions. There are three types of PEP: standards track, process, and informational. The standards-track PEPs are for major new features or changes for Python, where the community needs to discuss and decide before (say) removing the global interpreter lock (GIL). Process PEPs are similar but are related to Python governance and development practices around the code base. If accepted by the steering council, these become binding, and (if applicable) work is to commence on implementing the proposal.
Informational PEPs are, as the name suggests, to provide guidelines or other information to the Python community; these PEPs do not represent formal consensus and are non-binding. As such, they generally would not be considered suitable as a basis of major new features landing in CPython's main branch, but work has proceeded on Python's JIT on the basis of PEP 744 ("JIT Compilation"), which is an informational PEP.
That PEP was only introduced several months after CPython core developer Brandt Bucher had already merged the pull request (PR) to add a JIT compiler in January 2024, ahead of the Python 3.13 release.
Thomas Wouters, a steering council member who was serving as the release manager for Python 3.13, stepped in a few days later and asked why the feature had been submitted before a PEP had been submitted or accepted. Ultimately, Wouters persuaded Bucher that a PEP was warranted, and he agreed to start work on one. PEP 744 was announced in April 2024. LWN covered some of that discussion at the time, and Bucher's PyCon US 2024 and PyCon US 2025 talks on the JIT compiler.
There is a "JIT Planning for 3.15 and 3.16" tracking issue on GitHub, created in September 2025, to track goals and work the JIT developers believe was needed to enable the JIT by default by the Python 3.16 release in 2027. But the work was continuing without a standards-track PEP that indicated larger community agreement and awareness.
Hit pause
In its announcement, the council took pains to note that it was not
criticizing the JIT effort or those behind the work: "This has been hard, deeply
technical work that has been done with great care, and the recent performance
improvements are real and encouraging.
" However, because the project had
been underway and undergone a few re-architectures, the council decided, "now is a good
time to re-evaluate the JIT's informal status in the project
".
The council set a window of six months for a new PEP to be submitted and resolved; it said that the JIT code is to be removed from the main branch and any development would need to continue outside that repository if a PEP is not accepted within that time frame.
We know this asks something of the people who have invested years in this work, and we don't take that lightly. We see this not as winding the project down but as giving it, and the community, the clarity and the explicit commitment that a change of this magnitude to CPython's runtime deserves.
The council asked that the PEP address several points; first, it should cover
"how the JIT will be sustained and maintained over the long term
". It
would also need to explain how the JIT would keep compatibility with other
CPython features and tooling, if the JIT would be compatible (or incompatible)
with third-party JIT implementations, as well as whether the JIT architecture is
considered stable or would change further. The council also asked for "clear,
measurable success metrics and timelines
"
Why now?
Naturally, there were questions about the announcement. Antoine Pitrou said
that the council's decision seemed reasonable but wondered if there was "any
further background
" that prompted it. Wouters replied
that there had not been "a single triggering request
" for the PEP, but
the announcement was released after the 3.15 beta
to indicate the council was "okay with the status quo for 3.15
". The JIT
is still included as an experimental feature in 3.15 and includes
major updates such as a new tracing frontend, a basic form of register
allocation, and several optimizations.
Peter Bierma asked
for clarification on the council's deadline: he thought that it was unlikely
that it would be possible to meet the deadline when some PEPs, such as PEP 703 ("Making the Global
Interpreter Lock Optional in CPython"), have taken five months to be accepted by
the council after being formally submitted. Pablo Galindo Salgado indicated
that the council would be flexible if the PEP was stuck in discussion or in its
queue for consideration. Wouters added
that the council was trying to drive a "clear decision from the
community
", because the JIT is a significant change that deserves
serious attention. "That doesn't necessarily mean the JIT immediately gets
ripped out when that six month deadline is hit – we're not unreasonable – but we
do want this to be taken seriously.
"
The decision to stop development until a PEP is accepted, Mark Shannon said,
put JIT contributors in an awkward position. He asked if work to improve the JIT
could continue for a month or two "to give time for the PEP to be discussed
properly
". Council member and JIT contributor Savannah Ostrowski replied
that she didn't think that the grace period Shannon asked for was
necessary. "We understand the work is ongoing and the current state isn't the
final state (as is true of most things in open source).
"
Shannon clarified
that he was worried about losing momentum and contributors. "There is other
work I personally can do, on memory allocation and such, but PRs will bitrot and
other contributors may lose interest.
" Jiahao Li, who had made contributions
to the JIT, asked
if there were "clear and minor optimizations
" that might be acceptable
to continue. Alyssa Coghlan suggested
that a grace period might be warranted for any in-flight pull requests,
especially those from new contributors. "Saying 'no new PRs on this topic
until a PEP is approved' is one thing, shifting the goal posts for already in
progress changes is something else
".
Council member Donghee Na was
not convinced that exceptions were a good idea. Even if the policy was
adjusted to allow PRs that were already open, "I still think our main focus
should be on writing the PEP. Involving those contributors in the PEP process
would also be a good experience for them as part of CPython's development
process.
"
On June 8, Diego Russo, a CPython core developer and JIT contributor, replied
that he had discussed next steps with Shannon and they were working on a
draft. The "JIT Go Brrr" draft PEP was announced
on July 3 by Ken Jin. The PEP name may be a nod to the "doesjitgobrrr" web site that tracks
the performance of the JIT versus the standard CPython interpreter. "Go Brrr" is
a reference to a
meme about the US Federal reserve printing money with a caption including
the phrase "money printer go brrr
".
New PEP
The PEP, authored by Bucher, Jin, and Ostrowski, lays out the current status for the JIT, as well providing a two-and-a-half year timeline with the milestones and goals for the JIT to become a non-experimental feature. The PEP leaves the decision of whether to enable the JIT by default to the Python release manager, rather than setting a condition for that to occur. Currently the JIT is included in the Python binaries for Windows and macOS, but it is disabled by default; some Linux distributions (the PEP cites Fedora and Gentoo) also include the JIT but leave it disabled by default. Interested users can turn on the JIT by setting PYTHON_JIT=1 as an environment variable.
The first year would be focused on developer-experience improvements, making
the JIT compatible with free-threaded (no-GIL) Python, avoiding regressions,
as well as adding further testing for native Python profilers and
debuggers. The second year target, which is scheduled for the first beta of
Python 3.17, is "at least 20% performance geometric mean
improvement
" measured by the Python Performance Benchmark
Suite (pyperformance) when using the JIT and free-threaded Python versus
free-threaded Python alone.
The last milestone, to be completed by the first 3.17 release candidate, is compatibility review: running the test suites of the top PyPI packages (exactly how many is not specified) to assess JIT compatibility with existing code.
The PEP also calls for adding support for multiple versions of the LLVM compiler; currently, building Python with the JIT enabled requires a specific version of LLVM. Building the JIT for Python 3.14 requires LLVM 19 and Python 3.15 requires LLVM 21; both versions of LLVM have reached end of life. LLVM is required because it is used to create templates called "stencils" (example) for the JIT.
There is a separate standards-track proposal, PEP 774 ("Removing the LLVM requirement for JIT builds"), that would remove the LLVM requirement entirely, but it has not yet been accepted. The current situation is a problem for Linux distributors that support versions of Python in long-term-support releases, as discussed in this thread on the Python forum.
The PEP also proposes some
changes to the JIT's frontend infrastructure. Specifically, it calls for
replacing the current trace-recording frontend of the JIT compiler with a
method-based frontend to make the JIT easier to maintain and make it "more
traditional and teachable
", which is not the case now. "The current
tracing frontend can produce head-scratching results even for very simple
benchmarking programs.
" The trace-recording frontend is explained in detail
in a blog
post by Jin from May 2026.
Discussion
Cesare Di Mauro noted that the PEP mentioned that the JIT might use more memory, but it made no clear statement about the goals for memory consumption. Jin said that was a good point and planned to take it up with the co-authors of the PEP to include an upper limit on additional memory use.
Wouters, who clarified he was speaking as himself and not as a council
member, thought
that the PEP really felt like it was two PEPs: one that was showing the criteria
for acceptance, and one that explained how the proposers expected to meet the
criteria. "Fundamentally, the discussion about the minimum expectations for a
supported JIT is distinct from how to get there, especially as we have different
proposals for how to get there.
" He also questioned the firm timeline that
was included in the PEP. "It's just not how development works in an
open-source project, especially one that cares about backward
compatibility.
"
He wanted to see an explicit discussion in the PEP about the JIT's startup
time, warmup time, and memory overhead. These, he said, did not need to be
"particularly strict numbers
", but if those metrics were not tracked, it
would not be possible to understand the cost paid when the JIT is enabled.
The other requirement he voiced was about maintainability of the JIT and its support
among the core CPython team members. "We should focus on making whatever
design we end up with understandable, and understood by the
Core team. We need to make sure enough people work on it and spend time with
it
". Shannon agreed
that "this seems like two PEPs
", and implementation details in the current
PEP seemed out of place.
Bucher replied
the PEP was "providing what the SC asked for
" and that the
authors had put a lot of effort into creating a cohesive PEP. "A separate PEP
seems like it makes the process more complicated and opaque, not less. Here, we
have a way to present a complete story
". He also thought that the current
JIT "can be understood and is accessible to other members [of the community]
outside the core team
". Ostrowski added
that it would make her uncomfortable to have the PEP include goals for the JIT
without "everything we've thought through alongside it
". Goals without
plans, she said, aren't really goals at all.
Wouters responded
that he understood where Bucher was coming from now. He added that his
understanding of the council's request, though, was meant to be for the current
JIT and not a future one. "If the plans in this PEP for the future JIT were
rejected, that still leaves the fate of the current JIT unclear.
" Jin replied
that the PEP was not proposing a new or future JIT, though it might seem that
way for those unfamiliar with the recent JIT progress. "The design we
described might seem like a radical change, but most of it is already in the
current CPython main branch! Again, the only change is growing support for
methods.
"
CinderX is an
extension for improving the performance of the Python runtime that includes a
JIT. Kevin Newton, one of the contributors to CinderX, also
thought the proposal should be two PEPs. More importantly, he believed that
the PEP "very much understates the sizeable difference between a tracing JIT
and a method-at-a-time JIT
" and was glossing over some important details. He
said that CinderX had already run into some of the problems that the JIT
developers would face in replacing the current frontend. He also worried about
the focus on simplicity:
JITs and dynamic language runtimes are some of the more complex pieces of software out there. I promise I'm sympathetic to having too little energy and contributors, and it makes sense that you would want the things you mention. But I worry that eschewing complexity in favor of making a JIT compiler "fit" in someone's head ultimately results in a JIT compiler not worth having.
Jin said
that he appreciated Newton's expertise with CinderX and other JITs, but he
disagreed that it would require a lot of changes to support methods for the
current state of the JIT in CPython. The developers had not yet implemented
"the usual complex things
" yet, which meant that it would not be highly
complex to switch between the two at this time. He also disagreed that there was
a mandate to produce two PEPs from the steering council, and wanted to avoid
putting the burden of doing so on the JIT developers.
The "this should be two PEPs" theme continued with a lengthy comment from CPython core developer Jeremy Hylton. He called for separate PEPs describing the design of the JIT, how various parts of the interpreter runtime interact, as well as one that would describe metrics, timelines, and maintenance plans.
Eric Snow, also a CPython core developer, pushed
back against the "ongoing pressure
" and expressed support for the
JIT. He thought documenting the design and addressing concerns was worth doing
but disagreed with blocking further development in the main
repository. There was a risk, he cautioned, that making extended demands that
seemed like busy work would drive away contributors and turn Python into a
project "in which mostly only enterprise teams participate
".
Russo said
he had worked on the JIT almost since its inception and felt the work should
continue; he did, however, support splitting the document into two PEPs. He
thought that trying to cover everything in one PEP broadened the discussion and
made it harder to reach consensus. "The Steering Council's requests can be
addressed through multiple focused PEPs rather than trying to fit everything
into one document. Once we have an agreed baseline, follow-up PEPs can evolve
individual parts of the JIT independently.
"
Status
The discussion seems to have lost momentum, without any official statement from the council about whether it also feels there should be multiple PEPs or if it is satisfied with the current draft. There has been no commitment from any of the PEP's authors to split up the current document or produce new PEPs.
On August 17, Wouters posted
a summary of the council's meeting from August 6. The summary noted that the council
"had office hours
" with the authors "discussing the state of the PEP
and whether it answered the questions the SC asked in its request for a
PEP
", but did not elaborate on the results of that discussion. PEP 836
was listed as an agenda item for the council's next meeting, but minutes from
that meeting have not yet been posted.
For now, the development of the JIT seems to be largely on hold. No one seems to be voicing direct opposition to the JIT work, just a fair number of people who are asking for more information and debating the details.
The "rnull" Rust block driver
The null block driver (null_blk) is a small driver that is mostly useful for benchmarking block-layer implementations. It accepts all requests and marks them complete as quickly as possible, doing as little work as possible. In June 2026, Andreas Hindborg shared a patch set implementing the same functionality in Rust, in order to show that a simple block driver is now possible to write using the kernel's Rust APIs and to enable comparisons between the C and Rust implementations. A minimal version of the "rnull" driver is already present in the mainline kernel, but Hindborg's patch set brings it up to feature parity with the C version.
The rnull driver
Most of Hindborg's patch set is dedicated to adding the last few Rust abstractions required to build a block driver at all. The implementation follows the same general pattern as the last Rust driver that LWN looked at, for the AX88796B networking device. It starts by declaring a new kernel module using the module!() macro, and then creates a new Rust type to represent the module. Unlike the Rust AX88796B driver, Hindborg's driver uses pinning to store a reference to the configfs interface, which complicates the module's initialization function.
The bulk of the function is wrapped in a call to pin_init_scope(), which takes a block of code describing how to initialize a piece of memory and uses that to construct a pinned (immovable) object in-place, without exposing raw uninitialized memory to the Rust code. Other than that one complication, the initialization function is straightforward: it reads module parameters, creates the requested number of disk-device objects, and then stores the configfs interface and list of disks in the module's pinned data:
pin_init::pin_init_scope(move || -> Result<_, Error> {
// Read module parameters:
let blocking = module_parameters::blocking.value();
// Other parameters elided
...
// Build a tag set (part of how requests are mapped to hardware queues)
// for the module-wide configfs settings to use
let shared_tag_set = NullBlkDevice::build_tag_set(...);
// Create disks
let mut disks = KVec::new();
for i in 0..module_parameters::nr_devices.value() {
// Some local variables elided
...
let disk = NullBlkDevice::new(...)?;
disks.push(disk, GFP_KERNEL)?;
}
// Store pointers in pinned module data
Ok(try_pin_init!(Self {
configfs_subsystem <- configfs::subsystem(shared_tag_set),
param_disks <- new_mutex!(disks),
}))
})
Each block device is represented by a NullBlkDevice structure, which includes various configuration parameters to implement support for bad blocks, bandwidth limits, device zones, and the other testing options that null_blk supports. The structure implements the Operations trait, which describes how disk operations for the device should be performed. The #[vtable] macro is used to package the functions of the trait into a vtable (a structure full of function pointers) that looks indistinguishable from the C implementation to the rest of the kernel. The block I/O subsystem structures used to track the known block devices on the system store a pointer to that vtable. The actual implementations of the functions themselves accept arbitrary requests and immediately mark them as complete.
The core function for this is queue_rq_internal(), which takes (among other things) a pointer to a Request structure that wraps struct request from the kernel's C code. The code is slightly complicated by the need to handle fault injection, but when that is turned off the core logic to handle a request (with editorialized comments) looks like this:
// Acquire the lock on the request
let mut rq = rq.start();
if rq.command() == mq::Command::Flush {
// If the rnull device has been configured to save writes in memory,
// flush that storage.
if this.memory_backed {
this.storage.flush(&hw_data);
}
// Regardless, mark the request as handled and return.
this.complete_request(rq);
return Ok(());
}
if rq.is_poll() {
// If the request is trying to poll for completion of something,
// put it in the poll queue so that a later poll will complete it.
hw_data.lock().poll_queue.push_head(rq)
// ... discarding the potential error about a full queue because it is
// sized such that it should never be overfilled.
.expect("Buffer is sized to hold all in-flight requests")
} else {
// Otherwise, just mark it as complete
this.complete_request(rq);
}
return Ok(());
The more interesting part, for other people wishing to write block drivers, will be the scaffolding around that core logic, which shows how to make a driver configurable and register it as a provider of block devices. The initialization code to read module parameters and expose configfs settings, especially, should be similar between different drivers.
The configfs code exposes the same settings that the null_blk driver does, controlling the size of the emulated block device, whether it reports itself to be a rotational or solid-state drive, and so on. The configfs interface also uses #[vtable], but in a slightly more confusing way: rather than constructing a single vtable that encapsulates the definition of a Rust trait, the code generates multiple vtables, one for each defined configfs attribute, distinguished via const generics. Some of the simpler settings instead use macros such as configfs_simple_bool_field!() to reduce the amount of boilerplate necessary.
One of the configfs attributes that cannot be simplified with those macros is the "badblocks" setting, which controls which sectors report errors when using error injection. The code for that attribute shows how to use the Rust configfs interface. The show() function controls how the setting is displayed to the user; the store() function is used to update the configuration when the user writes to the appropriate configfs file. The "12" in the impl line associates this implementation with the twelfth configfs attribute, and the #[vtable] macro packages it all up as a vtable in the format that configfs's C code expects:
#[vtable]
impl configfs::AttributeOperations<12> for DeviceConfig {
type Data = DeviceConfig;
fn show(this: &DeviceConfig, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
let ret = this.data.lock().bad_blocks.show(page, false);
if ret < 0 {
Err(Error::from_errno(ret as c_int))
} else {
Ok(ret as usize)
}
}
fn store(this: &DeviceConfig, page: &[u8]) -> Result {
for line in core::str::from_utf8(page)?.lines() {
// Parse each line and set the appropriate settings in the
// DeviceConfig.
...
}
Ok(())
}
}
When the kernel module is loaded, the Rust configfs wrapper automatically registers the configfs::Subsystem structure containing those vtables with configfs. When the user invokes the proper incantations:
# mount -t configfs none /config
# mkdir /config/rnull/<block_device_name>
# echo 1 > /config/rnull/<block_device_name>/power
The configfs code creates a new GenDisk structure, which corresponds to struct gendisk on the C side of the kernel. That structure stores a pointer to the NullBlkDevice vtable.
Future block drivers
Given that the main purpose of null_blk is benchmarking, a natural question is how its performance stacks up against the C implementation. Exactly how much overhead do the Rust bindings introduce? The Rust for Linux project's documentation on the driver shows a benchmark comparing performance between the two drivers on the 6.19-rc5 kernel. As is frequently the case in benchmarking, the comparison is not straightforward. Single-threaded performance is a little worse, as is the performance at higher queue depths, but performance is actually better for some sizes of request, and most tested setups have no statistically distinguishable difference.
Of course, the real point of Hindborg's patch set is not to supplant the C-based null block driver; it is to demonstrate that it is now possible to write new, more interesting block drivers in Rust. Currently, device drivers in Rust can be divided into two general categories: big projects, which have developers willing to implement all of the new Rust abstractions required for them, and little drivers that someone has contributed for a specific device. The former category, which includes Android's Rust binder, Nova, and Tyr, receives a lot of the attention, but given that there are a long tail of tiny, obscure, neglected drivers for niche devices in the kernel, it is arguably the latter category that has more to gain from adopting Rust.
As of August 2026, the kernel has Rust drivers in the latter category for two families of networking devices (the AX88796B and QT2025), TH1520 pulse-width modulation controllers, and CPU-frequency management. That is not much, but these small drivers provide a blueprint for users who want to add support for their own niche devices and who may not be confident in their ability to write correct kernel C. Hindborg's rnull driver provides the same kind of blueprint for adding new block devices to the kernel. Perhaps we will soon see drivers for niche block devices coming to the mailing lists.
Using steal time to moderate CPU demands
Virtualization can increase CPU utilization by allowing a large number of virtual CPUs to share a smaller number of physical CPUs. The amount of CPU time that is actually available does not change, though, so heavy activity on too many virtual CPUs can lead to contention and significant performance loss. The steal governor patch series from Shrikanth Hegde is an attempt to address that problem with a mechanism that allows virtual machines to voluntarily reduce the number of virtual CPUs they use when contention is high.From a virtual machine's point of view, contention for a physical CPU is clearly an undesirable thing. When contention occurs, the physical CPU will be unavailable at times when the virtual machine is trying to make use of it; that slows the execution of the workload. The situation can be worse than that, though, if a virtual CPU is preempted while holding locks needed elsewhere in the same virtual machine. At that point, threads that do still have access to a physical CPU may waste their execution time spinning on locks that the preempted CPU is no longer able to free, with possibly severe effects on performance. That is the sort of situation that causes customers to reconsider shared hosting.
Hegde's solution calls for virtual machines to take notice of when contention for physical CPUs is high and to reduce their demands to alleviate that contention.
Steal time and preferred CPUs
The amount of time that a virtual CPU spends waiting for access to a physical CPU is known as "steal time" — execution time that was "stolen" from the virtual machine by somebody else. On a Linux system, the amount of steal time experienced in a virtual machine can be read from /proc/stat, or seen with utilities like top or vmstat. The level of steal time seen by a virtual CPU can be used as a measure of how much contention for the physical CPU is being experienced.
Hegde's patch set uses steal time to help maintain (in ways that will be described shortly) a "preferred CPU" set. The preferred CPUs are a subset of the active virtual CPUs available to the virtual machine; as much as possible, the kernel on that virtual machine will try to schedule its tasks only on the preferred CPUs, leaving the others idle. When the virtual machine starts, the preferred set contains all of the active CPUs. Should the level of steal time experienced become too high, one or more CPUs will be removed from the preferred set. When steal time goes below a lower threshold, CPUs can be restored to the preferred set.
The scheduler makes use of the preferred set in few small but significant ways:
- Whenever the time comes to wake a sleeping task, that task will be placed on one of the preferred CPUs if possible.
- At each regular scheduler tick, the kernel checks whether the current CPU is in the preferred set. If not, the running task, if any, will be pushed out of the current CPU to run on one of the preferred CPUs instead.
- Load balancing will avoid moving tasks onto CPUs that are not in the preferred set.
One important exception to these rules is that a task's CPU affinities will be honored. If a task is only eligible to run on non-preferred CPUs, it will be placed on one of those CPUs. Other than that, though, this machinery will cause any CPUs that are removed from the preferred set to go mostly idle, concentrating the virtual machine's tasks on the preferred set and reducing the number of physical CPUs that the virtual machine is contending for.
One might argue that the result is simply to move the problem around. Contention arises because there is more load on the system than its physical CPUs are able to handle; that load will not go away just because the set of virtual CPUs available to a virtual machine has been reduced. What does happen, though, is that the preemption decisions are moved into the virtual machine, which has more information about the workload and which tasks should be allowed to run first. That can allow the virtual machine to run high-priority tasks, or tasks holding contended locks, before others, leading to better decisions overall.
Policy
The policy part of this system is encapsulated in a "driver" called the steal_governor. It is not actually implemented as a driver, though; it runs as a workqueue item that continually resubmits itself. It is controlled by three parameters: interval_ms regulates how often it checks the experienced steal time, while low_threshold and high_threshold set (as percentages) the amount of steal time that should lead to an increase or decrease in the number of preferred CPUs, respectively. Interestingly, these parameters do not appear in sysfs; instead, they are implemented as module parameters, a configuration method that has been discouraged in recent years. Changing any of these parameters requires unloading and reloading the steal_governor module. The default value for interval_ms is 1000ms; the low and high thresholds default to 2% and 5%, respectively.
On each iteration, the governor compares the amount of steal time to the high threshold. If that threshold is exceeded, the governor will look for a core that contains no housekeeping CPUs; all CPUs in that core will be removed from the preferred set (subject to the obvious restriction that at least one CPU must remain in the preferred set). No other immediate action is taken; the scheduler tweaks described above will eventually cause tasks to move away from the non-preferred CPUs. If, instead, the steal time drops below the low threshold, one core's worth of CPUs will be added back to the preferred set (until the point where all CPUs are preferred).
The policy implementation may be enough for a proof of concept, but it may end up falling short for real deployments. At a minimum, the ability to change the governor's parameters without unloading and reloading a module would be a clear improvement. There does not seem to be a reason why these values could not be changed directly using sysfs or sysctl knobs. Even then, though, it seems inevitable that somebody will want the ability to control the preferred CPU set from user space, or, even more inevitably, with a BPF program.
Another potential problem, of course, is the entirely voluntary nature of this mechanism; it is nice that each virtual machine can react independently, and that there is no need for an overall control or communication mechanism, but the result is a system that is dependent on universal cooperation. If only some virtual machines reduce their preferred CPU count, they will be penalized relative to those that do not. That may limit the applicability of this mechanism on multi-tenant systems where some users may not feel inclined (or may be unable) to cooperate.
On systems where cooperation can be expected, though, the results would
appear to be good. The cover letter includes data from a number of
benchmark runs showing improvements from about 2% for schbench to
over 44% for some hackbench
runs. Hegde summarizes the results as: "Many improvement across archs
especially with real life workloads
".
This patch series has been circulating since the first RFC
version in May 2025. It has been through 11 revisions — after
several RFC versions — and has evolved considerably over that time. It has
not, as yet, acquired the Acked-by or Reviewed-by tags that might indicate
readiness for merging into the mainline, but Hegde nonetheless said that
"I believe the series has now converged and is ready for merge
consideration
". Whether the scheduler maintainers agree will likely
become clear sometime after the close of the merge window.
This work was discussed at the 2026 Power Management and Scheduling in the Linux Kernel Summit; the video from that session is available.
Governing GNOMEs: how the project's technical decision-making is evolving
Emmanuele Bassi kicked off a project to improve GNOME's technical governance with a presentation about his ideas (video) at GUADEC 2025. His nudging has led the project to, slowly, work on creating more formal structures for technical governance. It is adopting a teams structure and looking toward creating a steering committee, as well as bootstrapping a Request for Comments (RFC) process. If adopted, GNOME would require RFCs for design, user experience, architectural, and other changes that carry a major impact on the project.
GNOME and governance
GNOME was founded in 1997; its non-profit foundation followed in 2001 to provide support for the project by managing funds, overseeing legal assets such as trademarks, maintaining development infrastructure, and running events. The original charter for the foundation, however, made it clear that there was no taste for rigid structure around technical governance:
GNOME sits on the frontier of the Linux application market, and is likely to continue to face growing pains as we try to meet the needs of ISVs (Independent Software Vendors) and others who are joining the movement.
It would be impossible to impose a high degree of bureaucratic structure onto a heretofore amorphous and somewhat anarchic community. And it shouldn't be done, anyway.
Bassi makes the case in the write-up of
his governance talk, that the "over-reliance on personal projects and
taste
" has resulted in GNOME being "a loosey-goosey collection of cats,
herded together by whoever shows up with 'a vision'
". He writes that GNOME's
software quality has improved over the years, but only because the project has a
few people maintaining a lot of components—thus things are consistent, but
also means that maintainers are in danger of burnout.
Bassi argued for doing away with the individual maintainer model in favor of shared responsibility. In the discussion on GNOME's Discourse forum in August 2025, he detailed the formal technical-governance system that he envisioned. It includes a change-proposal process, teams for parts of the project, such as a platform team for the application-development layer, a core apps team for GNOME applications, a tooling team for development tools, and so forth. He also proposed a steering committee formed from representatives of the teams. Changes that impact multiple teams would be discussed and documented in public, then published for posterity.
The proposal to get rid of individual maintainers was a sticking point for
some GNOME contributors. Adrian Vovk thought that
GNOME had too few people for "this bureaucratic process
", and expected
there would still be de facto maintainers who had the institutional knowledge
over "their corner of the stack
". Michael Catanzaro said it was
unrealistic to do away with maintainers entirely, since "GNOME is a big
collection of small projects, and teams with a large scope and perspective are
just not a better way of working on small projects
". He did allow that it
would be fine to give teams the power to overrule individual maintainers.
Allan Day worried that the proposal was trying to do too much at once:
Formalized teams plus steering committee plus RFC process is a lot. Out of those three elements the development teams is the most high-risk and complex. I can't help but wonder whether that part of the plan should be decoupled and given more time/space to evolve.
A year later...
The governance work has been evolving slowly, or more
slowly than Bassi had hoped, at any rate. On July 17, at GUADEC 2026, he
provided an update on GNOME's governance work, in his "Some more governance"
talk (video). "I
toyed with the idea of calling the talk 'governance will continue until morale
improves', but that was a little bit too on the nose, to be honest.
"
He said that he had expected his proposal to be contentious, but he received
valuable feedback instead. "Everyone agreed that technical governance had to
be improved in the project
". Unfortunately, there were few people actually
working on the governance improvements, "which means that people were looking
at other people to unblock the issue, and they were waiting for somebody to come
along and tell them what to do
". He thought that GNOME would adopt new
technical governance quickly, but people "really don't know where to
start
".
Progress has been made, though; he said there are now rules defining what a team is
and what constitutes an active or inactive team. There is an entire chapter in
the GNOME Project Handbook
that defines what a team is, how teams should collaborate, and spaces on GNOME's GitLab instance for each
team. He said that there is currently a bindings team and that he had been
"collecting people like Pokémon
" who work on "any platform
library
" to create a platform team.
So the goal of the platform team is whenever somebody is contributing to the core library, a new feature, a new setting, a new widget, a new API, it doesn't matter what, it doesn't matter how big, you come to the platform team and you talk to us. If you're inside already at the platform team, you know what to do. If you're outside because you're a new contributor or you are interested in something for your application, you come to the platform team.
The governance process effort has also identified inactive teams, such as the documentation team; Bassi said that it needed reviving or to be shut down, since there hasn't been any activity except his own in refreshing the GNOME Help web site.
Anyone who wanted to start their own team, he said, should follow the rules
in the handbook or come to him for a template. "The important thing is [they]
all have regular meetings and publish their agenda so that people are aware of it; people
can jump in and help you out. And use the GNOME infrastructure because it's there
for a reason
".
The steering committee, however, has not yet been created. Bassi said there
were still open questions: for example, who gets to be on the committee and for
how long? Should it be a decision-making or an arbitration body? How can GNOME
avoid the committee becoming a "small subset of people steering the
project in a direction that the rest of the community doesn't care about
"?
All of those questions are still unanswered.
RFC process
The path to answering some of those questions may lie in the RFC process,
which Bassi is emphatically not leading. Bassi said that he did not want to be
involved in the development of the RFC process, "because there is nothing
that trips a bunch of nerds like rule lawyering
" and there is nothing that
nerds hate more than bureaucracy, "except the one they come up
with
". Instead, Sofie Herold is leading the charge for the RFC process. She
began
the discussion on July 27, with a draft RFC proposal and suggested that
it should be the first test of the process as RFC-0001. Unfortunately, the first
draft seems to have been erased at some point, but a
more recent draft is available.
Even though Bassi's governance proposal included a RFC-like change process,
and adopting bits of it would involve an RFC process,
RFC-0001 presents itself as an alternative to Bassi's proposal. It has a smaller
scope in the hopes of avoiding being "stuck with a proposal that covers too many
aspects and details of the project's governance to be realistically discussed in
one package
".
Under the proposal, RFCs will be created in a GNOME/rfcs repository
on GNOME's GitLab instance, and it calls for a thread to be created on GNOME's
forum for discussion of RFCs. Any member of the GNOME Foundation can create an RFC as
a merge request (MR), and the MRs can be locked so that only foundation members
can comment. There are examples of situations that call for an RFC to be
created, such as resolving stalled discussions or handling major design
decisions. The proposal states that an RFC "cannot override the competencies
and powers given to certain groups or people by the GNOME Foundation
"
(whatever those powers might be—they are left unspecified).
When an RFC is created, it is driven by one or more editors ("the author
as well as additionally specified editors
"), and can be amended during
discussion by editors or stakeholders. The definition of "stakeholder" is "is
anyone whose work or projects in GNOME are meaningfully affected by the proposed
change
", which could be a person, a team, or a group as large as all GNOME
Foundation members. An RFC should list stakeholders when it is created, but
additional stakeholders "must be added
" if two members of a team
believe their team is a stakeholder.
If someone objects to all or part of an RFC, they can raise a "concern" which
may be accepted by any stakeholder (excepting the person who raised the concern
in the first place). It is unclear how it would be handled if stakeholders
disagree about concerns and their resolution. The RFC specification is a bit
vague about expected discussion length; it states that there is a 14-day final
comment period to raise new concerns before an RFC is accepted or rejected
"once discussion has died down
", but it does not dictate any requirement
that a discussion take at least a certain amount of time.
According to the draft, after the final comment period ends then any stakeholder can choose to either accept (merge) the RFC or reject (close the MR) it.
Lucas Baudin asked
for examples of changes that would go through the RFC process. Bassi provided
a few changes that he thought would need RFCs, such as switching
documentation formats and changing
GNOME's recommended image-loader library. Matthias Clasen agreed;
he also thought that the examples emphasized the need for the RFC process to be
lightweight and focused on raising awareness of changes. He said he was pretty
sure that none of the changes Bassi shared as examples would have been completed
"if there had been a prolonged, concern-heavy discussion of all the
eventualities and unlikely failures before any code was written.
"
On August 31, Sam Thursfield said
that he had been holding off on a comment while he digested the RFC text,
"but nothing new has come from that, so I think the best thing to do is adopt
the process and start using it
". Herold said
that comments had died down and "we are slowly moving towards final comment
period
". If no new concerns have been raised before September 4, she
planned to announce a final comment period via a blog post, This Week in GNOME, and an announcement
on GNOME's Discourse forum. "In general, I think it might be best if we just
start using the RFC process and then implement the lessons learned
later.
"
Change is afoot
Next year, GNOME will have its 30th anniversary. The project has made it this
far without a formal technical-governance process, but a case can be made (and
has been made) that it's past time for the project to adopt one and shed its
"amorphous and somewhat anarchic
" ways. Assuming the RFC process is
adopted, it will be interesting to see what the first proposals are and how
well the process works once it's put to the test.
The rest of the 7.3 merge window
By the time Linus Torvalds released 7.3-rc1 and closed the merge window for this release, 15,267 non-merge changesets had been pulled into the mainline repository. That is the second-highest commit count for an -rc1 release in the kernel's history; only the 6.7-rc1 release, which included nearly 3,000 commits of bcachefs history, had more. About 13,000 of those commits entered the mainline after the first 7.3 merge-window summary was written so, needless to say, there are a lot of changes to cover.The most interesting changes made in the latter part of the 7.3 merge window include:
Architecture-specific
- The s390 architecture has a new cpuidle subsystem based on the kernel's generic cpuidle infrastructure. Also new for s390 is kernel control-flow-integrity support using the Clang compiler's software-integrity features.
BPF
- BPF kfuncs can now be marked with the KF_SPINLOCK_SAFE flag, indicating that they can safely be called with a spinlock held.
- It is easier to pass arena pointers into BPF kfuncs; a kfunc parameter that is declared with a magic suffix (__arena) to its name will automatically be offset into the arena's space and cast to the appropriate type. There is also an __arena__nullable variant for pointers that might be passed as NULL. See this commit for more information. This feature also works for struct_ops arguments.
- BPF programs can now have access to global per-CPU data; see this merge message for more information.
- The BPF verifier now provides more information on verification errors, making it easier to debug the source of the problem. See this merge message (scroll past the version information at the top) for more information.
Core kernel
- The remaining pieces of the sub-scheduler
feature for sched_ext have been merged; the feature has been
declared complete and working. From the
merge message: "
a root BPF scheduler can now hand a cgroup subtree over to a nested sub-scheduler together with revocable CPU grants, and the sub-scheduler owns all scheduling decisions for its tasks on those CPUs.
" - Dynamic probes (kprobes, uprobes, and fprobes) are able to perform some simple type casting using the kernel's BTF data; in 7.3, that capability has been extended significantly. Support for boot-time probes has also been improved. See this merge message for an overview.
- The kernel has gained better working-set tracking for virtual machines; see this article for an overview of this work, which is arguably the largest chunk of LLM-assisted core code merged to date.
- The DAMON subsystem now supports data-attributes-only monitoring, for users who are more interested in the types of memory being accessed than the specifics of which memory is being accessed. See this changelog for an overview.
- The kexec handover mechanism has gained improved handling of huge pages allocated at boot time; those pages are now marked and preserved over a live update to a new kernel.
Filesystems and block I/O
- The ntfs3 filesystem has gained basic support for alternative data streams, which are accessed with a colon in the file name. So, for example, "cat file:query_streams" will list the streams associated with a file. See this changelog for some more information.
- The competing ntfs filesystem now has read-only support for Windows overlay filter (WOF) compression.
- The NFS server has gained CB_NOTIFY support for directory delegations. In short, this means that the server can report specific changes within a directory to the other side, allowing caches to be retained in many cases.
- Support for version 1 of the Btrfs free-space cache has been deprecated since the 6.11 release; in 7.3, it is being removed altogether. Older filesystems will still work, though perhaps a bit more slowly. The btrfstune tool can be used to convert a filesystem to use the newer (version 2) free-space cache. See this commit for some more information.
- The long-deprecated (since 5.9) usebackuproot Btrfs mount option has been removed; rescue=usebackuproot should be used instead.
- Buffered I/O to block devices can now use the RWF_DONTCACHE flag to avoid keeping data in the page cache.
- The ksmbd in-kernel SMB filesystem server has gained a number of new features, including Apple Time Machine support, per-share SMB3 encryption support, SMB Direct RDMA encryption, and more; see this merge message for the full list.
- The Filesystem in Userspace (FUSE) subsystem now has better support for buffer pools and zero-copy I/O when used with io_uring. See this documentation commit for some more information.
- The F2FS filesystem has gained the ability to dynamically remove partitions from a filesystem's pool, and to put them back at a later time. This commit contains some documentation on this feature.
Hardware support
- Clock: R-Car X5H clocks, Amlogic A9 SoC clock controllers, Rockchip RV1106 clock controllers, Qualcomm Glymur EVA and camera clock controllers, Hawi video clock controllers, Qualcomm Shikra global and audio core clock controllers, Qualcomm Nord display and graphics clock controllers, Maili video clock controllers, ESWIN EIC7700 HSP clock controllers, UltraRISC DP1000 clock controllers, Cixtech Sky1 audio subsystem clock controllers, and MediaTek MT8173 mfgtop clock controllers.
- GPIO and pin control: Realtek DHC RTD1625 GPIO controllers, MediaTek MT6858 pin controllers, Airoha en7523 and an7563 SoC pin controllers, and Qualcomm Maili pin controllers.
- Graphics: Anbernic TD4310 LCD panels, Chipone ICNA35XX panels, Ilitek ILI9488-based panels, Ilitek ILI7807S-based panels, Renesas R63419 dual-DSI video mode panels, and Novatek NT36536 panels.
- Hardware monitoring: Silergy SQ24860 regulators, ROHM BD12780 and BD12790 hot-swap controllers, PolarFire SoC (MPFS) temperature and voltage sensors, ESWIN EIC7700 voltage and temperature sensors, MPS MPQ82D00 step-down controllers, Kandou KB9002 PCIe retimers, Analog Devices MAX16545, MAX16550, and Volterra VT7505 PMBus controllers, MPS MPQ8646 buck converters, Altera SoC FPGA temperature and voltage sensors, and Qualcomm SPMI PMIC MBG temperature monitors.
- Industrial I/O: Analog Devices ADF41513 PLL frequency synthesizers, QST QMC5883L and QMC6308 3-axis magnetic sensors, NXP MCF54415 digital-to-analog converters, MediaTek MT6323 PMIC auxiliary analog-to-digital converters, AMD Versal system monitors, Texas Instruments ADS112C14/ADS122C14 analog-to-digital converters, InvenSense ICM-42607 motion trackers, Analog Devices LTC2378 analog-to-digital converters, Sensirion SLF3S liquid flow sensors, and Microchip MCP47A1 digital-to-analog converters.
- Input: Imagis ISA1200 haptic feedback units, MSI Claw game pads, HyperX microphone mute buttons, and AMD SFH tablet-mode switches.
- Media: Sony IMX471 and IMX678 sensors.
- Miscellaneous: R-Car X5H power-domain controllers, Spreadtrum SC2730 power regulators, Nuvoton MA35D1 QSPI controllers, Lenovo SE30 Gen 2 and SE60 watchdog timers, Nuvoton MA35D1 watchdog timers, LeapIO RAID adapters, TI BQ25630 battery chargers, SG Micro SGM41542 chargers, AMD AXI I3C master controllers, Axiado mailboxes, AMD Halo Box RGB LED controllers, SpacemiT K3 USB3/PCIe PHYs, Qualcomm QMP PCIe PHYs, Airoha SMC eFuses, Intel silicon security engine interfaces, Qualcomm MAILI interconnects, AMD MicroBlaze/V BRAM-based remote processors, ESWIN EIC7700 HSP reset controllers, Cix Sky1 audio subsystem reset controllers, Analog Devices LTC3220 18-channel LED controllers, and Silergy SY7758 backlight controllers.
- Networking: Analog Devices ADIN1140 10BASE-T1S PHYs and MAC-PHYs, Morse Micro mm81x WiFi interfaces, NXP IW61x WiFi chipsets, Realtek 8922DE/8922DE-VS PCI WiFi adapters, DAPU Telecom DAP8211R(I) gigabit Ethernet PHYs, Intel E2100 control-plane functions, and MediaTek MT7628 Embedded Ethernet switches.
- Sound: AWINIC AW88399 codecs, Qualcomm WSA885X codecs, and Realtek RT766 SDCA codecs.
Miscellaneous
- Changes to the user-space perf tool include a new function view for perf c2c; see this merge message for the full list of changes.
Networking
- It is now possible to use big TCP packets in UDP tunnels managed with VXLAN and GENEVE.
Security-related
- There is a new sysctl knob, crypto/af_alg_restrict, that regulates access to the AF_ALG cryptographic API from user space. The default is to partly restrict access to this feature (which may well be removed entirely in the future). See this changelog for an overview of the new knob, and this article for some context.
- The verification of signed BPF programs has been tightened by having the kernel verify the integrity of a program's metadata prior to loading it. See this merge message and this documentation commit for more information, and this article for some context.
- The landlock_restrict_self() system call now accepts a new flag, LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS, that sets the "no new privileges" flag for the calling process, but only after the setup of the new rule set passed to the call succeeds. This commit contains some documentation for this feature.
- The AppArmor security module now supports loading of compressed policies.
Internal kernel changes
- Rust-support additions include I/O types and projection, the fwctl API, and sleepable read-copy-update (SRCU).
- The new rv wakeup monitor can report situations where a low-priority task is waking a realtime task — often an indication of priority inversion.
- An expedited read-copy-update (RCU) grace period will now cause ordinary callbacks to be called along with the expedited ones.
- There is a new ioctl() command for the memory-allocation profiling feature. It allows the kernel to filter out unwanted information before passing the allocation data to user space, significantly improving performance. See this changelog for the (limited) documentation that exists.
- The low-level internals of the swap subsystem have been reworked around a new swap_ops structure, cleaning up the code and facilitating future improvements.
- With regard to exported symbols, 153 were removed, but an impressive 523 were added. There were also three kfuncs removed and 32 added. See this page for a full list of the changes to exported symbols and kfuncs.
The changes in 7.3-rc1 were contributed by 2,450 developers, of whom 520 were first-time contributors. There are Assisted-by tags in 1,264 of those commits — that is just over 8% of the total, but is also surely a significant undercount of LLM-assisted commits in the kernel.
Now comes the stabilization period, when bugs are found and fixed before the 7.3 release, which is most likely to happen on October 18. The 7.2 release saw over 3,000 commits applied after 7.2-rc1; if, as seems probable, that pattern repeats itself in the coming weeks, 7.3 will end up with the most commits of any kernel release — so far.
Securely suspending LUKS-encrypted disks
When a laptop is asleep, its memory is not unreadable. The right tooling can attach to the computer's memory bus and read out its contents, and cold-boot attacks can theoretically read values from memory for a short time after the computer loses power. That is really an unavoidable fact about the hardware, but some users would still like to ensure that, even if this happens, their long-term encryption keys, such as the key for full-disk encryption, remain unreadable. In June 2026, Ingo Blechschmidt discovered that Linux kernel versions after 6.9 (released in May 2024) were not erasing disk-encryption keys when a laptop was put to sleep, even when configured to do so. He quickly identified a potential fix, which has been merged, but it was not a comprehensive solution.
Sleeping with encrypted disks
Wiping the running system's disk-encryption keys poses a bit of a chicken-and-egg problem: without the keys present, any attempt to read something from the disk will block. Suspending access to the root disk by wiping the encryption key and then putting the computer to sleep nearly guarantees that when it is woken, the system will attempt to read files required by the screen-locker executable from disk, causing the whole system to deadlock.
Therefore, most distributions do not actually wipe the disk-encryption keys when putting a system to sleep. Instead, they keep the keys resident in memory to provide a more seamless experience, since cold-boot attacks are rare and difficult. Despite that, users who want more thorough protections can enable them. Debian was the first distribution to allow it, and uses a slightly involved mechanism to do so. When the computer is preparing to sleep, it creates a RAM disk holding all of the programs and configuration files required to prompt the user for their disk-encryption passphrase before wiping the encryption keys. When the computer is woken from sleep, the prompting program on that RAM disk runs first, unlocking the disk again and adding its key to the kernel's keyring. Subsequently, future accesses to the disk will succeed, so the rest of the user-space programs can awaken normally.
Debian packages this setup as
cryptsetup-suspend, which has been ported to several other
distributions. When Blechschmidt attempted to port
cryptsetup-suspend to NixOS, he noticed that
the encryption key remained in the memory of the virtual machine
on which he was testing. Additional testing showed that the problem was in the
kernel.
"There is something uniquely unsettling about trusting a security
mechanism for years and learning it was never doing the thing.
"
The bug
In 2024, Christian Brauner worked to clean up some device-mapper code to use the block-device file-descriptor-based interface rather than the older handle-based interface. As part of that refactoring, this line:
bdev_handle = bdev_open_by_dev(dev, mode, _dm_claim_ptr, NULL);
Became:
bdev_file = bdev_file_open_by_dev(dev, mode, _dm_claim_ptr, NULL);
It is not immediately obvious why this would cause a problem. The actual bug concerns how the thread keyring of the process that requested the block device operation is handled. When a user-space process acquires a reference to the device-mapper device for an encrypted disk, including when, for example, cryptsetup asks to relock a disk by wiping the disk-encryption key, the created bdev_file holds a reference to the thread keyring. The older handle-based interface did not do that, which is why the behavior changed.
Normally, it makes sense for a struct file in the kernel to cache the relevant credentials associated with it. In this case, however, the kernel keeps a reference to the file after the corresponding user-space process has exited, keeping the thread keyring (which contains a copy of the disk-encryption key) alive. So, even when the kernel wipes its own copies of the key from memory, as requested, the copy in the thread keyring remains behind.
The fix, which was merged in July 2026 for the 7.2 kernel, is to instruct the kernel to use its own credentials for the created file, rather than the thread's keyring:
scoped_with_kernel_creds()
bdev_file = bdev_file_open_by_dev(dev, mode, _dm_claim_ptr, NULL);
(That code uses the kernel's scoped cleanup helper macros to temporarily override credentials in the security context of a task with the kernel's own credentials.)
With that change, the thread keyring is freed as soon as cryptsetup exits, and the kernel's copy of the disk-encryption key is wiped on request, so the key does not remain resident in memory. However, that does little for people who have to run kernels earlier than 7.2. In response to Blechschmidt's discovery of the bug, cryptsetup maintainer Ondrej Kozina added a workaround to the tool that creates an extra intermediary keyring that can be explicitly revoked when cryptsetup exits. That way, even if a buggy kernel pins the key from the thread's keyring, that key will no longer be usable to access the disk's main encryption key. That change is included in the project's 2.8.7 release, from late July 2026.
Explicitly freeing the keyring is an important precaution in any case, Kozina said, because there are other kernel subsystems that can pin keyrings. Ensuring that none of them have been invoked incorrectly is a much less robust solution than modifying cryptsetup to work around the problem. Blechschmidt's fix only applies to encrypted block devices backed by physical devices; block devices backed by loopback interfaces or other less-common configurations may still encounter the bug.
NixOS's new suspend code
Ultimately, Blechschmidt's porting attempt was successful. He has since released an experimental program that takes a similar approach to securely suspending with full-disk encryption on NixOS. He has also added an integration test to NixOS that verifies that the keys are correctly wiped on suspend, so that the bug cannot be inadvertently reintroduced.
Debian's cryptsetup-suspend has a somewhat benign race condition: since the program first wipes the disk-encryption keys and then asks the kernel to put the computer to sleep, there is a brief window where a kernel task attempting to access the disk could lock up waiting for the key to be available. When this happens, the computer fails to go to sleep, which is annoying at best and can lead to overheating at worst. Blechschmidt's NixOS version uses a kernel patch to wipe the keys and trigger sleep mode at the same time, eliminating the potential race. It still needs to use a RAM disk to allow the user to enter the disk-encryption passphrase after the computer wakes.
Considering that cryptsetup-suspend is not enabled by default on any distribution, it's unclear exactly how many users would really have been bothered by this bug. By default, disk encryption keys remain in memory when a computer is put to sleep, and this does not seem to cause much concern. But it's nice to know that, when explicitly configured to, Linux systems will now follow through on wiping the encryption keys on sleep.
A note on subscription prices from LWN
The online publication industry, as a whole, is struggling, with challenges coming from multiple directions. Thanks to the support of all of you, our readers, LWN would appear to be doing better than most. But the world has changed around us and, in particular, prices have changed considerably. By now, you probably know where this is going: subscription prices at LWN will be increasing as of September 15.We adopted the subscription model in late 2002; it was one of the best decisions we have ever made. This model makes us independent of the volatile (and surveillance-driven) advertising market and aligns our interests with those of our readers. But it does depend on support from those readers; if you have not yet subscribed to LWN, please consider doing so now — our subscribers are the only reason we continue to exist.
We have only increased prices twice in the 24 years since adopting this model; the last increase was in early 2022, nearly five years ago. That increase helped to keep us on a stable footing, and a lot more besides. We were able to hire Daroc Alden and Joe Brockmeier, and they have greatly increased the depth and range of our coverage. The LWN site has been improved in a number of ways, with features like articles in EPUB format, markdown formatting for comments, the kernel source database, full-text email and RSS feeds, dark-mode support, the public topic list, and more. A lot of effort has also gone into keeping the site alive, responsive, and reader-friendly in the face of escalating scraper attacks.
Since the 2022 price change, according to the undoubtedly reliable numbers from the US government, consumer-price inflation has added up to almost exactly 20%. Some costs (health insurance, naturally) have gone up rather more than that. We will be matching the inflation number, though, and increase prices by approximately 20%; the new monthly prices will be:
Level Price Starving hacker $6.00 Professional hacker $11.00 Project leader $19.00 Maniacal supporter $55.00
Prices for group subscriptions will be increased by the same amount.
All subscriptions purchased ahead of the change will remain valid through the original expiration date. The policy for individual monthly subscriptions is a little different this time; all monthly subscriptions that were active before this announcement went out will be charged at the old rate for the following six months. Reminders will be sent out to monthly subscribers before the new rates take effect.
There are few things we like less than raising prices, which is why we have done it so rarely. It would be far better to keep LWN as inexpensive as possible and make it up in volume. Subscriber growth has stalled, though, in recent years, making that strategy unworkable for now. We are working on schemes to bring in more subscribers again, but that is a long-term process; getting there requires some short-term help.
In January, LWN will begin its 30th year of publication. There is really only one reason why we are still here and vital after all that time: it is because our readers have always supported us. There are not many people who have had the good fortune to write for such a loyal community, and we are deeply grateful for it. Thank you, as always, for supporting LWN.
Page editor: Joe Brockmeier
Inside this week's LWN.net Weekly Edition
- Briefs: Kernel infrastructure; Debian AI; Dolphin 26.08; Firefox 155; Incus 7.4; OpenShot 4.0; Quotes; ...
- Announcements: Newsletters, conferences, security updates, patches, and more.