|
|
Log in / Subscribe / Register

LWN.net Weekly Edition for August 6, 2026

Welcome to the LWN.net Weekly Edition for August 6, 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)

The beginning of a process-builder API

By Jonathan Corbet
August 4, 2026
The recent discussion on "spawn templates" raised questions about whether it was time to provide an alternative to the classic Unix fork()/exec() pattern for process creation. One idea that was raised there was to shift the template pattern into an interface that could be used to efficiently assemble new processes from bare cloth, without duplicating the parent process. Preferably, that interface would be able to implement posix_spawn(). Li Chen, the author of the spawn-template work, has now responded with a patch series (written with significant LLM assistance) showing what a process-builder API for Linux might look like.

In the Unix model, a call to fork() (which ends up being a variant of clone() on Linux systems) creates a copy of the calling process, which involves a fair amount of work. The child then typically modifies its environment in whatever ways are necessary — opening or closing files, for example — before making a call to execve() to run a new program. That latter call ends up throwing away most of the work that was done to copy the parent process, which is not entirely efficient. In cases where the intent is to immediately run a different program, a better model might be to piece together the new process from the beginning, without involving (much of) the parent process's state.

Process creation

In Chen's patch series, the way to do that is to start by creating an empty process with a call to the existing pidfd_open() system call:

    new_process_fd = pidfd_open(0, PIDFD_EMPTY);

The new PIDFD_EMPTY flag requests the creation of a process shell that will have its details filled out later. The return value is a real pidfd, but most of the resources associated with a process are not yet present. There is no process ID, no task structure in the kernel, and no charge against the parent's process-count resource limit. Most kernel operations that act on a pidfd will refuse to do anything with this one at this stage.

The next step is to put together the information that drives the construction of the new process; this work is centered around this structure:

    struct pidfd_spawn_run_args {
	__u32 flags;
	__u32 nr_actions;
	__aligned_u64 path;
	__aligned_u64 argv;
	__aligned_u64 envp;
	__aligned_u64 actions;
	__u32 action_size;
	__u32 reserved0;
	__u64 reserved[2];
    };

The path field is a pointer to a string containing the path to the executable that the new process should run; as described below, it can be NULL in some cases. The argv and envp parameters point to the usual argument and environment arrays. The flags field must be zero, as must the reserved fields. Filling in those fields (the rest will be covered shortly) provides enough information to build and run the process with a call to the first of two new system calls:

    int pidfd_spawn_run(int pidfd, struct pidfd_spawn_run_args *args, int arg_size);

Here, pidfd is the pidfd for the under-construction process, args is a pointer to the above structure, and arg_size is the size of that structure. If all goes well, this call will create the full process and set it running with the indicated program; the return value will be the ID of the now fully fleshed-out process. The original pidfd remains valid and attached to this process. Should some sort of error happen, instead, the process shell will be left in a sort of dead state, and any further attempts to operate on it will fail.

Configuration

Providing an executable image, arguments, and environment is normally just the beginning of configuring a new process; a typical application will want to set up the process's file descriptors and, perhaps, adjust many other things. That is what the actions field of the pidfd_spawn_run_args structure is for. It points to an array of this structure type:

    struct pidfd_spawn_action {
	__u32 type;
	__u32 flags;
	__u32 fd;
	__u32 newfd;
	__u64 reserved[2];
    };

The type field describes an action that should be carried out before the process is instantiated and launched. The actions currently defined in this patch set (which are a small subset of what would eventually be needed) are:

  • PIDFD_SPAWN_ACTION_DUP2: duplicates an existing file descriptor using dup2(). The existing file descriptor should be passed in the fd field, while the intended new descriptor goes in newfd.
  • PIDFD_SPAWN_ACTION_CLOSE_RANGE: closes the range of file descriptors between fd and newfd (inclusive).
  • PIDFD_SPAWN_ACTION_FCHDIR: changes the new process's working directory to the one identified by fd.

PIDFD_SPAWN_ACTION_CLOSE_RANGE allows the CLOSE_RANGE_CLOEXEC and CLOSE_RANGE_UNSHARE flags supported by the close_range() system call; flags must be zero for the other two actions. The nr_actions field in the pidfd_spawn_run_args structure indicates how many actions are present, while action_size is the size of the pidfd_spawn_action structures. These actions will be carried out before the executable image is located, meaning that changing the working directory affects how a relative path to that image is resolved.

If any of the actions fail at pidfd_spawn_run() time, the entire system call will fail and the new process will not be launched.

The second new system call is an alternative configuration interface for some aspects of the new process:

    int pidfd_config(int pidfd, unsigned int cmd, char *ukey, char *value,
    		     int aux);

This system call is meant to be useful beyond the spawn functionality; in this patch set, though, it can only do one thing. With a cmd of PIDFD_CONFIG_SET_STRING, it can set a string-based parameter to the given value. The only such parameter in this set is PIDFD_CONFIG_KEY_PATH, which sets the path to the executable to run. This call must be made if the path pointer passed to pidfd_spawn_run() will be NULL. If a non-NULL path is passed to that system call, it will override a path configured with pidfd_config().

What's missing

This series is meant to be a proof of the concept that would help the community decide whether the overall direction makes sense or not. So it does not implement much of what would be wanted in the final result. As mentioned above, the set of available actions is much smaller than it would eventually need to be. To be able to implement posix_spawn(), the kernel would have to support actions to define signal handling, control scheduler parameters, open files, and more. For the most part, these are just a matter of programming once the form of the desired interface is established.

