Skip to content

rbd: replace O(n) trash list scan with O(1) ID-based trash removal - #6472

Merged
mergify[bot] merged 4 commits into
ceph:develfrom
Rakshith-R:trash-cleanup-by-id
Aug 18, 2026
Merged

rbd: replace O(n) trash list scan with O(1) ID-based trash removal#6472
mergify[bot] merged 4 commits into
ceph:develfrom
Rakshith-R:trash-cleanup-by-id

Conversation

@Rakshith-R

Copy link
Copy Markdown
Contributor

Describe what this PR does

Replace ensureImageCleanup() - which scans the entire RBD trash list
to find an image by name - with direct O(1) removal by image ID using
the new removeImageFromTrash() helper.

The image ID is always available: modern volumes store it in OMAP at
creation time, and legacy volumes get it backfilled by storeImageID()
during the first generateVolumeFromVolumeID() call.

Commit 1 - rbd: capture parent image ID in getImageInfo

Add ParentImageID field to rbdImage and populate it in
getImageInfo() from GetParent().Image.ImageID. Valid even when the
parent is in trash.

Commit 2 - rbd: make trash remove idempotent and add removeImageFromTrash

Add removeImageFromTrash() as an O(1) helper that removes a trashed
image by its known ID. Make trashRemoveImage() treat ENOENT as success
on both the ceph mgr and direct paths (image already purged).

Commit 3 - rbd: avoid trash ls in DeleteVolume/DeleteSnapshot retry paths

In checkErrAndUndoReserve() and cleanUpImageAndSnapReservation(),
switch from ensureImageCleanup() to removeImageFromTrash(). Also fix
a pre-existing ErrorLog format string mismatch (2 format verbs, 3 args).

Commit 4 - rbd: remove ensureImageCleanup and use ID-based trash removal

In DeleteTempImage(), use the volume's ParentImageID to identify a
trashed temp clone instead of scanning the trash list. Remove
ensureImageCleanup() entirely - no callers remain.

Is there anything that requires special attention

  • DeleteTempImage() relies on being called before rbdVol.Delete() so
    that GetParent() data is still valid. This ordering already exists in
    cleanupRBDImage() and is now documented with a comment.
  • When parent info is unavailable in DeleteTempImage() (temp clone not
    in trash), it returns success - same behavior as the old code when the
    trash scan found nothing.

The change is backward compatible. No API or OMAP schema changes.

Future concerns

  • GetTrashList is still used in waitForCleanTrash() (e2e test helper).
    That is unrelated to production code paths.

Checklist:

  • Commit Message Formatting: Commit titles and messages follow
    guidelines in the developer
    guide
    .
  • Reviewed the developer guide on Submitting a Pull
    Request
  • Pending release
    notes

    updated with breaking and/or notable changes for the next major release.
    N/A - internal optimization, no user-facing changes.
  • Documentation has been updated, if necessary.
    N/A - no doc changes needed, internal refactor only.
  • Unit tests have been added, if necessary.
    N/A - functions require a live Ceph cluster (librbd calls), not unit-testable.
    Existing e2e delete/snapshot tests exercise these code paths.
  • Integration tests have been added, if necessary.
    N/A - existing e2e tests for DeleteVolume, DeleteSnapshot, and volume
    cloning already cover the trash cleanup paths exercised by this change.

Show available bot commands

These commands are normally not required, but in case of issues, leave any of
the following bot commands in an otherwise empty comment in this PR:

  • /retest ci/centos/<job-name>: retest the <job-name> after unrelated
    failure (please report the failure too!)

@Rakshith-R
Rakshith-R requested review from a team as code owners August 14, 2026 10:01
Copilot AI lite review requested due to automatic review settings August 14, 2026 10:01
@Rakshith-R

Copy link
Copy Markdown
Contributor Author

/test ci/centos/mini-e2e-operator/k8s-1.36

@mergify mergify Bot added the component/rbd Issues related to RBD label Aug 14, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors RBD deletion/trash-cleanup paths to avoid O(n) trash-list scans by switching to ID-based trash removal, and propagates parent image IDs to enable faster cleanup of temporary clone images during volume clone workflows.

