Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c8485e4d authored by Trond Myklebust's avatar Trond Myklebust
Browse files

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: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 40d2549d
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -1117,10 +1117,12 @@ call_transmit_status(struct rpc_task *task)
		 * then hold onto the transport lock.
		 */
	case -ECONNREFUSED:
	case -ECONNRESET:
	case -ENOTCONN:
	case -EHOSTDOWN:
	case -EHOSTUNREACH:
	case -ENETUNREACH:
	case -EPIPE:
		rpc_task_force_reencode(task);
	}
}
@@ -1162,9 +1164,12 @@ call_status(struct rpc_task *task)
			xprt_conditional_disconnect(task->tk_xprt,
					req->rq_connect_cookie);
		break;
	case -ECONNRESET:
	case -ECONNREFUSED:
	case -ENOTCONN:
		rpc_force_rebind(clnt);
		rpc_delay(task, 3*HZ);
	case -EPIPE:
	case -ENOTCONN:
		task->tk_action = call_bind;
		break;
	case -EAGAIN:
+16 −22
Original line number Diff line number Diff line
@@ -901,7 +901,11 @@ void xprt_transmit(struct rpc_task *task)
	req->rq_connect_cookie = xprt->connect_cookie;
	req->rq_xtime = jiffies;
	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);
	spin_lock_bh(&xprt->transport_lock);

@@ -917,16 +921,6 @@ void xprt_transmit(struct rpc_task *task)
	else if (!req->rq_received)
		rpc_sleep_on(&xprt->pending, task, xprt_timer);
	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)
+12 −14
Original line number Diff line number Diff line
@@ -594,6 +594,8 @@ static int xs_udp_send_request(struct rpc_task *task)
		/* Still some bytes left; set up for a retry later. */
		status = -EAGAIN;
	}
	if (!transport->sock)
		goto out;

	switch (status) {
	case -ENOTSOCK:
@@ -603,19 +605,17 @@ static int xs_udp_send_request(struct rpc_task *task)
	case -EAGAIN:
		xs_nospace(task);
		break;
	default:
		dprintk("RPC:       sendmsg returned unrecognized error %d\n",
			-status);
	case -ENETUNREACH:
	case -EPIPE:
	case -ECONNREFUSED:
		/* When the server has died, an ICMP port unreachable message
		 * prompts ECONNREFUSED. */
		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;
}

@@ -697,6 +697,8 @@ static int xs_tcp_send_request(struct rpc_task *task)
		status = -EAGAIN;
		break;
	}
	if (!transport->sock)
		goto out;

	switch (status) {
	case -ENOTSOCK:
@@ -706,21 +708,17 @@ static int xs_tcp_send_request(struct rpc_task *task)
	case -EAGAIN:
		xs_nospace(task);
		break;
	default:
		dprintk("RPC:       sendmsg returned unrecognized error %d\n",
			-status);
	case -ECONNRESET:
		xs_tcp_shutdown(xprt);
	case -ECONNREFUSED:
	case -ENOTCONN:
	case -EPIPE:
		status = -ENOTCONN;
		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;
}