@@ -697,47 +697,59 @@ func (ri *rbdImage) trashRemoveImage(ctx context.Context) error {
697
697
return nil
698
698
}
699
699
700
+ func getImageSpec (spec librbd.ImageSpec ) string {
701
+ if spec .Trash {
702
+ return spec .ImageID
703
+ }
704
+
705
+ if spec .PoolNamespace != "" {
706
+ return fmt .Sprintf ("%s/%s/%s" , spec .PoolName , spec .PoolNamespace , spec .ImageName )
707
+ }
708
+
709
+ return fmt .Sprintf ("%s/%s" , spec .PoolName , spec .ImageName )
710
+ }
711
+
712
+ // getCloneDepth walks the parents of the image and returns the number of
713
+ // images in the chain.
714
+ //
715
+ // This function re-uses the ioctx of the image to open all images in the
716
+ // chain. There is no need to open new ioctx's for every image.
700
717
func (ri * rbdImage ) getCloneDepth (ctx context.Context ) (uint , error ) {
701
- var depth uint
702
- vol := rbdVolume {}
718
+ var (
719
+ depth uint
720
+ parent librbd.ImageSpec
721
+ )
703
722
704
- vol . Pool = ri .Pool
705
- vol . Monitors = ri . Monitors
706
- vol . RbdImageName = ri . RbdImageName
707
- vol . RadosNamespace = ri . RadosNamespace
708
- vol . conn = ri . conn . Copy ()
723
+ image , err : = ri .open ()
724
+ if err != nil {
725
+ return 0 , fmt . Errorf ( "failed to open image %s: %w" , ri , err )
726
+ }
727
+ defer image . Close ()
709
728
710
729
for {
711
- if vol .RbdImageName == "" {
712
- return depth , nil
713
- }
714
- err := vol .openIoctx ()
715
- if err != nil {
716
- return depth , err
730
+ // get the librbd.ImageSpec of the parent
731
+ info , err := image .GetParent ()
732
+ if errors .Is (err , librbd .ErrNotFound ) {
733
+ // image does not have more parents
734
+ break
735
+ } else if err != nil {
736
+ return 0 , fmt .Errorf ("failed to get parent of image %s: %w" , ri , err )
717
737
}
718
738
719
- err = vol .getImageInfo ()
720
- // FIXME: create and destroy the vol inside the loop.
721
- // see https://github.com/ceph/ceph-csi/pull/1838#discussion_r598530807
722
- vol .ioctx .Destroy ()
723
- vol .ioctx = nil
724
- if err != nil {
725
- // if the parent image is moved to trash the name will be present
726
- // in rbd image info but the image will be in trash, in that case
727
- // return the found depth
728
- if errors .Is (err , ErrImageNotFound ) {
729
- return depth , nil
730
- }
731
- log .ErrorLog (ctx , "failed to check depth on image %s: %s" , & vol , err )
739
+ // of there is a parent, count it to the depth
740
+ depth ++
732
741
733
- return depth , err
734
- }
735
- if vol .ParentName != "" {
736
- depth ++
742
+ // open the parent image, so that the for-loop can continue
743
+ // with checking for the parent of the parent
744
+ parent = info .Image
745
+ image , err = librbd .OpenImageById (ri .ioctx , parent .ImageID , librbd .NoSnapshot )
746
+ if err != nil {
747
+ return 0 , fmt .Errorf ("failed to open parent image ID %q, at depth %d: %w" , parent .ImageID , depth , err )
737
748
}
738
- vol .RbdImageName = vol .ParentName
739
- vol .Pool = vol .ParentPool
749
+ defer image .Close ()
740
750
}
751
+
752
+ return depth , nil
741
753
}
742
754
743
755
type trashSnapInfo struct {
0 commit comments