@@ -92,8 +92,6 @@ const (
92
92
RundSocketDir = "/host/etc/kubernetes/volumes/rund/"
93
93
// VolumeDirRemove volume dir remove
94
94
VolumeDirRemove = "/host/etc/kubernetes/volumes/disk/remove"
95
- // InputOutputErr tag
96
- InputOutputErr = "input/output error"
97
95
// CreateDiskARN ARN parameter of the CreateDisk interface
98
96
CreateDiskARN = "alibabacloud.com/createdisk-arn"
99
97
// PVC annotation key of KMS key ID, override the storage class parameter kmsKeyId
@@ -682,9 +680,44 @@ func addDiskXattr(diskID string) (err error) {
682
680
return unix .Setxattr (device , DiskXattrName , []byte (diskID ), 0 )
683
681
}
684
682
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
+
686
718
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 )
688
721
689
722
if ! ns .locks .TryAcquire (req .VolumeId ) {
690
723
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
693
726
694
727
// check block device mountpoint
695
728
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 )
715
738
}
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
- }
721
739
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 )
732
745
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 )
739
747
}
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 )
746
750
}
747
751
} 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
+ }
755
756
}
757
+ logger .V (2 ).Info ("targetPath cleaned up" )
756
758
757
759
if IsVFNode () {
758
760
if err := unbindBdfDisk (req .VolumeId ); err != nil {
@@ -771,7 +773,7 @@ func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstag
771
773
}
772
774
}
773
775
774
- err : = addDiskXattr (req .VolumeId )
776
+ err = addDiskXattr (req .VolumeId )
775
777
if err != nil {
776
778
klog .Errorf ("NodeUnstageVolume: addDiskXattr %s failed: %v" , req .VolumeId , err )
777
779
}
0 commit comments