mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 01:10:04 +00:00
RxRPC rewrite
-----BEGIN PGP SIGNATURE----- iQIVAwUAV90ZnPSw1s6N8H32AQKguA//Q7lvTa3n3DFvMQcIPsyJZ6VniUqksTA1 wmQrw4GHXRUgM8UWz7G9Y5aqxUp2q6y6Vm9BeHkQ2bYZjSrOx5Dc/AImWhBn5au+ h+HZYcEs4mFM5AoVT7GK8o/nNODDjNt2qwcH/Nf8+SM7Xf52zYHelrSteLZZ1YWO S1m4pa5YUBa/ICD3+K52lWq9SCG0VMmy41UHDXU6uSakfN62rn9ZYCcNeathlJGS 2D0cG3GzYYHiBZ1CkmdPQgGQhTM3wzI+0OvbNnidFlF78zVDlxX8C9zgWs/VlTCg 02ok4+ftzDojgXH9W+DziEiyCNq14GTDbrdSai5WA+vHVGagr6OoSwDWgPHkXBvW pYQh7jqRoBOKN2fsVkU0t19hPc2CCVGYMh49A6AFv8lgS+nWoDXOlmZ0snh8deQg Z0HO5mx+V+4yJplBlwH6ncvbRB9ywpsvIuLriZXC/aJg6aY4a8nrU35d1+6xUaM7 RBMud0uj+7oU+sC9N7CuM8m8HpBOg6+qAsbsfATSwadMRcMdS4LSoXcBg0WvljIH JmtL924yEnMDw1yPkmuDBcQ9K6DuxeOYZg4A2756tBtGulxuVjntmI1MVAQlsbqH CnNPWpxIDoLRQsHVcYWS5O1F16drGobzFhmj7Hf/6HmGa28x7nQhDafzfFj/3Dos MAdM2pdO2x8= =MjVT -----END PGP SIGNATURE----- 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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
5b0c6fc8ef
8 changed files with 88 additions and 69 deletions
|
@ -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) {
|
||||
|
|
|
@ -31,7 +31,7 @@ static void rxrpc_set_timer(struct rxrpc_call *call)
|
|||
_enter("{%ld,%ld,%ld:%ld}",
|
||||
call->ack_at - now, call->resend_at - now, call->expire_at - now,
|
||||
call->timer.expires - now);
|
||||
|
||||
|
||||
read_lock_bh(&call->state_lock);
|
||||
|
||||
if (call->state < RXRPC_CALL_COMPLETE) {
|
||||
|
@ -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,24 +833,22 @@ 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;
|
||||
|
||||
spin_lock(&rxrpc_client_conn_cache_lock);
|
||||
nr_conns = --rxrpc_nr_client_conns;
|
||||
if (nr_conns < rxrpc_max_client_connections &&
|
||||
!list_empty(&rxrpc_waiting_client_conns)) {
|
||||
next = list_entry(rxrpc_waiting_client_conns.next,
|
||||
struct rxrpc_connection, cache_link);
|
||||
rxrpc_get_connection(next);
|
||||
rxrpc_activate_conn(next);
|
||||
}
|
||||
|
||||
next = NULL;
|
||||
if (nr_conns < rxrpc_max_client_connections &&
|
||||
!list_empty(&rxrpc_waiting_client_conns)) {
|
||||
next = list_entry(rxrpc_waiting_client_conns.next,
|
||||
struct rxrpc_connection, cache_link);
|
||||
rxrpc_get_connection(next);
|
||||
rxrpc_activate_conn(next);
|
||||
spin_unlock(&rxrpc_client_conn_cache_lock);
|
||||
}
|
||||
|
||||
spin_unlock(&rxrpc_client_conn_cache_lock);
|
||||
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],
|
||||
&rx_pkt_offset, &rx_pkt_len);
|
||||
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,
|
||||
copy);
|
||||
if (ret < 0)
|
||||
ret2 = skb_copy_datagram_iter(skb, rx_pkt_offset, iter,
|
||||
copy);
|
||||
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 (last) {
|
||||
ASSERTCMP(seq, ==, READ_ONCE(call->rx_top));
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (after(seq, top)) {
|
||||
ret = -EAGAIN;
|
||||
if (test_bit(RXRPC_CALL_RX_LAST, &call->flags))
|
||||
ret = 1;
|
||||
}
|
||||
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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue