Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rbd: prevent calling rbdVolume.Destroy() after an error #4564

Open
wants to merge 1 commit into
base: devel
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion internal/rbd/nodeserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,6 @@ func (ns *NodeServer) populateRbdVol(
} else {
rv, err = GenVolFromVolID(ctx, volID, cr, req.GetSecrets())
if err != nil {
rv.Destroy()
log.ErrorLog(ctx, "error generating volume %s: %v", volID, err)

return nil, status.Errorf(codes.Internal, "error generating volume %s: %v", volID, err)
Expand Down
35 changes: 28 additions & 7 deletions internal/rbd/rbd_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,8 @@ func updateSnapshotDetails(rbdSnap *rbdSnapshot) error {
}

// generateVolumeFromVolumeID generates a rbdVolume structure from the provided identifier.
// The returned rbdVolume is connected in case no error occurred, and should be
// cleaned up with rbdVolume.Destroy().
func generateVolumeFromVolumeID(
ctx context.Context,
volumeID string,
Expand Down Expand Up @@ -1116,6 +1118,13 @@ func generateVolumeFromVolumeID(
if err != nil {
return rbdVol, err
}
// in case of any error call Destroy for cleanup.
defer func() {
if err != nil {
rbdVol.Destroy()
}
}()

rbdVol.JournalPool = rbdVol.Pool

imageAttributes, err := j.GetImageAttributes(
Expand Down Expand Up @@ -1163,6 +1172,8 @@ func generateVolumeFromVolumeID(

// GenVolFromVolID generates a rbdVolume structure from the provided identifier, updating
// the structure with elements from on-disk image metadata as well.
// The returned rbdVolume is connected in case no error occurred, and should be
// cleaned up with rbdVolume.Destroy().
func GenVolFromVolID(
ctx context.Context,
volumeID string,
Expand All @@ -1185,17 +1196,27 @@ func GenVolFromVolID(
!errors.Is(err, ErrImageNotFound) {
return vol, err
}
defer func() {
if err != nil {
vol.Destroy()
}
}()
Comment on lines +1199 to +1203
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in case of err the volume is already destroyed above, do we need to destroy it again? if yes , can you please add check check for vol !=nil

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generateVolumeFromVolumeID() should now only return a connected volume if no error occurred. But it is possible that this function itself detects an error below. In that case, the .Destroy() function should be called too.

Destroying a volume that is already destroyed is fine, extra checks for that just make the code more complex.


// Check clusterID mapping exists
mapping, mErr := util.GetClusterMappingInfo(vi.ClusterID)
if mErr != nil {
return vol, mErr
mapping, err := util.GetClusterMappingInfo(vi.ClusterID)
if err != nil {
return vol, err
}
if mapping != nil {
rbdVol, vErr := generateVolumeFromMapping(ctx, mapping, volumeID, vi, cr, secrets)
if !errors.Is(vErr, util.ErrKeyNotFound) && !errors.Is(vErr, util.ErrPoolNotFound) &&
!errors.Is(vErr, ErrImageNotFound) {
return rbdVol, vErr
// create a new volume based on the mapping, cleanup the old volume
if vol != nil {
vol.Destroy()
}
Comment on lines +1212 to +1214
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when will we hit this one? In case of error we are already doing the Destory and in case of non-nil error case the vol is returned at line 1197

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not clear to me if this can be hit, better destroy something that could have been at line 1194.

If the vol was connected, and generateVolumeFromMapping() overwrites that variable, the 1st vol would leak and no .Destroy() would be done on it.


vol, err = generateVolumeFromMapping(ctx, mapping, volumeID, vi, cr, secrets)
if !errors.Is(err, util.ErrKeyNotFound) && !errors.Is(err, util.ErrPoolNotFound) &&
!errors.Is(err, ErrImageNotFound) {
return vol, err
}
}

Expand Down