diff --git a/weed/command/mount_common.go b/weed/command/mount_common.go index bbabe56ac8..5321c1af78 100644 --- a/weed/command/mount_common.go +++ b/weed/command/mount_common.go @@ -14,6 +14,7 @@ import ( "runtime/debug" "strconv" "strings" + "sync" "time" "google.golang.org/grpc" @@ -269,6 +270,27 @@ func createMountRoot(wfs *mount.WFS, mountRoot, bucketRootPath string, filerAddr return true } +// mountSocketCleanup returns a func that removes the control socket this mount +// listens on, unless a later mount of the same directory has replaced it. +func mountSocketCleanup(socketPath string) func() { + listened, err := os.Lstat(socketPath) + if err != nil { + return func() {} + } + var once sync.Once + return func() { + once.Do(func() { + current, err := os.Lstat(socketPath) + if err != nil || !os.SameFile(current, listened) { + return + } + if err := os.Remove(socketPath); err != nil && !os.IsNotExist(err) { + glog.Warningf("remove mount socket %s: %v", socketPath, err) + } + }) + } +} + // serveMountGrpc exposes the local control socket used by "weed mount.stats". func serveMountGrpc(wfs *mount.WFS, listener net.Listener) { grpcS := pb.NewGrpcServer() diff --git a/weed/command/mount_common_test.go b/weed/command/mount_common_test.go index 48878cca53..a472f59178 100644 --- a/weed/command/mount_common_test.go +++ b/weed/command/mount_common_test.go @@ -5,6 +5,9 @@ package command import ( "bytes" "context" + "net" + "os" + "path/filepath" "testing" "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb" @@ -213,3 +216,42 @@ func Test_ensureBucketAllowEmptyFolders(t *testing.T) { }) } } + +func Test_mountSocketCleanup(t *testing.T) { + dir, err := os.MkdirTemp("", "swmnt") + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { os.RemoveAll(dir) }) + socketPath := filepath.Join(dir, "mount.sock") + listen := func() { + l, err := net.Listen("unix", socketPath) + if err != nil { + t.Skipf("unix sockets unavailable: %v", err) + } + t.Cleanup(func() { l.Close() }) + } + exists := func() bool { + _, err := os.Lstat(socketPath) + return err == nil + } + + listen() + removeMountSocket := mountSocketCleanup(socketPath) + removeMountSocket() + removeMountSocket() + if exists() { + t.Fatalf("%s is still there after the mount exited", socketPath) + } + + listen() + removeMountSocket = mountSocketCleanup(socketPath) + if err := os.Remove(socketPath); err != nil { + t.Fatal(err) + } + listen() + removeMountSocket() + if !exists() { + t.Fatalf("exiting mount removed the socket of a later mount of the same directory") + } +} diff --git a/weed/command/mount_std.go b/weed/command/mount_std.go index b047443c13..1988adcad3 100644 --- a/weed/command/mount_std.go +++ b/weed/command/mount_std.go @@ -69,10 +69,14 @@ func RunMount(option *MountOptions, umask os.FileMode) bool { if err != nil { glog.Fatalf("Failed to listen on %s: %v", *option.localSocket, err) } + removeMountSocket := mountSocketCleanup(*option.localSocket) + defer removeMountSocket() + grace.OnInterrupt(removeMountSocket) // detect mount folder mode if *option.dirAutoCreate { if err := os.MkdirAll(dir, os.FileMode(0777)&^umask); err != nil { + removeMountSocket() glog.Fatalf("failed to create directory %s:%v", dir, err) } } @@ -113,6 +117,7 @@ func RunMount(option *MountOptions, umask os.FileMode) bool { // Ensure target mount point availability skipAutofs := option.hasAutofs != nil && *option.hasAutofs if isValid := checkMountPointAvailable(dir, skipAutofs); !isValid { + removeMountSocket() glog.Fatalf("Target mount point is not available: %s, please check!", dir) return true } @@ -231,6 +236,7 @@ func RunMount(option *MountOptions, umask os.FileMode) bool { if err != nil { // A failed mount is an environment problem (no /dev/fuse, fusermount not // setuid, stale mount point); the goroutine dump Fatalf adds buries it. + removeMountSocket() glog.Exitf("Mount fail: %v", err) } grace.OnInterrupt(func() { diff --git a/weed/command/mount_windows.go b/weed/command/mount_windows.go index 71cd6a3189..872278c3db 100644 --- a/weed/command/mount_windows.go +++ b/weed/command/mount_windows.go @@ -73,6 +73,9 @@ func RunMount(option *MountOptions, umask os.FileMode) bool { if err != nil { glog.Fatalf("Failed to listen on %s: %v", *option.localSocket, err) } + removeMountSocket := mountSocketCleanup(*option.localSocket) + defer removeMountSocket() + grace.OnInterrupt(removeMountSocket) uidGidMapper, err := meta_cache.NewUidGidMapper(*option.uidMap, *option.gidMap) if err != nil {