diff options
author | Max Kellermann <max@duempel.org> | 2014-09-26 13:29:44 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2014-10-01 23:10:32 +0200 |
commit | 0661fd6f7c66ae888b6fc253af6dd0514798eff5 (patch) | |
tree | 9cc213a9d3be7709f937df4cfb40255d74146338 /src/lib/nfs/Connection.hxx | |
parent | edd003b62af802fae7828336628adb0ea3f6bd21 (diff) | |
download | mpd-0661fd6f7c66ae888b6fc253af6dd0514798eff5.tar.gz mpd-0661fd6f7c66ae888b6fc253af6dd0514798eff5.tar.xz mpd-0661fd6f7c66ae888b6fc253af6dd0514798eff5.zip |
lib/nfs/FileReader: postpone the nfs_close_async() call
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().
Diffstat (limited to 'src/lib/nfs/Connection.hxx')
-rw-r--r-- | src/lib/nfs/Connection.hxx | 33 |
1 files changed, 32 insertions, 1 deletions
diff --git a/src/lib/nfs/Connection.hxx b/src/lib/nfs/Connection.hxx index 880b7d467..b3db37c5d 100644 --- a/src/lib/nfs/Connection.hxx +++ b/src/lib/nfs/Connection.hxx @@ -26,8 +26,11 @@ #include "event/DeferredMonitor.hxx" #include "util/Error.hxx" +#include <boost/intrusive/list.hpp> + #include <string> #include <list> +#include <forward_list> struct nfs_context; class NfsCallback; @@ -47,13 +50,19 @@ class NfsConnection : SocketMonitor, DeferredMonitor { */ const bool open; + /** + * The file handle scheduled to be closed as soon as + * the operation finishes. + */ + struct nfsfh *close_fh; + public: explicit CancellableCallback(NfsCallback &_callback, NfsConnection &_connection, bool _open) :CancellablePointer<NfsCallback>(_callback), connection(_connection), - open(_open) {} + open(_open), close_fh(nullptr) {} bool Open(nfs_context *context, const char *path, int flags, Error &error); @@ -63,6 +72,12 @@ class NfsConnection : SocketMonitor, DeferredMonitor { uint64_t offset, size_t size, Error &error); + /** + * Cancel the operation and schedule a call to + * nfs_close_async() with the given file handle. + */ + void CancelAndScheduleClose(struct nfsfh *fh); + private: static void Callback(int err, struct nfs_context *nfs, void *data, void *private_data); @@ -79,6 +94,15 @@ class NfsConnection : SocketMonitor, DeferredMonitor { typedef CancellableList<NfsCallback, CancellableCallback> CallbackList; CallbackList callbacks; + /** + * A list of NFS file handles (struct nfsfh *) which shall be + * closed as soon as nfs_service() returns. If we close the + * file handle while in nfs_service(), libnfs may crash, and + * deferring this call to after nfs_service() avoids this + * problem. + */ + std::forward_list<struct nfsfh *> deferred_close; + Error postponed_mount_error; /** @@ -135,6 +159,7 @@ public: void Cancel(NfsCallback &callback); void Close(struct nfsfh *fh); + void CancelAndClose(struct nfsfh *fh, NfsCallback &callback); protected: virtual void OnNfsConnectionError(Error &&error) = 0; @@ -145,6 +170,12 @@ private: } void DestroyContext(); + + /** + * Invoke nfs_close_async() after nfs_service() returns. + */ + void DeferClose(struct nfsfh *fh); + bool MountInternal(Error &error); void BroadcastMountSuccess(); void BroadcastMountError(Error &&error); |