Improve NFS retry logic

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4845 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2012-06-14 23:27:02 +00:00
parent bf1542f7ab
commit 680d9ccc13
3 changed files with 133 additions and 69 deletions

View File

@ -80,6 +80,10 @@ struct nfsstats nfsstats;
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: nfs_init
****************************************************************************/
void nfs_init(void)
{
nfs_true = txdr_unsigned(TRUE);
@ -89,6 +93,10 @@ void nfs_init(void)
rpcclnt_init();
}
/****************************************************************************
* Name: nfs_connect
****************************************************************************/
int nfs_connect(struct nfsmount *nmp)
{
struct rpcclnt *rpc;
@ -114,13 +122,20 @@ int nfs_connect(struct nfsmount *nmp)
rpc->rc_path = nmp->nm_path;
rpc->rc_name = &nmp->nm_nam;
rpc->rc_sotype = nmp->nm_sotype;
rpc->rc_retry = nmp->nm_retry;
nmp->nm_rpcclnt = rpc;
return rpcclnt_connect(rpc);
}
/* NFS disconnect. Clean up and unlink. */
/****************************************************************************
* Name: nfs_disconnect
*
* Description:
* NFS disconnect. Clean up and unlink.
*
****************************************************************************/
void nfs_disconnect(struct nfsmount *nmp)
{

View File

@ -512,6 +512,7 @@ struct rpcclnt
uint8_t rc_clntflags; /* For RPCCLNT_* flags */
uint8_t rc_sotype; /* Type of socket */
uint8_t rc_retry; /* Max retries */
/* These describe the current RPC call */

View File

@ -150,10 +150,18 @@ static void rpcclnt_fmtheader(FAR struct rpc_call_header *ch,
* Private Functions
****************************************************************************/
/* This is the nfs send routine. Returns EINTR if the RPC is terminated, 0
* otherwise - set RPCCALL_MUSTRESEND if the send fails for any reason - do any
* cleanup required by recoverable socket errors.
*/
/****************************************************************************
* Name: rpcclnt_send
*
* Description:
* This is the nfs send routine.
*
* Returned Value:
* Returns EINTR if the RPC is terminated, 0 otherwise - set
* RPCCALL_MUSTRESEND if the send fails for any reason - do anycleanup
* required by recoverable socket errors. *
*
****************************************************************************/
static int rpcclnt_send(FAR struct rpcclnt *rpc, int procid, int prog,
FAR void *call, int reqlen)
@ -190,15 +198,18 @@ static int rpcclnt_send(FAR struct rpcclnt *rpc, int procid, int prog,
return error;
}
/* Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all
* done by psock_recvfrom(). For SOCK_STREAM, first get the
* Record Mark to find out how much more there is to get. We must
* lock the socket against other receivers until we have an entire
* rpc request/reply.
*/
/****************************************************************************
* Name: rpcclnt_receive
*
* Description:
* Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all done
* by psock_recvfrom().
*
****************************************************************************/
static int rpcclnt_receive(FAR struct rpcclnt *rpc, struct sockaddr *aname,
int proc, int program, void *reply, size_t resplen)
static int rpcclnt_receive(FAR struct rpcclnt *rpc, FAR struct sockaddr *aname,
int proc, int program, FAR void *reply,
size_t resplen)
{
ssize_t nbytes;
int error = 0;
@ -219,36 +230,35 @@ static int rpcclnt_receive(FAR struct rpcclnt *rpc, struct sockaddr *aname,
return error;
}
/* Implement receipt of reply on a socket. We must search through the list of
* received datagrams matching them with outstanding requests using the xid,
* until ours is found.
*/
/****************************************************************************
* Name: rpcclnt_reply
*
* Description:
* Received the RPC reply on the socket.
*
****************************************************************************/
static int rpcclnt_reply(FAR struct rpcclnt *rpc, int procid, int prog,
void *reply, size_t resplen)
FAR void *reply, size_t resplen)
{
FAR struct rpc_reply_header *replyheader;
uint32_t rxid;
int error;
int count;
/* Loop around until we get our own reply */
for (count = 0; count < 9; count++)
{
/* Get the next RPC reply off the socket */
/* Get the next RPC reply from the socket */
error = rpcclnt_receive(rpc, rpc->rc_name, procid, prog, reply, resplen);
if (error != 0)
{
fdbg("ERROR: rpcclnt_receive returned: %d\n");
/* Ignore non-fatal errors and try again */
/* If we failed because of a timeout, then try sending the CALL
* message again.
*/
if (error != EINTR && error != ERESTART && error != EWOULDBLOCK)
if (error == EAGAIN || error == ETIMEDOUT || error == EINTR)
{
fdbg(" Ignoring routing error\n");
continue;
rpc->rc_callflags |= RPCCALL_MUSTRESEND;
}
return error;
@ -262,24 +272,22 @@ static int rpcclnt_reply(FAR struct rpcclnt *rpc, int procid, int prog,
if (replyheader->rp_direction != rpc_reply)
{
rpc_statistics(rpcinvalid);
continue;
fdbg("ERROR: Different RPC REPLY returned\n");
rpc->rc_callflags |= RPCCALL_MUSTRESEND;
error = EAGAIN;
return error;
}
return OK;
}
/* Here if we tried to receive the response 9 times. If we failed
* because of a timeout, then try sending the CALL message again.
*/
if (error == EAGAIN || error == ETIMEDOUT)
{
rpc->rc_callflags |= RPCCALL_MUSTRESEND;
}
return error;
}
/* Get a new (non-zero) xid */
/****************************************************************************
* Name: rpcclnt_newxid
*
* Description:
* Get a new (non-zero) xid
*
****************************************************************************/
static uint32_t rpcclnt_newxid(void)
{
@ -307,7 +315,13 @@ static uint32_t rpcclnt_newxid(void)
return rpcclnt_xid;
}
/* Format the common part of the call header */
/****************************************************************************
* Name: rpcclnt_fmtheader
*
* Description:
* Format the common part of the call header
*
****************************************************************************/
static void rpcclnt_fmtheader(FAR struct rpc_call_header *ch,
uint32_t xid, int prog, int vers, int procid)
@ -336,6 +350,14 @@ static void rpcclnt_fmtheader(FAR struct rpc_call_header *ch,
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: rpcclnt_init
*
* Description:
* Initialize the RPC client
*
****************************************************************************/
void rpcclnt_init(void)
{
/* RPC constants how about actually using more than one of these! */
@ -353,9 +375,14 @@ void rpcclnt_init(void)
fvdbg("RPC initialized\n");
}
/* Initialize sockets and congestion for a new RPC connection. We do not free
* the sockaddr if error.
*/
/****************************************************************************
* Name: rpcclnt_connect
*
* Description:
* Initialize sockets for a new RPC connection. We do not free the
* sockaddr if an error occurs.
*
****************************************************************************/
int rpcclnt_connect(struct rpcclnt *rpc)
{
@ -561,6 +588,14 @@ bad:
return error;
}
/****************************************************************************
* Name: rpcclnt_disconnect
*
* Description:
* Disconnect from the NFS server.
*
****************************************************************************/
void rpcclnt_disconnect(struct rpcclnt *rpc)
{
struct socket *so;
@ -572,6 +607,14 @@ void rpcclnt_disconnect(struct rpcclnt *rpc)
}
}
/****************************************************************************
* Name: rpcclnt_umount
*
* Description:
* Un-mount the NFS file system.
*
****************************************************************************/
int rpcclnt_umount(struct rpcclnt *rpc)
{
struct sockaddr *saddr;
@ -656,15 +699,20 @@ bad:
return error;
}
/* Code from nfs_request - goes something like this - fill in task struct -
* links task into list - calls nfs_send() for first transmit - calls
* nfs_receive() to get reply - fills in reply (which should be initialized
* prior to calling), which is valid when 0.
/****************************************************************************
* Name: rpcclnt_request
*
* Note that reply->result_* are invalid unless reply->type ==
* RPC_MSGACCEPTED and reply->status == RPC_SUCCESS and that reply->verf_*
* are invalid unless reply->type == RPC_MSGACCEPTED
*/
* Description:
* Perform the RPC reqquest. Logic formats the RPC CALL message and calls
* rpcclnt_send to send the RPC CALL message. It then calls rpcclnt_reply()
* to get the response. It may attempt to re-send the CALL message on
* certain errors.
*
* On successful receipt, it verifies the RPC level of the returned values.
* (There may still be be NFS layer errors that will be deted by calling
* logic).
*
****************************************************************************/
int rpcclnt_request(FAR struct rpcclnt *rpc, int procnum, int prog,
int version, FAR void *request, size_t reqlen,
@ -724,7 +772,7 @@ int rpcclnt_request(FAR struct rpcclnt *rpc, int procnum, int prog,
retries++;
}
while ((rpc->rc_callflags & RPCCALL_MUSTRESEND) != 0 && retries <= RPC_MAXREXMIT);
while ((rpc->rc_callflags & RPCCALL_MUSTRESEND) != 0 && retries <= rpc->rc_retry);
if (error != OK)
{