mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	SUNRPC: Handle ECONNREFUSED correctly in xprt_transmit()
If we get an ECONNREFUSED error, we currently go to sleep on the 'xprt->sending' wait queue. The problem is that no timeout is set there, and there is nothing else that will wake the task up later. We should deal with ECONNREFUSED in call_status, given that is where we also deal with -EHOSTDOWN, and friends. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
		
							parent
							
								
									40d2549db5
								
							
						
					
					
						commit
						c8485e4d63
					
				
					 3 changed files with 35 additions and 38 deletions
				
			
		| 
						 | 
					@ -1117,10 +1117,12 @@ call_transmit_status(struct rpc_task *task)
 | 
				
			||||||
		 * then hold onto the transport lock.
 | 
							 * then hold onto the transport lock.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
	case -ECONNREFUSED:
 | 
						case -ECONNREFUSED:
 | 
				
			||||||
 | 
						case -ECONNRESET:
 | 
				
			||||||
	case -ENOTCONN:
 | 
						case -ENOTCONN:
 | 
				
			||||||
	case -EHOSTDOWN:
 | 
						case -EHOSTDOWN:
 | 
				
			||||||
	case -EHOSTUNREACH:
 | 
						case -EHOSTUNREACH:
 | 
				
			||||||
	case -ENETUNREACH:
 | 
						case -ENETUNREACH:
 | 
				
			||||||
 | 
						case -EPIPE:
 | 
				
			||||||
		rpc_task_force_reencode(task);
 | 
							rpc_task_force_reencode(task);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1162,9 +1164,12 @@ call_status(struct rpc_task *task)
 | 
				
			||||||
			xprt_conditional_disconnect(task->tk_xprt,
 | 
								xprt_conditional_disconnect(task->tk_xprt,
 | 
				
			||||||
					req->rq_connect_cookie);
 | 
										req->rq_connect_cookie);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						case -ECONNRESET:
 | 
				
			||||||
	case -ECONNREFUSED:
 | 
						case -ECONNREFUSED:
 | 
				
			||||||
	case -ENOTCONN:
 | 
					 | 
				
			||||||
		rpc_force_rebind(clnt);
 | 
							rpc_force_rebind(clnt);
 | 
				
			||||||
 | 
							rpc_delay(task, 3*HZ);
 | 
				
			||||||
 | 
						case -EPIPE:
 | 
				
			||||||
 | 
						case -ENOTCONN:
 | 
				
			||||||
		task->tk_action = call_bind;
 | 
							task->tk_action = call_bind;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case -EAGAIN:
 | 
						case -EAGAIN:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -901,7 +901,11 @@ void xprt_transmit(struct rpc_task *task)
 | 
				
			||||||
	req->rq_connect_cookie = xprt->connect_cookie;
 | 
						req->rq_connect_cookie = xprt->connect_cookie;
 | 
				
			||||||
	req->rq_xtime = jiffies;
 | 
						req->rq_xtime = jiffies;
 | 
				
			||||||
	status = xprt->ops->send_request(task);
 | 
						status = xprt->ops->send_request(task);
 | 
				
			||||||
	if (status == 0) {
 | 
						if (status != 0) {
 | 
				
			||||||
 | 
							task->tk_status = status;
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dprintk("RPC: %5u xmit complete\n", task->tk_pid);
 | 
						dprintk("RPC: %5u xmit complete\n", task->tk_pid);
 | 
				
			||||||
	spin_lock_bh(&xprt->transport_lock);
 | 
						spin_lock_bh(&xprt->transport_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -917,16 +921,6 @@ void xprt_transmit(struct rpc_task *task)
 | 
				
			||||||
	else if (!req->rq_received)
 | 
						else if (!req->rq_received)
 | 
				
			||||||
		rpc_sleep_on(&xprt->pending, task, xprt_timer);
 | 
							rpc_sleep_on(&xprt->pending, task, xprt_timer);
 | 
				
			||||||
	spin_unlock_bh(&xprt->transport_lock);
 | 
						spin_unlock_bh(&xprt->transport_lock);
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Note: at this point, task->tk_sleeping has not yet been set,
 | 
					 | 
				
			||||||
	 *	 hence there is no danger of the waking up task being put on
 | 
					 | 
				
			||||||
	 *	 schedq, and being picked up by a parallel run of rpciod().
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	task->tk_status = status;
 | 
					 | 
				
			||||||
	if (status == -ECONNREFUSED)
 | 
					 | 
				
			||||||
		rpc_sleep_on(&xprt->sending, task, NULL);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void do_xprt_reserve(struct rpc_task *task)
 | 
					static inline void do_xprt_reserve(struct rpc_task *task)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -594,6 +594,8 @@ static int xs_udp_send_request(struct rpc_task *task)
 | 
				
			||||||
		/* Still some bytes left; set up for a retry later. */
 | 
							/* Still some bytes left; set up for a retry later. */
 | 
				
			||||||
		status = -EAGAIN;
 | 
							status = -EAGAIN;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (!transport->sock)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (status) {
 | 
						switch (status) {
 | 
				
			||||||
	case -ENOTSOCK:
 | 
						case -ENOTSOCK:
 | 
				
			||||||
| 
						 | 
					@ -603,19 +605,17 @@ static int xs_udp_send_request(struct rpc_task *task)
 | 
				
			||||||
	case -EAGAIN:
 | 
						case -EAGAIN:
 | 
				
			||||||
		xs_nospace(task);
 | 
							xs_nospace(task);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							dprintk("RPC:       sendmsg returned unrecognized error %d\n",
 | 
				
			||||||
 | 
								-status);
 | 
				
			||||||
	case -ENETUNREACH:
 | 
						case -ENETUNREACH:
 | 
				
			||||||
	case -EPIPE:
 | 
						case -EPIPE:
 | 
				
			||||||
	case -ECONNREFUSED:
 | 
						case -ECONNREFUSED:
 | 
				
			||||||
		/* When the server has died, an ICMP port unreachable message
 | 
							/* When the server has died, an ICMP port unreachable message
 | 
				
			||||||
		 * prompts ECONNREFUSED. */
 | 
							 * prompts ECONNREFUSED. */
 | 
				
			||||||
		clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
 | 
							clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
 | 
					 | 
				
			||||||
		dprintk("RPC:       sendmsg returned unrecognized error %d\n",
 | 
					 | 
				
			||||||
			-status);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
	return status;
 | 
						return status;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -697,6 +697,8 @@ static int xs_tcp_send_request(struct rpc_task *task)
 | 
				
			||||||
		status = -EAGAIN;
 | 
							status = -EAGAIN;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (!transport->sock)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (status) {
 | 
						switch (status) {
 | 
				
			||||||
	case -ENOTSOCK:
 | 
						case -ENOTSOCK:
 | 
				
			||||||
| 
						 | 
					@ -706,21 +708,17 @@ static int xs_tcp_send_request(struct rpc_task *task)
 | 
				
			||||||
	case -EAGAIN:
 | 
						case -EAGAIN:
 | 
				
			||||||
		xs_nospace(task);
 | 
							xs_nospace(task);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							dprintk("RPC:       sendmsg returned unrecognized error %d\n",
 | 
				
			||||||
 | 
								-status);
 | 
				
			||||||
	case -ECONNRESET:
 | 
						case -ECONNRESET:
 | 
				
			||||||
		xs_tcp_shutdown(xprt);
 | 
							xs_tcp_shutdown(xprt);
 | 
				
			||||||
	case -ECONNREFUSED:
 | 
						case -ECONNREFUSED:
 | 
				
			||||||
	case -ENOTCONN:
 | 
						case -ENOTCONN:
 | 
				
			||||||
	case -EPIPE:
 | 
						case -EPIPE:
 | 
				
			||||||
		status = -ENOTCONN;
 | 
					 | 
				
			||||||
		clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
 | 
							clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		dprintk("RPC:       sendmsg returned unrecognized error %d\n",
 | 
					 | 
				
			||||||
			-status);
 | 
					 | 
				
			||||||
		clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
 | 
					 | 
				
			||||||
		xs_tcp_shutdown(xprt);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
	return status;
 | 
						return status;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue