diff --git a/.gitignore b/.gitignore index 058686994..781733c25 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ -/pkg +/gopath /go-bindata /machine* /bin -/src .vagrant *.etcd diff --git a/build b/build index a56254995..92494a123 100755 --- a/build +++ b/build @@ -1,12 +1,12 @@ #!/bin/sh -e -if [ ! -h src/github.com/coreos/etcd ]; then - mkdir -p src/github.com/coreos/ - ln -s ../../.. src/github.com/coreos/etcd +if [ ! -h gopath/src/github.com/coreos/etcd ]; then + mkdir -p gopath/src/github.com/coreos/ + ln -s ../../../.. gopath/src/github.com/coreos/etcd fi export GOBIN=${PWD}/bin -export GOPATH=${PWD} +export GOPATH=${PWD}/gopath export GOFMTPATH="./bench ./config ./discovery ./etcd ./error ./http ./log main.go ./metrics ./mod ./server ./store ./tests" # Don't surprise user by formatting their codes by stealth diff --git a/pkg/btrfs/.util_linux.go.swp b/pkg/btrfs/.util_linux.go.swp new file mode 100644 index 000000000..36326a025 Binary files /dev/null and b/pkg/btrfs/.util_linux.go.swp differ diff --git a/pkg/btrfs/btrfs.go b/pkg/btrfs/btrfs.go new file mode 100644 index 000000000..66e062df9 --- /dev/null +++ b/pkg/btrfs/btrfs.go @@ -0,0 +1,72 @@ +package btrfs + +import ( + "fmt" + "os" + "runtime" + "syscall" + "unsafe" + + "github.com/coreos/etcd/log" +) + +const ( + // from Linux/include/uapi/linux/magic.h + BTRFS_SUPER_MAGIC = 0x9123683E + + // from Linux/include/uapi/linux/fs.h + FS_NOCOW_FL = 0x00800000 + FS_IOC_GETFLAGS = 0x80086601 + FS_IOC_SETFLAGS = 0x40086602 +) + +// IsBtrfs checks whether the file is in btrfs +func IsBtrfs(path string) bool { + // btrfs is linux-only filesystem + // exit on other platforms + if runtime.GOOS != "linux" { + return false + } + var buf syscall.Statfs_t + if err := syscall.Statfs(path, &buf); err != nil { + log.Warnf("Failed to statfs: %v", err) + return false + } + log.Debugf("The type of path %v is %v", path, buf.Type) + if buf.Type != BTRFS_SUPER_MAGIC { + return false + } + log.Infof("The path %v is in btrfs", path) + return true +} + +// SetNOCOWFile sets NOCOW flag for file +func SetNOCOWFile(path string) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + fileinfo, err := file.Stat() + if err != nil { + return err + } + if fileinfo.IsDir() { + return fmt.Errorf("skip directory") + } + if fileinfo.Size() != 0 { + return fmt.Errorf("skip nonempty file") + } + + var attr int + if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, file.Fd(), FS_IOC_GETFLAGS, uintptr(unsafe.Pointer(&attr))); errno != 0 { + return errno + } + attr |= FS_NOCOW_FL + if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, file.Fd(), FS_IOC_SETFLAGS, uintptr(unsafe.Pointer(&attr))); errno != 0 { + return errno + } + log.Infof("Set NOCOW to path %v succeeded", path) + return nil +} diff --git a/pkg/btrfs/btrfs_test.go b/pkg/btrfs/btrfs_test.go new file mode 100644 index 000000000..b841aa370 --- /dev/null +++ b/pkg/btrfs/btrfs_test.go @@ -0,0 +1,31 @@ +package btrfs + +import ( + "io/ioutil" + "os" + "os/exec" + "strings" + "testing" +) + +func TestSetNOCOW(t *testing.T) { + f, err := ioutil.TempFile(".", "etcdtest") + if err != nil { + t.Fatal("Failed creating temp dir") + } + name := f.Name() + f.Close() + defer os.Remove(name) + + if IsBtrfs(name) { + SetNOCOWFile(name) + cmd := exec.Command("lsattr", name) + out, err := cmd.Output() + if err != nil { + t.Fatal("Failed executing lsattr") + } + if !strings.Contains(string(out), "---------------C") { + t.Fatal("Failed setting NOCOW:\n", string(out)) + } + } +} diff --git a/server/peer_server.go b/server/peer_server.go index 72d8c0f95..8c8c74a02 100644 --- a/server/peer_server.go +++ b/server/peer_server.go @@ -19,6 +19,7 @@ import ( etcdErr "github.com/coreos/etcd/error" "github.com/coreos/etcd/log" "github.com/coreos/etcd/metrics" + "github.com/coreos/etcd/pkg/btrfs" "github.com/coreos/etcd/store" ) @@ -291,6 +292,13 @@ func (s *PeerServer) Start(snapshot bool, discoverURL string, peers []string) er s.raftServer.Init() + // Set NOCOW for data directory in btrfs + if btrfs.IsBtrfs(s.raftServer.LogPath()) { + if err := btrfs.SetNOCOWFile(s.raftServer.LogPath()); err != nil { + log.Warnf("Failed setting NOCOW: %v", err) + } + } + s.findCluster(discoverURL, peers) s.closeChan = make(chan bool) diff --git a/test.sh b/test.sh index 4cf444209..1397e11db 100755 --- a/test.sh +++ b/test.sh @@ -23,6 +23,9 @@ go test -v ./server/v2/tests -race go test -i ./mod/lock/v2/tests go test -v ./mod/lock/v2/tests +go test -i ./pkg/btrfs +go test -v ./pkg/btrfs + go test -i ./tests/functional ETCD_BIN_PATH=$(pwd)/bin/etcd go test -v ./tests/functional -race