aboutsummaryrefslogtreecommitdiff
path: root/pkg/driver/mounter.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/driver/mounter.go')
-rw-r--r--pkg/driver/mounter.go91
1 files changed, 68 insertions, 23 deletions
diff --git a/pkg/driver/mounter.go b/pkg/driver/mounter.go
index 53ac26a..38baa26 100644
--- a/pkg/driver/mounter.go
+++ b/pkg/driver/mounter.go
@@ -1,7 +1,10 @@
package driver
import (
+ "context"
"fmt"
+ "os"
+ "syscall"
"time"
"os/exec"
@@ -16,8 +19,19 @@ type Config struct {
Filer string
}
+type Mount interface {
+ Unmount() error
+}
+
type Mounter interface {
- Mount(target string) error
+ Mount(target string) (Mount, error)
+}
+
+type fuseMount struct {
+ path string
+ cmd *exec.Cmd
+
+ finished chan struct{}
}
func newMounter(volumeID string, readOnly bool, driver *SeaweedFsDriver, volContext map[string]string) (Mounter, error) {
@@ -34,52 +48,83 @@ func newMounter(volumeID string, readOnly bool, driver *SeaweedFsDriver, volCont
return newSeaweedFsMounter(volumeID, path, collection, readOnly, driver, volContext)
}
-func fuseMount(path string, command string, args []string) error {
+func newFuseMount(path string, command string, args []string) (Mount, error) {
cmd := exec.Command(command, args...)
glog.V(0).Infof("Mounting fuse with command: %s and args: %s", command, args)
+ // log fuse process messages - we need an easy way to investigate crashes in case it happens
+ cmd.Stderr = os.Stderr
+ cmd.Stdout = os.Stdout
+
err := cmd.Start()
if err != nil {
glog.Errorf("running weed mount: %v", err)
- return fmt.Errorf("Error fuseMount command: %s\nargs: %s\nerror: %v", command, args, err)
+ return nil, fmt.Errorf("Error fuseMount command: %s\nargs: %s\nerror: %v", command, args, err)
+ }
+
+ m := &fuseMount{
+ path: path,
+ cmd: cmd,
+
+ finished: make(chan struct{}),
}
// avoid zombie processes
go func() {
if err := cmd.Wait(); err != nil {
- glog.Errorf("weed mount process %d exit: %v", cmd.Process.Pid, err)
+ glog.Errorf("weed mount exit, pid: %d, path: %v, error: %v", cmd.Process.Pid, path, err)
+ } else {
+ glog.Infof("weed mount exit, pid: %d, path: %v", cmd.Process.Pid, path)
}
+
+ close(m.finished)
}()
- return waitForMount(path, 10*time.Second)
+ if err = waitForMount(path, 10*time.Second); err != nil {
+ glog.Errorf("weed mount timeout, pid: %d, path: %v", cmd.Process.Pid, path)
+
+ _ = m.finish(time.Second * 10)
+ return nil, err
+ } else {
+ return m, nil
+ }
}
-func fuseUnmount(path string) error {
- m := mount.New("")
+func (fm *fuseMount) finish(timeout time.Duration) error {
+ // ignore error, just inform we want process to exit
+ _ = fm.cmd.Process.Signal(syscall.Signal(1))
- if ok, err := m.IsLikelyNotMountPoint(path); !ok || mount.IsCorruptedMnt(err) {
- if err := m.Unmount(path); err != nil {
+ if err := fm.waitFinished(timeout); err != nil {
+ glog.Errorf("weed mount terminate timeout, pid: %d, path: %v", fm.cmd.Process.Pid, fm.path)
+ _ = fm.cmd.Process.Kill()
+ if err = fm.waitFinished(time.Second * 1); err != nil {
+ glog.Errorf("weed mount kill timeout, pid: %d, path: %v", fm.cmd.Process.Pid, fm.path)
return err
}
}
- // as fuse quits immediately, we will try to wait until the process is done
- process, err := findFuseMountProcess(path)
- if err != nil {
- glog.Errorf("Error getting PID of fuse mount: %s", err)
- return nil
- }
- if process == nil {
- glog.Warningf("Unable to find PID of fuse mount %s, it must have finished already", path)
+ return nil
+}
+
+func (fm *fuseMount) waitFinished(timeout time.Duration) error {
+ ctx, cancel := context.WithTimeout(context.Background(), timeout)
+ defer cancel()
+ select {
+ case <-ctx.Done():
+ return context.DeadlineExceeded
+ case <-fm.finished:
return nil
}
- glog.Infof("Found fuse pid %v of mount %s, checking if it still runs", process.Pid, path)
- return waitForProcess(process, 1)
}
-func newConfigFromSecrets(secrets map[string]string) *Config {
- t := &Config{
- Filer: secrets["filer"],
+func (fm *fuseMount) Unmount() error {
+ m := mount.New("")
+
+ if ok, err := m.IsLikelyNotMountPoint(fm.path); !ok || mount.IsCorruptedMnt(err) {
+ if err := m.Unmount(fm.path); err != nil {
+ return err
+ }
}
- return t
+
+ return fm.finish(time.Second * 30)
}