From 5945c55ae441fb36adca961ed97ab56d978443be Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 11 Jun 2012 21:41:00 +0200 Subject: [PATCH] nfs4: Correctly handle timeouts and other rpc errors --- .../kernel/file_systems/nfs4/RPCServer.cpp | 24 +++++++-- .../kernel/file_systems/nfs4/RPCServer.h | 1 + .../kernel/file_systems/nfs4/Request.cpp | 51 +++++++++++++++++-- .../kernel/file_systems/nfs4/Request.h | 5 +- 4 files changed, 70 insertions(+), 11 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index 5d62e265e2..329daec6ec 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -154,15 +154,28 @@ Server::SendCallAsync(Call* call, Reply** reply, Request** request) fRequests.AddRequest(req); + *request = req; + return ResendCallAsync(call, req); +} + + +status_t +Server::ResendCallAsync(Call* call, Request* req) +{ + if (fThreadError != B_OK) { + fRequests.FindRequest(req->fXID); + delete req; + return fThreadError; + } + XDR::WriteStream& stream = call->Stream(); status_t result = fConnection->Send(stream.Buffer(), stream.Size()); if (result != B_OK) { - fRequests.FindRequest(xid); + fRequests.FindRequest(req->fXID); delete req; return result; } - *request = req; return B_OK; } @@ -198,7 +211,9 @@ Server::_Listener() while (!fThreadCancel) { result = fConnection->Receive(&buffer, &size); - if (result != B_OK) { + if (result == B_NO_MEMORY) + continue; + else if (result != B_OK) { fThreadError = result; return result; } @@ -206,8 +221,7 @@ Server::_Listener() Reply* reply = new(std::nothrow) Reply(buffer, size); if (reply == NULL) { free(buffer); - fThreadError = result; - return B_NO_MEMORY; + continue; } Request* req = fRequests.FindRequest(reply->GetXID()); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index bd10454ccc..8241cd6ee3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -52,6 +52,7 @@ public: status_t SendCallAsync(Call* call, Reply** reply, Request** request); + status_t ResendCallAsync(Call* call, Request* req); inline status_t WaitCall(Request* request, bigtime_t time = kWaitTime); inline status_t CancelCall(Request* request); diff --git a/src/add-ons/kernel/file_systems/nfs4/Request.cpp b/src/add-ons/kernel/file_systems/nfs4/Request.cpp index 65efca366d..125bdc9aa8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Request.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Request.cpp @@ -13,12 +13,17 @@ status_t Request::Send() { - return _TrySend(); + switch (fServer->ID().fProtocol) { + case ProtocolUDP: return _SendUDP(); + case ProtocolTCP: return _SendTCP(); + } + + return B_BAD_VALUE; } status_t -Request::_TrySend() +Request::_SendUDP() { RPC::Reply *rpl; RPC::Request *rpc; @@ -29,15 +34,51 @@ Request::_TrySend() result = fServer->WaitCall(rpc); if (result != B_OK) { - fServer->CancelCall(rpc); - delete rpc; - return result; + int attempts = 1; + while (result != B_OK && attempts++ < kRetryLimit) + result = fServer->ResendCallAsync(fBuilder.Request(), rpc); + + if (attempts == kRetryLimit) { + fServer->CancelCall(rpc); + delete rpc; + return result; + } } return fReply.SetTo(rpl); } +status_t +Request::_SendTCP() +{ + RPC::Reply *rpl; + RPC::Request *rpc; + + status_t result; + int attempts = 0; + do { + result = fServer->SendCallAsync(fBuilder.Request(), &rpl, &rpc); + if (result == B_NO_MEMORY) + return result; + else if (result != B_OK) { + fServer->Repair(); + continue; + } + + result = fServer->WaitCall(rpc); + if (result != B_OK) { + fServer->CancelCall(rpc); + delete rpc; + + fServer->Repair(); + } + } while (result != B_OK && attempts++ < kRetryLimit); + + return fReply.SetTo(rpl); +} + + void Request::Reset() { diff --git a/src/add-ons/kernel/file_systems/nfs4/Request.h b/src/add-ons/kernel/file_systems/nfs4/Request.h index 60dc99b8f5..317bd3fbd4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Request.h +++ b/src/add-ons/kernel/file_systems/nfs4/Request.h @@ -25,12 +25,15 @@ public: void Reset(); private: - status_t _TrySend(); + status_t _SendUDP(); + status_t _SendTCP(); RPC::Server* fServer; RequestBuilder fBuilder; ReplyInterpreter fReply; + + static const int kRetryLimit = 5; };