@@ -95,8 +95,6 @@ const (
95
95
RundSocketDir = "/host/etc/kubernetes/volumes/rund/"
96
96
// VolumeDirRemove volume dir remove
97
97
VolumeDirRemove = "/host/etc/kubernetes/volumes/disk/remove"
98
- // InputOutputErr tag
99
- InputOutputErr = "input/output error"
100
98
// CreateDiskARN ARN parameter of the CreateDisk interface
101
99
CreateDiskARN = "alibabacloud.com/createdisk-arn"
102
100
// PVC annotation key of KMS key ID, override the storage class parameter kmsKeyId
@@ -708,9 +706,44 @@ func addDiskXattr(diskID string) (err error) {
708
706
return unix .Setxattr (device , DiskXattrName , []byte (diskID ), 0 )
709
707
}
710
708
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
+
712
744
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 )
714
747
715
748
if ! ns .locks .TryAcquire (req .VolumeId ) {
716
749
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
719
752
720
753
// check block device mountpoint
721
754
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 )
741
764
}
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
- }
747
765
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 )
758
771
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 )
765
773
}
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 )
772
776
}
773
777
} 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
+ }
781
782
}
783
+ logger .V (2 ).Info ("targetPath cleaned up" )
782
784
783
785
if IsVFNode () {
784
786
if err := unbindBdfDisk (req .VolumeId ); err != nil {
@@ -797,7 +799,7 @@ func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstag
797
799
}
798
800
}
799
801
800
- err : = addDiskXattr (req .VolumeId )
802
+ err = addDiskXattr (req .VolumeId )
801
803
if err != nil {
802
804
klog .Errorf ("NodeUnstageVolume: addDiskXattr %s failed: %v" , req .VolumeId , err )
803
805
}
0 commit comments