The other big gap is that pidfd_spawn_run() does not actually create a new process from scratch; instead, the implementation is based on vfork() internally. In theory, it should be possible to replace the implementation transparently, with the only change visible to user space being better performance, once the API is agreed upon. In practice, that may not be a small job. The kernel only ever creates two special-purpose processes (init and kthreadd) from scratch; the machinery to do that for the general case does not exist. That, too, is a matter of programming — perhaps a fair amount of it.

First, though, the API must be agreed upon. The series was posted on July 16, but has only garnered a single review comment as of this writing. It will need to attract a lot more eyeballs before a fuller implementation can be considered. A number of people have been asking for this kind of process-creation interface for years; now would be a good time for them to take a look to see whether this proposal is close to what they have in mind.

Comments (27 posted)

Fedora considers conflict-of-interest policy

By Joe Brockmeier
August 4, 2026

The Fedora Council is considering a conflict-of-interest (COI) policy for its decision-making bodies, such as the Fedora Engineering Steering Committee (FESCo), special-interest groups (SIGs), and any other groups or individuals that report to the council and are responsible for decisions that impact the Fedora project. The current draft does not, however, apply to the council itself. The public discussion for the COI policy began on July 23 and seems to be nearing completion, with the council set to discuss the topic again during its meeting on August 13.

Motivation

It is not unusual for open-source projects to have COI policies. In fact, it might even seem a bit unusual for a project like Fedora, which has so many other well-defined policies, to lack one. In announcing the discussion, Aoife Moloney said the council's idea to pursue a COI policy came from the fallout of "a decision made by a governance group in Fedora that removed someone's ability to contribute to the project in a certain way" about 18 months ago.

The decision Moloney vaguely referred to was FESCo's questionable handling of a request to revoke Peter Robinson's status as a provenpackager, which grants the ability to commit to all packages in Fedora and not merely the ones he owns. FESCo had voted in a private meeting to strip Robinson of the status and took the unusual step of announcing the revocation publicly with an accusation that he had "continued to use his provenpackager privileges in an unapproved manner, frequently causing additional work for other maintainers" despite warnings. The Fedora Council overturned the decision and issued an apology to Robinson.

Emmanuel Seyman asked the council to provide a public accounting of the details behind FESCo's actions, as well as how each member voted, in April. He noted that FESCo had committed to publishing a public ticket with a summary of the private discussion in December 2024:

Since then, we have waited for the public ticket we were told would be created and we have had to vote for several FESCO elections without the full voting record of the people who voted then so that we can determine if we want them to stay on FESCO or not.

Council member Justin Wheeler indicated that the council had met to discuss the request, and that a summary would be posted "by the end of the day today" on May 7, but there was no update until June 5, when Moloney said that the council had decided against providing additional information. "Backtracking on the initial expectation of privacy under which those decisions were made in this incident would be disingenuous, and we lack the necessary context to form a retrospective opinion".

Wheeler followed up on July 6 to report again that the council would not be providing any further information on the revocation incident, but it was "committing to improving our Conflict of Interest policy as the mechanism to prevent this kind of governance issue in the future". This is something that Robinson had suggested: he said that Fedora needed a COI policy in a request to the council made in December 2024. Fedora Project Leader (FPL) Jef Spaleta supplied a draft policy to the council in July 2025, but it was not shared for public discussion until now.

Because the details of the complaint, or complaints, made against Robinson have never been brought to light, it is unclear what role a COI policy would have played in improving the situation. It may be that it was a member, or members, of FESCo who initiated the proceedings and then voted against Robinson rather than recusing themselves—but, for now, observers are left to wonder.

Draft policy

The policy begins with the disclaimer that it has been "generated using NotebookLM, and then revised using human editorial control". The policy's primary goal is to ensure that all decisions made by the project that affect a person's participation in Fedora, "are considered fair, impartial, and aligned with the best interests of the Fedora Project and its community".

The policy's scope includes "all individuals and groups participating in decision-making processes within any Fedora Project group or team operating beneath the Fedora Council": there is a non-exhaustive list of groups, teams, and so forth named, but it seems to broadly apply to any decision-making that happens in the project except the council's. It defines a conflict of interest as any time that a person's interests, or the interests of an organization they are affiliated with, "could reasonably be seen to influence, or appear to influence, their ability to make objective decisions on behalf of the Fedora Project". The conflicting interest might be "financial gain, professional advancement, personal relationships, or loyalty to another organization".

The policy proposal specifies that conflicts of interest are not automatically disqualifying for participating in discussions or voting on matters. It acknowledges that, for example, many Fedora contributors are employed by Red Hat and may frequently face what could be a conflict of interest.

The draft requires that if an individual "believes they may have a conflict of interest related to a specific discussion, vote, or task", then they should declare that conflict as early as possible. The draft is a bit fuzzy, unfortunately. It states that a person should recuse themselves from a decision-making process if there is a COI, but also suggests that a possible COI be discussed so that a person could still be allowed to participate in a decision if the decision-making group believes that it is non-disqualifying.

