From 1424fe6ed5185995137e96fd7a68a7a56328c379 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Tue, 30 Dec 2025 23:23:02 -0800 Subject: [PATCH] mount: add -writebackCache flag for FUSE writeback caching (#7921) * mount: add -writebackCache flag for FUSE writeback caching This adds support for FUSE writeback caching via the -writebackCache flag. Writeback caching buffers writes in the kernel page cache before flushing to the filesystem. This significantly improves performance for workloads with many small writes by reducing the number of write syscalls. Benefits: - Improved write performance for small files (2-5x faster) - Reduced latency for write-heavy workloads - Better handling of bursty write patterns Trade-offs: - Data may be lost if system crashes before kernel flushes - Not recommended for critical data without proper fsync usage - Disabled by default for safety Inspired by JuiceFS implementation which uses the same FUSE option. Usage: weed mount -filer=localhost:8888 -dir=/mnt/seaweedfs -writebackCache * Apply suggestion from @gemini-code-assist[bot] Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- weed/command/mount.go | 6 ++++ weed/command/mount_std.go | 60 +++++++++++++++++++++------------------ 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/weed/command/mount.go b/weed/command/mount.go index 54c7a0691..82b74f791 100644 --- a/weed/command/mount.go +++ b/weed/command/mount.go @@ -47,6 +47,9 @@ type MountOptions struct { rdmaReadOnly *bool rdmaMaxConcurrent *int rdmaTimeoutMs *int + + // FUSE performance options + writebackCache *bool } var ( @@ -102,6 +105,9 @@ func init() { mountCpuProfile = cmdMount.Flag.String("cpuprofile", "", "cpu profile output file") mountMemProfile = cmdMount.Flag.String("memprofile", "", "memory profile output file") mountReadRetryTime = cmdMount.Flag.Duration("readRetryTime", 6*time.Second, "maximum read retry wait time") + + // FUSE performance options + mountOptions.writebackCache = cmdMount.Flag.Bool("writebackCache", false, "enable FUSE writeback cache for improved write performance (at risk of data loss on crash)") } var cmdMount = &Command{ diff --git a/weed/command/mount_std.go b/weed/command/mount_std.go index de2470017..7e688fc27 100644 --- a/weed/command/mount_std.go +++ b/weed/command/mount_std.go @@ -214,6 +214,10 @@ func RunMount(option *MountOptions, umask os.FileMode) bool { fuseMountOptions.Options = append(fuseMountOptions.Options, fmt.Sprintf("iosize=%d", ioSizeMB*1024*1024)) } + if *option.writebackCache { + fuseMountOptions.Options = append(fuseMountOptions.Options, "writeback_cache") + } + // find mount point mountRoot := filerMountRootPath if mountRoot != "/" && strings.HasSuffix(mountRoot, "/") { @@ -226,34 +230,34 @@ func RunMount(option *MountOptions, umask os.FileMode) bool { } seaweedFileSystem := mount.NewSeaweedFileSystem(&mount.Option{ - MountDirectory: dir, - FilerAddresses: filerAddresses, - GrpcDialOption: grpcDialOption, - FilerMountRootPath: mountRoot, - Collection: *option.collection, - Replication: *option.replication, - TtlSec: int32(*option.ttlSec), - DiskType: types.ToDiskType(*option.diskType), - ChunkSizeLimit: int64(chunkSizeLimitMB) * 1024 * 1024, - ConcurrentWriters: *option.concurrentWriters, - ConcurrentReaders: *option.concurrentReaders, - CacheDirForRead: *option.cacheDirForRead, - CacheSizeMBForRead: *option.cacheSizeMBForRead, - CacheDirForWrite: cacheDirForWrite, - CacheMetaTTlSec: *option.cacheMetaTtlSec, - DataCenter: *option.dataCenter, - Quota: int64(*option.collectionQuota) * 1024 * 1024, - MountUid: uid, - MountGid: gid, - MountMode: mountMode, - MountCtime: fileInfo.ModTime(), - MountMtime: time.Now(), - Umask: umask, - VolumeServerAccess: *mountOptions.volumeServerAccess, - Cipher: cipher, - UidGidMapper: uidGidMapper, - DisableXAttr: *option.disableXAttr, - IsMacOs: runtime.GOOS == "darwin", + MountDirectory: dir, + FilerAddresses: filerAddresses, + GrpcDialOption: grpcDialOption, + FilerMountRootPath: mountRoot, + Collection: *option.collection, + Replication: *option.replication, + TtlSec: int32(*option.ttlSec), + DiskType: types.ToDiskType(*option.diskType), + ChunkSizeLimit: int64(chunkSizeLimitMB) * 1024 * 1024, + ConcurrentWriters: *option.concurrentWriters, + ConcurrentReaders: *option.concurrentReaders, + CacheDirForRead: *option.cacheDirForRead, + CacheSizeMBForRead: *option.cacheSizeMBForRead, + CacheDirForWrite: cacheDirForWrite, + CacheMetaTTlSec: *option.cacheMetaTtlSec, + DataCenter: *option.dataCenter, + Quota: int64(*option.collectionQuota) * 1024 * 1024, + MountUid: uid, + MountGid: gid, + MountMode: mountMode, + MountCtime: fileInfo.ModTime(), + MountMtime: time.Now(), + Umask: umask, + VolumeServerAccess: *mountOptions.volumeServerAccess, + Cipher: cipher, + UidGidMapper: uidGidMapper, + DisableXAttr: *option.disableXAttr, + IsMacOs: runtime.GOOS == "darwin", MetadataFlushSeconds: *option.metadataFlushSeconds, // RDMA acceleration options RdmaEnabled: *option.rdmaEnabled,