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
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <nfsc/libnfs.h>
|
#include <nfsc/libnfs.h>
|
||||||
|
#include <nfsc/libnfs-raw-nfs4.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -20,6 +21,8 @@ extern "C" {
|
|||||||
#include <poll.h> /* for POLLIN, POLLOUT */
|
#include <poll.h> /* for POLLIN, POLLOUT */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <string.h> // for strstr()
|
||||||
|
|
||||||
static constexpr Event::Duration NFS_MOUNT_TIMEOUT =
|
static constexpr Event::Duration NFS_MOUNT_TIMEOUT =
|
||||||
std::chrono::minutes(1);
|
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
|
inline void
|
||||||
NfsConnection::CancellableCallback::Callback(int err, void *data) noexcept
|
NfsConnection::CancellableCallback::Callback(int err, void *data) noexcept
|
||||||
{
|
{
|
||||||
assert(connection.GetEventLoop().IsInside());
|
assert(connection.GetEventLoop().IsInside());
|
||||||
|
|
||||||
|
auto &_connection = connection;
|
||||||
|
const bool is_fatal = IsFatalNfsConnectionError(err, (const char *)data);
|
||||||
|
|
||||||
if (!IsCancelled()) {
|
if (!IsCancelled()) {
|
||||||
assert(close_fh == nullptr);
|
assert(close_fh == nullptr);
|
||||||
|
|
||||||
@@ -162,6 +181,11 @@ NfsConnection::CancellableCallback::Callback(int err, void *data) noexcept
|
|||||||
|
|
||||||
connection.callbacks.Remove(*this);
|
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
|
void
|
||||||
|
Reference in New Issue
Block a user