From 275cd9d1d06ffa45d4f1f04f7ab6e0d4fa80fa1a Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 30 Jan 2025 17:02:44 +0100 Subject: [PATCH] lib/nfs/Connection: give up connection after NFS4ERR_EXPIRED Once a NFS request fails with NFS4ERR_EXPIRED, the whole connection is broken and we need to open a new one. I wish libnfs would report this to us as a connection-level error, but instead only the one request fails; therefore this workaround is an ugly kludge. Closes https://github.com/MusicPlayerDaemon/MPD/issues/2175 --- src/lib/nfs/Connection.cxx | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/lib/nfs/Connection.cxx b/src/lib/nfs/Connection.cxx index 1901d43f2..40bd2a407 100644 --- a/src/lib/nfs/Connection.cxx +++ b/src/lib/nfs/Connection.cxx @@ -10,6 +10,7 @@ extern "C" { #include +#include } #include @@ -20,6 +21,8 @@ extern "C" { #include /* for POLLIN, POLLOUT */ #endif +#include // for strstr() + static constexpr Event::Duration NFS_MOUNT_TIMEOUT = std::chrono::minutes(1); @@ -130,11 +133,27 @@ NfsConnection::CancellableCallback::PrepareDestroyContext() noexcept } } +/** + * Determine whether this is a fatal error and we need to close the + * connection and reopen a new one. + */ +static constexpr bool +IsFatalNfsConnectionError(int err, const char *msg) noexcept +{ + /* nfsstat3_to_errno() translates NFS4ERR_EXPIRED to ERANGE, + so unfortunately we need to search the error message */ + return err == -ERANGE && msg != nullptr && + strstr(msg, "NFS4ERR_EXPIRED") != nullptr; +} + inline void NfsConnection::CancellableCallback::Callback(int err, void *data) noexcept { assert(connection.GetEventLoop().IsInside()); + auto &_connection = connection; + const bool is_fatal = IsFatalNfsConnectionError(err, (const char *)data); + if (!IsCancelled()) { assert(close_fh == nullptr); @@ -162,6 +181,11 @@ NfsConnection::CancellableCallback::Callback(int err, void *data) noexcept connection.callbacks.Remove(*this); } + + if (is_fatal) + /* this was a fatal connection error; we need to teat + down the NFS connection */ + _connection.BroadcastError(std::make_exception_ptr(NfsClientError(-err, (const char *)data))); } void