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
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* 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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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,67 +230,64 @@ 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 */
|
||||
/* Get the next RPC reply from the socket */
|
||||
|
||||
for (count = 0; count < 9; count++)
|
||||
error = rpcclnt_receive(rpc, rpc->rc_name, procid, prog, reply, resplen);
|
||||
if (error != 0)
|
||||
{
|
||||
/* Get the next RPC reply off the socket */
|
||||
fdbg("ERROR: rpcclnt_receive returned: %d\n");
|
||||
|
||||
error = rpcclnt_receive(rpc, rpc->rc_name, procid, prog, reply, resplen);
|
||||
if (error != 0)
|
||||
{
|
||||
fdbg("ERROR: rpcclnt_receive returned: %d\n");
|
||||
/* If we failed because of a timeout, then try sending the CALL
|
||||
* message again.
|
||||
*/
|
||||
|
||||
/* Ignore non-fatal errors and try again */
|
||||
if (error == EAGAIN || error == ETIMEDOUT || error == EINTR)
|
||||
{
|
||||
rpc->rc_callflags |= RPCCALL_MUSTRESEND;
|
||||
}
|
||||
|
||||
if (error != EINTR && error != ERESTART && error != EWOULDBLOCK)
|
||||
{
|
||||
fdbg(" Ignoring routing error\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Get the xid and check that it is an RPC replysvr */
|
||||
|
||||
replyheader = (FAR struct rpc_reply_header *)reply;
|
||||
rxid = replyheader->rp_xid;
|
||||
|
||||
if (replyheader->rp_direction != rpc_reply)
|
||||
{
|
||||
rpc_statistics(rpcinvalid);
|
||||
continue;
|
||||
}
|
||||
|
||||
return OK;
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Here if we tried to receive the response 9 times. If we failed
|
||||
* because of a timeout, then try sending the CALL message again.
|
||||
*/
|
||||
/* Get the xid and check that it is an RPC replysvr */
|
||||
|
||||
if (error == EAGAIN || error == ETIMEDOUT)
|
||||
{
|
||||
replyheader = (FAR struct rpc_reply_header *)reply;
|
||||
rxid = replyheader->rp_xid;
|
||||
|
||||
if (replyheader->rp_direction != rpc_reply)
|
||||
{
|
||||
rpc_statistics(rpcinvalid);
|
||||
fdbg("ERROR: Different RPC REPLY returned\n");
|
||||
rpc->rc_callflags |= RPCCALL_MUSTRESEND;
|
||||
}
|
||||
return error;
|
||||
error = EAGAIN;
|
||||
return error;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user