@@ -19,11 +19,9 @@ package mountreconcile
19
19
import (
20
20
"bytes"
21
21
"fmt"
22
- "os"
23
22
goexec "os/exec"
24
23
"path"
25
24
"strings"
26
- "syscall"
27
25
"time"
28
26
29
27
"github.com/cvmfs-contrib/cvmfs-csi/internal/exec"
@@ -42,13 +40,29 @@ type Opts struct {
42
40
func RunBlocking (o * Opts ) error {
43
41
t := time .NewTicker (o .Period )
44
42
43
+ doReconcile := func () {
44
+ log .Tracef ("Reconciling /cvmfs" )
45
+ if err := reconcile (); err != nil {
46
+ log .Errorf ("Failed to reconcile /cvmfs: %v" , err )
47
+ }
48
+ }
49
+
50
+ // Run at start so that broken mounts after nodeplugin Pod
51
+ // restart are cleaned up.
52
+ //
53
+ // Known issue with CVMFS v2.11.0: first run of cvmfs_talk
54
+ // on corrupted mounts sometimes results in the program exiting
55
+ // due to SIGABRT, as a result of a failed assertion:
56
+ // (num_bytes >= 0)
57
+ // && (static_cast<size_t>(num_bytes) == nbyte)
58
+ // This does not trigger reconciliation. On the second retry,
59
+ // the command runs normally and the mount is cleaned.
60
+ doReconcile ()
61
+
45
62
for {
46
63
select {
47
64
case <- t .C :
48
- log .Tracef ("Reconciling /cvmfs" )
49
- if err := reconcile (); err != nil {
50
- log .Errorf ("Failed to reconcile /cvmfs: %v" , err )
51
- }
65
+ doReconcile ()
52
66
}
53
67
}
54
68
}
@@ -108,28 +122,14 @@ func repoNeedsUnmount(repo string) (bool, error) {
108
122
const cvmfsErrConnRefused = "(111 - Connection refused)\x0A "
109
123
const cvmfsErrClientNotRunning = "Seems like CernVM-FS is not running"
110
124
111
- if bytes .HasSuffix (out , []byte (cvmfsErrConnRefused )) ||
112
- bytes .HasPrefix (out , []byte (cvmfsErrClientNotRunning )) {
113
- // It seems that the CVMFS client exited.
114
- // Use stat syscall to check for ENOTCONN, i.e. the mount is corrupted,
115
- // confirming what cvmfs_talk returned.
116
-
117
- _ , err := os .Stat (path .Join (mountPathPrefix , repo ))
118
- if err != nil {
119
- if err .(* os.PathError ).Err == syscall .ENOTCONN {
120
- return true , nil
121
- }
122
-
123
- // It's something else.
124
- return false , fmt .Errorf ("unexpected error from stat: %v" , err )
125
- }
125
+ outputHasKnownErr := bytes .HasSuffix (out , []byte (cvmfsErrConnRefused )) ||
126
+ bytes .HasPrefix (out , []byte (cvmfsErrClientNotRunning ))
126
127
127
- // stat should have failed! Fall through and fail.
128
+ if ! outputHasKnownErr {
129
+ return false , fmt .Errorf ("failed to talk to CVMFS client (%v): %s" , err , out )
128
130
}
129
131
130
- // If we got here, the error reported by cvmfs_talk
131
- // is something else and we should fail too.
132
- return false , fmt .Errorf ("failed to talk to CVMFS client (%v): %s" , err , out )
132
+ return true , nil
133
133
}
134
134
135
135
func reconcile () error {
0 commit comments