The council would mediate or adjudicate any situations where there is a disagreement or dispute about conflict of interest. The policy is open-ended on the question of what happens if a person has a conflict of interest or if a decision seems to have been influenced by one. Remediation steps, it says, "should be taken on a case-by-case basis".

Discussion

Christopher Boni pointed out the apparent contradiction between the draft's language about recusals and its note that conflicts are not automatically disqualifying. FESCo member Fabio Valentini replied that the apparent contradiction is resolved if one assumes that recusal only applies "to the decision process for whether the previously declared conflict of interest disqualifies this person or any remediation actions should be taken" (point 6 in the draft policy). He did, however, say that this should be made explicit in the policy if that was the intent.

FESCo member "Maxwell G" said that he understood that the council was unable to escalate decisions to itself, "but I think the rest of this should also apply to decision-making within Council itself". Valentini agreed and suggested that perhaps the council could "escalate 'down'" to a body like FESCo.

One concern that surfaced during the discussion was the idea that FESCo members might have to recuse themselves from voting on their own change proposals. Miro Hrončok said that it had been repeatedly agreed that FESCo members were allowed to vote in favor of their own proposals. "It should also be totally OK to run for a body to fight for my own interests. As long as disclosure is made, I don't believe we should automatically require abstentions."

Most seemed to agree a COI policy would be a good thing, even if the draft needed polishing. However, FESCo member Zbigniew Jędrzejewski-Szmek argued that it was unnecessary. He said that FESCo decision to remove Robinson's provenpackager status was not influenced "in any strong way" by conflicts of interest, and a COI policy would not have made a difference.

I see various decisions taken in Fedora slowly or erroneously (in hindsight), but those issues have little to do with conflicts of interest. I'd name the following reasons: lack of time to investigate details, misunderstandings about scope, preferences for certain technologies or approaches, overambitious plans, tiredness, lack of synchronization, etc. In some cases personal sympathies or trust/distrust between people exists, but those [are] not the obvious types of relationships that would be disclosed under the proposed policy.

It does seem unlikely that members of FESCo, or other bodies, could be reasonably held to the standard of recusing themselves from decisions based on, say, a dislike for another contributor.

Aleksandra Fedorova seemed to agree that a policy was unwarranted. "We don't need more policies to state and govern the obvious. It just brings corporate-style bureaucracy to the human-oriented project." She later said that it might make sense to have a COI policy for "decisions that can not be done in public" such as code-of-conduct complaints or other sensitive topics. "If a decision can not be fully discussed and justified in public, there is no easy default way to gain trust, and some explicit conflict of interest considerations could help." She suggested a much smaller policy:

Decisions regarding Code of Conduct issues and other questions, related to access rights of a specific person in the Fedora Project, should not be made by people who are directly involved in such a conduct.

Moloney said that she would be in favor of reducing the scope of the policy to decisions that need to be made privately. Jędrzejewski-Szmek said that he thought Fedorova's suggested text was great. "Can we take that one sentence and add it somewhere in the top-level governance docs and call it a day?"

The council discussed the policy during the open floor portion of its meeting on July 29. Moloney said that the council had decided to redraft the document and allow two more weeks of feedback. It will be discussed again at the council meeting scheduled for August 13.

Comments (2 posted)

Buffer sizes for FUSE io_uring

By Jake Edge
August 3, 2026

LSFMM+BPF

The Filesystem in Userspace (FUSE) subsystem provides a way to service filesystem requests from a user-space server, which moves the format-handling code out of the kernel. The FUSE server can use the io_uring facility for better performance, but Bernd Schubert is concerned that memory is being wasted because the current implementation has a single, large buffer size that is excessive for small I/O operations. He led a discussion on that topic in the filesystem track of the 2026 Linux Storage, Filesystem, Memory Management, and BPF Summit in Zagreb, Croatia.

Currently, libfuse sets up eight entries per ring, with each entry defaulting to the maximum payload size (8MB), though switching to 4MB is also possible, he began. Normally one or two entries per ring are needed to achieve maximum throughput to the disk (which can be local or over the network), but there is also a need to handle metadata requests, for operations like stat() or directory listings. "You don't want to disturb your streaming I/O while you are doing these metadata requests".

Those smaller requests might be 16KB or 128KB. In order to saturate the I/O bandwidth with requests of that size, however, a larger number of buffers is needed. "The question is how we do this." The existing implementation uses entries with a separate header and payload structure, but each has the same payload size.

Schubert noted that Joanne Koong has been working on patches to change the buffer handling for FUSE io_uring that would separate the headers from the payloads. Each entry would still have a header, but the payload buffers would be shared. There would no longer be a one-to-one mapping between entries and payloads, and the payloads would be available in multiple sizes.

[Bernd Schubert]

Schubert has envisioned a different approach with, say, four different payload sizes. There would be entries that used 4KB, 64KB, 128KB, and 1MB payload sizes; the 4KB entries would have 128 buffers available, while the larger sizes would only have two buffers available. He has not written the code to implement his idea, but he thinks that it would work: the right-sized entry from a single ring would be chosen based on the size of the I/O operation.

In a discussion that he had with Koong the day before, she said that the problem could be solved with multiple rings instead of multiple sizes on a single ring. Each ring would have a different buffer size and there would be code to choose the right one based on the size of the I/O, which is similar to the code that Schubert envisions. His concern is that having multiple rings means making more system calls, so his preference would be to have a single ring. The user-space FUSE server would need to monitor multiple rings and service I/O operations from each.

