mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 10:33:35 +00:00
rbd: flatten datasource image before creating volume
This commit ensures that parent image is flattened before creating volume. - If the data source is a PVC, the underlying image's parent is flattened(which would be a temp clone or snapshot). hard & soft limit is reduced by 2 to account for depth that will be added by temp & final clone. - If the data source is a Snapshot, the underlying image is itself flattened. hard & soft limit is reduced by 1 to account for depth that will be added by the clone which will be restored from the snapshot. Flattening step for resulting PVC image restored from snapshot is removed. Flattening step for temp clone & final image is removed when pvc clone is being created. Fixes: #2190 Signed-off-by: Rakshith R <rar@redhat.com>
This commit is contained in:
@ -286,7 +286,7 @@ func (cs *ControllerServer) CreateVolume(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = flattenParentImage(ctx, parentVol, cr)
|
||||
err = flattenParentImage(ctx, parentVol, rbdSnap, cr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -297,11 +297,9 @@ func (cs *ControllerServer) CreateVolume(
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if !errors.Is(err, ErrFlattenInProgress) {
|
||||
errDefer := undoVolReservation(ctx, rbdVol, cr)
|
||||
if errDefer != nil {
|
||||
log.WarningLog(ctx, "failed undoing reservation of volume: %s (%s)", req.GetName(), errDefer)
|
||||
}
|
||||
errDefer := undoVolReservation(ctx, rbdVol, cr)
|
||||
if errDefer != nil {
|
||||
log.WarningLog(ctx, "failed undoing reservation of volume: %s (%s)", req.GetName(), errDefer)
|
||||
}
|
||||
}
|
||||
}()
|
||||
@ -318,12 +316,38 @@ func (cs *ControllerServer) CreateVolume(
|
||||
return buildCreateVolumeResponse(req, rbdVol), nil
|
||||
}
|
||||
|
||||
func flattenParentImage(ctx context.Context, rbdVol *rbdVolume, cr *util.Credentials) error {
|
||||
// flattenParentImage is to be called before proceeding with creating volume,
|
||||
// with datasource. This function flattens the parent image accordingly to
|
||||
// make sure no flattening is required during or after the new volume creation.
|
||||
// For parent volume, it's parent(temp clone or snapshot) is flattened.
|
||||
// For parent snapshot, the snapshot itself is flattened.
|
||||
func flattenParentImage(
|
||||
ctx context.Context,
|
||||
rbdVol *rbdVolume,
|
||||
rbdSnap *rbdSnapshot,
|
||||
cr *util.Credentials) error {
|
||||
// flatten the image's parent before the reservation to avoid
|
||||
// stale entries in post creation if we return ABORT error and the
|
||||
// DeleteVolume RPC is not called.
|
||||
// reducing the limit for cloned images to make sure the limit is in range,
|
||||
// If the intermediate clone reaches the depth we may need to return ABORT
|
||||
// error message as it need to be flatten before continuing, this may leak
|
||||
// omap entries and stale temporary snapshots in corner cases, if we reduce
|
||||
// the limit and check for the depth of the parent image clain itself we
|
||||
// can flatten the parent images before used to avoid the stale omap entries.
|
||||
hardLimit := rbdHardMaxCloneDepth
|
||||
softLimit := rbdSoftMaxCloneDepth
|
||||
if rbdVol != nil {
|
||||
// flatten the image or its parent before the reservation to avoid
|
||||
// stale entries in post creation if we return ABORT error and the
|
||||
// delete volume is not called
|
||||
err := rbdVol.flattenCloneImage(ctx)
|
||||
// choosing 2, since cloning image creates a temp clone and a final clone which
|
||||
// will add a total depth of 2.
|
||||
const depthToAvoidFlatten = 2
|
||||
if rbdHardMaxCloneDepth > depthToAvoidFlatten {
|
||||
hardLimit = rbdHardMaxCloneDepth - depthToAvoidFlatten
|
||||
}
|
||||
if rbdSoftMaxCloneDepth > depthToAvoidFlatten {
|
||||
softLimit = rbdSoftMaxCloneDepth - depthToAvoidFlatten
|
||||
}
|
||||
err := rbdVol.flattenParent(ctx, hardLimit, softLimit)
|
||||
if err != nil {
|
||||
return getGRPCErrorForCreateVolume(err)
|
||||
}
|
||||
@ -335,6 +359,32 @@ func flattenParentImage(ctx context.Context, rbdVol *rbdVolume, cr *util.Credent
|
||||
return err
|
||||
}
|
||||
}
|
||||
if rbdSnap != nil {
|
||||
err := rbdSnap.Connect(cr)
|
||||
if err != nil {
|
||||
return getGRPCErrorForCreateVolume(err)
|
||||
}
|
||||
// in case of any error call Destroy for cleanup.
|
||||
defer func() {
|
||||
if err != nil {
|
||||
rbdSnap.Destroy()
|
||||
}
|
||||
}()
|
||||
|
||||
// choosing 1, since restore from snapshot adds one depth.
|
||||
const depthToAvoidFlatten = 1
|
||||
if rbdHardMaxCloneDepth > depthToAvoidFlatten {
|
||||
hardLimit = rbdHardMaxCloneDepth - depthToAvoidFlatten
|
||||
}
|
||||
if rbdSoftMaxCloneDepth > depthToAvoidFlatten {
|
||||
softLimit = rbdSoftMaxCloneDepth - depthToAvoidFlatten
|
||||
}
|
||||
|
||||
err = rbdSnap.flattenRbdImage(ctx, false, hardLimit, softLimit)
|
||||
if err != nil {
|
||||
return getGRPCErrorForCreateVolume(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -574,10 +624,8 @@ func (cs *ControllerServer) createBackingImage(
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if !errors.Is(err, ErrFlattenInProgress) {
|
||||
if deleteErr := rbdVol.deleteImage(ctx); deleteErr != nil {
|
||||
log.ErrorLog(ctx, "failed to delete rbd image: %s with error: %v", rbdVol, deleteErr)
|
||||
}
|
||||
if deleteErr := rbdVol.deleteImage(ctx); deleteErr != nil {
|
||||
log.ErrorLog(ctx, "failed to delete rbd image: %s with error: %v", rbdVol, deleteErr)
|
||||
}
|
||||
}
|
||||
}()
|
||||
@ -586,15 +634,6 @@ func (cs *ControllerServer) createBackingImage(
|
||||
return status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
if rbdSnap != nil {
|
||||
err = rbdVol.flattenRbdImage(ctx, false, rbdHardMaxCloneDepth, rbdSoftMaxCloneDepth)
|
||||
if err != nil {
|
||||
log.ErrorLog(ctx, "failed to flatten image %s: %v", rbdVol, err)
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user