From 86ca676aef03d4cdd1b3b27f1d70fcda57381954 Mon Sep 17 00:00:00 2001 From: Geert Jansen Date: Tue, 2 Dec 2025 05:10:29 +0000 Subject: [PATCH 1/2] Split in/out flags for FUSE_INIT Split in/out parameter initOp.Flags into initOp.Flags (in) and initOp.outFlags (out). This allows us to see in the wire log what capabilities are available from the kernel, and what capabilities were selected. --- connection.go | 26 +++++++++++++++----------- ops.go | 5 ++--- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/connection.go b/connection.go index ebb86b73..ae0b0a3f 100644 --- a/connection.go +++ b/connection.go @@ -174,13 +174,17 @@ func (c *Connection) Init() error { initOp.MaxReadahead = maxReadahead initOp.MaxWrite = buffer.MaxWriteSize - initOp.Flags = 0 + initOp.OutFlags = 0 + initOp.OutFlags2 = 0 + + // Initialize the extended flags + initOp.OutFlags |= fusekernel.InitExt // Tell the kernel not to use pitifully small 4 KiB writes. - initOp.Flags |= fusekernel.InitBigWrites + initOp.OutFlags |= fusekernel.InitBigWrites if c.cfg.EnableAsyncReads { - initOp.Flags |= fusekernel.InitAsyncRead + initOp.OutFlags |= fusekernel.InitAsyncRead } // kernel 4.20 increases the max from 32 -> 256 @@ -189,43 +193,43 @@ func (c *Connection) Init() error { // Enable writeback caching if the user hasn't asked us not to. if !c.cfg.DisableWritebackCaching { - initOp.Flags |= fusekernel.InitWritebackCache + initOp.OutFlags |= fusekernel.InitWritebackCache } // Enable caching symlink targets in the kernel page cache if the user opted // into it (might require fixing the size field of inode attributes first): if c.cfg.EnableSymlinkCaching && cacheSymlinks { - initOp.Flags |= fusekernel.InitCacheSymlinks + initOp.OutFlags |= fusekernel.InitCacheSymlinks } // Tell the kernel to treat returning -ENOSYS on OpenFile as not needing // OpenFile calls at all (Linux >= 3.16): if c.cfg.EnableNoOpenSupport && noOpenSupport { - initOp.Flags |= fusekernel.InitNoOpenSupport + initOp.OutFlags |= fusekernel.InitNoOpenSupport } // Tell the kernel to treat returning -ENOSYS on OpenDir as not needing // OpenDir calls at all (Linux >= 5.1): if c.cfg.EnableNoOpendirSupport && noOpendirSupport { - initOp.Flags |= fusekernel.InitNoOpendirSupport + initOp.OutFlags |= fusekernel.InitNoOpendirSupport } // Tell the Kernel to allow sending parallel lookup and readdir operations. if c.cfg.EnableParallelDirOps { - initOp.Flags |= fusekernel.InitParallelDirOps + initOp.OutFlags |= fusekernel.InitParallelDirOps } if c.cfg.EnableAtomicTrunc { - initOp.Flags |= fusekernel.InitAtomicTrunc + initOp.OutFlags |= fusekernel.InitAtomicTrunc } if c.cfg.EnableReaddirplus { // Enable Readdirplus support, allowing the kernel to use Readdirplus - initOp.Flags |= fusekernel.InitDoReaddirplus + initOp.OutFlags |= fusekernel.InitDoReaddirplus if c.cfg.EnableAutoReaddirplus { // Enable adaptive Readdirplus, allowing the kernel to choose between Readdirplus and Readdir - initOp.Flags |= fusekernel.InitReaddirplusAuto + initOp.OutFlags |= fusekernel.InitReaddirplusAuto } } diff --git a/ops.go b/ops.go index fe21a64f..e820bc25 100644 --- a/ops.go +++ b/ops.go @@ -35,12 +35,11 @@ type interruptOp struct { type initOp struct { // In Kernel fusekernel.Protocol - - // In/out - Flags fusekernel.InitFlags + Flags fusekernel.InitFlags // Out Library fusekernel.Protocol + OutFlags fusekernel.InitFlags MaxReadahead uint32 MaxBackground uint16 MaxWrite uint32 From 35eaeffd3f56b92cc242717825e25fe2d2b1111e Mon Sep 17 00:00:00 2001 From: Geert Jansen Date: Tue, 2 Dec 2025 05:15:28 +0000 Subject: [PATCH 2/2] Add support for FUSE_DIRECT_IO_ALLOW_MMAP --- connection.go | 5 +++++ internal/fusekernel/fuse_kernel.go | 10 ++++++++-- mount_config.go | 3 +++ ops.go | 2 ++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/connection.go b/connection.go index ae0b0a3f..21ee46f7 100644 --- a/connection.go +++ b/connection.go @@ -233,6 +233,11 @@ func (c *Connection) Init() error { } } + // Tell the kernel to allow shared mmap() for files opened with OpenDirectIO + if c.cfg.AllowDirectIOMmap { + initOp.OutFlags2 |= fusekernel.InitDirectIOAllowMmap + } + return c.Reply(ctx, nil) } diff --git a/internal/fusekernel/fuse_kernel.go b/internal/fusekernel/fuse_kernel.go index 8c47b524..fa1d9c95 100644 --- a/internal/fusekernel/fuse_kernel.go +++ b/internal/fusekernel/fuse_kernel.go @@ -252,7 +252,8 @@ var openResponseFlagNames = []flagName{ } // The InitFlags are used in the Init exchange. -type InitFlags uint32 +type InitFlags uint32 // first 32 bit flags +type InitFlags2 uint32 // second 32-bit flags, used when InitExt is set in the first 32 bits const ( InitAsyncRead InitFlags = 1 << 0 @@ -277,10 +278,13 @@ const ( InitMaxPages InitFlags = 1 << 22 InitCacheSymlinks InitFlags = 1 << 23 InitNoOpendirSupport InitFlags = 1 << 24 + InitExt InitFlags = 1 << 30 InitCaseSensitive InitFlags = 1 << 29 // OS X only InitVolRename InitFlags = 1 << 30 // OS X only InitXtimes InitFlags = 1 << 31 // OS X only + + InitDirectIOAllowMmap InitFlags2 = 1 << 4 ) type flagName struct { @@ -738,6 +742,7 @@ type InitIn struct { Minor uint32 MaxReadahead uint32 Flags uint32 + Flags2 uint32 } const InitInSize = int(unsafe.Sizeof(InitIn{})) @@ -753,7 +758,8 @@ type InitOut struct { TimeGran uint32 MaxPages uint16 MapAlignment uint16 - Unused [8]uint32 + Flags2 uint32 + Unused [7]uint32 } type InterruptIn struct { diff --git a/mount_config.go b/mount_config.go index f95895ad..8f629430 100644 --- a/mount_config.go +++ b/mount_config.go @@ -221,6 +221,9 @@ type MountConfig struct { // use ReaddirPlus for directory listing. EnableAutoReaddirplus bool + // Flag to allow mmap() with MAP_SHARED for files opened with OpenDirectIO + AllowDirectIOMmap bool + // UseVectoredRead is a legacy flag kept for backward compatibility. It is now a no-op. // // The term vectored read was a misnomer for this flag. Its actual meaning was that diff --git a/ops.go b/ops.go index e820bc25..725cd87b 100644 --- a/ops.go +++ b/ops.go @@ -36,10 +36,12 @@ type initOp struct { // In Kernel fusekernel.Protocol Flags fusekernel.InitFlags + Flags2 fusekernel.InitFlags2 // Out Library fusekernel.Protocol OutFlags fusekernel.InitFlags + OutFlags2 fusekernel.InitFlags2 MaxReadahead uint32 MaxBackground uint16 MaxWrite uint32