Another concern that he has with multiple rings is for applications on systems partitioned to run Linux on just a few cores, which means that a single core may be responsible for polling multiple rings. "That gets painful."

FUSE maintainer Miklos Szeredi asked whether Schubert's plan required managing buffer allocations in a large pool of memory, but Schubert said that it did not. Handling allocations that way would lead to fragmentation, so his method simply statically sets up multiple buffers of each size; when there are no more 4KB buffers, for example, the requester will have to wait. There was some question about perhaps using the larger sizes in that case, but he thinks those are too precious to be used that way.

Koong said that she is concerned that waiting for an available buffer of the right size will add unneeded latency. With her multi-ring solution, the other rings can provide a buffer for a request instead of waiting for one of the right size. She asked: "If you have a small request and there are larger buffers available, why are you making the small request wait until there is a small buffer available?" Schubert said that in that case, there are already 128 requests in flight, so adding another has no real benefit.

There was some back and forth between them, with Schubert wanting to avoid the user-space complexity of handling multiple io_uring rings, while Koong is looking to make the best use of all available buffers. She said that she did not see a need for more than two different buffer sizes, one small for metadata and one large for data. Schubert said that was fine, but that it still meant polling multiple rings if the different sizes are on different rings as Koong has proposed.

An attendee asked about the io_uring performance problems that are being seen, but Schubert said that it is not performance that he is trying to improve. He wants to reduce the memory usage as there is a need for many metadata requests, but if they all have to be the same size as the I/O requests, lots of memory is wasted.

Koong raised the issue of head-of-line blocking, which she said was an advantage to having multiple rings: one thread could be handling the data I/O while another was handling the metadata requests. Schubert said that the current libfuse may still be handling requests in a synchronous fashion, which could cause smaller I/O operations to block behind the larger ones, but that switching libfuse to handle io_uring operations asynchronously should solve that problem. Koong was not convinced that a libfuse change of that sort would work well with custom libraries that have their own idea of how the I/O will be handled. Schubert agreed that could be a problem, but thought it was rare, which Koong disagreed with.

Schubert said that he was planning to add coroutine support to libfuse, which should make it possible for servers to avoid the head-of-line blocking problem when only using the libfuse thread. He noted that it is already possible to write a FUSE server that avoids the problem, but it must do so using additional threads that handle asynchronous io_uring operations.

At that point, the session had run out of time and it was not entirely clear where things go from there.

Comments (4 posted)

Examining other network namespaces using BPF

By Daroc Alden
August 5, 2026

LSFMM+BPF

Jordan Rife's work involves writing BPF programs for Cilium that interface with Kubernetes networking. As part of that work, he wants to enable BPF programs with appropriate permissions to iterate through the sockets of a different network namespace. He led a session about the idea at the 2026 Linux Storage, Filesystem, Memory-Management, and BPF Summit where the BPF developers in attendance were quick to suggest a number of related alternatives.

Socket-lb is a Cilium feature that uses the hooks for sockets associated with a given control group to balance connections across remote servers, while avoiding the per-packet overhead of network-address translation (NAT). In a setup that does not use socket-lb, a client might make a request to a frontend server that then uses NAT to route the connection transparently to a chosen backend server. Socket-lb improves on this by having the routing happen directly on the client device, still transparently to user space, but avoiding the extra network hop implied by NAT. In practice, socket-lb has some limitations, Rife said. If a selected backend goes away, for example, traffic will continue to be directed at that non-existent backend until Cilium cleans things up. Today, the software does that by using BPF iterators to walk through the available sockets and destroy them if needed.

That works, but only within a specific network namespace, since the namespaces are isolated from one another and cannot see each other's sockets. In practice, this means that Cilium's user-space component must enter the namespace of each Kubernetes pod running on the host, scan its sockets, and then exit the namespace and move on to the next one. This adds significant overhead to the whole process that isn't really needed, since Cilium has administrative access to all of the network namespaces anyway.

Worse, sockets aren't sorted by network namespace in the kernel, so every time Cilium's BPF program does its scan, it has to walk the entire hash table of sockets; the kernel filters sockets from other network namespaces before the BPF program sees them. So, Cilium ends up walking the list of every socket in the system once for each network namespace, which is inefficient. In his work, Rife said he had seen as many as 256 namespaces per computer.

His proposed solution is simple: create a new iterator, usable by BPF programs with appropriate privileges, that iterates through all of the sockets on the system at once, even those from foreign namespaces. That way, Cilium would not need to change network namespaces at all; it could simply use a BPF program to periodically scan the whole system for stale socket-lb sockets.

Jakub Sitnicki asked why Rife didn't keep a list of which sockets correspond to which backend directly, and then use those. BPF programs can store pointers to socket objects in socket maps, which can be used to store weak references (pointers that don't increment the socket's reference count, and therefore don't prevent it from being closed). So, such a scheme wouldn't keep sockets alive after their natural deaths, he noted. Rife did try that in 2025, but making it work was more complicated than it really should have been. In current kernels, BPF programs cannot destroy sockets from the context of an iterator over a socket map, because they would need to acquire the socket's lock. Fixing that requires rewriting a bunch of locking logic around access to sockets.

