Skip to content

Commit 3d8616d

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 9819c8b commit 3d8616d

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
// DiskMultiTenantEnable Enable disk multi-tenant mode
9896
DiskMultiTenantEnable = "DISK_MULTI_TENANT_ENABLE"
9997
// TenantUserUID tag
@@ -688,9 +686,44 @@ func addDiskXattr(diskID string) (err error) {
688686
return unix.Setxattr(device, DiskXattrName, []byte(diskID), 0)
689687
}
690688

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

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

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

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

763765
if IsVFNode() {
764766
if err := unbindBdfDisk(req.VolumeId); err != nil {
@@ -777,7 +779,7 @@ func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstag
777779
}
778780
}
779781

780-
err := addDiskXattr(req.VolumeId)
782+
err = addDiskXattr(req.VolumeId)
781783
if err != nil {
782784
klog.Errorf("NodeUnstageVolume: addDiskXattr %s failed: %v", req.VolumeId, err)
783785
}

pkg/disk/utils.go

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -872,20 +872,6 @@ func GetVolumeDeviceName(diskID string) (string, error) {
872872
return device, err
873873
}
874874

875-
// isPathAvailiable
876-
func isPathAvailiable(path string) error {
877-
f, err := os.Open(path)
878-
if err != nil {
879-
return fmt.Errorf("Open Path (%s) with error: %v ", path, err)
880-
}
881-
defer f.Close()
882-
_, err = f.Readdirnames(1)
883-
if err != nil && err != io.EOF {
884-
return fmt.Errorf("Read Path (%s) with error: %v ", path, err)
885-
}
886-
return nil
887-
}
888-
889875
func getBlockDeviceCapacity(devicePath string) int64 {
890876

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

0 commit comments

Comments
 (0)