@@ -523,6 +523,8 @@ func (s *ControllerService) createNFSVolume(ctx context.Context, req *csi.Create
523523// deleteNFSVolume deletes an NFS volume with ownership verification.
524524// Dataset deletion is retried for busy resource errors.
525525// If deleteStrategy is "retain", the volume is kept but CSI returns success.
526+ //
527+ //nolint:dupl // Intentionally similar dataset deletion pattern as iSCSI
526528func (s * ControllerService ) deleteNFSVolume (ctx context.Context , meta * VolumeMetadata ) (* csi.DeleteVolumeResponse , error ) {
527529 timer := metrics .NewVolumeOperationTimer (metrics .ProtocolNFS , "delete" )
528530 klog .V (4 ).Infof ("Deleting NFS volume: %s (dataset: %s, share ID: %d)" , meta .Name , meta .DatasetName , meta .NFSShareID )
@@ -623,34 +625,31 @@ func (s *ControllerService) deleteNFSVolume(ctx context.Context, meta *VolumeMet
623625 }
624626 }
625627
626- // Step 2: Delete any snapshots on the dataset first (handles promoted clone cleanup)
627- // This is necessary because after ZFS clone promotion, snapshots may have dependent
628- // clones that prevent deletion. Deleting with defer=true allows ZFS to clean up properly.
629- if meta .DatasetID != "" {
630- s .deleteDatasetSnapshots (ctx , meta .DatasetID )
631- }
632-
633- // Step 3: Delete ZFS dataset with retry logic for busy resources
628+ // Step 2: Delete dataset (try direct first, snapshot cleanup on failure)
634629 if meta .DatasetID == "" {
635630 klog .V (4 ).Infof ("No dataset ID provided, skipping dataset deletion" )
636631 } else {
637- klog .V (4 ).Infof ("Deleting dataset: %s (with retry for busy resources)" , meta .DatasetID )
632+ klog .V (4 ).Infof ("Deleting dataset: %s" , meta .DatasetID )
633+
634+ firstErr := s .apiClient .DeleteDataset (ctx , meta .DatasetID )
635+ if firstErr != nil && ! isNotFoundError (firstErr ) {
636+ klog .Infof ("Direct deletion failed for %s: %v — cleaning up snapshots before retry" ,
637+ meta .DatasetID , firstErr )
638+ s .deleteDatasetSnapshots (ctx , meta .DatasetID )
639+
640+ retryConfig := retry .DeletionConfig ("delete-nfs-dataset" )
641+ err := retry .WithRetryNoResult (ctx , retryConfig , func () error {
642+ deleteErr := s .apiClient .DeleteDataset (ctx , meta .DatasetID )
643+ if deleteErr != nil && isNotFoundError (deleteErr ) {
644+ return nil
645+ }
646+ return deleteErr
647+ })
638648
639- retryConfig := retry .DeletionConfig ("delete-nfs-dataset" )
640- err := retry .WithRetryNoResult (ctx , retryConfig , func () error {
641- deleteErr := s .apiClient .DeleteDataset (ctx , meta .DatasetID )
642- if deleteErr != nil && isNotFoundError (deleteErr ) {
643- // Dataset already deleted - not an error (idempotency)
644- klog .V (4 ).Infof ("Dataset %s not found, assuming already deleted (idempotency)" , meta .DatasetID )
645- return nil
649+ if err != nil {
650+ timer .ObserveError ()
651+ return nil , status .Errorf (codes .Internal , "Failed to delete dataset %s: %v" , meta .DatasetID , err )
646652 }
647- return deleteErr
648- })
649-
650- if err != nil {
651- // All retries exhausted or non-retryable error
652- timer .ObserveError ()
653- return nil , status .Errorf (codes .Internal , "Failed to delete dataset %s: %v" , meta .DatasetID , err )
654653 }
655654 klog .V (4 ).Infof ("Successfully deleted dataset %s" , meta .DatasetID )
656655 }
0 commit comments