Skip to content

Commit

Permalink
Merge tag 'rxrpc-rewrite-20160917-1' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…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>
  • Loading branch information
David S. Miller committed Sep 19, 2016
2 parents 029ac21 + 182f505 commit 5b0c6fc
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 70 deletions.
2 changes: 2 additions & 0 deletions net/rxrpc/call_accept.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
14 changes: 5 additions & 9 deletions net/rxrpc/call_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
Expand All @@ -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;

Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand Down
46 changes: 22 additions & 24 deletions net/rxrpc/call_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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);
}

/*
Expand Down Expand Up @@ -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);
Expand Down
29 changes: 13 additions & 16 deletions net/rxrpc/conn_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;

Expand All @@ -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;

spin_lock(&rxrpc_client_conn_cache_lock);
nr_conns = --rxrpc_nr_client_conns;
if (test_bit(RXRPC_CONN_COUNTED, &conn->flags)) {
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);

Expand Down
6 changes: 4 additions & 2 deletions net/rxrpc/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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;
Expand Down
7 changes: 6 additions & 1 deletion net/rxrpc/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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),
Expand Down
53 changes: 36 additions & 17 deletions net/rxrpc/recvmsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -177,15 +181,17 @@ 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(). */
smp_store_release(&call->rx_hard_ack, hard_ack);

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);
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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);

Expand All @@ -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);
Expand All @@ -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;
}

Expand All @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion net/rxrpc/sendmsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit 5b0c6fc

Please sign in to comment.