@@ -26,15 +26,23 @@ var onlyVolumeCapAccessMode = csi.VolumeCapability_AccessMode{
2626
2727type controllerServer struct {
2828 csi.UnimplementedControllerServer
29- connector cloud.Interface
29+ // connector is the CloudStack client interface
30+ connector cloud.Interface
31+
32+ // A map storing all volumes with ongoing operations so that additional operations
33+ // for that same volume (as defined by VolumeID/volume name) return an Aborted error
3034 volumeLocks * util.VolumeLocks
35+
36+ // A map storing all volumes/snapshots with ongoing operations.
37+ operationLocks * util.OperationLock
3138}
3239
3340// NewControllerServer creates a new Controller gRPC server.
3441func NewControllerServer (connector cloud.Interface ) csi.ControllerServer {
3542 return & controllerServer {
36- connector : connector ,
37- volumeLocks : util .NewVolumeLocks (),
43+ connector : connector ,
44+ volumeLocks : util .NewVolumeLocks (),
45+ operationLocks : util .NewOperationLock (),
3846 }
3947}
4048
@@ -237,6 +245,14 @@ func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol
237245 }
238246 defer cs .volumeLocks .Release (volumeID )
239247
248+ // lock out volumeID for clone and expand operation
249+ if err := cs .operationLocks .GetDeleteLock (volumeID ); err != nil {
250+ logger .Error (err , "Failed to acquire delete operation lock" )
251+
252+ return nil , status .Error (codes .Aborted , err .Error ())
253+ }
254+ defer cs .operationLocks .ReleaseDeleteLock (volumeID )
255+
240256 logger .Info ("Deleting volume" ,
241257 "volumeID" , volumeID ,
242258 )
@@ -448,25 +464,24 @@ func (cs *controllerServer) ControllerExpandVolume(ctx context.Context, req *csi
448464 logger := klog .FromContext (ctx )
449465 logger .V (6 ).Info ("ControllerExpandVolume: called" , "args" , protosanitizer .StripSecrets (* req ))
450466
451- expandVolumeLock := util .NewOperationLock (ctx )
452-
453467 volumeID := req .GetVolumeId ()
454468 if len (volumeID ) == 0 {
455469 return nil , status .Error (codes .InvalidArgument , "Volume ID not provided" )
456470 }
457- err := expandVolumeLock .GetExpandLock (volumeID )
458- if err != nil {
459- logger .Error (err , "failed acquiring expand lock" , "volumeID" , volumeID )
460-
461- return nil , status .Errorf (codes .Aborted , util .VolumeOperationAlreadyExistsFmt , volumeID )
462- }
463- defer expandVolumeLock .ReleaseExpandLock (volumeID )
464471
465472 capRange := req .GetCapacityRange ()
466473 if capRange == nil {
467474 return nil , status .Error (codes .InvalidArgument , "Capacity range not provided" )
468475 }
469476
477+ // lock out parallel requests against the same volume ID
478+ if acquired := cs .volumeLocks .TryAcquire (volumeID ); ! acquired {
479+ logger .Error (errors .New (util .ErrVolumeOperationAlreadyExistsVolumeID ), "failed to acquire volume lock" , "volumeID" , volumeID )
480+
481+ return nil , status .Errorf (codes .Aborted , util .VolumeOperationAlreadyExistsFmt , volumeID )
482+ }
483+ defer cs .volumeLocks .Release (volumeID )
484+
470485 volSizeBytes := capRange .GetRequiredBytes ()
471486 volSizeGB := util .RoundUpBytesToGB (volSizeBytes )
472487 maxVolSize := capRange .GetLimitBytes ()
@@ -496,6 +511,15 @@ func (cs *controllerServer) ControllerExpandVolume(ctx context.Context, req *csi
496511 NodeExpansionRequired : true ,
497512 }, nil
498513 }
514+
515+ // lock out volumeID for clone and delete operation
516+ if err := cs .operationLocks .GetExpandLock (volumeID ); err != nil {
517+ logger .Error (err , "failed acquiring expand lock" , "volumeID" , volumeID )
518+
519+ return nil , status .Error (codes .Aborted , err .Error ())
520+ }
521+ defer cs .operationLocks .ReleaseExpandLock (volumeID )
522+
499523 err = cs .connector .ExpandVolume (ctx , volumeID , volSizeGB )
500524 if err != nil {
501525 return nil , status .Errorf (codes .Internal , "Could not resize volume %q to size %v: %v" , volumeID , volSizeGB , err )
0 commit comments