1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
package driver
import (
"context"
"fmt"
"os"
"syscall"
"time"
"os/exec"
"github.com/seaweedfs/seaweedfs/weed/glog"
"k8s.io/utils/mount"
)
// Config holds values to configure the driver
type Config struct {
// Region string
Filer string
}
type Unmounter interface {
Unmount() error
}
type Mounter interface {
Mount(target string) (Unmounter, error)
}
type fuseUnmounter struct {
path string
cmd *exec.Cmd
finished chan struct{}
}
func newMounter(volumeID string, readOnly bool, driver *SeaweedFsDriver, volContext map[string]string) (Mounter, error) {
path, ok := volContext["path"]
if !ok {
path = fmt.Sprintf("/buckets/%s", volumeID)
}
collection, ok := volContext["collection"]
if !ok {
collection = volumeID
}
return newSeaweedFsMounter(volumeID, path, collection, readOnly, driver, volContext)
}
func fuseMount(path string, command string, args []string) (Unmounter, 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 nil, fmt.Errorf("Error fuseMount command: %s\nargs: %s\nerror: %v", command, args, err)
}
fu := &fuseUnmounter{
path: path,
cmd: cmd,
finished: make(chan struct{}),
}
// avoid zombie processes
go func() {
if err := cmd.Wait(); err != nil {
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(fu.finished)
}()
if err = waitForMount(path, 10*time.Second); err != nil {
glog.Errorf("weed mount timeout, pid: %d, path: %v", cmd.Process.Pid, path)
_ = fu.finish(time.Second * 10)
return nil, err
} else {
return fu, nil
}
}
func (fu *fuseUnmounter) finish(timeout time.Duration) error {
// ignore error, just inform we want process to exit
_ = fu.cmd.Process.Signal(syscall.Signal(1))
if err := fu.waitFinished(timeout); err != nil {
glog.Errorf("weed mount terminate timeout, pid: %d, path: %v", fu.cmd.Process.Pid, fu.path)
_ = fu.cmd.Process.Kill()
if err = fu.waitFinished(time.Second * 1); err != nil {
glog.Errorf("weed mount kill timeout, pid: %d, path: %v", fu.cmd.Process.Pid, fu.path)
return err
}
}
return nil
}
func (fu *fuseUnmounter) waitFinished(timeout time.Duration) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
select {
case <-ctx.Done():
return context.DeadlineExceeded
case <-fu.finished:
return nil
}
}
func (fu *fuseUnmounter) Unmount() error {
m := mount.New("")
if ok, err := m.IsLikelyNotMountPoint(fu.path); !ok || mount.IsCorruptedMnt(err) {
if err := m.Unmount(fu.path); err != nil {
return err
}
}
return fu.finish(time.Second * 30)
}
|