Merge pull request #2816 from greatroar/noatime

Set O_NOATIME flag on Linux
This commit is contained in:
MichaelEischer
2022-02-07 21:38:31 +01:00
committed by GitHub
5 changed files with 112 additions and 0 deletions

View File

@@ -24,6 +24,7 @@ func (fs Local) Open(name string) (File, error) {
if err != nil {
return nil, err
}
_ = setFlags(f)
return f, nil
}
@@ -37,6 +38,7 @@ func (fs Local) OpenFile(name string, flag int, perm os.FileMode) (File, error)
if err != nil {
return nil, err
}
_ = setFlags(f)
return f, nil
}

View File

@@ -0,0 +1,21 @@
package fs
import (
"os"
"golang.org/x/sys/unix"
)
// SetFlags tries to set the O_NOATIME flag on f, which prevents the kernel
// from updating the atime on a read call.
//
// The call fails when we're not the owner of the file or root. The caller
// should ignore the error, which is returned for testing only.
func setFlags(f *os.File) error {
fd := f.Fd()
flags, err := unix.FcntlInt(fd, unix.F_GETFL, 0)
if err == nil {
_, err = unix.FcntlInt(fd, unix.F_SETFL, flags|unix.O_NOATIME)
}
return err
}

View File

@@ -0,0 +1,67 @@
package fs
import (
"io"
"io/ioutil"
"os"
"testing"
"time"
rtest "github.com/restic/restic/internal/test"
"golang.org/x/sys/unix"
)
func TestNoatime(t *testing.T) {
f, err := ioutil.TempFile("", "restic-test-noatime")
if err != nil {
t.Fatal(err)
}
defer func() {
_ = f.Close()
err = Remove(f.Name())
if err != nil {
t.Fatal(err)
}
}()
// Only run this test on common filesystems that support O_NOATIME.
// On others, we may not get an error.
if !supportsNoatime(t, f) {
t.Skip("temp directory may not support O_NOATIME, skipping")
}
// From this point on, we own the file, so we should not get EPERM.
_, err = io.WriteString(f, "Hello!")
rtest.OK(t, err)
_, err = f.Seek(0, io.SeekStart)
rtest.OK(t, err)
getAtime := func() time.Time {
info, err := f.Stat()
rtest.OK(t, err)
return ExtendedStat(info).AccessTime
}
atime := getAtime()
err = setFlags(f)
rtest.OK(t, err)
_, err = f.Read(make([]byte, 1))
rtest.OK(t, err)
rtest.Equals(t, atime, getAtime())
}
func supportsNoatime(t *testing.T, f *os.File) bool {
var fsinfo unix.Statfs_t
err := unix.Fstatfs(int(f.Fd()), &fsinfo)
rtest.OK(t, err)
return fsinfo.Type == unix.BTRFS_SUPER_MAGIC ||
fsinfo.Type == unix.EXT2_SUPER_MAGIC ||
fsinfo.Type == unix.EXT3_SUPER_MAGIC ||
fsinfo.Type == unix.EXT4_SUPER_MAGIC ||
fsinfo.Type == unix.TMPFS_MAGIC
}

View File

@@ -0,0 +1,12 @@
//go:build !linux
// +build !linux
package fs
import "os"
// OS-specific replacements of setFlags can set file status flags
// that improve I/O performance.
func setFlags(*os.File) error {
return nil
}