In early 2026, MongoDB stopped working with Linux kernels 6.19+, leading to a new kernel-drama. I discovered it by accident after a system update, trying to start my usual MongoDB container and receiving a exit 139 exit code. The cause of the issue was less trivial than I thought, and I had to do some digging to understand it and get it working again. What follows is the story of the incident (so far).

2013 -> 2018 - Restartable Sequences (RSEQ) Arrive in the Kernel

At Linux Plumbers Conf 2013 in New Orleans, Google developers Paul Turner and Andrew Hunter demonstrated a solution they were already experimenting with within the company: LPC - PerCpu Atomics. This is a feature they added to their Linux kernels to access shared data at CPU level from userspace without the need for locks or other low-performance atomic instructions. In the following years, two different sets of patches were presented to add the feature, which then converged on one, spearheaded by Mathieu Desnoyers of EfficiOS, with the goal of including it in the 4.15 kernel release in early 2018. Unfortunately, Linus blocked the patches due to a lack of real-world use cases and related metrics. Eventually, after a few more months, all the necessary data was gathered, and the new set of patches brought RSEQ to the 4.18 kernel in August of the same year. Mathieu Desnoyers himself summarized the five years of work required to achieve this result in the article “The 5-year journey to bring restartable sequences to Linux”.

2020 - TCMalloc

In 2020, Google released the first version of its TCMalloc library.

TCMalloc is Google’s customized implementation of C’s malloc() and C++’s operator new used for memory allocation within our C and C++ code… It provides benefits such as performance scales with highly parallel applications. TCMalloc is designed to be more efficient at scale than other implementations.

The benefits for highly parallel applications are also achieved through the use of a shared CPU-level cache. This cache is implemented using Restartable Sequences.

The “TC” prefix in TCMalloc refers to Thread Caching, which in its early versions was the library’s defining feature. Despite the changes it has undergone over time, it has not changed its name.

2024 -> 2026 - MongoDB 8 and TCMalloc

In October 2024, MongoDB 8 updated Google’s TCMalloc library to use its per-CPU cache instead of per-thread, thus increasing performance.

The claimed performance improvements compared to version 7 are:

  • Up to 36% better read throughput.
  • Up to 32% better performance for typical web applications.
  • Up to 20% faster concurrent writes during replication.

To date (April 2026), several other patch and minor releases have been released up to 8.2 (with 8.3 coming soon).

Glib vs TCMalloc

TCMalloc was one of the first libraries to support and use RSEQ since Kernel 4.18. Glibc added support for it in release 2.35 (February 2022), but there’s a problem: if you use Glibc with TCMalloc in the same project, it won’t work as expected. Glibc will register the structure (struct) to use with RSEQ before TCMalloc does, and then TCMalloc will no longer be able to use RSEQ. Without RSEQ, TCMalloc uses the per-thread cache instead of the per-CPU cache. Applications like MongoDB avoid this situation by disabling the specific Glibc functionality with the environment variable GLIBC_TUNABLES=glibc.pthread.rseq=0, thus leaving the TCMalloc environment variable enabled. This system has worked for years and continues to work today, but understanding the cause of the incompatibility brings us closer to the current problem.

The cause of the incompatibility

The incompatibility between Glibc’s RSEQ and TCMalloc has been known since 2022, and over the years, the same developer who ported RSEQ to the kernel has offered to help TCMalloc by providing specific information about the problem and how to fix it. This is the read-only cpu_id_start field exposed by the kernel in userspace, which TCMalloc uses creatively. TCMalloc not only writes to that field, but also expects the kernel to update its value:

When a thread is rescheduled, the kernel overwrites cpu_id_start with the current CPU number, which signals that the cached address is no longer valid.

Although the kernel effectively updates that field just as TCMalloc expects, the RSEQ specification never stated this behavior. TCMalloc thus exploited an undocumented kernel feature, and this is what makes TCMalloc incompatible with Glibc. Furthermore, although TCMalloc’s operation has been known for years, Google has done nothing to make it compliant with the specification that Glibc does. When activating Kernel debug mode for RSEQ, TCMallc stops working because this mode performs checks that, for some reason, are not present in normal mode.

2026 - Linux 6.19, Glibc, and RSEQ perf

