Skip to content

Commit 324c9a8

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 6fc9c76 commit 324c9a8

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
@@ -92,8 +92,6 @@ const (
9292
RundSocketDir = "/host/etc/kubernetes/volumes/rund/"
9393
// VolumeDirRemove volume dir remove
9494
VolumeDirRemove = "/host/etc/kubernetes/volumes/disk/remove"
95-
// InputOutputErr tag
96-
InputOutputErr = "input/output error"
9795
// CreateDiskARN ARN parameter of the CreateDisk interface
9896
CreateDiskARN = "alibabacloud.com/createdisk-arn"
9997
// PVC annotation key of KMS key ID, override the storage class parameter kmsKeyId
@@ -682,9 +680,44 @@ func addDiskXattr(diskID string) (err error) {
682680
return unix.Setxattr(device, DiskXattrName, []byte(diskID), 0)
683681
}
684682

685-
// target format: /var/lib/kubelet/plugins/kubernetes.io/csi/pv/pv-disk-1e7001e0-c54a-11e9-8f89-00163e0e78a0/globalmount
683+
func ensureUnmounted(mounter k8smount.Interface, target string) error {
684+
notmounted, err := mounter.IsLikelyNotMountPoint(target)
685+
if err != nil {
686+
return fmt.Errorf("failed to check if %s is not a mount point after unmount: %w", target, err)
687+
}
688+
if !notmounted {
689+
return fmt.Errorf("path %s is still mounted after unmount", target)
690+
}
691+
return nil
692+
}
693+
694+
func cleanupVolumeDeviceMount(path string) error {
695+
err := unix.Unmount(path, 0)
696+
if err != nil {
697+
switch {
698+
case errors.Is(err, unix.ENOENT):
699+
return nil
700+
case errors.Is(err, unix.EINVAL):
701+
// Maybe not mounted, proceed to remove it. If not, unlink will report error.
702+
default:
703+
return err
704+
}
705+
}
706+
707+
errUnlink := unix.Unlink(path)
708+
if errUnlink == nil {
709+
return nil
710+
}
711+
if err != nil {
712+
return fmt.Errorf("failed to unlink %s: %w", path, errUnlink)
713+
} else {
714+
return fmt.Errorf("failed to unmount %s: %w; then failed to unlink: %w", path, err, errUnlink)
715+
}
716+
}
717+
686718
func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstageVolumeRequest) (*csi.NodeUnstageVolumeResponse, error) {
687-
klog.Infof("NodeUnstageVolume:: Starting to Unmount volume, volumeId: %s, target: %v", req.VolumeId, req.StagingTargetPath)
719+
logger := klog.FromContext(ctx)
720+
logger.Info("Starting to Unmount volume", "target", req.StagingTargetPath)
688721

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

694727
// check block device mountpoint
695728
targetPath := req.GetStagingTargetPath()
696-
tmpPath := filepath.Join(req.GetStagingTargetPath(), req.VolumeId)
697-
if IsFileExisting(tmpPath) {
698-
fileInfo, err := os.Lstat(tmpPath)
699-
if err != nil {
700-
if strings.Contains(strings.ToLower(err.Error()), InputOutputErr) {
701-
if err = isPathAvailiable(targetPath); err != nil {
702-
if err = ns.k8smounter.Unmount(targetPath); err != nil {
703-
klog.Errorf("NodeUnstageVolume: umount target %s(input/output error) with error: %v", targetPath, err)
704-
return nil, status.Errorf(codes.InvalidArgument, "NodeUnstageVolume umount target %s with errror: %v", targetPath, err)
705-
}
706-
klog.Warningf("NodeUnstageVolume: target path %s show input/output error: %v, umount it.", targetPath, err)
707-
}
708-
} else {
709-
klog.Errorf("NodeUnstageVolume: lstat mountpoint: %s with error: %s", tmpPath, err.Error())
710-
return nil, status.Error(codes.InvalidArgument, "NodeUnstageVolume: stat mountpoint error: "+err.Error())
711-
}
712-
} else {
713-
if (fileInfo.Mode() & os.ModeDevice) != 0 {
714-
klog.Infof("NodeUnstageVolume: mountpoint %s, is block device", tmpPath)
729+
err := unix.Unmount(targetPath, 0)
730+
if err != nil {
731+
switch {
732+
case errors.Is(err, unix.ENOENT):
733+
logger.Info("targetPath not exist, continue to detach")
734+
case errors.Is(err, unix.EINVAL):
735+
// Maybe unmounted, lets check
736+
if errCheck := ensureUnmounted(ns.k8smounter, targetPath); errCheck != nil {
737+
return nil, status.Errorf(codes.Internal, "failed to unmount %s: %v. %v", targetPath, err, errCheck)
715738
}
716-
// if mountpoint not a block device, maybe something wrong happened in VolumeStageVolume.
717-
// when pod deleted, the volume should be detached
718-
targetPath = tmpPath
719-
}
720-
}
721739

722-
// Step 1: check folder exists and umount
723-
msgLog := ""
724-
if IsFileExisting(targetPath) {
725-
notmounted, err := ns.k8smounter.IsLikelyNotMountPoint(targetPath)
726-
if err != nil {
727-
klog.Errorf("NodeUnstageVolume: VolumeId: %s, check mountPoint: %s error: %v", req.VolumeId, targetPath, err)
728-
return nil, status.Error(codes.Internal, err.Error())
729-
}
730-
if !notmounted {
731-
err = ns.k8smounter.Unmount(targetPath)
740+
// really umounted, check volumeDevice
741+
// Note: we remove the blockPath, but not targetPath, because the former is created by us, while the latter is created by CO.
742+
blockPath := filepath.Join(targetPath, req.VolumeId)
743+
logger.Info("targetPath may not be a mountpoint, checking volumeDevice")
744+
err := cleanupVolumeDeviceMount(blockPath)
732745
if err != nil {
733-
klog.Errorf("NodeUnstageVolume: VolumeId: %s, umount path: %s failed with: %v", req.VolumeId, targetPath, err)
734-
return nil, status.Error(codes.Internal, err.Error())
735-
}
736-
notmounted, err = ns.k8smounter.IsLikelyNotMountPoint(targetPath)
737-
if err != nil {
738-
return nil, status.Errorf(codes.Internal, "failed to check if %s is not a mount point after umount: %v", targetPath, err)
746+
return nil, status.Errorf(codes.Internal, "failed to cleanup volumeDevice path %s: %v", blockPath, err)
739747
}
740-
if !notmounted {
741-
klog.Errorf("NodeUnstageVolume: TargetPath mounted yet, volumeId: %s, Target: %s", req.VolumeId, targetPath)
742-
return nil, status.Error(codes.Internal, "NodeUnstageVolume: TargetPath mounted yet with target"+targetPath)
743-
}
744-
} else {
745-
msgLog = fmt.Sprintf("NodeUnstageVolume: VolumeId: %s, mountpoint: %s not mounted, skipping and continue to detach", req.VolumeId, targetPath)
748+
default:
749+
return nil, status.Errorf(codes.Internal, "failed to unmount %s: %v", targetPath, err)
746750
}
747751
} else {
748-
msgLog = fmt.Sprintf("NodeUnstageVolume: VolumeId: %s, Path %s doesn't exist, continue to detach", req.VolumeId, targetPath)
749-
}
750-
751-
if msgLog == "" {
752-
klog.Infof("NodeUnstageVolume: Unmount TargetPath successful, target %v, volumeId: %s", targetPath, req.VolumeId)
753-
} else {
754-
klog.Infof(msgLog)
752+
err := ensureUnmounted(ns.k8smounter, targetPath)
753+
if err != nil {
754+
return nil, status.Error(codes.Internal, err.Error())
755+
}
755756
}
757+
logger.V(2).Info("targetPath cleaned up")
756758

757759
if IsVFNode() {
758760
if err := unbindBdfDisk(req.VolumeId); err != nil {
@@ -771,7 +773,7 @@ func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstag
771773
}
772774
}
773775

774-
err := addDiskXattr(req.VolumeId)
776+
err = addDiskXattr(req.VolumeId)
775777
if err != nil {
776778
klog.Errorf("NodeUnstageVolume: addDiskXattr %s failed: %v", req.VolumeId, err)
777779
}

pkg/disk/utils.go

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -853,20 +853,6 @@ func GetVolumeDeviceName(diskID string) (string, error) {
853853
return device, err
854854
}
855855

856-
// isPathAvailiable
857-
func isPathAvailiable(path string) error {
858-
f, err := os.Open(path)
859-
if err != nil {
860-
return fmt.Errorf("Open Path (%s) with error: %v ", path, err)
861-
}
862-
defer f.Close()
863-
_, err = f.Readdirnames(1)
864-
if err != nil && err != io.EOF {
865-
return fmt.Errorf("Read Path (%s) with error: %v ", path, err)
866-
}
867-
return nil
868-
}
869-
870856
func getBlockDeviceCapacity(devicePath string) int64 {
871857

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

0 commit comments

Comments
 (0)