mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-08 15:41:15 +02:00
* mount: implement fallocate instead of reporting it unsupported Fallocate answered ENOSYS, so the kernel marked the mount as having no fallocate and returned EOPNOTSUPP. glibc then fell back to its emulation, which preads a byte from every block already inside the file to see if it is allocated; on a write-only descriptor that pread is EBADF, and posix_fallocate returned it. Volume space is assigned when a write is flushed, so nothing can be reserved up front: a range inside the file is answered OK untouched, and one past the end grows the file the way a truncate would. A mode we cannot honor is refused with ENOTSUP, not ENOSYS, so the kernel keeps sending the ones we do. Claude-Session: https://claude.ai/code/session_01XG6sAAdkqTwWffqK5h4rH9 * mount: let a fallocate that allocates nothing past the quota and worm guards A range already inside the file, and any FALLOC_FL_KEEP_SIZE request, reserve no space and rewrite no entry, but the preflight refused them with ENOSPC on a full mount and EPERM on a worm-enforced file. Decide the no-op first and guard only the growth. Claude-Session: https://claude.ai/code/session_01XG6sAAdkqTwWffqK5h4rH9 * mount: charge a fallocate growth to the uncommitted byte counter Write charges the counter by how much the file grew, so the writes that fill a range fallocate already extended charge nothing and the real-time quota check never sees that data — only the periodic filer refresh does. Count the growth where it happens. Claude-Session: https://claude.ai/code/session_01XG6sAAdkqTwWffqK5h4rH9 * mount: charge a truncate-up growth to the uncommitted byte counter Same gap Fallocate had: Write charges the counter by how much the file grew, so the writes that fill a range ftruncate already extended charge nothing and the real-time quota check never sees that data. Count the growth where it happens; a shrink still leaves the counter alone, since it is only ever raised and then reset by the periodic filer refresh. Claude-Session: https://claude.ai/code/session_01XG6sAAdkqTwWffqK5h4rH9
39 lines
1.2 KiB
Go
39 lines
1.2 KiB
Go
package mount
|
|
|
|
import (
|
|
"sync/atomic"
|
|
"testing"
|
|
|
|
"github.com/seaweedfs/go-fuse/v2/fuse"
|
|
)
|
|
|
|
// TestSetAttrChargesTheGrowth pins the quota accounting for a truncate up: the
|
|
// writes that fill the range do not grow the file, so they charge nothing and
|
|
// the growth has to be counted where it happens, as Write and Fallocate do.
|
|
func TestSetAttrChargesTheGrowth(t *testing.T) {
|
|
atomic.StoreInt64(&uncommittedBytes, 0)
|
|
wfs, fh := newOpenFileHandle(t, 10)
|
|
wfs.option.Quota = 100 << 20
|
|
|
|
in := &fuse.SetAttrIn{}
|
|
in.NodeId = fh.inode
|
|
in.Valid = fuse.FATTR_SIZE
|
|
in.Size = 8192
|
|
var out fuse.AttrOut
|
|
if status := wfs.SetAttr(nil, in, &out); status != fuse.OK {
|
|
t.Fatalf("SetAttr size up: got %v, want OK", status)
|
|
}
|
|
if got := wfs.GetUncommittedBytes(); got != 8192-10 {
|
|
t.Fatalf("uncommitted bytes: got %d, want %d", got, 8192-10)
|
|
}
|
|
|
|
// Truncating back down frees space rather than consuming it.
|
|
in.Size = 0
|
|
if status := wfs.SetAttr(nil, in, &out); status != fuse.OK {
|
|
t.Fatalf("SetAttr size down: got %v, want OK", status)
|
|
}
|
|
if got := wfs.GetUncommittedBytes(); got != 8192-10 {
|
|
t.Fatalf("uncommitted bytes after a shrink: got %d, want %d", got, 8192-10)
|
|
}
|
|
}
|