From ba1b8533a57dc2ff1d5e3822aa575d15e7e35dcf Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 13 May 2024 16:39:46 +0200 Subject: [PATCH] lib/nfs/Connection: fix assertion failure on mount timeout When nfs_destroy_context() is called while nfs_mount_async() is in progress, libnfs invokes MountCallback(-EINTR) (but only if a NFS RPC call is in progress; if the TCP connect is in progress, that callback is not invoked). If the mount operation had timed out, OnMountTimeout() set mount_state=FINISHED, which triggered an assertion failure in MountCallback(); this commit adds a check on whether the mount has timed out and ignores the MountCallback. --- src/lib/nfs/Connection.cxx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/lib/nfs/Connection.cxx b/src/lib/nfs/Connection.cxx index c07b545cb..db23ec1fb 100644 --- a/src/lib/nfs/Connection.cxx +++ b/src/lib/nfs/Connection.cxx @@ -195,6 +195,12 @@ NfsConnection::~NfsConnection() noexcept assert(context != nullptr); socket_event.ReleaseSocket(); + + /* cancel the timer before calling nfs_destroy_context() so + MountCallback() knows the mount call is being canceled; + checking status==-EINTR would be ambiguous */ + mount_timeout_event.Cancel(); + nfs_destroy_context(context); } @@ -533,6 +539,15 @@ NfsConnection::MountCallback(int status, [[maybe_unused]] nfs_context *nfs, { assert(GetEventLoop().IsInside()); assert(context == nfs); + + if (!mount_timeout_event.IsPending()) { + /* called by nfs_destroy_context() while destructing + this NfsConnection instance */ + assert(status == -EINTR); + assert(mount_state == MountState::FINISHED); + return; + } + assert(mount_state == MountState::WAITING); mount_state = MountState::FINISHED;