Skip to content

Commit 39ed64e

Browse files
authored
Merge pull request kubernetes#88569 from andyzhangx/csi-corrupt-mnt-fix
fix: corrupted mount point in csi driver node stage/publish
2 parents fdb2cb4 + 5a6435a commit 39ed64e

File tree

4 files changed

+60
-7
lines changed

4 files changed

+60
-7
lines changed

pkg/volume/csi/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ go_library(
4242
"//vendor/google.golang.org/grpc/codes:go_default_library",
4343
"//vendor/google.golang.org/grpc/status:go_default_library",
4444
"//vendor/k8s.io/klog:go_default_library",
45+
"//vendor/k8s.io/utils/mount:go_default_library",
4546
"//vendor/k8s.io/utils/strings:go_default_library",
4647
],
4748
)
@@ -86,6 +87,7 @@ go_test(
8687
"//staging/src/k8s.io/client-go/util/testing:go_default_library",
8788
"//staging/src/k8s.io/component-base/featuregate/testing:go_default_library",
8889
"//vendor/github.com/container-storage-interface/spec/lib/go/csi:go_default_library",
90+
"//vendor/github.com/stretchr/testify/assert:go_default_library",
8991
"//vendor/k8s.io/klog:go_default_library",
9092
],
9193
)

pkg/volume/csi/csi_attacher.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import (
2828

2929
"k8s.io/klog"
3030

31-
"k8s.io/api/core/v1"
31+
v1 "k8s.io/api/core/v1"
3232
storage "k8s.io/api/storage/v1"
3333
apierrors "k8s.io/apimachinery/pkg/api/errors"
3434
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -228,13 +228,19 @@ func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMo
228228
return errors.New(log("attacher.MountDevice failed, deviceMountPath is empty"))
229229
}
230230

231+
corruptedDir := false
231232
mounted, err := isDirMounted(c.plugin, deviceMountPath)
232233
if err != nil {
233234
klog.Error(log("attacher.MountDevice failed while checking mount status for dir [%s]", deviceMountPath))
234-
return err
235+
if isCorruptedDir(deviceMountPath) {
236+
corruptedDir = true // leave to CSI driver to handle corrupted mount
237+
klog.Warning(log("attacher.MountDevice detected corrupted mount for dir [%s]", deviceMountPath))
238+
} else {
239+
return err
240+
}
235241
}
236242

237-
if mounted {
243+
if mounted && !corruptedDir {
238244
klog.V(4).Info(log("attacher.MountDevice skipping mount, dir already mounted [%s]", deviceMountPath))
239245
return nil
240246
}
@@ -287,7 +293,7 @@ func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMo
287293

288294
// Store volume metadata for UnmountDevice. Keep it around even if the
289295
// driver does not support NodeStage, UnmountDevice still needs it.
290-
if err = os.MkdirAll(deviceMountPath, 0750); err != nil {
296+
if err = os.MkdirAll(deviceMountPath, 0750); err != nil && !corruptedDir {
291297
return errors.New(log("attacher.MountDevice failed to create dir %#v: %v", deviceMountPath, err))
292298
}
293299
klog.V(4).Info(log("created target path successfully [%s]", deviceMountPath))

pkg/volume/csi/csi_mounter.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
"k8s.io/kubernetes/pkg/features"
3737
"k8s.io/kubernetes/pkg/volume"
3838
volumetypes "k8s.io/kubernetes/pkg/volume/util/types"
39+
"k8s.io/utils/mount"
3940
utilstrings "k8s.io/utils/strings"
4041
)
4142

@@ -105,12 +106,18 @@ func (c *csiMountMgr) SetUp(mounterArgs volume.MounterArgs) error {
105106
func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
106107
klog.V(4).Infof(log("Mounter.SetUpAt(%s)", dir))
107108

109+
corruptedDir := false
108110
mounted, err := isDirMounted(c.plugin, dir)
109111
if err != nil {
110-
return errors.New(log("mounter.SetUpAt failed while checking mount status for dir [%s]: %v", dir, err))
112+
if isCorruptedDir(dir) {
113+
corruptedDir = true // leave to CSI driver to handle corrupted mount
114+
klog.Warning(log("mounter.SetUpAt detected corrupted mount for dir [%s]", dir))
115+
} else {
116+
return errors.New(log("mounter.SetUpAt failed while checking mount status for dir [%s]: %v", dir, err))
117+
}
111118
}
112119

113-
if mounted {
120+
if mounted && !corruptedDir {
114121
klog.V(4).Info(log("mounter.SetUpAt skipping mount, dir already mounted [%s]", dir))
115122
return nil
116123
}
@@ -211,7 +218,7 @@ func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error
211218
}
212219

213220
// create target_dir before call to NodePublish
214-
if err := os.MkdirAll(dir, 0750); err != nil {
221+
if err := os.MkdirAll(dir, 0750); err != nil && !corruptedDir {
215222
return errors.New(log("mounter.SetUpAt failed to create dir %#v: %v", dir, err))
216223
}
217224
klog.V(4).Info(log("created target path successfully [%s]", dir))
@@ -417,6 +424,11 @@ func isDirMounted(plug *csiPlugin, dir string) (bool, error) {
417424
return !notMnt, nil
418425
}
419426

427+
func isCorruptedDir(dir string) bool {
428+
_, pathErr := mount.PathExists(dir)
429+
return pathErr != nil && mount.IsCorruptedMnt(pathErr)
430+
}
431+
420432
// removeMountDir cleans the mount dir when dir is not mounted and removed the volume data file in dir
421433
func removeMountDir(plug *csiPlugin, mountPath string) error {
422434
klog.V(4).Info(log("removing mount path [%s]", mountPath))

pkg/volume/csi/csi_mounter_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package csi
1919
import (
2020
"context"
2121
"fmt"
22+
"io/ioutil"
2223
"math/rand"
2324
"os"
2425
"path"
@@ -27,6 +28,8 @@ import (
2728

2829
"reflect"
2930

31+
"github.com/stretchr/testify/assert"
32+
3033
api "k8s.io/api/core/v1"
3134
storage "k8s.io/api/storage/v1"
3235
storagev1beta1 "k8s.io/api/storage/v1beta1"
@@ -825,3 +828,33 @@ func TestUnmounterTeardown(t *testing.T) {
825828
}
826829

827830
}
831+
832+
func TestIsCorruptedDir(t *testing.T) {
833+
existingMountPath, err := ioutil.TempDir(os.TempDir(), "blobfuse-csi-mount-test")
834+
if err != nil {
835+
t.Fatalf("failed to create tmp dir: %v", err)
836+
}
837+
defer os.RemoveAll(existingMountPath)
838+
839+
tests := []struct {
840+
desc string
841+
dir string
842+
expectedResult bool
843+
}{
844+
{
845+
desc: "NotExist dir",
846+
dir: "/tmp/NotExist",
847+
expectedResult: false,
848+
},
849+
{
850+
desc: "Existing dir",
851+
dir: existingMountPath,
852+
expectedResult: false,
853+
},
854+
}
855+
856+
for i, test := range tests {
857+
isCorruptedDir := isCorruptedDir(test.dir)
858+
assert.Equal(t, test.expectedResult, isCorruptedDir, "TestCase[%d]: %s", i, test.desc)
859+
}
860+
}

0 commit comments

Comments
 (0)