So, for years, the cpu_id_start field was updated by the kernel just as TCMalloc needed it, even though this wasn’t the intended behavior. No one noticed it because RSEQ was used almost exclusively by Google and its TCMalloc. However, when Glibc began supporting RSEQ, performance issues emerged, and kernel developers began working on rewriting the RSEQ code to overcome the initial implementation. TCMalloc relied on specific conditions that occurred.

To understand [..] when a thread is rescheduled to another CPU, we overlap the top 4 bytes of the cached address with __rseq_abi.cpu_id_start. When a thread is rescheduled the kernel overwrites cpu_id_start with the current CPU number, which gives us the signal that the cached address is not valid anymore. To distinguish the high part of the cached address from the CPU number, we set the top bit in the cached address, real CPU numbers (<2^31) do not have this bit set. ref.

However, with the rewriting of RSEQ, this behaviour were changed because they did not comply with the ABI (Application Binary Interface) initially foreseen.

When addressing the performance issues of RSEQ the unconditional update stopped to exist under the valid assumption that the kernel has only to satisfy the guaranteed ABI properties, especially when they are enforcable by RSEQ debug. ref.:

In January 2026, the imminent incompatibility with the new kernel version was reported by a Google developer who had noticed it from internal automated tests. The kernel developers’ response, however, was negative: “You’ve known about it for years and haven’t done anything” and “you’ve deliberately abused the RSEQ implementation for your own gain.” Furthermore, the same mailing list thread states that the changes made to the kernel conform to the specification encoded in the RSEQ self-tests:

The correctness of these changes has been validated by the rseq self-tests, and I don’t see how that commit would violate the guaranteed ABI.

On February 8, 2026, Kernel 6.19 was released, including the RSEQ changes.

Domino Effect

On February 20, 2026, a report titled “Mongod hard-crashes exactly every 30 seconds (SIGSEGV)” appeared on GitHub describing this strange issue without any apparent explanation or specific logs. In the following weeks, were created various tickets on MongoDB’s Jira. It only takes a few days before the origin of the problem is understood: it is related to changes affecting Glibc, TCMalloc, RSEQ and recent Kernels. Even external projects like Arch Linux are aware of the problem but find confirmation in the January 2026 kernel thread that it is a TCMalloc issue: therefore, it is not a kernel problem.

Only a month later, on March 13th, a ticket in the TCMalloc project was opened to report the problem with kernels 6.19+, but the first response from a user is the famous Linus quote:

WE DO NOT BREAK USERSPACE!

If TCMalloc has worked for years and now a kernel change is breaking it, it is the kernel that needs to take a step back.

A problem and a solution

Given TCMalloc’s inaction, on April 22nd, a MongoDB developer wrote to the Kernel mailing list explaining the problem. The key point is what we now know:

It breaks TCMalloc specifically by failing to overwrite the cpu_id_start field at points where it was relied on for correctness.

He also adds that the solution is simple:

It would be sufficient for TCMalloc’s internal usage if every time the kernel nulled out rseq_cs, it also wrote the CPU ID to cpu_id_start. That should be essentially free since you’re already writing to the same cache line.

These statements are followed by responses from the kernel developers, who recall him that TCMalloc had been aware of the problem for years, and that they had been warned several times…

At dawn, look to the East

After an initial wave of negative responses from Kernel developers, Linus Torvalds took over the discussion admonishing them.

We will have to fix this. It clearly violates our regression rules.

The only “ABI guarantee” is what people actually see and use, not some debug option that wasn’t enabled. If that rule was actually an important part of the ABI, it shouldn’t have been a debug thing.

Furthermore, instead of criticizing TCMalloc’s behavior that others were pointing out as an “abuse” of RSEQ, he defended it:

That’s how clever hacks work - they take advantage of things past their design parameters. “If it works, it’s not stupid”.

Finally, he reminded the Kernel number one rule:

There is one major rule in kernel development, and it is “we don’t break user space”.

So either the previous functionality is restored or they’ll have to find a way to adapt the new one without causing problems for TCMalloc.

Waiting

Now we just have to wait for the new kernel release with the fix or stay at versions <6.19. In the meantime, you can use the environment variable GLIBC_TUNABLES="glibc.pthread.rseq=1" which, by enabling Glibc’s RSEQ, has the side effect of disabling TCMalloc’s RSEQ, but this will cause MongoDB to lose performance (in fact, this is not an officially supported solution).