nfs4: Correctly handle timeouts and other rpc errors
This commit is contained in:
@@ -154,15 +154,28 @@ Server::SendCallAsync(Call* call, Reply** reply, Request** request)
|
|||||||
|
|
||||||
fRequests.AddRequest(req);
|
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();
|
XDR::WriteStream& stream = call->Stream();
|
||||||
status_t result = fConnection->Send(stream.Buffer(), stream.Size());
|
status_t result = fConnection->Send(stream.Buffer(), stream.Size());
|
||||||
if (result != B_OK) {
|
if (result != B_OK) {
|
||||||
fRequests.FindRequest(xid);
|
fRequests.FindRequest(req->fXID);
|
||||||
delete req;
|
delete req;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
*request = req;
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +211,9 @@ Server::_Listener()
|
|||||||
|
|
||||||
while (!fThreadCancel) {
|
while (!fThreadCancel) {
|
||||||
result = fConnection->Receive(&buffer, &size);
|
result = fConnection->Receive(&buffer, &size);
|
||||||
if (result != B_OK) {
|
if (result == B_NO_MEMORY)
|
||||||
|
continue;
|
||||||
|
else if (result != B_OK) {
|
||||||
fThreadError = result;
|
fThreadError = result;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -206,8 +221,7 @@ Server::_Listener()
|
|||||||
Reply* reply = new(std::nothrow) Reply(buffer, size);
|
Reply* reply = new(std::nothrow) Reply(buffer, size);
|
||||||
if (reply == NULL) {
|
if (reply == NULL) {
|
||||||
free(buffer);
|
free(buffer);
|
||||||
fThreadError = result;
|
continue;
|
||||||
return B_NO_MEMORY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Request* req = fRequests.FindRequest(reply->GetXID());
|
Request* req = fRequests.FindRequest(reply->GetXID());
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ public:
|
|||||||
|
|
||||||
status_t SendCallAsync(Call* call, Reply** reply,
|
status_t SendCallAsync(Call* call, Reply** reply,
|
||||||
Request** request);
|
Request** request);
|
||||||
|
status_t ResendCallAsync(Call* call, Request* req);
|
||||||
inline status_t WaitCall(Request* request,
|
inline status_t WaitCall(Request* request,
|
||||||
bigtime_t time = kWaitTime);
|
bigtime_t time = kWaitTime);
|
||||||
inline status_t CancelCall(Request* request);
|
inline status_t CancelCall(Request* request);
|
||||||
|
|||||||
@@ -13,12 +13,17 @@
|
|||||||
status_t
|
status_t
|
||||||
Request::Send()
|
Request::Send()
|
||||||
{
|
{
|
||||||
return _TrySend();
|
switch (fServer->ID().fProtocol) {
|
||||||
|
case ProtocolUDP: return _SendUDP();
|
||||||
|
case ProtocolTCP: return _SendTCP();
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Request::_TrySend()
|
Request::_SendUDP()
|
||||||
{
|
{
|
||||||
RPC::Reply *rpl;
|
RPC::Reply *rpl;
|
||||||
RPC::Request *rpc;
|
RPC::Request *rpc;
|
||||||
@@ -29,10 +34,46 @@ Request::_TrySend()
|
|||||||
|
|
||||||
result = fServer->WaitCall(rpc);
|
result = fServer->WaitCall(rpc);
|
||||||
if (result != B_OK) {
|
if (result != B_OK) {
|
||||||
|
int attempts = 1;
|
||||||
|
while (result != B_OK && attempts++ < kRetryLimit)
|
||||||
|
result = fServer->ResendCallAsync(fBuilder.Request(), rpc);
|
||||||
|
|
||||||
|
if (attempts == kRetryLimit) {
|
||||||
fServer->CancelCall(rpc);
|
fServer->CancelCall(rpc);
|
||||||
delete rpc;
|
delete rpc;
|
||||||
return result;
|
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);
|
return fReply.SetTo(rpl);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,12 +25,15 @@ public:
|
|||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t _TrySend();
|
status_t _SendUDP();
|
||||||
|
status_t _SendTCP();
|
||||||
|
|
||||||
RPC::Server* fServer;
|
RPC::Server* fServer;
|
||||||
|
|
||||||
RequestBuilder fBuilder;
|
RequestBuilder fBuilder;
|
||||||
ReplyInterpreter fReply;
|
ReplyInterpreter fReply;
|
||||||
|
|
||||||
|
static const int kRetryLimit = 5;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user