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.

239 lines
7.3 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 RunMount(&mountOptions, os.FileMode(umask))
  44. }
  45. func RunMount(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. serverFriendlyName := strings.ReplaceAll(*option.filer, ",", "+")
  125. // mount fuse
  126. fuseMountOptions := &fuse.MountOptions{
  127. AllowOther: *option.allowOthers,
  128. Options: nil,
  129. MaxBackground: 128,
  130. MaxWrite: 1024 * 1024 * 2,
  131. MaxReadAhead: 1024 * 1024 * 2,
  132. IgnoreSecurityLabels: false,
  133. RememberInodes: false,
  134. FsName: serverFriendlyName + ":" + filerMountRootPath,
  135. Name: "seaweedfs",
  136. SingleThreaded: false,
  137. DisableXAttrs: false,
  138. Debug: *option.debug,
  139. EnableLocks: false,
  140. ExplicitDataCacheControl: false,
  141. DirectMount: true,
  142. DirectMountFlags: 0,
  143. //SyncRead: false, // set to false to enable the FUSE_CAP_ASYNC_READ capability
  144. //EnableAcl: true,
  145. }
  146. if *option.nonempty {
  147. fuseMountOptions.Options = append(fuseMountOptions.Options, "nonempty")
  148. }
  149. if *option.readOnly {
  150. if runtime.GOOS == "darwin" {
  151. fuseMountOptions.Options = append(fuseMountOptions.Options, "rdonly")
  152. } else {
  153. fuseMountOptions.Options = append(fuseMountOptions.Options, "ro")
  154. }
  155. }
  156. if runtime.GOOS == "darwin" {
  157. // https://github-wiki-see.page/m/macfuse/macfuse/wiki/Mount-Options
  158. ioSizeMB := 1
  159. for ioSizeMB*2 <= *option.chunkSizeLimitMB && ioSizeMB*2 <= 32 {
  160. ioSizeMB *= 2
  161. }
  162. fuseMountOptions.Options = append(fuseMountOptions.Options, "daemon_timeout=600")
  163. fuseMountOptions.Options = append(fuseMountOptions.Options, "noapplexattr")
  164. // fuseMountOptions.Options = append(fuseMountOptions.Options, "novncache") // need to test effectiveness
  165. fuseMountOptions.Options = append(fuseMountOptions.Options, "slow_statfs")
  166. fuseMountOptions.Options = append(fuseMountOptions.Options, "volname="+serverFriendlyName)
  167. fuseMountOptions.Options = append(fuseMountOptions.Options, fmt.Sprintf("iosize=%d", ioSizeMB*1024*1024))
  168. }
  169. // find mount point
  170. mountRoot := filerMountRootPath
  171. if mountRoot != "/" && strings.HasSuffix(mountRoot, "/") {
  172. mountRoot = mountRoot[0 : len(mountRoot)-1]
  173. }
  174. seaweedFileSystem := mount.NewSeaweedFileSystem(&mount.Option{
  175. MountDirectory: dir,
  176. FilerAddresses: filerAddresses,
  177. GrpcDialOption: grpcDialOption,
  178. FilerMountRootPath: mountRoot,
  179. Collection: *option.collection,
  180. Replication: *option.replication,
  181. TtlSec: int32(*option.ttlSec),
  182. DiskType: types.ToDiskType(*option.diskType),
  183. ChunkSizeLimit: int64(chunkSizeLimitMB) * 1024 * 1024,
  184. ConcurrentWriters: *option.concurrentWriters,
  185. CacheDir: *option.cacheDir,
  186. CacheSizeMB: *option.cacheSizeMB,
  187. DataCenter: *option.dataCenter,
  188. Quota: int64(*option.collectionQuota) * 1024 * 1024,
  189. MountUid: uid,
  190. MountGid: gid,
  191. MountMode: mountMode,
  192. MountCtime: fileInfo.ModTime(),
  193. MountMtime: time.Now(),
  194. Umask: umask,
  195. VolumeServerAccess: *mountOptions.volumeServerAccess,
  196. Cipher: cipher,
  197. UidGidMapper: uidGidMapper,
  198. })
  199. server, err := fuse.NewServer(seaweedFileSystem, dir, fuseMountOptions)
  200. if err != nil {
  201. glog.Fatalf("Mount fail: %v", err)
  202. }
  203. grace.OnInterrupt(func() {
  204. unmount.Unmount(dir)
  205. })
  206. seaweedFileSystem.StartBackgroundTasks()
  207. fmt.Printf("This is SeaweedFS version %s %s %s\n", util.Version(), runtime.GOOS, runtime.GOARCH)
  208. server.Serve()
  209. return true
  210. }