From 0661fd6f7c66ae888b6fc253af6dd0514798eff5 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 26 Sep 2014 13:29:44 +0200 Subject: 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(). --- src/lib/nfs/Connection.hxx | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'src/lib/nfs/Connection.hxx') 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 + #include #include +#include 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(_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 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 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); -- cgit v1.2.3