From caab3934ab17cdd56e82e09d47eedeaf563f5a81 Mon Sep 17 00:00:00 2001 From: patacongo Date: Thu, 14 Jun 2012 23:27:02 +0000 Subject: Improve NFS retry logic git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4845 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/fs/nfs/rpc_clnt.c | 182 ++++++++++++++++++++++++++++++------------------ 1 file changed, 115 insertions(+), 67 deletions(-) (limited to 'nuttx/fs/nfs/rpc_clnt.c') diff --git a/nuttx/fs/nfs/rpc_clnt.c b/nuttx/fs/nfs/rpc_clnt.c index c20a04cd9..ed9550f20 100644 --- a/nuttx/fs/nfs/rpc_clnt.c +++ b/nuttx/fs/nfs/rpc_clnt.c @@ -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 */ - - 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 */ + fdbg("ERROR: rpcclnt_receive returned: %d\n"); - if (error != EINTR && error != ERESTART && error != EWOULDBLOCK) - { - fdbg(" Ignoring routing error\n"); - continue; - } + /* If we failed because of a timeout, then try sending the CALL + * message again. + */ - return error; - } + if (error == EAGAIN || error == ETIMEDOUT || error == EINTR) + { + rpc->rc_callflags |= RPCCALL_MUSTRESEND; + } - /* Get the xid and check that it is an RPC replysvr */ + return error; + } - replyheader = (FAR struct rpc_reply_header *)reply; - rxid = replyheader->rp_xid; + /* Get the xid and check that it is an RPC replysvr */ - if (replyheader->rp_direction != rpc_reply) - { - rpc_statistics(rpcinvalid); - continue; - } + replyheader = (FAR struct rpc_reply_header *)reply; + rxid = replyheader->rp_xid; - return OK; + if (replyheader->rp_direction != rpc_reply) + { + rpc_statistics(rpcinvalid); + fdbg("ERROR: Different RPC REPLY returned\n"); + rpc->rc_callflags |= RPCCALL_MUSTRESEND; + error = EAGAIN; + 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. - */ - - if (error == EAGAIN || error == ETIMEDOUT) - { - rpc->rc_callflags |= RPCCALL_MUSTRESEND; - } - 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) { -- cgit v1.2.3