You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

236 lines
7.2 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. //go:build linux || darwin
  2. // +build linux darwin
  3. package command
  4. import (
  5. "context"
  6. "fmt"
  7. "github.com/chrislusf/seaweedfs/weed/glog"
  8. "github.com/chrislusf/seaweedfs/weed/mount"
  9. "github.com/chrislusf/seaweedfs/weed/mount/meta_cache"
  10. "github.com/chrislusf/seaweedfs/weed/mount/unmount"
  11. "github.com/chrislusf/seaweedfs/weed/pb"
  12. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  13. "github.com/chrislusf/seaweedfs/weed/security"
  14. "github.com/chrislusf/seaweedfs/weed/storage/types"
  15. "github.com/hanwen/go-fuse/v2/fuse"
  16. "net/http"
  17. "os"
  18. "os/user"
  19. "runtime"
  20. "strconv"
  21. "strings"
  22. "time"
  23. "github.com/chrislusf/seaweedfs/weed/util"
  24. "github.com/chrislusf/seaweedfs/weed/util/grace"
  25. )
  26. func runMount(cmd *Command, args []string) bool {
  27. if *mountOptions.debug {
  28. go http.ListenAndServe(fmt.Sprintf(":%d", *mountOptions.debugPort), nil)
  29. }
  30. grace.SetupProfiling(*mountCpuProfile, *mountMemProfile)
  31. if *mountReadRetryTime < time.Second {
  32. *mountReadRetryTime = time.Second
  33. }
  34. util.RetryWaitTime = *mountReadRetryTime
  35. umask, umaskErr := strconv.ParseUint(*mountOptions.umaskString, 8, 64)
  36. if umaskErr != nil {
  37. fmt.Printf("can not parse umask %s", *mountOptions.umaskString)
  38. return false
  39. }
  40. if len(args) > 0 {
  41. return false
  42. }
  43. return RunMount2(&mountOptions, os.FileMode(umask))
  44. }
  45. func RunMount2(option *MountOptions, umask os.FileMode) bool {
  46. // basic checks
  47. chunkSizeLimitMB := *mountOptions.chunkSizeLimitMB
  48. if chunkSizeLimitMB <= 0 {
  49. fmt.Printf("Please specify a reasonable buffer size.")
  50. return false
  51. }
  52. // try to connect to filer
  53. filerAddresses := pb.ServerAddresses(*option.filer).ToAddresses()
  54. util.LoadConfiguration("security", false)
  55. grpcDialOption := security.LoadClientTLS(util.GetViper(), "grpc.client")
  56. var cipher bool
  57. var err error
  58. for i := 0; i < 10; i++ {
  59. err = pb.WithOneOfGrpcFilerClients(false, filerAddresses, grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
  60. resp, err := client.GetFilerConfiguration(context.Background(), &filer_pb.GetFilerConfigurationRequest{})
  61. if err != nil {
  62. return fmt.Errorf("get filer grpc address %v configuration: %v", filerAddresses, err)
  63. }
  64. cipher = resp.Cipher
  65. return nil
  66. })
  67. if err != nil {
  68. glog.V(0).Infof("failed to talk to filer %v: %v", filerAddresses, err)
  69. glog.V(0).Infof("wait for %d seconds ...", i+1)
  70. time.Sleep(time.Duration(i+1) * time.Second)
  71. }
  72. }
  73. if err != nil {
  74. glog.Errorf("failed to talk to filer %v: %v", filerAddresses, err)
  75. return true
  76. }
  77. filerMountRootPath := *option.filerMountRootPath
  78. // clean up mount point
  79. dir := util.ResolvePath(*option.dir)
  80. if dir == "" {
  81. fmt.Printf("Please specify the mount directory via \"-dir\"")
  82. return false
  83. }
  84. unmount.Unmount(dir)
  85. // detect mount folder mode
  86. if *option.dirAutoCreate {
  87. os.MkdirAll(dir, os.FileMode(0777)&^umask)
  88. }
  89. fileInfo, err := os.Stat(dir)
  90. // collect uid, gid
  91. uid, gid := uint32(0), uint32(0)
  92. mountMode := os.ModeDir | 0777
  93. if err == nil {
  94. mountMode = os.ModeDir | os.FileMode(0777)&^umask
  95. uid, gid = util.GetFileUidGid(fileInfo)
  96. fmt.Printf("mount point owner uid=%d gid=%d mode=%s\n", uid, gid, mountMode)
  97. } else {
  98. fmt.Printf("can not stat %s\n", dir)
  99. return false
  100. }
  101. // detect uid, gid
  102. if uid == 0 {
  103. if u, err := user.Current(); err == nil {
  104. if parsedId, pe := strconv.ParseUint(u.Uid, 10, 32); pe == nil {
  105. uid = uint32(parsedId)
  106. }
  107. if parsedId, pe := strconv.ParseUint(u.Gid, 10, 32); pe == nil {
  108. gid = uint32(parsedId)
  109. }
  110. fmt.Printf("current uid=%d gid=%d\n", uid, gid)
  111. }
  112. }
  113. // mapping uid, gid
  114. uidGidMapper, err := meta_cache.NewUidGidMapper(*option.uidMap, *option.gidMap)
  115. if err != nil {
  116. fmt.Printf("failed to parse %s %s: %v\n", *option.uidMap, *option.gidMap, err)
  117. return false
  118. }
  119. // Ensure target mount point availability
  120. if isValid := checkMountPointAvailable(dir); !isValid {
  121. glog.Fatalf("Expected mount to still be active, target mount point: %s, please check!", dir)
  122. return true
  123. }
  124. // mount fuse
  125. fuseMountOptions := &fuse.MountOptions{
  126. AllowOther: *option.allowOthers,
  127. Options: nil,
  128. MaxBackground: 128,
  129. MaxWrite: 1024 * 1024 * 2,
  130. MaxReadAhead: 1024 * 1024 * 2,
  131. IgnoreSecurityLabels: false,
  132. RememberInodes: false,
  133. FsName: *option.filer + ":" + filerMountRootPath,
  134. Name: "seaweedfs",
  135. SingleThreaded: false,
  136. DisableXAttrs: false,
  137. Debug: *option.debug,
  138. EnableLocks: false,
  139. ExplicitDataCacheControl: false,
  140. DirectMount: true,
  141. DirectMountFlags: 0,
  142. //SyncRead: false, // set to false to enable the FUSE_CAP_ASYNC_READ capability
  143. //EnableAcl: true,
  144. }
  145. if *option.nonempty {
  146. fuseMountOptions.Options = append(fuseMountOptions.Options, "nonempty")
  147. }
  148. if *option.readOnly {
  149. if runtime.GOOS == "darwin" {
  150. fuseMountOptions.Options = append(fuseMountOptions.Options, "rdonly")
  151. } else {
  152. fuseMountOptions.Options = append(fuseMountOptions.Options, "ro")
  153. }
  154. }
  155. if runtime.GOOS == "darwin" {
  156. // https://github-wiki-see.page/m/macfuse/macfuse/wiki/Mount-Options
  157. ioSizeMB := 1
  158. for ioSizeMB*2 <= *option.chunkSizeLimitMB && ioSizeMB*2 <= 32 {
  159. ioSizeMB *= 2
  160. }
  161. fuseMountOptions.Options = append(fuseMountOptions.Options, "daemon_timeout=600")
  162. fuseMountOptions.Options = append(fuseMountOptions.Options, "noapplexattr")
  163. // fuseMountOptions.Options = append(fuseMountOptions.Options, "novncache") // need to test effectiveness
  164. fuseMountOptions.Options = append(fuseMountOptions.Options, "slow_statfs")
  165. fuseMountOptions.Options = append(fuseMountOptions.Options, "volname="+*option.filer)
  166. fuseMountOptions.Options = append(fuseMountOptions.Options, fmt.Sprintf("iosize=%d", ioSizeMB*1024*1024))
  167. }
  168. // find mount point
  169. mountRoot := filerMountRootPath
  170. if mountRoot != "/" && strings.HasSuffix(mountRoot, "/") {
  171. mountRoot = mountRoot[0 : len(mountRoot)-1]
  172. }
  173. seaweedFileSystem := mount.NewSeaweedFileSystem(&mount.Option{
  174. MountDirectory: dir,
  175. FilerAddresses: filerAddresses,
  176. GrpcDialOption: grpcDialOption,
  177. FilerMountRootPath: mountRoot,
  178. Collection: *option.collection,
  179. Replication: *option.replication,
  180. TtlSec: int32(*option.ttlSec),
  181. DiskType: types.ToDiskType(*option.diskType),
  182. ChunkSizeLimit: int64(chunkSizeLimitMB) * 1024 * 1024,
  183. ConcurrentWriters: *option.concurrentWriters,
  184. CacheDir: *option.cacheDir,
  185. CacheSizeMB: *option.cacheSizeMB,
  186. DataCenter: *option.dataCenter,
  187. MountUid: uid,
  188. MountGid: gid,
  189. MountMode: mountMode,
  190. MountCtime: fileInfo.ModTime(),
  191. MountMtime: time.Now(),
  192. Umask: umask,
  193. VolumeServerAccess: *mountOptions.volumeServerAccess,
  194. Cipher: cipher,
  195. UidGidMapper: uidGidMapper,
  196. })
  197. server, err := fuse.NewServer(seaweedFileSystem, dir, fuseMountOptions)
  198. if err != nil {
  199. glog.Fatalf("Mount fail: %v", err)
  200. }
  201. grace.OnInterrupt(func() {
  202. unmount.Unmount(dir)
  203. })
  204. seaweedFileSystem.StartBackgroundTasks()
  205. fmt.Printf("This is SeaweedFS version %s %s %s\n", util.Version(), runtime.GOOS, runtime.GOARCH)
  206. server.Serve()
  207. return true
  208. }