Skip to content

cephfs: MDCache request cleanup #62630

Merged
vshankar merged 2 commits intoceph:mainfrom
theanalyst:batch-getattr-fixes
Nov 17, 2025
Merged

cephfs: MDCache request cleanup #62630
vshankar merged 2 commits intoceph:mainfrom
theanalyst:batch-getattr-fixes

Conversation

@theanalyst
Copy link
Member

@theanalyst theanalyst commented Apr 2, 2025

When BatchGetAttr finds no new head, we end up passing a potential null request object to Finisher which crashes later. Handle this
Fixes: https://tracker.ceph.com/issues/70769

Contribution Guidelines

  • To sign and title your commits, please refer to Submitting Patches to Ceph.

  • If you are submitting a fix for a stable branch (e.g. "quincy"), please refer to Submitting Patches to Ceph - Backports for the proper workflow.

  • When filling out the below checklist, you may click boxes directly in the GitHub web UI. When entering or editing the entire PR message in the GitHub web UI editor, you may also select a checklist item by adding an x between the brackets: [x]. Spaces and capitalization matter when checking off items this way.

Checklist

  • Tracker (select at least one)
    • References tracker ticket
    • Very recent bug; references commit where it was introduced
    • New feature (ticket optional)
    • Doc update (no ticket needed)
    • Code cleanup (no ticket needed)
  • Component impact
    • Affects Dashboard, opened tracker ticket
    • Affects Orchestrator, opened tracker ticket
    • No impact that needs to be tracked
  • Documentation (select at least one)
    • Updates relevant documentation
    • No doc update is appropriate
  • Tests (select at least one)
Show available Jenkins commands

In cases where there is a single element in a batch_op_map,new_batch_head
is a nullptr, when this is retried at Finisher we'd hit one of the asserts when
dereferencing

Fixes: https://tracker.ceph.com/issues/70769
Signed-off-by: Abhishek Lekshmanan <abhishek.lekshmanan@cern.ch>
Ignore null requests

Signed-off-by: Abhishek Lekshmanan <abhishek.lekshmanan@cern.ch>
@github-actions github-actions bot added the cephfs Ceph File System label Apr 2, 2025
@theanalyst
Copy link
Member Author

The main fix is the first commit; the second commit adds a couple of null checks, though this may prevent hiding actual issues so happy to drop it.

@vshankar
Copy link
Contributor

vshankar commented Apr 7, 2025

@mchangir PTAL

@mchangir
Copy link
Contributor

mchangir commented Apr 8, 2025

@theanalyst the crash is most probably this issue #62684

@theanalyst
Copy link
Member Author

@theanalyst the crash is most probably this issue #62684
@mchangir
That explains the locking issue, however if you see what happens when we find a new batch head currently:

    auto new_batch_head = it->second->find_new_head();
    if (!new_batch_head) {
      mdr->batch_op_map->erase(it);
    } 
    mds->finisher->queue(new C_MDS_RetryRequest(this, new_batch_head));
  }

if the new_batch_head is not found it defaults to null, and this is passed to Finisher. We see this happening quite a lot if you launch requests with find etc on a large tree where a single inode might have only a single batch request and then you pass nullptr to Finisher which crashes. So I believe passing a non null new_batch_head is needed. What do you think?

@mchangir
Copy link
Contributor

mchangir commented Apr 9, 2025

@theanalyst the crash is most probably this issue #62684
@mchangir
That explains the locking issue, however if you see what happens when we find a new batch head currently:

    auto new_batch_head = it->second->find_new_head();
    if (!new_batch_head) {
      mdr->batch_op_map->erase(it);
    } 
    mds->finisher->queue(new C_MDS_RetryRequest(this, new_batch_head));
  }

if the new_batch_head is not found it defaults to null, and this is passed to Finisher. We see this happening quite a lot if you launch requests with find etc on a large tree where a single inode might have only a single batch request and then you pass nullptr to Finisher which crashes. So I believe passing a non null new_batch_head is needed. What do you think?

@theanalyst would you be able to form a set of bash commands that mimic your workload ?
I'd like to run them and see the crash myself.

@dvanders
Copy link
Contributor

I've just seen this in the wild on a single active v18.2.7 fs. I don't have any more detail about the use-case that triggered it.

@vshankar vshankar self-assigned this Jul 8, 2025
@vshankar
Copy link
Contributor

@mchangir I believe @theanalyst shared the reproducer elsewhere (via mail?). Could you please update the tracker with those details please. I will plan to have a look then.

@sajibreadd
Copy link
Member

sajibreadd commented Jul 29, 2025

From the codeflow, what I can understand, when a session gets evicted it tries to clear the requests,

while (!session->requests.empty()) {
    auto mdr = MDRequestRef(*session->requests.begin());
    mdcache->request_kill(mdr);
  }

This void MDCache::request_kill(MDRequestRef &mdr) function in turns is doing the request_cleanup

While following the comment,

void MDCache::request_kill(MDRequestRef &mdr) {
 // rollback peer requests is tricky. just let the request proceed.

mds wants to just proceed the request marking it as a killed request. But when it comes to batch_head request, either it should replaced by new batch head(which is not killed) request completely in the request_cleanup and let it proceed or we should remove this assert as we are allowing the killed batch head to proceed. So the comment, // Should already be reset in request_cleanup(). doesn't justify.

void Server::dispatch_client_request(MDRequestRef &mdr) {
 // we shouldn't be waiting on anyone.
 ceph_assert(!mdr->has_more() || mdr->more()->waiting_on_peer.empty());

 if (mdr->killed) {
   // Should already be reset in request_cleanup().
   ceph_assert(!mdr->is_batch_head());

@vshankar
Copy link
Contributor

@mchangir gentle nudge on this.

Comment on lines +10093 to +10094
} else {
mds->finisher->queue(new C_MDS_RetryRequest(this, new_batch_head));
Copy link
Contributor

Choose a reason for hiding this comment

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

this looks sensible to me ... wrapping the re-queuing in an else block probably got missed earlier

Copy link
Member Author

Choose a reason for hiding this comment

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

For most of the crashes we see in the Finisher, this seems like the most logical place. I also tried adding print statements and I can see that we indeed queue up a null new_batch_head when the request gets killed and the inode doesn't have a new_batch_head. Finally we crash in finish where we try to access this nullptr

@github-actions
Copy link

This pull request has been automatically marked as stale because it has not had any activity for 60 days. It will be closed if no further activity occurs for another 30 days.
If you are a maintainer or core committer, please follow-up on this pull request to identify what steps should be taken by the author to move this proposed change forward.
If you are the author of this pull request, thank you for your proposed contribution. If you believe this change is still appropriate, please ensure that any feedback has been addressed and ask for a code review.

@github-actions github-actions bot added the stale label Oct 18, 2025
@vshankar vshankar removed the stale label Oct 18, 2025
@vshankar
Copy link
Contributor

(unmarking stale)

I haven't been following the discussion here closely. @mchangir - Is this good to go? What about @sajibreadd comment #62630 (comment) ?

@vshankar
Copy link
Contributor

vshankar commented Nov 2, 2025

This PR is under test in https://tracker.ceph.com/issues/73693.

Copy link
Contributor

@vshankar vshankar left a comment

Choose a reason for hiding this comment

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

@vshankar vshankar merged commit b5ebfaf into ceph:main Nov 17, 2025
12 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants