diff --git a/src/lib/nfs/Connection.cxx b/src/lib/nfs/Connection.cxx index 89ef24312..853cacc9a 100644 --- a/src/lib/nfs/Connection.cxx +++ b/src/lib/nfs/Connection.cxx @@ -94,6 +94,14 @@ NfsConnection::CancellableCallback::Callback(int err, void *data) cb.OnNfsError(Error(nfs_domain, err, (const char *)data)); } else { + if (open) { + /* a nfs_open_async() call was cancelled - to + avoid a memory leak, close the newly + allocated file handle immediately */ + struct nfsfh *fh = (struct nfsfh *)data; + connection.Close(fh); + } + connection.callbacks.Remove(*this); } } @@ -157,7 +165,7 @@ NfsConnection::Open(const char *path, int flags, NfsCallback &callback, { assert(!callbacks.Contains(callback)); - auto &c = callbacks.Add(callback, *this); + auto &c = callbacks.Add(callback, *this, true); if (!c.Open(context, path, flags, error)) { callbacks.Remove(c); return false; @@ -172,7 +180,7 @@ NfsConnection::Stat(struct nfsfh *fh, NfsCallback &callback, Error &error) { assert(!callbacks.Contains(callback)); - auto &c = callbacks.Add(callback, *this); + auto &c = callbacks.Add(callback, *this, false); if (!c.Stat(context, fh, error)) { callbacks.Remove(c); return false; @@ -188,7 +196,7 @@ NfsConnection::Read(struct nfsfh *fh, uint64_t offset, size_t size, { assert(!callbacks.Contains(callback)); - auto &c = callbacks.Add(callback, *this); + auto &c = callbacks.Add(callback, *this, false); if (!c.Read(context, fh, offset, size, error)) { callbacks.Remove(c); return false; diff --git a/src/lib/nfs/Connection.hxx b/src/lib/nfs/Connection.hxx index f6e5d2949..880b7d467 100644 --- a/src/lib/nfs/Connection.hxx +++ b/src/lib/nfs/Connection.hxx @@ -39,11 +39,21 @@ class NfsConnection : SocketMonitor, DeferredMonitor { class CancellableCallback : public CancellablePointer { NfsConnection &connection; + /** + * Is this a nfs_open_async() operation? If yes, then + * we need to call nfs_close_async() on the new file + * handle as soon as the callback is invoked + * successfully. + */ + const bool open; + public: explicit CancellableCallback(NfsCallback &_callback, - NfsConnection &_connection) + NfsConnection &_connection, + bool _open) :CancellablePointer(_callback), - connection(_connection) {} + connection(_connection), + open(_open) {} bool Open(nfs_context *context, const char *path, int flags, Error &error);