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:
parent
bf1542f7ab
commit
680d9ccc13
@ -80,6 +80,10 @@ struct nfsstats nfsstats;
|
|||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: nfs_init
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
void nfs_init(void)
|
void nfs_init(void)
|
||||||
{
|
{
|
||||||
nfs_true = txdr_unsigned(TRUE);
|
nfs_true = txdr_unsigned(TRUE);
|
||||||
@ -89,6 +93,10 @@ void nfs_init(void)
|
|||||||
rpcclnt_init();
|
rpcclnt_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: nfs_connect
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
int nfs_connect(struct nfsmount *nmp)
|
int nfs_connect(struct nfsmount *nmp)
|
||||||
{
|
{
|
||||||
struct rpcclnt *rpc;
|
struct rpcclnt *rpc;
|
||||||
@ -114,13 +122,20 @@ int nfs_connect(struct nfsmount *nmp)
|
|||||||
rpc->rc_path = nmp->nm_path;
|
rpc->rc_path = nmp->nm_path;
|
||||||
rpc->rc_name = &nmp->nm_nam;
|
rpc->rc_name = &nmp->nm_nam;
|
||||||
rpc->rc_sotype = nmp->nm_sotype;
|
rpc->rc_sotype = nmp->nm_sotype;
|
||||||
|
rpc->rc_retry = nmp->nm_retry;
|
||||||
|
|
||||||
nmp->nm_rpcclnt = rpc;
|
nmp->nm_rpcclnt = rpc;
|
||||||
|
|
||||||
return rpcclnt_connect(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)
|
void nfs_disconnect(struct nfsmount *nmp)
|
||||||
{
|
{
|
||||||
|
@ -512,6 +512,7 @@ struct rpcclnt
|
|||||||
|
|
||||||
uint8_t rc_clntflags; /* For RPCCLNT_* flags */
|
uint8_t rc_clntflags; /* For RPCCLNT_* flags */
|
||||||
uint8_t rc_sotype; /* Type of socket */
|
uint8_t rc_sotype; /* Type of socket */
|
||||||
|
uint8_t rc_retry; /* Max retries */
|
||||||
|
|
||||||
/* These describe the current RPC call */
|
/* These describe the current RPC call */
|
||||||
|
|
||||||
|
@ -150,10 +150,18 @@ static void rpcclnt_fmtheader(FAR struct rpc_call_header *ch,
|
|||||||
* Private Functions
|
* 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
|
* Name: rpcclnt_send
|
||||||
* cleanup required by recoverable socket errors.
|
*
|
||||||
*/
|
* 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,
|
static int rpcclnt_send(FAR struct rpcclnt *rpc, int procid, int prog,
|
||||||
FAR void *call, int reqlen)
|
FAR void *call, int reqlen)
|
||||||
@ -190,15 +198,18 @@ static int rpcclnt_send(FAR struct rpcclnt *rpc, int procid, int prog,
|
|||||||
return error;
|
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
|
* Name: rpcclnt_receive
|
||||||
* 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
|
* Description:
|
||||||
* rpc request/reply.
|
* 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,
|
static int rpcclnt_receive(FAR struct rpcclnt *rpc, FAR struct sockaddr *aname,
|
||||||
int proc, int program, void *reply, size_t resplen)
|
int proc, int program, FAR void *reply,
|
||||||
|
size_t resplen)
|
||||||
{
|
{
|
||||||
ssize_t nbytes;
|
ssize_t nbytes;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
@ -219,36 +230,35 @@ static int rpcclnt_receive(FAR struct rpcclnt *rpc, struct sockaddr *aname,
|
|||||||
return error;
|
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,
|
* Name: rpcclnt_reply
|
||||||
* until ours is found.
|
*
|
||||||
*/
|
* Description:
|
||||||
|
* Received the RPC reply on the socket.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
static int rpcclnt_reply(FAR struct rpcclnt *rpc, int procid, int prog,
|
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;
|
FAR struct rpc_reply_header *replyheader;
|
||||||
uint32_t rxid;
|
uint32_t rxid;
|
||||||
int error;
|
int error;
|
||||||
int count;
|
|
||||||
|
|
||||||
/* Loop around until we get our own reply */
|
/* Get the next RPC reply from the socket */
|
||||||
|
|
||||||
for (count = 0; count < 9; count++)
|
|
||||||
{
|
|
||||||
/* Get the next RPC reply off the socket */
|
|
||||||
|
|
||||||
error = rpcclnt_receive(rpc, rpc->rc_name, procid, prog, reply, resplen);
|
error = rpcclnt_receive(rpc, rpc->rc_name, procid, prog, reply, resplen);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
{
|
{
|
||||||
fdbg("ERROR: rpcclnt_receive returned: %d\n");
|
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");
|
rpc->rc_callflags |= RPCCALL_MUSTRESEND;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
@ -262,24 +272,22 @@ static int rpcclnt_reply(FAR struct rpcclnt *rpc, int procid, int prog,
|
|||||||
if (replyheader->rp_direction != rpc_reply)
|
if (replyheader->rp_direction != rpc_reply)
|
||||||
{
|
{
|
||||||
rpc_statistics(rpcinvalid);
|
rpc_statistics(rpcinvalid);
|
||||||
continue;
|
fdbg("ERROR: Different RPC REPLY returned\n");
|
||||||
|
rpc->rc_callflags |= RPCCALL_MUSTRESEND;
|
||||||
|
error = EAGAIN;
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
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.
|
* Name: rpcclnt_newxid
|
||||||
*/
|
*
|
||||||
|
* Description:
|
||||||
if (error == EAGAIN || error == ETIMEDOUT)
|
* Get a new (non-zero) xid
|
||||||
{
|
*
|
||||||
rpc->rc_callflags |= RPCCALL_MUSTRESEND;
|
****************************************************************************/
|
||||||
}
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get a new (non-zero) xid */
|
|
||||||
|
|
||||||
static uint32_t rpcclnt_newxid(void)
|
static uint32_t rpcclnt_newxid(void)
|
||||||
{
|
{
|
||||||
@ -307,7 +315,13 @@ static uint32_t rpcclnt_newxid(void)
|
|||||||
return rpcclnt_xid;
|
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,
|
static void rpcclnt_fmtheader(FAR struct rpc_call_header *ch,
|
||||||
uint32_t xid, int prog, int vers, int procid)
|
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
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: rpcclnt_init
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Initialize the RPC client
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
void rpcclnt_init(void)
|
void rpcclnt_init(void)
|
||||||
{
|
{
|
||||||
/* RPC constants how about actually using more than one of these! */
|
/* RPC constants how about actually using more than one of these! */
|
||||||
@ -353,9 +375,14 @@ void rpcclnt_init(void)
|
|||||||
fvdbg("RPC initialized\n");
|
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)
|
int rpcclnt_connect(struct rpcclnt *rpc)
|
||||||
{
|
{
|
||||||
@ -561,6 +588,14 @@ bad:
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: rpcclnt_disconnect
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Disconnect from the NFS server.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
void rpcclnt_disconnect(struct rpcclnt *rpc)
|
void rpcclnt_disconnect(struct rpcclnt *rpc)
|
||||||
{
|
{
|
||||||
struct socket *so;
|
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)
|
int rpcclnt_umount(struct rpcclnt *rpc)
|
||||||
{
|
{
|
||||||
struct sockaddr *saddr;
|
struct sockaddr *saddr;
|
||||||
@ -656,15 +699,20 @@ bad:
|
|||||||
return error;
|
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
|
* Name: rpcclnt_request
|
||||||
* nfs_receive() to get reply - fills in reply (which should be initialized
|
|
||||||
* prior to calling), which is valid when 0.
|
|
||||||
*
|
*
|
||||||
* Note that reply->result_* are invalid unless reply->type ==
|
* Description:
|
||||||
* RPC_MSGACCEPTED and reply->status == RPC_SUCCESS and that reply->verf_*
|
* Perform the RPC reqquest. Logic formats the RPC CALL message and calls
|
||||||
* are invalid unless reply->type == RPC_MSGACCEPTED
|
* 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 rpcclnt_request(FAR struct rpcclnt *rpc, int procnum, int prog,
|
||||||
int version, FAR void *request, size_t reqlen,
|
int version, FAR void *request, size_t reqlen,
|
||||||
@ -724,7 +772,7 @@ int rpcclnt_request(FAR struct rpcclnt *rpc, int procnum, int prog,
|
|||||||
|
|
||||||
retries++;
|
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)
|
if (error != OK)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user