aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS1
-rw-r--r--src/lib/nfs/Connection.cxx24
-rw-r--r--src/lib/nfs/Connection.hxx9
3 files changed, 32 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index d20dba397..c84f4b891 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,7 @@ ver 0.19.7 (not yet released)
- nfs: fix crash while canceling a failing file open operation
- nfs: fix memory leak on connection failure
- nfs: fix reconnect after mount failure
+ - nfs: implement mount timeout (60 seconds)
* playlist
- don't skip non-existent songs in "listplaylist"
* fix memory allocator bug on Windows
diff --git a/src/lib/nfs/Connection.cxx b/src/lib/nfs/Connection.cxx
index 4b6a6fc78..9d9cd8a52 100644
--- a/src/lib/nfs/Connection.cxx
+++ b/src/lib/nfs/Connection.cxx
@@ -34,6 +34,8 @@ extern "C" {
#include <poll.h> /* for POLLIN, POLLOUT */
+static constexpr unsigned NFS_MOUNT_TIMEOUT = 60;
+
inline bool
NfsConnection::CancellableCallback::Stat(nfs_context *ctx,
const char *path,
@@ -379,6 +381,11 @@ NfsConnection::DestroyContext()
in_destroy = true;
#endif
+ if (!mount_finished) {
+ assert(TimeoutMonitor::IsActive());
+ TimeoutMonitor::Cancel();
+ }
+
/* cancel pending DeferredMonitor that was scheduled to notify
new leases */
DeferredMonitor::Cancel();
@@ -528,6 +535,9 @@ NfsConnection::MountCallback(int status, gcc_unused nfs_context *nfs,
mount_finished = true;
+ assert(TimeoutMonitor::IsActive() || in_destroy);
+ TimeoutMonitor::Cancel();
+
if (status < 0) {
postponed_mount_error.Format(nfs_domain, status,
"nfs_mount_async() failed: %s",
@@ -560,6 +570,8 @@ NfsConnection::MountInternal(Error &error)
postponed_mount_error.Clear();
mount_finished = false;
+ TimeoutMonitor::ScheduleSeconds(NFS_MOUNT_TIMEOUT);
+
#ifndef NDEBUG
in_service = false;
in_event = false;
@@ -621,6 +633,18 @@ NfsConnection::BroadcastError(Error &&error)
}
void
+NfsConnection::OnTimeout()
+{
+ assert(GetEventLoop().IsInside());
+ assert(!mount_finished);
+
+ mount_finished = true;
+ DestroyContext();
+
+ BroadcastMountError(Error(nfs_domain, "Mount timeout"));
+}
+
+void
NfsConnection::RunDeferred()
{
assert(GetEventLoop().IsInside());
diff --git a/src/lib/nfs/Connection.hxx b/src/lib/nfs/Connection.hxx
index 310ccdc44..3969a7e8f 100644
--- a/src/lib/nfs/Connection.hxx
+++ b/src/lib/nfs/Connection.hxx
@@ -23,6 +23,7 @@
#include "Lease.hxx"
#include "Cancellable.hxx"
#include "event/SocketMonitor.hxx"
+#include "event/TimeoutMonitor.hxx"
#include "event/DeferredMonitor.hxx"
#include "util/Error.hxx"
@@ -40,7 +41,7 @@ class NfsCallback;
/**
* An asynchronous connection to a NFS server.
*/
-class NfsConnection : SocketMonitor, DeferredMonitor {
+class NfsConnection : SocketMonitor, TimeoutMonitor, DeferredMonitor {
class CancellableCallback : public CancellablePointer<NfsCallback> {
NfsConnection &connection;
@@ -142,7 +143,8 @@ public:
gcc_nonnull_all
NfsConnection(EventLoop &_loop,
const char *_server, const char *_export_name)
- :SocketMonitor(_loop), DeferredMonitor(_loop),
+ :SocketMonitor(_loop), TimeoutMonitor(_loop),
+ DeferredMonitor(_loop),
server(_server), export_name(_export_name),
context(nullptr) {}
@@ -227,6 +229,9 @@ private:
/* virtual methods from SocketMonitor */
virtual bool OnSocketReady(unsigned flags) override;
+ /* virtual methods from TimeoutMonitor */
+ void OnTimeout() final;
+
/* virtual methods from DeferredMonitor */
virtual void RunDeferred() override;
};