diff --git a/weed/command/fuse_std.go b/weed/command/fuse_std.go index 8fb52d5d8..3fb7236af 100644 --- a/weed/command/fuse_std.go +++ b/weed/command/fuse_std.go @@ -12,6 +12,7 @@ import ( "syscall" "time" + "github.com/seaweedfs/seaweedfs/weed/glog" "github.com/seaweedfs/seaweedfs/weed/util" util_http "github.com/seaweedfs/seaweedfs/weed/util/http" ) @@ -267,6 +268,19 @@ func runFuse(cmd *Command, args []string) bool { fmt.Fprintf(os.Stderr, "failed to parse 'sys.novncache' value %q: %v\n", parameter.value, err) return false } + case "autofs": + if parsed, err := strconv.ParseBool(parameter.value); err == nil { + mountOptions.hasAutofs = &parsed + } else { + fmt.Fprintf(os.Stderr, "failed to parse 'autofs' value %q: %v\n", parameter.value, err) + return false + } + case "_netdev": + // _netdev is used for systemd/fstab parser to signify that this is a network mount but systemd + // mount sometimes can't strip them off. Meanwhile, fuse3 would refuse to run with _netdev, we + // strip them here if it fails to be stripped by the caller. + //(See https://github.com/seaweedfs/seaweedfs/wiki/fstab/948a70df5c0d9d2d27561b96de53bde07a29d2db) + glog.V(0).Infof("ignoring _netdev mount option") default: t := parameter.name if parameter.value != "true" { diff --git a/weed/command/mount.go b/weed/command/mount.go index b45233fb4..f1bacae8b 100644 --- a/weed/command/mount.go +++ b/weed/command/mount.go @@ -58,6 +58,11 @@ type MountOptions struct { // macOS-specific FUSE options novncache *bool + + // if true, we assume autofs exists over current mount point. Autofs (the kernel one, used by systemd automount) + // is expected to be mounted as a shim between auto-mounted fs and original mount point to provide auto mount. + // with this option, we ignore autofs mounted on the same point. + hasAutofs *bool } var ( @@ -98,6 +103,7 @@ func init() { mountOptions.debugPort = cmdMount.Flag.Int("debug.port", 6061, "http port for debugging") mountOptions.localSocket = cmdMount.Flag.String("localSocket", "", "default to /tmp/seaweedfs-mount-.sock") mountOptions.disableXAttr = cmdMount.Flag.Bool("disableXAttr", false, "disable xattr") + mountOptions.hasAutofs = cmdMount.Flag.Bool("autofs", false, "ignore autofs mounted on the same mountpoint (useful when systemd.automount and autofs is used)") mountOptions.fuseCommandPid = 0 // Periodic metadata flush to protect against orphan chunk cleanup diff --git a/weed/command/mount_darwin.go b/weed/command/mount_darwin.go index 05d6a1bc4..f1408eee0 100644 --- a/weed/command/mount_darwin.go +++ b/weed/command/mount_darwin.go @@ -1,5 +1,5 @@ package command -func checkMountPointAvailable(dir string) bool { +func checkMountPointAvailable(dir string, skipAutofs bool) bool { return true } diff --git a/weed/command/mount_freebsd.go b/weed/command/mount_freebsd.go index 05d6a1bc4..f1408eee0 100644 --- a/weed/command/mount_freebsd.go +++ b/weed/command/mount_freebsd.go @@ -1,5 +1,5 @@ package command -func checkMountPointAvailable(dir string) bool { +func checkMountPointAvailable(dir string, skipAutofs bool) bool { return true } diff --git a/weed/command/mount_linux.go b/weed/command/mount_linux.go index 2d5f11c26..326fda931 100644 --- a/weed/command/mount_linux.go +++ b/weed/command/mount_linux.go @@ -69,7 +69,7 @@ type Info struct { // Mounted determines if a specified mountpoint has been mounted. // On Linux it looks at /proc/self/mountinfo and on Solaris at mnttab. -func mounted(mountPoint string) (bool, error) { +func mounted(mountPoint string, skipAutofs bool) (bool, error) { entries, err := parseMountTable() if err != nil { return false, err @@ -78,6 +78,10 @@ func mounted(mountPoint string) (bool, error) { // Search the table for the mountPoint for _, e := range entries { if e.Mountpoint == mountPoint { + // Check if the mountpoint is autofs + if skipAutofs && e.Fstype == "autofs" { + continue + } return true, nil } } @@ -137,13 +141,13 @@ func parseInfoFile(r io.Reader) ([]*Info, error) { return out, nil } -func checkMountPointAvailable(dir string) bool { +func checkMountPointAvailable(dir string, skipAutofs bool) bool { mountPoint := dir if mountPoint != "/" && strings.HasSuffix(mountPoint, "/") { mountPoint = mountPoint[0 : len(mountPoint)-1] } - if mounted, err := mounted(mountPoint); err != nil || mounted { + if mounted, err := mounted(mountPoint, skipAutofs); err != nil || mounted { if err != nil { glog.Errorf("check %s: %v", mountPoint, err) } diff --git a/weed/command/mount_std.go b/weed/command/mount_std.go index 57aca5f5c..5b272cbeb 100644 --- a/weed/command/mount_std.go +++ b/weed/command/mount_std.go @@ -223,13 +223,21 @@ func RunMount(option *MountOptions, umask os.FileMode) bool { } // Ensure target mount point availability - if isValid := checkMountPointAvailable(dir); !isValid { + skipAutofs := option.hasAutofs != nil && *option.hasAutofs + if isValid := checkMountPointAvailable(dir, skipAutofs); !isValid { glog.Fatalf("Target mount point is not available: %s, please check!", dir) return true } serverFriendlyName := strings.ReplaceAll(*option.filer, ",", "+") + // When autofs/systemd-mount is used, FsName must be "fuse" so util-linux/mount can recognize + // it as a pseudo filesystem. Otherwise, preserve the descriptive name for mount/df output. + fsName := serverFriendlyName + ":" + filerMountRootPath + if skipAutofs { + fsName = "fuse" + } + // mount fuse fuseMountOptions := &fuse.MountOptions{ AllowOther: *option.allowOthers, @@ -239,7 +247,7 @@ func RunMount(option *MountOptions, umask os.FileMode) bool { MaxReadAhead: 1024 * 1024 * 2, IgnoreSecurityLabels: false, RememberInodes: false, - FsName: serverFriendlyName + ":" + filerMountRootPath, + FsName: fsName, Name: "seaweedfs", SingleThreaded: false, DisableXAttrs: *option.disableXAttr,