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().
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user