Skip to content

Commit 712c93d

Browse files
fix(csi): route RWX Block volumes to upstream hotplug detach
WrappedControllerService.ControllerUnpublishVolume decided between NFS cleanup and upstream hotplug detach using only hasRWXAccessMode(pvc). RWX Block volumes (KubeVirt live-migration disks) match that check and were routed to the NFS path, which only deletes a CiliumNetworkPolicy. For a block volume that CNP does not exist, so removeCNPOwnerReference returns successfully without doing anything, and the function reports success without ever calling upstream's hotplug detach. The DataVolume entry stays in VM.spec.template.spec.volumes; when the same PVC later attaches to a different VM, linstor-csi's anti-split-brain check sees pods from two different VMs referencing the same RWX block PVC and rejects the attach permanently. Introduce isNFSVolume(pvc) requiring both ReadWriteMany access mode and VolumeMode=Filesystem (always true for PVCs provisioned via our NFS CreateVolume path). RWX Block now delegates to upstream, which removes the entry from VM spec via RemoveVolumeFromVM. The same predicate replaces the access-mode check in ControllerExpandVolume - RWX Block volumes still need in-VM disk expansion. Fixes #2634 Assisted-By: Claude <[email protected]> Signed-off-by: Myasnikov Daniil <[email protected]>
1 parent ee9d154 commit 712c93d

1 file changed

Lines changed: 23 additions & 6 deletions

File tree

‎packages/apps/kubernetes/images/kubevirt-csi-driver/controller.go‎

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -362,12 +362,15 @@ func (w *WrappedControllerService) ControllerPublishVolume(ctx context.Context,
362362
}, nil
363363
}
364364

365-
// ControllerUnpublishVolume for NFS volumes: deletes CiliumNetworkPolicy.
366-
// For RWO volumes, delegates to upstream (hotplug removal).
365+
// ControllerUnpublishVolume for NFS volumes (RWX Filesystem): deletes CiliumNetworkPolicy.
366+
// For everything else (RWO and RWX Block), delegates to upstream so the hotplug
367+
// DataVolume is removed from VM.spec.template.spec.volumes. RWX Block volumes used
368+
// for live migration must NOT be treated as NFS — their cleanup goes through upstream
369+
// hotplug removal, otherwise stale VM-spec entries permanently block re-attachment to
370+
// a different VM via the anti-split-brain check (issue #2634).
367371
func (w *WrappedControllerService) ControllerUnpublishVolume(ctx context.Context, req *csi.ControllerUnpublishVolumeRequest) (*csi.ControllerUnpublishVolumeResponse, error) {
368372
dvName := req.GetVolumeId()
369373

370-
// Determine if NFS by checking infra PVC access modes
371374
pvc, err := w.infraClient.CoreV1().PersistentVolumeClaims(w.infraNamespace).Get(ctx, dvName, metav1.GetOptions{})
372375
if err != nil {
373376
if errors.IsNotFound(err) {
@@ -376,7 +379,7 @@ func (w *WrappedControllerService) ControllerUnpublishVolume(ctx context.Context
376379
return nil, err
377380
}
378381

379-
if !hasRWXAccessMode(pvc) {
382+
if !isNFSVolume(pvc) {
380383
return w.ControllerService.ControllerUnpublishVolume(ctx, req)
381384
}
382385

@@ -404,11 +407,12 @@ func (w *WrappedControllerService) ControllerExpandVolume(ctx context.Context, r
404407
return nil, err
405408
}
406409

407-
// For NFS volumes, no node-side expansion is needed
410+
// For NFS volumes (RWX Filesystem), no node-side expansion is needed. RWX Block
411+
// volumes still require node-side expansion of the in-VM disk.
408412
pvc, err := w.infraClient.CoreV1().PersistentVolumeClaims(w.infraNamespace).Get(ctx, req.GetVolumeId(), metav1.GetOptions{})
409413
if err != nil {
410414
klog.Warningf("Failed to check PVC access mode for %s/%s: %v", w.infraNamespace, req.GetVolumeId(), err)
411-
} else if hasRWXAccessMode(pvc) {
415+
} else if isNFSVolume(pvc) {
412416
resp.NodeExpansionRequired = false
413417
}
414418

@@ -544,6 +548,19 @@ func hasRWXAccessMode(pvc *corev1.PersistentVolumeClaim) bool {
544548
return false
545549
}
546550

551+
// isNFSVolume reports whether the PVC was provisioned by our CreateVolume NFS path
552+
// (RWX + Filesystem). RWX Block volumes are upstream hotplug volumes used for live
553+
// migration and must NOT be handled as NFS.
554+
func isNFSVolume(pvc *corev1.PersistentVolumeClaim) bool {
555+
if !hasRWXAccessMode(pvc) {
556+
return false
557+
}
558+
if pvc.Spec.VolumeMode != nil && *pvc.Spec.VolumeMode == corev1.PersistentVolumeBlock {
559+
return false
560+
}
561+
return true
562+
}
563+
547564
// getNFSExport extracts the NFS export URL from a PersistentVolume.
548565
// Supports both native NFS PVs and CSI PVs with nfs-export volume attribute.
549566
func getNFSExport(pv *corev1.PersistentVolume) (string, error) {

0 commit comments

Comments
 (0)