diff options
| author | Ankush Patel | 2026-02-14 03:41:23 +1300 |
|---|---|---|
| committer | Ankush Patel | 2026-02-14 03:41:23 +1300 |
| commit | 8d8fb15f0b3680add1f3b28c062b573a92221ab0 (patch) | |
| tree | fbd54302af652c38eb292167919125a8b57f5d2a /internal/syscallcompat/quirks_linux.go | |
| parent | 903fc9d077a81d9224de4207d1672c0b1127cf42 (diff) | |
| parent | 5f5c34ac78cb9d1765ce9cabe87420c32f9d867e (diff) | |
Merge branch 'master' into freebsd-support
Diffstat (limited to 'internal/syscallcompat/quirks_linux.go')
| -rw-r--r-- | internal/syscallcompat/quirks_linux.go | 40 |
1 files changed, 38 insertions, 2 deletions
diff --git a/internal/syscallcompat/quirks_linux.go b/internal/syscallcompat/quirks_linux.go index 87af03d..35f754d 100644 --- a/internal/syscallcompat/quirks_linux.go +++ b/internal/syscallcompat/quirks_linux.go @@ -1,11 +1,38 @@ package syscallcompat import ( + "syscall" + "golang.org/x/sys/unix" "github.com/rfjakob/gocryptfs/v2/internal/tlog" ) +// FS_NOCOW_FL is the flag set by "chattr +C" to disable copy-on-write on +// btrfs. Not exported by golang.org/x/sys/unix, value from linux/fs.h. +const FS_NOCOW_FL = 0x00800000 + +// dirHasNoCow checks whether the directory at the given path has the +// NOCOW (No Copy-on-Write) attribute set (i.e. "chattr +C"). +// When a directory has this attribute, files created within it inherit +// NOCOW, which makes fallocate work correctly on btrfs because writes +// go in-place rather than through COW. +func dirHasNoCow(path string) bool { + fd, err := syscall.Open(path, syscall.O_RDONLY|syscall.O_DIRECTORY, 0) + if err != nil { + tlog.Debug.Printf("dirHasNoCow: Open %q failed: %v", path, err) + return false + } + defer syscall.Close(fd) + + flags, err := unix.IoctlGetInt(fd, unix.FS_IOC_GETFLAGS) + if err != nil { + tlog.Debug.Printf("dirHasNoCow: FS_IOC_GETFLAGS on %q failed: %v", path, err) + return false + } + return flags&FS_NOCOW_FL != 0 +} + // DetectQuirks decides if there are known quirks on the backing filesystem // that need to be workarounded. // @@ -21,10 +48,19 @@ func DetectQuirks(cipherdir string) (q uint64) { // Preallocation on Btrfs is broken ( https://github.com/rfjakob/gocryptfs/issues/395 ) // and slow ( https://github.com/rfjakob/gocryptfs/issues/63 ). // + // The root cause is that btrfs COW allocates new blocks on write even for + // preallocated extents, defeating the purpose of fallocate. However, if the + // backing directory has the NOCOW attribute (chattr +C), writes go in-place + // and fallocate works correctly. + // // Cast to uint32 avoids compile error on arm: "constant 2435016766 overflows int32" if uint32(st.Type) == unix.BTRFS_SUPER_MAGIC { - // LogQuirk is called in fusefrontend/root_node.go - q |= QuirkBtrfsBrokenFalloc + if dirHasNoCow(cipherdir) { + tlog.Debug.Printf("DetectQuirks: Btrfs detected but cipherdir has NOCOW attribute (chattr +C), fallocate should work correctly") + } else { + // LogQuirk is called in fusefrontend/root_node.go + q |= QuirkBtrfsBrokenFalloc + } } return q |
