diff --git a/weed/storage/backend/volume_create_linux.go b/weed/storage/backend/volume_create_linux.go index 92c66c6941..28aeb6ed1d 100644 --- a/weed/storage/backend/volume_create_linux.go +++ b/weed/storage/backend/volume_create_linux.go @@ -4,7 +4,8 @@ package backend import ( "os" - "syscall" + + "golang.org/x/sys/unix" "github.com/seaweedfs/seaweedfs/weed/glog" ) @@ -15,8 +16,11 @@ func CreateVolumeFile(fileName string, preallocate int64, memoryMapSizeMB uint32 return nil, e } if preallocate != 0 { - syscall.Fallocate(int(file.Fd()), 1, 0, preallocate) - glog.V(1).Infof("Preallocated %d bytes disk space for %s", preallocate, fileName) + if err := unix.Fallocate(int(file.Fd()), unix.FALLOC_FL_KEEP_SIZE, 0, preallocate); err != nil { + glog.Warningf("Preallocate %d bytes disk space for %s: %v", preallocate, fileName, err) + } else { + glog.V(1).Infof("Preallocated %d bytes disk space for %s", preallocate, fileName) + } } return NewDiskFile(file), nil } diff --git a/weed/storage/backend/volume_create_linux_test.go b/weed/storage/backend/volume_create_linux_test.go new file mode 100644 index 0000000000..14eeffd178 --- /dev/null +++ b/weed/storage/backend/volume_create_linux_test.go @@ -0,0 +1,50 @@ +//go:build linux + +package backend + +import ( + "os" + "path/filepath" + "syscall" + "testing" + + "golang.org/x/sys/unix" +) + +func TestCreateVolumeFilePreallocateKeepsSize(t *testing.T) { + dir := t.TempDir() + const preallocate = 1 << 20 + + probe, err := os.Create(filepath.Join(dir, "probe")) + if err != nil { + t.Fatalf("create probe: %v", err) + } + err = unix.Fallocate(int(probe.Fd()), unix.FALLOC_FL_KEEP_SIZE, 0, preallocate) + probe.Close() + if err != nil { + t.Skipf("fallocate not supported in %s: %v", dir, err) + } + + fileName := filepath.Join(dir, "1.dat") + f, err := CreateVolumeFile(fileName, preallocate, 0) + if err != nil { + t.Fatalf("CreateVolumeFile: %v", err) + } + defer f.Close() + + size, _, err := f.GetStat() + if err != nil { + t.Fatalf("GetStat: %v", err) + } + if size != 0 { + t.Errorf("file size = %d, want 0", size) + } + + var st syscall.Stat_t + if err := syscall.Stat(fileName, &st); err != nil { + t.Fatalf("stat: %v", err) + } + if st.Blocks*512 < preallocate { + t.Errorf("allocated %d bytes, want at least %d", st.Blocks*512, preallocate) + } +}