Changes:

  • Add ParentImageID to rbdImage and populate it via getImageInfo() to enable identifying trashed parents by ID.
  • Make trash removal idempotent on ENOENT and introduce removeImageFromTrash() as a helper for ID-based trash purge.
  • Update delete retry/cleanup paths (DeleteVolume/DeleteSnapshot and temp-clone cleanup) to use ID-based trash removal and fix a logging format mismatch.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
internal/rbd/rbd_util.go Adds ParentImageID, introduces removeImageFromTrash(), updates DeleteTempImage() to remove temp clones from trash by ID, and makes trash removal idempotent.
internal/rbd/controllerserver.go Switches retry/cleanup paths to removeImageFromTrash() and updates a log line to fix formatting.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread internal/rbd/rbd_util.go
Comment thread internal/rbd/rbd_util.go
@YiteGu

YiteGu commented Aug 14, 2026

Copy link
Copy Markdown
Member

@Rakshith-R I've been thinking about how to solve this problem lately. This PR is very very nice.

@Rakshith-R
Rakshith-R force-pushed the trash-cleanup-by-id branch from 6c6efd6 to e0e1fe0 Compare August 14, 2026 10:35

@nixpanic nixpanic left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks!

@nixpanic

Copy link
Copy Markdown
Member

/queue

@ceph-csi-bot

Copy link
Copy Markdown
Collaborator

@Mergifyio rebase

@mergify

mergify Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

rebase

🛑 The pull request rule doesn't match anymore

Details

This action has been cancelled.

Store the parent image's ID (from GetParent().Image.ImageID) in a new
ParentImageID field on rbdImage. This ID is valid even when the parent
is in trash, enabling O(1) trash removal without scanning the entire
trash list.

Reset ParentImageID to empty when GetParent returns ErrNotFound (no
parent or parent link severed by flatten).

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: Rakshith R <rar@redhat.com>
Make trashRemoveImage() treat ENOENT as success on both the ceph mgr
(AddTrashRemove) and direct (TrashRemove) paths - the image was already
purged from trash. The mgr path checks rados.ErrNotFound before
isCephMgrSupported to avoid misclassifying ENOENT as a mgr failure.

Add removeImageFromTrash() as an O(1) helper that removes a trashed
image by its known ID.

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: Rakshith R <rar@redhat.com>
In checkErrAndUndoReserve() and cleanUpImageAndSnapReservation(), use
removeImageFromTrash() to remove the trashed image directly by its
known ID from the OMAP journal instead of scanning the entire trash
list with ensureImageCleanup().

The image ID is always available in OMAP: modern volumes store it at
creation time, and legacy volumes get it backfilled by storeImageID()
during the first (successful) generateVolumeFromVolumeID() call while
the image is still alive.

Also fix pre-existing ErrorLog format string mismatch in
cleanUpImageAndSnapReservation (2 format verbs but 3 arguments).

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: Rakshith R <rar@redhat.com>
In DeleteTempImage(), use the volume's parent info (ParentImageID) to
identify a trashed temp clone by ID instead of scanning the trash list.
This works because cleanupRBDImage() calls DeleteTempImage() before
rbdVol.Delete(), so the child image still exists and GetParent() data
is valid.

When parent info is unavailable (temp clone not in trash), treat it as
already removed and return success.

Remove ensureImageCleanup() entirely - the O(n) GetTrashList scan is no
longer needed. All volume/snapshot image IDs are stored in OMAP at
creation time and backfilled by storeImageID() on first access, so
ImageID is always available for direct O(1) trash removal.

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: Rakshith R <rar@redhat.com>
@ceph-csi-bot ceph-csi-bot added ok-to-test Label to trigger E2E tests and removed queued/rebase labels Aug 17, 2026
@ceph-csi-bot

Copy link
Copy Markdown
Collaborator

/test ci/centos/k8s-e2e-external-storage/1.34

@ceph-csi-bot

Copy link
Copy Markdown
Collaborator

/test ci/centos/upgrade-tests-cephfs

@ceph-csi-bot

Copy link
Copy Markdown
Collaborator

/test ci/centos/k8s-e2e-external-storage/1.36

@ceph-csi-bot

Copy link
Copy Markdown
Collaborator