One workaround would be to add a sleepable variant of bpf_sock_destroy() that would acquire the socket lock itself, which Martin Lau had suggested to him, he said. Ultimately, Rife had abandoned the idea, but he could come back to it if the whole-machine iterator he was proposing wasn't acceptable. Sitnicki wanted to know why the socket map iterator wasn't sleepable in the first place. Rife didn't know, although he speculated that there might be some challenges around the interaction of RCU and the socket lock. Lau clarified that many BPF iterators are sleepable, it is just the socket map in particular that has this problem.

One of Rife's colleagues is working on tracking metadata for all sockets in a separate map, and that might also be a workaround. Yet another approach would be to make bpf_sock_destroy() itself work from the context of a socket map iterator, Rife said. That's hard to do without adding a reference count, and therefore some memory overhead, or changing the semantics of the iterator. But allowing sufficiently privileged BPF programs to iterate over all network namespaces is a much simpler solution all around, he thought.

Daniel Borkmann mentioned that the BPF maintainers had discussed adding an iterator over network namespaces; perhaps references from that iterator could be passed to the socket map iterator as a trusted input, he suggested, which would let the existing socket map iterator work without requiring Cilium's user-space component to change network namespaces. Rife pointed out that would still end up walking all of the sockets on the machine multiple times, it would just do it from entirely within the kernel.

Sitnicki and Lau had a brief side conversation about how the current code finds network namespace references, and potential improvements there. Rife agreed to look into it, and consult the networking maintainers, but observed that it still wouldn't solve his efficiency problem.

John Fastabend noted that Cilium caches raw socket pointers in several places, because BPF socket maps are not expandable, "which is obnoxious." Pointers to sockets stored in BPF socket maps are automatically cleaned up when the socket is destroyed; socket pointers stored as opaque values in a BPF arena are much more convenient to store for tracking purposes, but aren't automatically cleaned up and can't be dereferenced. Sitnicki pointed out that storing socket pointers in BPF arenas wouldn't work well for Rife's use case. Fastabend replied that it doesn't work well for him either, but there are lots of reasons to want to stash sockets somewhere more flexible. He suggested changing BPF socket maps to be resizeable.

It would be nice to be able to mount sockfs (a virtual filesystem that allows users to manage sockets, including permissions, using the filesystem API) and pin sockets that way, Sitnicki remarked. That would avoid the need for BPF maps entirely. Lau commented that someone had a patch in progress that does something tangentially related to that, but still thought that being able to iterate over everything, as Rife proposed, would be useful.

Sitnicki asked whether Rife had considered obtaining a duplicate file descriptor for the UDP socket backend processes that might go away, holding onto them in a daemon, and using those references to clean them up when needed. Rife explained that he'd like to do the whole thing from BPF. Fastabend wanted to know whether this was also a problem for TCP sockets. Borkmann explained that the normal TCP reset mechanism would take care of things, but only after a long-enough timeout that some customers preferred the faster failover provided by socket-lb, so it was used for both UDP and TCP.

At that point the session devolved into a discussion about what other applications could potentially use a resizeable socket map, before running out of time. Despite the many alternatives the assembled developers raised to Rife's idea, none seemed hostile to it, just interested in painting the bikeshed a different color. As of the beginning of August, there is not yet any accepted solution to Rife's problem.

Comments (5 posted)

FUSE status and plans

By Jake Edge
August 5, 2026

LSFMM+BPF

Filesystem in Userspace (FUSE) maintainer Miklos Szeredi led a birds-of-a-feather (BoF) discussion about the subsystem at the 2026 Linux Storage, Filesystem, Memory Management, and BPF Summit. In it, he talked about maintenance challenges, proposed features and their status, and his plans for a new FUSE API. There is a lot of interest and activity in the FUSE community these days it seems.

He began by noting that he feels he "is not a good maintainer". There are two parts to being a maintainer, he thinks, "one is to keep bugs out and the other is to let features in". He is good at the first, but not at the second. One way to address that is for FUSE to have a co-maintainer. "If someone volunteers, I'd be very happy." There were some, perhaps joking, suggestions made by attendees, but no one stepped up to help co-maintain FUSE itself.

Features and cleanups

Szeredi moved on to a list of pending features, starting with Darrick Wong's iomap-based user-space API for FUSE. That patch set is large, Szeredi said, increasing the size of FUSE in the kernel by at least 30%. The FUSE-based famfs patches from John Groves are much smaller and he hoped that some progress on those had been made in the famfs session earlier in the day. He also mentioned Joanne Koong's zero-copy support for io_uring in FUSE, compound commands from Horst Birthelmer, a file handle user-space API for FUSE by Luis Henriques, the io_uring buffer size discussion that Bernd Schubert led in the previous session, and Koong's large folio support for FUSE. Meanwhile, Szeredi has been working on restructuring and cleaning up the FUSE API.

He went into some details of the cleanup, starting with a separation of the transport and filesystem layers that has made its way into the upcoming 7.2 kernel. He has plans to do the same for character devices in user space (CUSE) and virtiofs. Beyond that, he wants to provide multiple types of layers, citing existing network and io_uring transports as examples needing better separation. He also wants to pull the superblock operations out of inode.c into their own C file and to split up the "very big" file.c into smaller files based on the type of I/O being used. He encouraged others to raise their cleanup ideas as well.

