diff --git a/backend/posix/posix.go b/backend/posix/posix.go index 6fd3caf..50f4456 100644 --- a/backend/posix/posix.go +++ b/backend/posix/posix.go @@ -234,7 +234,7 @@ func (p *Posix) CompleteMultipartUpload(bucket, object, uploadID string, parts [ } } - f, err := openTmpFile(metaTmpDir, object) + f, err := openTmpFile(metaTmpDir, object, 0) if err != nil { return nil, fmt.Errorf("open temp file: %w", err) } @@ -681,7 +681,7 @@ func (p *Posix) PutObjectPart(bucket, object, uploadID string, part int, length objdir := filepath.Join(bucket, metaTmpMultipartDir, fmt.Sprintf("%x", sum)) partPath := filepath.Join(objdir, uploadID, fmt.Sprintf("%v", part)) - f, err := openTmpFile(objdir, partPath) + f, err := openTmpFile(objdir, partPath, length) if err != nil { return "", fmt.Errorf("open temp file: %w", err) } @@ -734,7 +734,7 @@ func (p *Posix) PutObject(po *s3.PutObjectInput) (string, error) { xattr.Set(name, dirObjKey, nil) } else { // object is file - f, err := openTmpFile(metaTmpDir, *po.Key) + f, err := openTmpFile(metaTmpDir, *po.Key, po.ContentLength) if err != nil { return "", fmt.Errorf("open temp file: %w", err) } diff --git a/backend/posix/posix_darwin.go b/backend/posix/posix_darwin.go index 6a4739e..ee7103a 100644 --- a/backend/posix/posix_darwin.go +++ b/backend/posix/posix_darwin.go @@ -13,7 +13,7 @@ type tmpfile struct { objname string } -func openTmpFile(dir, obj string) (*tmpfile, error) { +func openTmpFile(dir, obj string, size int64) (*tmpfile, error) { // Create a temp file for upload while in progress (see link comments below). f, err := os.CreateTemp(dir, fmt.Sprintf("%x\n", sha256.Sum256([]byte(obj)))) diff --git a/backend/posix/posix_linux.go b/backend/posix/posix_linux.go index 123533c..6135372 100644 --- a/backend/posix/posix_linux.go +++ b/backend/posix/posix_linux.go @@ -8,6 +8,7 @@ import ( "os" "path/filepath" "strconv" + "syscall" "golang.org/x/sys/unix" ) @@ -20,7 +21,7 @@ type tmpfile struct { isOTmp bool } -func openTmpFile(dir, obj string) (*tmpfile, error) { +func openTmpFile(dir, obj string, size int64) (*tmpfile, error) { // O_TMPFILE allows for a file handle to an unnamed file in the filesystem. // This can help reduce contention within the namespace (parent directories), // etc. And will auto cleanup the inode on close if we never link this @@ -35,11 +36,29 @@ func openTmpFile(dir, obj string) (*tmpfile, error) { if err != nil { return nil, err } - return &tmpfile{f: f}, nil + tmp := &tmpfile{f: f} + // falloc is best effort, its fine if this fails + if size > 0 { + tmp.falloc(size) + } + return tmp, nil } f := os.NewFile(uintptr(fd), filepath.Join(procfddir, strconv.Itoa(fd))) - return &tmpfile{f: f, isOTmp: true}, nil + tmp := &tmpfile{f: f, isOTmp: true} + // falloc is best effort, its fine if this fails + if size > 0 { + tmp.falloc(size) + } + return tmp, nil +} + +func (tmp *tmpfile) falloc(size int64) error { + err := syscall.Fallocate(int(tmp.f.Fd()), 0, 0, size) + if err != nil { + return fmt.Errorf("fallocate: %v", err) + } + return nil } func (tmp *tmpfile) link() error {