@@ -80,8 +80,13 @@ func (hp *hostPath) NodePublishVolume(ctx context.Context, req *csi.NodePublishV
8080 return nil , status .Error (codes .NotFound , err .Error ())
8181 }
8282
83- if ! ephemeralVolume && ! vol .IsStaged {
84- return nil , status .Errorf (codes .FailedPrecondition , "Volume ('%s') must be staged before publishing." , vol .VolID )
83+ if ! ephemeralVolume {
84+ if vol .Staged .Empty () {
85+ return nil , status .Errorf (codes .FailedPrecondition , "volume %q must be staged before publishing" , vol .VolID )
86+ }
87+ if ! vol .Staged .Has (req .GetStagingTargetPath ()) {
88+ return nil , status .Errorf (codes .InvalidArgument , "volume %q was staged at %v, not %q" , vol .VolID , vol .Staged , req .GetStagingTargetPath ())
89+ }
8590 }
8691
8792 if req .GetVolumeCapability ().GetBlock () != nil {
@@ -184,7 +189,7 @@ func (hp *hostPath) NodePublishVolume(ctx context.Context, req *csi.NodePublishV
184189 }
185190
186191 vol .NodeID = hp .config .NodeID
187- vol .IsPublished = true
192+ vol .Published . Add ( targetPath )
188193 if err := hp .state .UpdateVolume (vol ); err != nil {
189194 return nil , err
190195 }
@@ -213,6 +218,11 @@ func (hp *hostPath) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpubl
213218 return nil , err
214219 }
215220
221+ if ! vol .Published .Has (targetPath ) {
222+ glog .V (4 ).Infof ("Volume %q is not published at %q, nothing to do." , volumeID , targetPath )
223+ return & csi.NodeUnpublishVolumeResponse {}, nil
224+ }
225+
216226 // Unmount only if the target path is really a mount point.
217227 if notMnt , err := mount .IsNotMountPoint (mount .New ("" ), targetPath ); err != nil {
218228 if ! os .IsNotExist (err ) {
@@ -238,7 +248,7 @@ func (hp *hostPath) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpubl
238248 return nil , fmt .Errorf ("failed to delete volume: %w" , err )
239249 }
240250 } else {
241- vol .IsPublished = false
251+ vol .Published . Remove ( targetPath )
242252 if err := hp .state .UpdateVolume (vol ); err != nil {
243253 return nil , err
244254 }
@@ -253,24 +263,39 @@ func (hp *hostPath) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolum
253263 if len (req .GetVolumeId ()) == 0 {
254264 return nil , status .Error (codes .InvalidArgument , "Volume ID missing in request" )
255265 }
256- if len (req .GetStagingTargetPath ()) == 0 {
266+ stagingTargetPath := req .GetStagingTargetPath ()
267+ if stagingTargetPath == "" {
257268 return nil , status .Error (codes .InvalidArgument , "Target path missing in request" )
258269 }
259270 if req .GetVolumeCapability () == nil {
260271 return nil , status .Error (codes .InvalidArgument , "Volume Capability missing in request" )
261272 }
262273
274+ // Lock before acting on global state. A production-quality
275+ // driver might use more fine-grained locking.
276+ hp .mutex .Lock ()
277+ defer hp .mutex .Unlock ()
278+
263279 vol , err := hp .state .GetVolumeByID (req .VolumeId )
264280 if err != nil {
265281 return nil , err
266282 }
267283
268- if hp .config .EnableAttach && ! vol .IsAttached {
284+ if hp .config .EnableAttach && ! vol .Attached {
269285 return nil , status .Errorf (codes .Internal , "ControllerPublishVolume must be called on volume '%s' before staging on node" ,
270286 vol .VolID )
271287 }
272288
273- vol .IsStaged = true
289+ if vol .Staged .Has (stagingTargetPath ) {
290+ glog .V (4 ).Infof ("Volume %q is already staged at %q, nothing to do." , req .VolumeId , stagingTargetPath )
291+ return & csi.NodeStageVolumeResponse {}, nil
292+ }
293+
294+ if ! vol .Staged .Empty () {
295+ return nil , status .Errorf (codes .FailedPrecondition , "volume %q is already staged at %v" , req .VolumeId , vol .Staged )
296+ }
297+
298+ vol .Staged .Add (stagingTargetPath )
274299 if err := hp .state .UpdateVolume (vol ); err != nil {
275300 return nil , err
276301 }
@@ -284,19 +309,30 @@ func (hp *hostPath) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstageV
284309 if len (req .GetVolumeId ()) == 0 {
285310 return nil , status .Error (codes .InvalidArgument , "Volume ID missing in request" )
286311 }
287- if len (req .GetStagingTargetPath ()) == 0 {
312+ stagingTargetPath := req .GetStagingTargetPath ()
313+ if stagingTargetPath == "" {
288314 return nil , status .Error (codes .InvalidArgument , "Target path missing in request" )
289315 }
290316
317+ // Lock before acting on global state. A production-quality
318+ // driver might use more fine-grained locking.
319+ hp .mutex .Lock ()
320+ defer hp .mutex .Unlock ()
321+
291322 vol , err := hp .state .GetVolumeByID (req .VolumeId )
292323 if err != nil {
293324 return nil , err
294325 }
295326
296- if vol .IsPublished {
297- return nil , status .Errorf (codes .Internal , "Volume '%s' is still pulished on '%s' node" , vol .VolID , vol .NodeID )
327+ if ! vol .Staged .Has (stagingTargetPath ) {
328+ glog .V (4 ).Infof ("Volume %q is not staged at %q, nothing to do." , req .VolumeId , stagingTargetPath )
329+ return & csi.NodeUnstageVolumeResponse {}, nil
330+ }
331+
332+ if ! vol .Published .Empty () {
333+ return nil , status .Errorf (codes .Internal , "volume %q is still published at %q on node %q" , vol .VolID , vol .Published , vol .NodeID )
298334 }
299- vol .IsStaged = false
335+ vol .Staged . Remove ( stagingTargetPath )
300336 if err := hp .state .UpdateVolume (vol ); err != nil {
301337 return nil , err
302338 }
0 commit comments