The user-space API for FUSE is more than 20 years old at this point and, like the FUSE kernel code, it has accumulated a fair amount of cruft. He has started working on a clean-slate API, "which is currently very slim" at around 2,000 lines of code, so 10% of the current FUSE API size. It is called "fusex", for FUSE extended or experimental, and is available in his FUSE tree. It has lots of limitations, since it only supports local filesystems, which is exactly opposite of the network-filesystem focus of the original FUSE, he said. It is synchronous-only as well, with no support for asynchronous operations. While fusex is currently being used as an experimental tree for adding various features that may eventually be migrated into the main FUSE code base, he would like to see it turn into "a new major version of the protocol".

Ted Ts'o raised a "somewhat related" problem with FUSE filesystems being used on non-Linux platforms. In particular, there are users of the fuse2fs FUSE client on macOS and Windows; Wong has been working on extending it to use more recent FUSE features, Ts'o said, and encountering problems with macFUSE. Ts'o would like to see a simpler user-space API since he looked at the existing one and also noted the 20 years of history embodied in it. He would like his FUSE driver to work on macOS and Windows, but realizes that might take a fair amount of coordination from developers on the other operating systems with the Linux FUSE project, which may not be happening. Szeredi noted that the last he heard from the macFUSE developers was 15 years earlier, so there is no real coordination.

Schubert said that he had been working on some libfuse problems that occur on the BSDs and he believes that macFUSE is based on libfuse. It is difficult to run the libfuse tests on the BSDs, and he does not have or want a BSD system; some BSD developers are working on a virtual machine running the OS so that the tests can be run, but he does not think there is any similar effort going on with macFUSE. Because of Apple's kernel-code restrictions, he said, the current approach is to mount a filesystem as NFS and use a FUSE-to-NFS translation layer. Due to those restrictions, he thought that native macFUSE development had ceased.

Ts'o said that he was running native macOS FUSE on his laptop using macFUSE. The problem is that Apple requires a signed kernel extension, so only a single developer can build a binary from the macFUSE source code on GitHub. Anyone who wants to use macFUSE must obtain the binary from the Apple store, he said; there may be ways for others who want to work on the code to register with Apple so they can run it locally on their laptop, however. Schubert said that FUSE-T is the project he was talking about, which Ts'o was not familiar with. Ts'o does have interest in making fuse2fs work on macOS and also has access to BSD virtual machines, so he may be able to help with some of that testing.

Sub-maintainers

Szeredi noted that he thought some of the pending FUSE features, such as iomap, file handles, and compound command support, should go into fusex, rather than the existing FUSE implementation. He also thought it would make sense for FUSE to have sub-maintainers for some pieces, such as the io_uring path; he laughingly noted that Schubert already had too much on his plate but had volunteered to sub-maintain FUSE io_uring. Schubert said that he always looks at patches affecting that path now and would like to be notified directly when changes are made to it, but Christian Brauner cautioned that it was unlikely that changes like the recent kmalloc() conversion would be copied to him even as a sub-maintainer.

Brauner also suggested that Koong should consider being an io_uring sub-maintainer. She somewhat hesitantly agreed, but had a more general concern that she wanted to bring up. She would like the FUSE development community to get more guidance from Szeredi about what is maintainable, especially with regard to user-space APIs, which are difficult to change. He has decades of experience that many newer FUSE developers lack, she said. Another attendee noted that sub-maintainers will only be effective if Szeredi defers to their judgment; Szeredi agreed, noting that he is not able to keep all of FUSE in his head anymore, so he has deferred things like FUSE io_uring to others.

User-space API is an important thing to get right, Szeredi said. Brauner agreed and noted that kernel developers "suck at this", but noted that he thinks that developers in the virtual filesystem (VFS) layer have gotten better in recent times "because we are closely in sync with the actual users". That helps with better APIs but also helps API adoption; "oftentimes you can design APIs that are just ignored by user space because they're not practical".

Brauner noted that the recent focus on extensibility in VFS APIs has been beneficial. Once a new feature has been implemented, interesting ideas for extensions arise; being able to easily accommodate them "has been invaluable in my experience". He noted that io_uring was another example where extensibility was baked in from the outset.

Amir Goldstein had already volunteered as a FUSE passthrough sub-maintainer but he seemed skeptical that adding more FUSE subsystem entries to the kernel MAINTAINERS file would be useful. Others disagreed, and Brauner noted that it may well be helpful for people's careers; the tooling, b4 in particular, makes good use of those entries. Szeredi added two new FUSE subsystems, io_uring and passthrough, along with the new maintainers; that change was merged for 7.2.

Schubert had suggested monthly or biweekly conference calls for FUSE, so Szeredi asked him to describe his thinking. There is a need to agree on the approach for features, Schubert said; currently, development can proceed for months until a patch review derails the feature. That leaves developers trying to explain to their management that they will need more time to develop a new set of patches. He suggested that designs be submitted to the mailing list before development begins; those designs could be discussed in the calls. Brauner said that he wished VFS developers would do that.

Fusex

Over the remote link, Wong asked about fusex and whether it was meant to work with the existing libfuse. Szeredi said, perhaps a bit hesitantly, that it was; Wong was hoping that switching his iomap work to fusex would not require changing any user-space code, but Szeredi could not promise that. He did not think that a lot of code was needed, but fusex is still lacking for some needed features.

