Fixes race condition when epoll_ctl() gets called after the socket has
been closed, which may affect a different socket created by another
thread meanwhile.
When rpc_reconnect_requeue() gets called from inside nfs_service(),
the NfsInputStream can stall completely because the old socket has
been unregistered from epoll automatically, but the new one has never
been registered. Therefore, nfs_service() will never be called again.
This kludge attempts to detect this condition by checking
nfs_which_events()==POLLOUT.
https://bugs.musicpd.org/view.php?id=4081
When mounting had not yet finished, SocketMonitor::IsDefined() was
always false, due to the workaround at the beginning of the function
that calls SocketMonitor::Steal(). This commit drops the IsDefined()
check because it was never necessary and breaks reconnect.
nfs_destroy_context() will invoke all pending callbacks with
err==-EINTR. In CancellableCallback::Callback(), this will invoke
NfsConnection::DeferClose(), which however is only designed to be
called from nfs_service(). In non-debug mode, this will leak memory
because nfs_close_async() is never called.
Workaround: before nfs_destroy_context(), invoke nfs_close_async() on
all pending file handles.
The method NfsConnection::CancellableCallback::Callback() will always
invoke NfsConnection::Close() on the file handle, even if the void
pointer is not a nfsfh. This can happen if the Open() was not
successful, e.g. when the file does not exist.
Clean up the "state" to indicate that there is no longer any
asynchronous operation. Fixes another NFS-related crash due to
cleanup of a non-existing asynchronous operation.
During the NfsLease::OnNfsConnectionFailed() call, the old (defunct)
nfs_context may be used to close file handles. Such code does not yet
exist, but will be added soon to fix other bugs.
Creating a NfsStorage sets its own export_name as the "base". Now
NfsFileReader can use this information to derive the export_name to be
mounted, instead of guessing. This solves the "too many connection"
problem on the NFS server while updating the database.
If an async opertion is in progress, nfs_close_async() will make
libnfs crash because the RPC callback will dereference an object that
was freed by nfs_close_async().