@@ -17,10 +17,15 @@ limitations under the License.
17
17
package gceGCEDriver
18
18
19
19
import (
20
+ "fmt"
21
+ "os"
22
+ "syscall"
23
+
20
24
csi "github.com/container-storage-interface/spec/lib/go/csi/v0"
21
25
"github.com/golang/glog"
22
26
"golang.org/x/net/context"
23
27
"google.golang.org/grpc"
28
+ "k8s.io/kubernetes/pkg/util/mount"
24
29
)
25
30
26
31
func NewVolumeCapabilityAccessMode (mode csi.VolumeCapability_AccessMode_Mode ) * csi.VolumeCapability_AccessMode {
@@ -58,3 +63,97 @@ func logGRPC(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, h
58
63
}
59
64
return resp , err
60
65
}
66
+
67
+ // UnmountMountPoint is a common unmount routine that unmounts the given path and
68
+ // deletes the remaining directory if successful.
69
+ // if extensiveMountPointCheck is true
70
+ // IsNotMountPoint will be called instead of IsLikelyNotMountPoint.
71
+ // IsNotMountPoint is more expensive but properly handles bind mounts.
72
+ func unmountMountPoint (mountPath string , mounter mount.Interface , extensiveMountPointCheck bool ) error {
73
+ pathExists , pathErr := pathExists (mountPath )
74
+ if ! pathExists {
75
+ glog .Warningf ("Warning: Unmount skipped because path does not exist: %v" , mountPath )
76
+ return nil
77
+ }
78
+ corruptedMnt := isCorruptedMnt (pathErr )
79
+ if pathErr != nil && ! corruptedMnt {
80
+ return fmt .Errorf ("Error checking path: %v" , pathErr )
81
+ }
82
+ return doUnmountMountPoint (mountPath , mounter , extensiveMountPointCheck , corruptedMnt )
83
+ }
84
+
85
+ // doUnmountMountPoint is a common unmount routine that unmounts the given path and
86
+ // deletes the remaining directory if successful.
87
+ // if extensiveMountPointCheck is true
88
+ // IsNotMountPoint will be called instead of IsLikelyNotMountPoint.
89
+ // IsNotMountPoint is more expensive but properly handles bind mounts.
90
+ // if corruptedMnt is true, it means that the mountPath is a corrupted mountpoint, Take it as an argument for convenience of testing
91
+ func doUnmountMountPoint (mountPath string , mounter mount.Interface , extensiveMountPointCheck bool , corruptedMnt bool ) error {
92
+ if ! corruptedMnt {
93
+ var notMnt bool
94
+ var err error
95
+ if extensiveMountPointCheck {
96
+ notMnt , err = mount .IsNotMountPoint (mounter , mountPath )
97
+ } else {
98
+ notMnt , err = mounter .IsLikelyNotMountPoint (mountPath )
99
+ }
100
+
101
+ if err != nil {
102
+ return err
103
+ }
104
+
105
+ if notMnt {
106
+ glog .Warningf ("Warning: %q is not a mountpoint, deleting" , mountPath )
107
+ return os .Remove (mountPath )
108
+ }
109
+ }
110
+
111
+ // Unmount the mount path
112
+ glog .V (4 ).Infof ("%q is a mountpoint, unmounting" , mountPath )
113
+ if err := mounter .Unmount (mountPath ); err != nil {
114
+ return err
115
+ }
116
+ notMnt , mntErr := mounter .IsLikelyNotMountPoint (mountPath )
117
+ if mntErr != nil {
118
+ return mntErr
119
+ }
120
+ if notMnt {
121
+ glog .V (4 ).Infof ("%q is unmounted, deleting the directory" , mountPath )
122
+ return os .Remove (mountPath )
123
+ }
124
+ return fmt .Errorf ("Failed to unmount path %v" , mountPath )
125
+ }
126
+
127
+ // pathExists returns true if the specified path exists.
128
+ func pathExists (path string ) (bool , error ) {
129
+ _ , err := os .Stat (path )
130
+ if err == nil {
131
+ return true , nil
132
+ } else if os .IsNotExist (err ) {
133
+ return false , nil
134
+ } else if isCorruptedMnt (err ) {
135
+ return true , err
136
+ } else {
137
+ return false , err
138
+ }
139
+ }
140
+
141
+ // isCorruptedMnt return true if err is about corrupted mount point
142
+ func isCorruptedMnt (err error ) bool {
143
+ if err == nil {
144
+ return false
145
+ }
146
+ var underlyingError error
147
+ switch pe := err .(type ) {
148
+ case nil :
149
+ return false
150
+ case * os.PathError :
151
+ underlyingError = pe .Err
152
+ case * os.LinkError :
153
+ underlyingError = pe .Err
154
+ case * os.SyscallError :
155
+ underlyingError = pe .Err
156
+ }
157
+
158
+ return underlyingError == syscall .ENOTCONN || underlyingError == syscall .ESTALE || underlyingError == syscall .EIO
159
+ }
0 commit comments