Skip to content

Commit dca9856

Browse files
committed
disk: re-implement StagingTargetPath cleanup logic
We should unlink the file we created for volumeDevice. We should check targetPath is not mounted before we check for volumeDevice, in case the user has a file with the same name. And the overall complexity is greatly reduced. We do not call stat() on the mounted path now, so no need to worry about EIO or similar.
1 parent d3d9b11 commit dca9856

File tree

2 files changed

+60
-72
lines changed

2 files changed

+60
-72
lines changed

pkg/disk/nodeserver.go

Lines changed: 60 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,6 @@ const (
9595
RundSocketDir = "/host/etc/kubernetes/volumes/rund/"
9696
// VolumeDirRemove volume dir remove
9797
VolumeDirRemove = "/host/etc/kubernetes/volumes/disk/remove"
98-
// InputOutputErr tag
99-
InputOutputErr = "input/output error"
10098
// CreateDiskARN ARN parameter of the CreateDisk interface
10199
CreateDiskARN = "alibabacloud.com/createdisk-arn"
102100
// PVC annotation key of KMS key ID, override the storage class parameter kmsKeyId
@@ -708,9 +706,44 @@ func addDiskXattr(diskID string) (err error) {
708706
return unix.Setxattr(device, DiskXattrName, []byte(diskID), 0)
709707
}
710708

711-
// target format: /var/lib/kubelet/plugins/kubernetes.io/csi/pv/pv-disk-1e7001e0-c54a-11e9-8f89-00163e0e78a0/globalmount
709+
func ensureUnmounted(mounter k8smount.Interface, target string) error {
710+
notmounted, err := mounter.IsLikelyNotMountPoint(target)
711+
if err != nil {
712+
return fmt.Errorf("failed to check if %s is not a mount point after unmount: %w", target, err)
713+
}
714+
if !notmounted {
715+
return fmt.Errorf("path %s is still mounted after unmount", target)
716+
}
717+
return nil
718+
}
719+
720+
func cleanupVolumeDeviceMount(path string) error {
721+
err := unix.Unmount(path, 0)
722+
if err != nil {
723+
switch {
724+
case errors.Is(err, unix.ENOENT):
725+
return nil
726+
case errors.Is(err, unix.EINVAL):
727+
// Maybe not mounted, proceed to remove it. If not, unlink will report error.
728+
default:
729+
return err
730+
}
731+
}
732+
733+
errUnlink := unix.Unlink(path)
734+
if errUnlink == nil {
735+
return nil
736+
}
737+
if err != nil {
738+
return fmt.Errorf("failed to unlink %s: %w", path, errUnlink)
739+
} else {
740+
return fmt.Errorf("failed to unmount %s: %w; then failed to unlink: %w", path, err, errUnlink)
741+
}
742+
}
743+
712744
func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstageVolumeRequest) (*csi.NodeUnstageVolumeResponse, error) {
713-
klog.Infof("NodeUnstageVolume:: Starting to Unmount volume, volumeId: %s, target: %v", req.VolumeId, req.StagingTargetPath)
745+
logger := klog.FromContext(ctx)
746+
logger.Info("Starting to Unmount volume", "target", req.StagingTargetPath)
714747

715748
if !ns.locks.TryAcquire(req.VolumeId) {
716749
return nil, status.Errorf(codes.Aborted, "There is already an operation for %s", req.VolumeId)
@@ -719,66 +752,35 @@ func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstag
719752

720753
// check block device mountpoint
721754
targetPath := req.GetStagingTargetPath()
722-
tmpPath := filepath.Join(req.GetStagingTargetPath(), req.VolumeId)
723-
if IsFileExisting(tmpPath) {
724-
fileInfo, err := os.Lstat(tmpPath)
725-
if err != nil {
726-
if strings.Contains(strings.ToLower(err.Error()), InputOutputErr) {
727-
if err = isPathAvailable(targetPath); err != nil {
728-
if err = ns.k8smounter.Unmount(targetPath); err != nil {
729-
klog.Errorf("NodeUnstageVolume: umount target %s(input/output error) with error: %v", targetPath, err)
730-
return nil, status.Errorf(codes.InvalidArgument, "NodeUnstageVolume umount target %s with error: %v", targetPath, err)
731-
}
732-
klog.Warningf("NodeUnstageVolume: target path %s show input/output error: %v, umount it.", targetPath, err)
733-
}
734-
} else {
735-
klog.Errorf("NodeUnstageVolume: lstat mountpoint: %s with error: %s", tmpPath, err.Error())
736-
return nil, status.Error(codes.InvalidArgument, "NodeUnstageVolume: stat mountpoint error: "+err.Error())
737-
}
738-
} else {
739-
if (fileInfo.Mode() & os.ModeDevice) != 0 {
740-
klog.Infof("NodeUnstageVolume: mountpoint %s, is block device", tmpPath)
755+
err := unix.Unmount(targetPath, 0)
756+
if err != nil {
757+
switch {
758+
case errors.Is(err, unix.ENOENT):
759+
logger.Info("targetPath not exist, continue to detach")
760+
case errors.Is(err, unix.EINVAL):
761+
// Maybe unmounted, lets check
762+
if errCheck := ensureUnmounted(ns.k8smounter, targetPath); errCheck != nil {
763+
return nil, status.Errorf(codes.Internal, "failed to unmount %s: %v. %v", targetPath, err, errCheck)
741764
}
742-
// if mountpoint not a block device, maybe something wrong happened in VolumeStageVolume.
743-
// when pod deleted, the volume should be detached
744-
targetPath = tmpPath
745-
}
746-
}
747765

748-
// Step 1: check folder exists and umount
749-
msgLog := ""
750-
if IsFileExisting(targetPath) {
751-
notmounted, err := ns.k8smounter.IsLikelyNotMountPoint(targetPath)
752-
if err != nil {
753-
klog.Errorf("NodeUnstageVolume: VolumeId: %s, check mountPoint: %s error: %v", req.VolumeId, targetPath, err)
754-
return nil, status.Error(codes.Internal, err.Error())
755-
}
756-
if !notmounted {
757-
err = ns.k8smounter.Unmount(targetPath)
766+
// really umounted, check volumeDevice
767+
// Note: we remove the blockPath, but not targetPath, because the former is created by us, while the latter is created by CO.
768+
blockPath := filepath.Join(targetPath, req.VolumeId)
769+
logger.Info("targetPath may not be a mountpoint, checking volumeDevice")
770+
err := cleanupVolumeDeviceMount(blockPath)
758771
if err != nil {
759-
klog.Errorf("NodeUnstageVolume: VolumeId: %s, umount path: %s failed with: %v", req.VolumeId, targetPath, err)
760-
return nil, status.Error(codes.Internal, err.Error())
761-
}
762-
notmounted, err = ns.k8smounter.IsLikelyNotMountPoint(targetPath)
763-
if err != nil {
764-
return nil, status.Errorf(codes.Internal, "failed to check if %s is not a mount point after umount: %v", targetPath, err)
772+
return nil, status.Errorf(codes.Internal, "failed to cleanup volumeDevice path %s: %v", blockPath, err)
765773
}
766-
if !notmounted {
767-
klog.Errorf("NodeUnstageVolume: TargetPath mounted yet, volumeId: %s, Target: %s", req.VolumeId, targetPath)
768-
return nil, status.Error(codes.Internal, "NodeUnstageVolume: TargetPath mounted yet with target"+targetPath)
769-
}
770-
} else {
771-
msgLog = fmt.Sprintf("NodeUnstageVolume: VolumeId: %s, mountpoint: %s not mounted, skipping and continue to detach", req.VolumeId, targetPath)
774+
default:
775+
return nil, status.Errorf(codes.Internal, "failed to unmount %s: %v", targetPath, err)
772776
}
773777
} else {
774-
msgLog = fmt.Sprintf("NodeUnstageVolume: VolumeId: %s, Path %s doesn't exist, continue to detach", req.VolumeId, targetPath)
775-
}
776-
777-
if msgLog == "" {
778-
klog.Infof("NodeUnstageVolume: Unmount TargetPath successful, target %v, volumeId: %s", targetPath, req.VolumeId)
779-
} else {
780-
klog.Info(msgLog)
778+
err := ensureUnmounted(ns.k8smounter, targetPath)
779+
if err != nil {
780+
return nil, status.Error(codes.Internal, err.Error())
781+
}
781782
}
783+
logger.V(2).Info("targetPath cleaned up")
782784

783785
if IsVFNode() {
784786
if err := unbindBdfDisk(req.VolumeId); err != nil {
@@ -797,7 +799,7 @@ func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstag
797799
}
798800
}
799801

800-
err := addDiskXattr(req.VolumeId)
802+
err = addDiskXattr(req.VolumeId)
801803
if err != nil {
802804
klog.Errorf("NodeUnstageVolume: addDiskXattr %s failed: %v", req.VolumeId, err)
803805
}

pkg/disk/utils.go

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -845,20 +845,6 @@ func GetVolumeDeviceName(diskID string) (string, error) {
845845
return device, err
846846
}
847847

848-
// isPathAvailable
849-
func isPathAvailable(path string) error {
850-
f, err := os.Open(path)
851-
if err != nil {
852-
return fmt.Errorf("Open Path (%s) with error: %v ", path, err)
853-
}
854-
defer f.Close()
855-
_, err = f.Readdirnames(1)
856-
if err != nil && err != io.EOF {
857-
return fmt.Errorf("Read Path (%s) with error: %v ", path, err)
858-
}
859-
return nil
860-
}
861-
862848
func getBlockDeviceCapacity(devicePath string) int64 {
863849

864850
file, err := os.Open(devicePath)

0 commit comments

Comments
 (0)