Commit 5b0c6fc8 authored by David S. Miller's avatar David S. Miller

Merge tag 'rxrpc-rewrite-20160917-1' of...

Merge tag 'rxrpc-rewrite-20160917-1' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs

David Howells says:

====================
rxrpc: Fixes & miscellany

Here are some more AF_RXRPC fix patches with a couple of miscellaneous
changes also.  Fixes include:

 (1) Make RxRPC IPv6 support conditional on IPv6 being available.

 (2) Move the condition check in rxrpc_locate_data() into the caller and
     check the error return.

 (3) Fix the detection of the last received packet in recvmsg.

 (4) Account calls that need acceptance and clean up any unaccepted ones if
     the socket gets closed.

 (5) Fix the cleanup of client connections.

 (6) Fix the soft-ACK parsing and the retransmission of packets based on
     those ACKs.

 (7) Suppress transmission of an ACK when there's no pending ACK to
     transmit because another thread stole it.

And some miscellany:

 (8) Whitespace removal.

 (9) Switch-value consistency in rxrpc_send_call_packet().

(10) Fix the basic transmission packet size to allow for spur-of-the-moment
     jumbo DATA packet production.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 029ac211 182f5056
......@@ -369,6 +369,8 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
if (rx->notify_new_call)
rx->notify_new_call(&rx->sk, call, call->user_call_ID);
else
sk_acceptq_added(&rx->sk);
spin_lock(&conn->state_lock);
switch (conn->state) {
......
......@@ -163,8 +163,7 @@ static void rxrpc_resend(struct rxrpc_call *call)
*/
now = jiffies;
resend_at = now + rxrpc_resend_timeout;
seq = cursor + 1;
do {
for (seq = cursor + 1; before_eq(seq, top); seq++) {
ix = seq & RXRPC_RXTX_BUFF_MASK;
annotation = call->rxtx_annotations[ix];
if (annotation == RXRPC_TX_ANNO_ACK)
......@@ -184,8 +183,7 @@ static void rxrpc_resend(struct rxrpc_call *call)
/* Okay, we need to retransmit a packet. */
call->rxtx_annotations[ix] = RXRPC_TX_ANNO_RETRANS;
seq++;
} while (before_eq(seq, top));
}
call->resend_at = resend_at;
......@@ -194,8 +192,7 @@ static void rxrpc_resend(struct rxrpc_call *call)
* lock is dropped, it may clear some of the retransmission markers for
* packets that it soft-ACKs.
*/
seq = cursor + 1;
do {
for (seq = cursor + 1; before_eq(seq, top); seq++) {
ix = seq & RXRPC_RXTX_BUFF_MASK;
annotation = call->rxtx_annotations[ix];
if (annotation != RXRPC_TX_ANNO_RETRANS)
......@@ -237,8 +234,7 @@ static void rxrpc_resend(struct rxrpc_call *call)
if (after(call->tx_hard_ack, seq))
seq = call->tx_hard_ack;
seq++;
} while (before_eq(seq, top));
}
out_unlock:
spin_unlock_bh(&call->lock);
......
......@@ -226,9 +226,6 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
(const void *)user_call_ID);
/* Publish the call, even though it is incompletely set up as yet */
call->user_call_ID = user_call_ID;
__set_bit(RXRPC_CALL_HAS_USERID, &call->flags);
write_lock(&rx->call_lock);
pp = &rx->calls.rb_node;
......@@ -242,10 +239,12 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
else if (user_call_ID > xcall->user_call_ID)
pp = &(*pp)->rb_right;
else
goto found_user_ID_now_present;
goto error_dup_user_ID;
}
rcu_assign_pointer(call->socket, rx);
call->user_call_ID = user_call_ID;
__set_bit(RXRPC_CALL_HAS_USERID, &call->flags);
rxrpc_get_call(call, rxrpc_call_got_userid);
rb_link_node(&call->sock_node, parent, pp);
rb_insert_color(&call->sock_node, &rx->calls);
......@@ -276,33 +275,22 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
_leave(" = %p [new]", call);
return call;
error:
write_lock(&rx->call_lock);
rb_erase(&call->sock_node, &rx->calls);
write_unlock(&rx->call_lock);
rxrpc_put_call(call, rxrpc_call_put_userid);
write_lock(&rxrpc_call_lock);
list_del_init(&call->link);
write_unlock(&rxrpc_call_lock);
error_out:
__rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR,
RX_CALL_DEAD, ret);
set_bit(RXRPC_CALL_RELEASED, &call->flags);
rxrpc_put_call(call, rxrpc_call_put);
_leave(" = %d", ret);
return ERR_PTR(ret);
/* We unexpectedly found the user ID in the list after taking
* the call_lock. This shouldn't happen unless the user races
* with itself and tries to add the same user ID twice at the
* same time in different threads.
*/
found_user_ID_now_present:
error_dup_user_ID:
write_unlock(&rx->call_lock);
ret = -EEXIST;
goto error_out;
error:
__rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR,
RX_CALL_DEAD, ret);
rxrpc_release_call(rx, call);
rxrpc_put_call(call, rxrpc_call_put);
_leave(" = %d", ret);
return ERR_PTR(ret);
}
/*
......@@ -476,6 +464,16 @@ void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx)
_enter("%p", rx);
while (!list_empty(&rx->to_be_accepted)) {
call = list_entry(rx->to_be_accepted.next,
struct rxrpc_call, accept_link);
list_del(&call->accept_link);
rxrpc_abort_call("SKR", call, 0, RX_CALL_DEAD, ECONNRESET);
rxrpc_send_call_packet(call, RXRPC_PACKET_TYPE_ABORT);
rxrpc_release_call(rx, call);
rxrpc_put_call(call, rxrpc_call_put);
}
while (!list_empty(&rx->sock_calls)) {
call = list_entry(rx->sock_calls.next,
struct rxrpc_call, sock_link);
......
......@@ -721,7 +721,6 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call)
}
ASSERTCMP(rcu_access_pointer(chan->call), ==, call);
ASSERTCMP(atomic_read(&conn->usage), >=, 2);
/* If a client call was exposed to the world, we save the result for
* retransmission.
......@@ -818,7 +817,7 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call)
static struct rxrpc_connection *
rxrpc_put_one_client_conn(struct rxrpc_connection *conn)
{
struct rxrpc_connection *next;
struct rxrpc_connection *next = NULL;
struct rxrpc_local *local = conn->params.local;
unsigned int nr_conns;
......@@ -834,13 +833,10 @@ rxrpc_put_one_client_conn(struct rxrpc_connection *conn)
ASSERTCMP(conn->cache_state, ==, RXRPC_CONN_CLIENT_INACTIVE);
if (!test_bit(RXRPC_CONN_COUNTED, &conn->flags))
return NULL;
if (test_bit(RXRPC_CONN_COUNTED, &conn->flags)) {
spin_lock(&rxrpc_client_conn_cache_lock);
nr_conns = --rxrpc_nr_client_conns;
next = NULL;
if (nr_conns < rxrpc_max_client_connections &&
!list_empty(&rxrpc_waiting_client_conns)) {
next = list_entry(rxrpc_waiting_client_conns.next,
......@@ -850,8 +846,9 @@ rxrpc_put_one_client_conn(struct rxrpc_connection *conn)
}
spin_unlock(&rxrpc_client_conn_cache_lock);
rxrpc_kill_connection(conn);
}
rxrpc_kill_connection(conn);
if (next)
rxrpc_activate_channels(next);
......
......@@ -238,7 +238,7 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb,
len = RXRPC_JUMBO_DATALEN;
if (flags & RXRPC_LAST_PACKET) {
if (test_and_set_bit(RXRPC_CALL_RX_LAST, &call->flags) &&
if (test_bit(RXRPC_CALL_RX_LAST, &call->flags) &&
seq != call->rx_top)
return rxrpc_proto_abort("LSN", call, seq);
} else {
......@@ -282,6 +282,8 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb,
call->rxtx_buffer[ix] = skb;
if (after(seq, call->rx_top))
smp_store_release(&call->rx_top, seq);
if (flags & RXRPC_LAST_PACKET)
set_bit(RXRPC_CALL_RX_LAST, &call->flags);
queued = true;
if (after_eq(seq, call->rx_expect_next)) {
......@@ -382,7 +384,7 @@ static void rxrpc_input_soft_acks(struct rxrpc_call *call, u8 *acks,
for (; nr_acks > 0; nr_acks--, seq++) {
ix = seq & RXRPC_RXTX_BUFF_MASK;
switch (*acks) {
switch (*acks++) {
case RXRPC_ACK_TYPE_ACK:
call->rxtx_annotations[ix] = RXRPC_TX_ANNO_ACK;
break;
......
......@@ -137,6 +137,11 @@ int rxrpc_send_call_packet(struct rxrpc_call *call, u8 type)
switch (type) {
case RXRPC_PACKET_TYPE_ACK:
spin_lock_bh(&call->lock);
if (!call->ackr_reason) {
spin_unlock_bh(&call->lock);
ret = 0;
goto out;
}
n = rxrpc_fill_out_ack(call, pkt);
call->ackr_reason = 0;
......@@ -177,7 +182,7 @@ int rxrpc_send_call_packet(struct rxrpc_call *call, u8 type)
&msg, iov, ioc, len);
if (ret < 0 && call->state < RXRPC_CALL_COMPLETE) {
switch (pkt->whdr.type) {
switch (type) {
case RXRPC_PACKET_TYPE_ACK:
rxrpc_propose_ACK(call, pkt->ack.reason,
ntohs(pkt->ack.maxSkew),
......
......@@ -134,6 +134,8 @@ static void rxrpc_end_rx_phase(struct rxrpc_call *call)
{
_enter("%d,%s", call->debug_id, rxrpc_call_states[call->state]);
ASSERTCMP(call->rx_hard_ack, ==, call->rx_top);
if (call->state == RXRPC_CALL_CLIENT_RECV_REPLY) {
rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, 0, 0, true, false);
rxrpc_send_call_packet(call, RXRPC_PACKET_TYPE_ACK);
......@@ -163,8 +165,10 @@ static void rxrpc_end_rx_phase(struct rxrpc_call *call)
*/
static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
{
struct rxrpc_skb_priv *sp;
struct sk_buff *skb;
rxrpc_seq_t hard_ack, top;
u8 flags;
int ix;
_enter("%d", call->debug_id);
......@@ -177,6 +181,8 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
ix = hard_ack & RXRPC_RXTX_BUFF_MASK;
skb = call->rxtx_buffer[ix];
rxrpc_see_skb(skb);
sp = rxrpc_skb(skb);
flags = sp->hdr.flags;
call->rxtx_buffer[ix] = NULL;
call->rxtx_annotations[ix] = 0;
/* Barrier against rxrpc_input_data(). */
......@@ -184,8 +190,8 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
rxrpc_free_skb(skb);
_debug("%u,%u,%lx", hard_ack, top, call->flags);
if (hard_ack == top && test_bit(RXRPC_CALL_RX_LAST, &call->flags))
_debug("%u,%u,%02x", hard_ack, top, flags);
if (flags & RXRPC_LAST_PACKET)
rxrpc_end_rx_phase(call);
}
......@@ -240,9 +246,6 @@ static int rxrpc_locate_data(struct rxrpc_call *call, struct sk_buff *skb,
int ret;
u8 annotation = *_annotation;
if (offset > 0)
return 0;
/* Locate the subpacket */
offset = sp->offset;
len = skb->len - sp->offset;
......@@ -281,13 +284,19 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
size_t remain;
bool last;
unsigned int rx_pkt_offset, rx_pkt_len;
int ix, copy, ret = 0;
int ix, copy, ret = -EAGAIN, ret2;
_enter("");
rx_pkt_offset = call->rx_pkt_offset;
rx_pkt_len = call->rx_pkt_len;
if (call->state >= RXRPC_CALL_SERVER_ACK_REQUEST) {
seq = call->rx_hard_ack;
ret = 1;
goto done;
}
/* Barriers against rxrpc_input_data(). */
hard_ack = call->rx_hard_ack;
top = smp_load_acquire(&call->rx_top);
......@@ -303,8 +312,15 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
if (msg)
sock_recv_timestamp(msg, sock->sk, skb);
ret = rxrpc_locate_data(call, skb, &call->rxtx_annotations[ix],
if (rx_pkt_offset == 0) {
ret2 = rxrpc_locate_data(call, skb,
&call->rxtx_annotations[ix],
&rx_pkt_offset, &rx_pkt_len);
if (ret2 < 0) {
ret = ret2;
goto out;
}
}
_debug("recvmsg %x DATA #%u { %d, %d }",
sp->hdr.callNumber, seq, rx_pkt_offset, rx_pkt_len);
......@@ -314,10 +330,12 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
if (copy > remain)
copy = remain;
if (copy > 0) {
ret = skb_copy_datagram_iter(skb, rx_pkt_offset, iter,
ret2 = skb_copy_datagram_iter(skb, rx_pkt_offset, iter,
copy);
if (ret < 0)
if (ret2 < 0) {
ret = ret2;
goto out;
}
/* handle piecemeal consumption of data packets */
_debug("copied %d @%zu", copy, *_offset);
......@@ -330,6 +348,7 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
if (rx_pkt_len > 0) {
_debug("buffer full");
ASSERTCMP(*_offset, ==, len);
ret = 0;
break;
}
......@@ -340,19 +359,19 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
rx_pkt_offset = 0;
rx_pkt_len = 0;
ASSERTIFCMP(last, seq, ==, top);
}
if (after(seq, top)) {
ret = -EAGAIN;
if (test_bit(RXRPC_CALL_RX_LAST, &call->flags))
if (last) {
ASSERTCMP(seq, ==, READ_ONCE(call->rx_top));
ret = 1;
goto out;
}
}
out:
if (!(flags & MSG_PEEK)) {
call->rx_pkt_offset = rx_pkt_offset;
call->rx_pkt_len = rx_pkt_len;
}
done:
_leave(" = %d [%u/%u]", ret, seq, top);
return ret;
}
......
......@@ -214,7 +214,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
goto maybe_error;
}
max = call->conn->params.peer->maxdata;
max = RXRPC_JUMBO_DATALEN;
max -= call->conn->security_size;
max &= ~(call->conn->size_align - 1UL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment