mirror of
https://github.com/octoleo/restic.git
synced 2024-11-26 06:46:34 +00:00
Merge pull request #2816 from greatroar/noatime
Set O_NOATIME flag on Linux
This commit is contained in:
commit
cc90f2ba6b
10
changelog/unreleased/pull-2816
Normal file
10
changelog/unreleased/pull-2816
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
Enhancement: backup no longer updates file access times on Linux
|
||||||
|
|
||||||
|
When reading files during backup, restic caused the operating system to update
|
||||||
|
the file access times. Note that this does not apply to filesystems with
|
||||||
|
disabled file access times.
|
||||||
|
|
||||||
|
Restic now instructs the operation system not to update the file access time,
|
||||||
|
if the user running restic is the file owner or has root permissions.
|
||||||
|
|
||||||
|
https://github.com/restic/restic/pull/2816
|
@ -24,6 +24,7 @@ func (fs Local) Open(name string) (File, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
_ = setFlags(f)
|
||||||
return f, nil
|
return f, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,6 +38,7 @@ func (fs Local) OpenFile(name string, flag int, perm os.FileMode) (File, error)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
_ = setFlags(f)
|
||||||
return f, nil
|
return f, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
21
internal/fs/setflags_linux.go
Normal file
21
internal/fs/setflags_linux.go
Normal 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
|
||||||
|
}
|
67
internal/fs/setflags_linux_test.go
Normal file
67
internal/fs/setflags_linux_test.go
Normal 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
|
||||||
|
}
|
12
internal/fs/setflags_other.go
Normal file
12
internal/fs/setflags_other.go
Normal 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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user