btrfs.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. package btrfs
  2. import (
  3. "fmt"
  4. "os"
  5. "runtime"
  6. "syscall"
  7. "unsafe"
  8. "github.com/coreos/etcd/log"
  9. )
  10. const (
  11. // from Linux/include/uapi/linux/magic.h
  12. BTRFS_SUPER_MAGIC = 0x9123683E
  13. // from Linux/include/uapi/linux/fs.h
  14. FS_NOCOW_FL = 0x00800000
  15. FS_IOC_GETFLAGS = 0x80086601
  16. FS_IOC_SETFLAGS = 0x40086602
  17. )
  18. // IsBtrfs checks whether the file is in btrfs
  19. func IsBtrfs(path string) bool {
  20. // btrfs is linux-only filesystem
  21. // exit on other platforms
  22. if runtime.GOOS != "linux" {
  23. return false
  24. }
  25. var buf syscall.Statfs_t
  26. if err := syscall.Statfs(path, &buf); err != nil {
  27. log.Warnf("Failed to statfs: %v", err)
  28. return false
  29. }
  30. log.Debugf("The type of path %v is %v", path, buf.Type)
  31. if buf.Type != BTRFS_SUPER_MAGIC {
  32. return false
  33. }
  34. log.Infof("The path %v is in btrfs", path)
  35. return true
  36. }
  37. // SetNOCOWFile sets NOCOW flag for file
  38. func SetNOCOWFile(path string) error {
  39. file, err := os.Open(path)
  40. if err != nil {
  41. return err
  42. }
  43. defer file.Close()
  44. fileinfo, err := file.Stat()
  45. if err != nil {
  46. return err
  47. }
  48. if fileinfo.IsDir() {
  49. return fmt.Errorf("skip directory")
  50. }
  51. if fileinfo.Size() != 0 {
  52. return fmt.Errorf("skip nonempty file")
  53. }
  54. var attr int
  55. if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, file.Fd(), FS_IOC_GETFLAGS, uintptr(unsafe.Pointer(&attr))); errno != 0 {
  56. return errno
  57. }
  58. attr |= FS_NOCOW_FL
  59. if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, file.Fd(), FS_IOC_SETFLAGS, uintptr(unsafe.Pointer(&attr))); errno != 0 {
  60. return errno
  61. }
  62. log.Infof("Set NOCOW to path %v succeeded", path)
  63. return nil
  64. }