Skip to content

Commit 5149e7d

Browse files
authored
Merge pull request #137 from NearNodeFlash/delete-ns-failure-crash
Remove deleted volumes from in memory list after failure. Also, add c…
2 parents cdc17ef + eb53672 commit 5149e7d

2 files changed

Lines changed: 52 additions & 11 deletions

File tree

pkg/manager-nnf/storage_pool.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,12 @@ func (p *StoragePool) replaceMissingVolumes() error {
242242
log.Info("replace missing volume")
243243
storage := unusedStorages[idx]
244244

245+
// Add safety check before creating volume
246+
if storage == nil || !storage.IsEnabled() || storageDeviceIsNil(storage) {
247+
log.Error(fmt.Errorf("storage unavailable"), "Cannot create volume: storage is nil, not enabled, or device is nil")
248+
return fmt.Errorf("Cannot create volume: storage unavailable for missing volume %v", missingVolume)
249+
}
250+
245251
volume, err := nvme.CreateVolume(storage, p.volumeCapacity)
246252
if err != nil {
247253
log.Error(err, "Failed to create replacement volume")
@@ -571,3 +577,16 @@ func (rh *storagePoolRecoveryReplayHandler) Done() (bool, error) {
571577

572578
return false, nil
573579
}
580+
581+
// Helper to check if storage device is nil
582+
func storageDeviceIsNil(s interface{}) bool {
583+
if s == nil {
584+
return true
585+
}
586+
// Use reflection to check for the unexported field
587+
type deviceGetter interface{ DeviceApi() interface{} }
588+
if dg, ok := s.(deviceGetter); ok {
589+
return dg.DeviceApi() == nil
590+
}
591+
return false
592+
}

pkg/manager-nvme/manager.go

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,8 @@ func (s *Storage) initialize() error {
410410
}
411411

412412
s.log.Info("identify common namespace attempt failed, retrying", "retryCount", retryCount)
413+
} else if ns == nil {
414+
return fmt.Errorf("Initialize Storage %s: IdentifyNamespace returned nil without error", s.id)
413415
} else {
414416
identifySuccess = true
415417
}
@@ -418,7 +420,6 @@ func (s *Storage) initialize() error {
418420
// Workaround for SSST drives that improperly report only one NumberOfLBAFormats, but actually
419421
// support two - with the second being the most performant 4096 sector size.
420422
if ns.NumberOfLBAFormats == 1 {
421-
422423
if ((1 << ns.LBAFormats[1].LBADataSize) == 4096) && (ns.LBAFormats[1].RelativePerformance == 0) {
423424
log.Info("Incorrect number of LBA formats", "expected", 2, "actual", ns.NumberOfLBAFormats)
424425
ns.NumberOfLBAFormats = 2
@@ -479,12 +480,18 @@ vol_loop:
479480
volIdsToDelete = append(volIdsToDelete, vol.id)
480481
}
481482

483+
var errs []error
482484
for _, volId := range volIdsToDelete {
483485
if err := s.deleteVolume(volId); err != nil {
484-
return err
486+
s.log.Error(err, "Failed to delete volume during purge", "volumeId", volId)
487+
errs = append(errs, fmt.Errorf("volume %s: %w", volId, err))
485488
}
486489
}
487490

491+
if len(errs) > 0 {
492+
return fmt.Errorf("purgeVolumes encountered errors: %v", errs)
493+
}
494+
488495
return nil
489496
}
490497

@@ -552,19 +559,19 @@ func (s *Storage) deleteVolume(volumeId string) error {
552559
log := volume.log
553560

554561
log.V(2).Info("Deleting namespace")
555-
if err := s.device.DeleteNamespace(volume.namespaceId); err != nil {
556-
log.Error(err, "Delete namespace failed")
557-
return err
562+
err := s.device.DeleteNamespace(volume.namespaceId)
563+
if err != nil {
564+
log.Error(err, "Delete namespace failed, removing from in-memory state anyway", "capacity", volume.capacityBytes)
565+
} else {
566+
log.V(1).Info("Deleted namespace", "capacity", volume.capacityBytes)
558567
}
559-
log.V(1).Info("Deleted namespace", "capacity", volume.capacityBytes)
560568

569+
// Whether or not there was an error, delete the volume in memory
561570
s.unallocatedBytes += volume.capacityBytes
571+
copy(s.volumes[idx:], s.volumes[idx+1:])
572+
s.volumes = s.volumes[:len(s.volumes)-1]
562573

563-
// remove the volume from the array
564-
copy(s.volumes[idx:], s.volumes[idx+1:]) // shift left 1 at idx
565-
s.volumes = s.volumes[:len(s.volumes)-1] // truncate tail
566-
567-
return nil
574+
return err
568575
}
569576
}
570577

@@ -603,6 +610,11 @@ func (s *Storage) recoverStorageVolumes() error {
603610
ns, err := s.device.IdentifyNamespace(nsid)
604611
if err != nil {
605612
log.Error(err, "Failed to identify namespace")
613+
continue
614+
}
615+
if ns == nil {
616+
log.Error(fmt.Errorf("IdentifyNamespace returned nil without error"), "Failed to identify namespace")
617+
continue
606618
}
607619

608620
blockSizeBytes := uint64(1 << ns.LBAFormats[ns.FormattedLBASize.Format].LBADataSize)
@@ -695,6 +707,9 @@ func (v *Volume) WaitFormatComplete() error {
695707
if err != nil {
696708
return err
697709
}
710+
if ns == nil {
711+
return fmt.Errorf("IdentifyNamespace returned nil without error")
712+
}
698713

699714
stalledCount := 0
700715
for ns.Utilization != 0 {
@@ -711,6 +726,9 @@ func (v *Volume) WaitFormatComplete() error {
711726
if err != nil {
712727
return err
713728
}
729+
if ns == nil {
730+
return fmt.Errorf("IdentifyNamespace returned nil without error")
731+
}
714732

715733
if lastUtilization == ns.Utilization {
716734
stalledCount++
@@ -1294,6 +1312,10 @@ func (mgr *Manager) StorageIdVolumeIdGet(storageId, volumeId string, model *sf.V
12941312
v.log.Error(err, "Identify Namespace Failed")
12951313
return ec.NewErrInternalServerError()
12961314
}
1315+
if ns == nil {
1316+
v.log.Error(fmt.Errorf("IdentifyNamespace returned nil without error"), "Identify Namespace Failed")
1317+
return ec.NewErrInternalServerError()
1318+
}
12971319

12981320
lbaFormat := ns.LBAFormats[ns.FormattedLBASize.Format]
12991321
blockSizeInBytes := int64(math.Pow(2, float64(lbaFormat.LBADataSize)))

0 commit comments

Comments
 (0)