summaryrefslogtreecommitdiff
path: root/src/lib/nfs
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2017-02-01 22:05:33 +0100
committerMax Kellermann <max@musicpd.org>2017-02-01 22:05:33 +0100
commitdf4af2b5501f332db248aedd792c2b55789823c5 (patch)
treee53a63614964da8dd8ddb699e68854ccd95a91f3 /src/lib/nfs
parent97132e3d385ae84f7aaeb6c94f24d2cf41d39b9c (diff)
parent0a033fb10aeca8bf6e6bfc9a2f9d9e793ee61ac9 (diff)
Merge tag 'v0.20.4'
release v0.20.4
Diffstat (limited to 'src/lib/nfs')
-rw-r--r--src/lib/nfs/Connection.cxx20
1 files changed, 18 insertions, 2 deletions
diff --git a/src/lib/nfs/Connection.cxx b/src/lib/nfs/Connection.cxx
index 16f6c001d..b417f2fab 100644
--- a/src/lib/nfs/Connection.cxx
+++ b/src/lib/nfs/Connection.cxx
@@ -396,6 +396,17 @@ NfsConnection::ScheduleSocket()
assert(GetEventLoop().IsInside());
assert(context != nullptr);
+ const int which_events = nfs_which_events(context);
+
+ if (which_events == POLLOUT && SocketMonitor::IsDefined())
+ /* kludge: if libnfs asks only for POLLOUT, it means
+ that it is currently waiting for the connect() to
+ finish - rpc_reconnect_requeue() may have been
+ called from inside nfs_service(); we must now
+ unregister the old socket and register the new one
+ instead */
+ SocketMonitor::Steal();
+
if (!SocketMonitor::IsDefined()) {
int _fd = nfs_get_fd(context);
if (_fd < 0)
@@ -405,7 +416,8 @@ NfsConnection::ScheduleSocket()
SocketMonitor::Open(_fd);
}
- SocketMonitor::Schedule(libnfs_to_events(nfs_which_events(context)));
+ SocketMonitor::Schedule(libnfs_to_events(which_events)
+ | SocketMonitor::HANGUP);
}
inline int
@@ -442,10 +454,14 @@ NfsConnection::OnSocketReady(unsigned flags)
bool closed = false;
const bool was_mounted = mount_finished;
- if (!mount_finished)
+ if (!mount_finished || (flags & SocketMonitor::HANGUP) != 0)
/* until the mount is finished, the NFS client may use
various sockets, therefore we unregister and
re-register it each time */
+ /* also re-register the socket if we got a HANGUP,
+ which is a sure sign that libnfs will close the
+ socket, which can lead to a race condition if
+ epoll_ctl() is called later */
SocketMonitor::Steal();
const int result = Service(flags);