Skip to content

Commit 655b870

Browse files
committed
rbd: include trashed parent images while calculating the clone depth
The `getCloneDepth()` function did not account for images that are in the trash. A trashed image can only be opened by the image-id, and not by name anymore. Closes: #4013 Signed-off-by: Niels de Vos <[email protected]>
1 parent 8b31f9d commit 655b870

File tree

1 file changed

+44
-32
lines changed

1 file changed

+44
-32
lines changed

internal/rbd/rbd_util.go

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -697,47 +697,59 @@ func (ri *rbdImage) trashRemoveImage(ctx context.Context) error {
697697
return nil
698698
}
699699

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.
700717
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+
)
703722

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()
709728

710729
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)
717737
}
718738

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++
732741

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)
737748
}
738-
vol.RbdImageName = vol.ParentName
739-
vol.Pool = vol.ParentPool
749+
defer image.Close()
740750
}
751+
752+
return depth, nil
741753
}
742754

743755
type trashSnapInfo struct {

0 commit comments

Comments
 (0)