Fusex is only for local filesystems, he reiterated, which means that the filesystem cannot change except through FUSE (and fusex). Doing so should not cause a crash, but the filesystem will not work correctly because fusex does not have the infrastructure to handle that case, which simplifies it greatly. It is simply a prototype, at this point, but if it continues on, it should add the ability to remotely change the filesystem "but in a much more sane way than it is currently done in the upstream FUSE".

Brauner asked if Szeredi thought of fusex as a replacement for the existing FUSE; Szeredi said that he did, but thought that the existing FUSE could never go away because fusex cannot be completely backward compatible. The two would share much of the same code, so the maintenance burden would not be huge; in fact, "getting rid of the corner cases and strange behaviors" should make overall maintenance easier.

Goldstein noted that the maintenance burden will need to include libfuse, which Szeredi agreed was the case. Schubert said that he is planning to start marking some libfuse functions as deprecated; hopefully filesystem developers will move away from them over time. Conversions away from using the deprecated functions could perhaps even be handled by LLMs, he said.

Schubert also asked about features, such as compound commands, which are being pushed to fusex; the companies that are developing those features may want to use them with the less-restrictive upstream FUSE. Szeredi said that he is not opposed to adding features to the main FUSE code base, but would like to merge fusex as a place to experiment and then features that are added to it can be merged back to regular FUSE. With that, the session ran out of time. Szeredi did post a summary of the session to the mailing list shortly after the summit.

Comments (3 posted)

The future of libraries in BPF

By Daroc Alden
July 31, 2026

LSFMM+BPF

Song Liu believes that the way that programmers assemble complex BPF programs will be changing rapidly in the future. At a session of the 2026 Linux Storage, Filesystem, Memory-Management, and BPF Summit, he shared his thoughts on what that change could look like, though he did not have any concrete proposals for what, if anything, the BPF maintainers should do. He anticipates an ecosystem of Rust BPF packages developing, which is significant because BPF does not really have a package manager at the moment.

There are not many existing, popular BPF libraries, Liu said. Those that exist are generally small header-only libraries, or deal with the user-space side of loading and managing BPF programs. It is not impossible to have BPF libraries; bpftrace has a standard library. Bpftrace can also import non-standard-library BPF C code in a manner similar to inline assembly in normal C code. "But I'm not sure people actually do this," he added.

Given that the rest of the programming world makes use of libraries, why not BPF? There are a few reasons. For one thing, there is no standard package manager or manner of distribution. Also, whether a BPF program passes the verifier can depend on properties of the whole program taken together, not just a function in isolation. This makes using libraries harder, and many people find it easier to copy an existing example and tweak it for their use than to build a reusable library. The one obvious exception to this trend is libarena, which was discussed earlier in the summit.

Emil Tsalapatis pointed out that another reason for the lack of libraries may be that many people write BPF programs as a single C file, and don't go through the steps required to link multiple BPF objects. He has observed that pattern when dealing with sched_ext schedulers, for example.

With Alexei Starovoitov planning on making BPF easier to write in Rust, there is the possibility that BPF libraries could start appearing on crates.io, Rust's package repository, Liu said. But that has its own problems: with many libraries, it can be hard to find the good, reliable ones. Also, libarena may change substantially if it is rewritten in Rust. Starovoitov clarified that libarena is written in C for now, "but we'll just convert it to Rust" when the time comes.

Liu then speculated about how the use of large language models (LLMs) might change the picture around the use of BPF libraries. He thinks they may be even more prone to copying and modifying existing solutions than human authors, but it is hard to be sure. Liu's prediction is that more BPF libraries will appear on crates.io; great libraries will remain as libraries, where merely good libraries will be copied, pasted, and modified. Bad libraries will cause problems and take time to convert into useful code. A lot of that prediction depends on how well LLMs adapt to changes in BPF's packaging culture, however.

Starovoitov said that he expects LLMs to quickly adapt to the use of libarena specifically. A copy of the library should be kept on GitHub, he said. Then sched_ext can include it as a Git submodule, and once LLMs "scrape the repo for the millionth time" they'll pick up on what has been moved into libarena code and start using it. As of July 2026, sched_ext has not yet added libarena as a submodule. In general, putting libraries into the places that LLMs know to look for them, such as GitHub, crates.io, etc., will help with adoption, Starovoitov said.

Liam Wiseheart asked what people expected to put in BPF libraries, other than basic data structures. "Whatever you want," Starovoitov answered. Some candidate answers were ventured by other attendees, including path printing and traversal, string manipulation, basic file globbing, and regular expressions.

Comments (2 posted)

Reconsidering O_CREAT|O_DIRECTORY

By Jonathan Corbet
July 30, 2026
Linux provides a system call (mkdir()) to create a directory, and a few variants of open() that can open a directory. There is, however, no system call in Linux that can create and open a directory in a single, race-free call. Jori Koolstra has been working on remedying that situation, most recently by repurposing a set of open() flags that currently return an error. There are, however, concerns that show just how hard it can be to create user-space interfaces that do not present traps for application developers.

Creating and opening a directory in a single system call is simpler and more efficient than using two, of course. It also can guard against the possibility that some other process will, between the creation and open steps, replace a directory with something else. Detecting that case is possible on Linux now, but it requires some defensive programming of the type that application developers are not always good at. Thus the desire for a more straightforward way to accomplish that pair of operations.