/test ci/centos/mini-e2e-helm/k8s-1.34

@ceph-csi-bot

Copy link
Copy Markdown
Collaborator

/test ci/centos/k8s-e2e-external-storage/1.35

@ceph-csi-bot

Copy link
Copy Markdown
Collaborator

/test ci/centos/upgrade-tests-rbd

@ceph-csi-bot

Copy link
Copy Markdown
Collaborator

/test ci/centos/mini-e2e-helm/k8s-1.36

@ceph-csi-bot

Copy link
Copy Markdown
Collaborator

/test ci/centos/mini-e2e/k8s-1.34

@ceph-csi-bot

Copy link
Copy Markdown
Collaborator

/test ci/centos/mini-e2e-helm/k8s-1.35

@ceph-csi-bot

Copy link
Copy Markdown
Collaborator

/test ci/centos/mini-e2e/k8s-1.35

@ceph-csi-bot

Copy link
Copy Markdown
Collaborator

/test ci/centos/mini-e2e/k8s-1.36

@ceph-csi-bot ceph-csi-bot added ci/in-progress/e2e This label acts like a guard and prevents Mergify from adding the `ok-to-test` label again. and removed ok-to-test Label to trigger E2E tests labels Aug 17, 2026
@mergify mergify Bot removed the ci/in-progress/e2e This label acts like a guard and prevents Mergify from adding the `ok-to-test` label again. label Aug 17, 2026
Comment thread internal/rbd/rbd_util.go
if vol.ParentName != "" {
depth++
}
vol.RbdImageName = vol.ParentName

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Now that we have ParentImageID, we need to add an assignment here.
vol.ImageID = vol.ParentImageID

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Now that we have ParentImageID, we need to add an assignment here. vol.ImageID = vol.ParentImageID

it's not used.

Comment thread internal/rbd/rbd_util.go
return nil, err
}

image, err := librbd.OpenImage(ri.ioctx, ri.RbdImageName, librbd.NoSnapshot)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If the imageID comes from the parentImageID, and the parentImage is in the trash, we should use librbd.OpenImageById(ri.ioctx, ri.ImageID, librbd.NoSnapshot).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If the imageID comes from the parentImageID, and the parentImage is in the trash, we should use librbd.OpenImageById(ri.ioctx, ri.ImageID, librbd.NoSnapshot).

There's no use case right now. We can add it when it is required.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

One scenario I'm considering is that when obtaining clone depth, the presence of the parent image in the trash might cause inaccurate clone depth calculations.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

	if err != nil {
		// if the parent image is moved to trash the name will be present
		// in rbd image info but the image will be in trash, in that case
		// return the found depth
		if errors.Is(err, rbderrors.ErrImageNotFound) {
			return depth, nil
		}

There's a comment in code regarding this.
Including trashed image in clonedepth calculation will lead to other complexities since trashed image cannot be flattened. Selective flattening logic in cephcsi is already complex. I would prefer it stay as is until there's a issue found relating to the scenario.

@iPraveenParihar

Copy link
Copy Markdown
Contributor

/retest ci/centos/mini-e2e-helm/k8s-1.36

@mergify

mergify Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Deprecation notice: This pull request comes from a fork and was queued with update_method=rebase and update_bot_account impersonation. This capability will be removed on July 1, 2026. After this date, the merge queue will no longer be able to rebase fork pull requests with this configuration. To avoid disruption, switch to update_method=merge in your queue rule.

@mergify

mergify Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • Entered queue2026-08-18 06:51 UTC · Rule: default · triggered by merge protections
  • Checks skipped · PR is already up-to-date
  • Merged2026-08-18 06:52 UTC · at 0cf959b9f1bcd3b0548f66dbaacd6775ee1f6bb7 · rebase

This pull request spent 48 seconds in the queue, including 6 seconds running CI.

Required conditions to merge

@mergify
mergify Bot merged commit 0c9084c into ceph:devel Aug 18, 2026
44 checks passed
@nixpanic nixpanic added the backport-to-release-v3.17 Label to backport from devel to release-v3.17 branch label Aug 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-to-release-v3.17 Label to backport from devel to release-v3.17 branch component/rbd Issues related to RBD

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants