diff --git a/src/lib/nfs/Connection.cxx b/src/lib/nfs/Connection.cxx index 66262dd95..876156ffc 100644 --- a/src/lib/nfs/Connection.cxx +++ b/src/lib/nfs/Connection.cxx @@ -175,12 +175,16 @@ events_to_libnfs(unsigned i) noexcept NfsConnection::NfsConnection(EventLoop &_loop, std::string_view _server, - std::string_view _export_name) noexcept + std::string_view _export_name) :socket_event(_loop, BIND_THIS_METHOD(OnSocketReady)), defer_new_lease(_loop, BIND_THIS_METHOD(RunDeferred)), mount_timeout_event(_loop, BIND_THIS_METHOD(OnMountTimeout)), server(_server), export_name(_export_name), - context(nullptr) {} + context(nfs_init_context()) +{ + if (context == nullptr) + throw std::runtime_error{"nfs_init_context() failed"}; +} NfsConnection::~NfsConnection() noexcept { @@ -189,11 +193,10 @@ NfsConnection::~NfsConnection() noexcept assert(active_leases.empty()); assert(callbacks.IsEmpty()); assert(deferred_close.empty()); + assert(context != nullptr); - if (context != nullptr) { - PrepareDestroyContext(); - nfs_destroy_context(context); - } + socket_event.ReleaseSocket(); + nfs_destroy_context(context); } void @@ -348,7 +351,6 @@ inline void NfsConnection::InternalClose(struct nfsfh *fh) noexcept { assert(GetEventLoop().IsInside()); - assert(context != nullptr); assert(fh != nullptr); nfs_close_async(context, fh, DummyCallback, nullptr); @@ -374,7 +376,6 @@ void NfsConnection::PrepareDestroyContext() noexcept { assert(GetEventLoop().IsInside()); - assert(context != nullptr); #ifndef NDEBUG assert(!in_destroy); @@ -410,7 +411,6 @@ NfsConnection::DeferClose(struct nfsfh *fh) noexcept assert(GetEventLoop().IsInside()); assert(in_event); assert(in_service); - assert(context != nullptr); assert(fh != nullptr); deferred_close.push_front(fh); @@ -420,7 +420,6 @@ void NfsConnection::ScheduleSocket() noexcept { assert(GetEventLoop().IsInside()); - assert(context != nullptr); const int which_events = nfs_which_events(context); @@ -449,7 +448,6 @@ inline int NfsConnection::Service(unsigned flags) noexcept { assert(GetEventLoop().IsInside()); - assert(context != nullptr); #ifndef NDEBUG assert(!in_event); @@ -462,7 +460,6 @@ NfsConnection::Service(unsigned flags) noexcept int result = nfs_service(context, events_to_libnfs(flags)); #ifndef NDEBUG - assert(context != nullptr); assert(in_service); in_service = false; #endif @@ -523,7 +520,6 @@ NfsConnection::OnSocketReady(unsigned flags) noexcept return; } - assert(context != nullptr); assert(nfs_get_fd(context) >= 0); #ifndef NDEBUG @@ -531,8 +527,7 @@ NfsConnection::OnSocketReady(unsigned flags) noexcept in_event = false; #endif - if (context != nullptr) - ScheduleSocket(); + ScheduleSocket(); } inline void @@ -568,13 +563,8 @@ inline void NfsConnection::MountInternal() { assert(GetEventLoop().IsInside()); - assert(context == nullptr); assert(mount_state == MountState::INITIAL); - context = nfs_init_context(); - if (context == nullptr) - throw std::runtime_error("nfs_init_context() failed"); - postponed_mount_error = std::exception_ptr(); mount_state = MountState::WAITING; diff --git a/src/lib/nfs/Connection.hxx b/src/lib/nfs/Connection.hxx index 01d7432f0..5d2f61c48 100644 --- a/src/lib/nfs/Connection.hxx +++ b/src/lib/nfs/Connection.hxx @@ -82,7 +82,7 @@ class NfsConnection { const std::string server, export_name; - nfs_context *context; + nfs_context *const context; using LeaseList = IntrusiveList; LeaseList new_leases, active_leases; @@ -126,10 +126,13 @@ class NfsConnection { #endif public: + /** + * Throws on error. + */ [[gnu::nonnull]] NfsConnection(EventLoop &_loop, std::string_view _server, - std::string_view _export_name) noexcept; + std::string_view _export_name); /** * Must be run from EventLoop's thread. diff --git a/src/lib/nfs/FileReader.cxx b/src/lib/nfs/FileReader.cxx index 39bcf9315..00cd1fc7b 100644 --- a/src/lib/nfs/FileReader.cxx +++ b/src/lib/nfs/FileReader.cxx @@ -266,8 +266,13 @@ NfsFileReader::OnDeferredOpen() noexcept { assert(state == State::DEFER); - state = State::MOUNT; + try { + connection = &nfs_get_connection(server, export_name); + } catch (...) { + OnNfsFileError(std::current_exception()); + return; + } - connection = &nfs_get_connection(server, export_name); connection->AddLease(*this); + state = State::MOUNT; } diff --git a/src/lib/nfs/Glue.cxx b/src/lib/nfs/Glue.cxx index 013e0abcc..ba15093bf 100644 --- a/src/lib/nfs/Glue.cxx +++ b/src/lib/nfs/Glue.cxx @@ -41,7 +41,7 @@ nfs_get_event_loop() noexcept NfsConnection & nfs_get_connection(std::string_view server, - std::string_view export_name) noexcept + std::string_view export_name) { assert(in_use > 0); diff --git a/src/lib/nfs/Glue.hxx b/src/lib/nfs/Glue.hxx index 7e5150ea4..5cd165e29 100644 --- a/src/lib/nfs/Glue.hxx +++ b/src/lib/nfs/Glue.hxx @@ -21,7 +21,10 @@ nfs_finish() noexcept; EventLoop & nfs_get_event_loop() noexcept; -[[gnu::pure]] +/** + * Throws on error. + */ +[[nodiscard]] NfsConnection & nfs_get_connection(std::string_view server, - std::string_view export_name) noexcept; + std::string_view export_name); diff --git a/src/lib/nfs/Manager.cxx b/src/lib/nfs/Manager.cxx index 07cc9766d..b8a3c0d6b 100644 --- a/src/lib/nfs/Manager.cxx +++ b/src/lib/nfs/Manager.cxx @@ -21,7 +21,7 @@ class NfsManager::ManagedConnection final public: ManagedConnection(NfsManager &_manager, EventLoop &_loop, std::string_view _server, - std::string_view _export_name) noexcept + std::string_view _export_name) :NfsConnection(_loop, _server, _export_name), manager(_manager) {} @@ -55,7 +55,7 @@ NfsManager::~NfsManager() noexcept } NfsConnection & -NfsManager::GetConnection(std::string_view server, std::string_view export_name) noexcept +NfsManager::GetConnection(std::string_view server, std::string_view export_name) { assert(GetEventLoop().IsInside()); diff --git a/src/lib/nfs/Manager.hxx b/src/lib/nfs/Manager.hxx index 21cdcfa02..d34004a72 100644 --- a/src/lib/nfs/Manager.hxx +++ b/src/lib/nfs/Manager.hxx @@ -41,9 +41,12 @@ public: return idle_event.GetEventLoop(); } - [[gnu::pure]] + /** + * Throws on error. + */ + [[nodiscard]] NfsConnection &GetConnection(std::string_view server, - std::string_view export_name) noexcept; + std::string_view export_name); private: void ScheduleDelete(ManagedConnection &c) noexcept; diff --git a/src/storage/plugins/NfsStorage.cxx b/src/storage/plugins/NfsStorage.cxx index 44933485f..4fe8d255c 100644 --- a/src/storage/plugins/NfsStorage.cxx +++ b/src/storage/plugins/NfsStorage.cxx @@ -141,7 +141,14 @@ private: assert(state != State::READY); assert(GetEventLoop().IsInside()); - connection = &nfs_get_connection(server, export_name); + try { + connection = &nfs_get_connection(server, export_name); + } catch (...) { + SetState(State::DELAY, std::current_exception()); + reconnect_timer.Schedule(std::chrono::minutes(10)); + return; + } + connection->AddLease(*this); SetState(State::CONNECTING);