In March, Koolstra attempted to address this problem with a patch series adding a new system call, mkdirat_fd(), that would return a file descriptor for the newly created directory. That system call was changed to mkdirat2() in a subsequent patch. There were a number of concerns about the implementation, but also about creating a new system call in the first place. Christian Brauner, in particular, thought that this problem was better solved with a modification to how open() handles a couple of existing flags.

Specifically, all of the open() variants support the O_DIRECTORY flag, which is necessary if the application is trying to open a directory rather than a normal file. Also supported is O_CREAT, which instructs open() to create the named file if it does not already exist. It would make sense to interpret the combination of those two flags as a request to create a directory and open it at the same time. Adding this capability to open(), Brauner said, would also make many of the other features of the system call, such as the ability to place restrictions on how the name is resolved, available for free. So, he concluded: "I think here it is pretty clear that O_DIRECTORY|O_CREAT is the right thing to do".

Koolstra duly implemented the new API as an RFC patch set, followed by three more RFC and three non-RFC versions; it was only after the last of those was posted that other developers started to take a serious look at the proposed API, and not all of them were convinced that it was the right approach. Pedro Falcato, in particular, argued that this API would be nearly impossible for applications to use in a portable way, given the number of different ways that O_CREAT|O_DIRECTORY has been interpreted in the past.

That story is, indeed, a bit complicated; LWN covered it in 2023. The ways in which Linux has handled an open() call with that flag combination include:

  • Older kernels would fail if the named file existed, returning ENOTDIR if it is a regular file and EISDIR if it is a directory. If, instead, nothing existed by the given name, open() would create a regular file, which seems unlikely to be what the caller wanted.
  • As of the 5.7 release in 2020, the kernel started returning an error in the last case, while still creating the file, which seemed even less likely to be what the developer was hoping for.
  • Brauner added a patch to 6.4 causing the kernel to fail with EINVAL for that flag combination in all cases.

Add in the fact that other systems supporting POSIX system calls have their own interpretation of that flag combination, Falcato said, and the result is going to be difficult to use properly:

If you're writing something that wants to be portable, or that intends to standardize on something, you have some 5 different behaviors all across the FOSS UNIX landscape, not considering everything else. It's also something that will, FWIW, probably never be included in POSIX because no one can agree on the semantics here.

TL;DR I don't see, given the reasons above, how users are supposed to use this without it being a total minefield.

He suggested that limiting the change to openat2() might be a better approach.

Brauner, though, dismissed the concern, saying: "I don't think any of this is really an argument worth considering". The behavior of that flag combination has been consistent on Linux for years, he said, so it makes sense to make better use of it now. Falcato pointed out that the older LTS kernels never received the 6.4 change and, as a result, do not have consistent behavior, and that user space would still have to perform "some pretty gnarly tests" to use the feature safely. Brauner suggested backporting the 6.4 fix, and added: "Feature testing has always been a pain that we forced onto userspace. I think we should continue with that proud tradition".

Christoph Hellwig disagreed:

We need an interface that is self discoverable on Linux. Any combination of flags that was accepted by previous kernels and gave different results than the new interface do not qualify for that.

He added that it was not possible to rely on a fix being backported to all of the old kernels in use.

Neil Brown suggested adding a new flag, OPENAT2_NEW_COMBINATION, that would cause openat2() to reject any flag combination that is not recognized. Any older kernels will immediately fail a call with that flag; new kernels can use it to enable combinations that were not previously supported, including O_CREAT|O_DIRECTORY. Brauner, though, once again dismissed Hellwig's concern as "a strawman". The fact that he was able to make that flag combination return an error without generating a single regression report, he said, was evidence that there is no risk to adding meaning to it now. Hellwig disagreed, saying that, once the combination is supported, applications will start using it, and they will break on older systems. It is, he said, necessary to add "APIs that don't accidentally do the wrong thing on any old kernel".

Koolstra had a different concern about the openat2() suggestion: seemingly a lot of seccomp() configurations still block openat2(). That could make the new feature unavailable on a lot of systems, reducing its value.

Toward the end of the discussion (so far), Brauner asked Koolstra to send a version with support in openat() and openat2(). He did not say whether the change to open() should remain, but complained that "we're deliberately crippling a useful extension for userspace". The latest version of the series from Koolstra enables that flag combination for all open() variants without any additional checks. Brauner has not yet applied that series, so we do not yet know if it will find its way into the mainline in that form or not.

Maintaining compatibility over the long term is not an easy task. It is hard enough to ensure that new kernels do not break older applications, but it can often be trickier to avoid breaking newer applications on older kernels. One of the key ways to do that is to provide ways for applications to discover whether a given feature is supported by the kernel or not. The disagreement here is over whether the proposed feature provides that discovery mechanism, with developers like Falcato and Hellwig saying "no", while Brauner feels that it is discoverable on all kernels that actually matter. There is only one chance to make the correct decision; once the new feature is exposed in a kernel release, it will be difficult to change thereafter.

Comments (36 posted)

Page editor: Joe Brockmeier

Inside this week's LWN.net Weekly Edition

  • Briefs: AISI hack; JFrog on CVEs; npm worm; AUR adoption; NetBSD 11.0; b4 0.16.0; C-Kermit 11; Rust LLM policy; Servo 0.4.0; Quotes; ...
  • 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