Skip to content

Add FUSE_DEV_IOC_CLONE support for multi-threaded reading#421

Open
ejc3 wants to merge 3 commits intocberner:masterfrom
ejc3:master
Open

Add FUSE_DEV_IOC_CLONE support for multi-threaded reading#421
ejc3 wants to merge 3 commits intocberner:masterfrom
ejc3:master

Conversation

@ejc3
Copy link

@ejc3 ejc3 commented Dec 19, 2025

Summary

Add support for multi-threaded FUSE request processing using FUSE_DEV_IOC_CLONE ioctl.

This enables multiple threads to read FUSE requests in parallel from cloned file descriptors, improving throughput for high-concurrency workloads.

API

// Primary session handles INIT and runs in main thread
let session = Session::new(fs, mountpoint, &Config::default())?;

// Clone fd for additional reader threads
let cloned_fd = session.clone_fd()?;
let reader_session = Session::from_fd_initialized(fs_clone, cloned_fd, SessionACL::All);
std::thread::spawn(move || reader_session.run());

session.run()?;

Changes

  • Add Session::clone_fd() - clones the FUSE fd using FUSE_DEV_IOC_CLONE ioctl (Linux only)
  • Add Session::from_fd_initialized() - creates a session from a cloned fd that skips INIT handshake
  • Make Session::run() public for external multi-reader use
  • Add conditional handshake skip when proto_version is pre-set

Tests

Added two integration tests:

  • clone_fd_multi_reader - verifies clone_fd() creates a valid fd
  • from_fd_initialized_works - tests concurrent readers processing requests

Platform Support

clone_fd() is only available on Linux (#[cfg(target_os = "linux")]).

@cberner
Copy link
Owner

cberner commented Dec 19, 2025

Please add a test for this functionality. Also, I don't really like the idea of making channel public. I think we should find a way to hide this functionality behind mount() or something like that

@ejc3 ejc3 marked this pull request as ready for review December 20, 2025 09:20
@cberner
Copy link
Owner

cberner commented Jan 26, 2026

@stepancheg I think you're working on a similar feature. Want to take a look and lemme know how they overlap, if at all?

@stepancheg
Copy link
Contributor

I left a comment in the other thread.

@ejc3
Copy link
Author

ejc3 commented Jan 26, 2026

I left a comment in the other thread.

Hi @stepancheg, can you point me there? I might not be on that issue / pull request. Thanks!

@cberner
Copy link
Owner

cberner commented Jan 31, 2026

It's this one: #572

@ejc3
Copy link
Author

ejc3 commented Feb 1, 2026

It's this one: #572

I rebased onto main, so those changes are incorporated now.

@cberner
Copy link
Owner

cberner commented Feb 1, 2026

The approach @stepancheg described seems better to me, because it provides a simpler interface to users. Can you take a look at that and let me know if your use case requires additional functionality or lower level access?

@ejc3 ejc3 force-pushed the master branch 8 times, most recently from ffe3ad3 to 984aaff Compare February 2, 2026 01:21
@ejc3
Copy link
Author

ejc3 commented Feb 2, 2026

I rebased again. #627 won’t work as is (as mentioned) because it doesn’t support the clone fd ioctl. Otherwise, if that was added, it should work.

@stepancheg
Copy link
Contributor

#627 won’t work as is (as mentioned) because it doesn’t support the clone fd ioctl

multiple event loops can work with and without ioctl. This is how libfuse works — single thread, multiple threads shared fd, or multiple threads clone fd with ioctl.

I started without ioctl, because I presume we should make version without ioctl work first, and then add ioctl on top.

@ejc3
Copy link
Author

ejc3 commented Feb 2, 2026 via email

@stepancheg
Copy link
Contributor

I was saying that there isn’t a perf improvement if we don’t do the clone though.

It is perf improvement if filesystem implementation does something non-trivial. But not as big as with ioctl.

stepancheg and others added 2 commits February 2, 2026 02:24
For now just add an option to spawn multiple threads. No `fuse_dev_ioc_clone` yet.

Before adding that ioctl, we need to write automated tests for
multithreading, e.g. that different threads actually process
messages. Some refactoring is desirable for that.

For now I tested by running with debug logs, which contain different thread names:

```
[2026-02-01T22:09:00.875147750Z DEBUG fuser::request] FUSE(7998) ino 0x000000000000044e RELEASE fh FileHandle(4611686018427388903), flags 0x8801, flush false, lock owner None thread=fuser-8
```

Note libfuse can run in multiple threads too in similar way, without
ioctl clone fd.
Replace ch.clone() (which just clones the Arc, sharing one fd) with
actual FUSE_DEV_IOC_CLONE ioctl that creates independent fds.

Without clone_fd: all threads serialize on one fd
With clone_fd: kernel distributes requests across fds (true parallelism)

- Add Channel::clone_fd() using FUSE_DEV_IOC_CLONE ioctl
- Update run() to use clone_fd() on Linux
- Fall back to ch.clone() on non-Linux (no true parallelism)
- Use existing fuse_dev_ioc_clone from ll/ioctl.rs instead of
  defining the ioctl inline
- Make clone_fd opt-in via Config.clone_fd (default false)
- Remove tests/clone_fd_test.rs (tests live in fuser-tests,
  examples/hello.rs already demonstrates the feature)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants