sp = rxrpc_skb(skb);
tseq = sp->hdr.seq;
serial = sp->hdr.serial;
last = sp->hdr.flags & RXRPC_LAST_PACKET;
/* Barrier against rxrpc_input_data(). */ if (after(tseq, call->rx_consumed))
smp_store_release(&call->rx_consumed, tseq);
rxrpc_free_skb(skb, rxrpc_skb_put_rotate);
trace_rxrpc_receive(call, last ? rxrpc_receive_rotate_last : rxrpc_receive_rotate,
serial, call->rx_consumed);
if (last)
set_bit(RXRPC_CALL_RECVMSG_READ_ALL, &call->flags);
/* Check to see if there's an ACK that needs sending. */
acked = atomic_add_return(call->rx_consumed - old_consumed,
&call->ackr_nr_consumed); if (acked > 8 &&
!test_and_set_bit(RXRPC_CALL_RX_IS_IDLE, &call->flags))
rxrpc_poke_call(call, rxrpc_call_poke_idle);
}
if (rxrpc_call_has_failed(call)) {
seq = call->ackr_window - 1;
ret = -EIO; goto done;
}
if (test_bit(RXRPC_CALL_RECVMSG_READ_ALL, &call->flags)) {
seq = call->ackr_window - 1;
ret = 1; goto done;
}
/* No one else can be removing stuff from the queue, so we shouldn't *needtheRxlocktowalkit.
*/
skb = skb_peek(&call->recvmsg_queue); while (skb) {
rxrpc_see_skb(skb, rxrpc_skb_see_recvmsg);
sp = rxrpc_skb(skb);
seq = sp->hdr.seq;
if (!(flags & MSG_PEEK))
trace_rxrpc_receive(call, rxrpc_receive_front,
sp->hdr.serial, seq);
/* We have to handle short, empty and used-up DATA packets. */
remain = len - *_offset;
copy = rx_pkt_len; if (copy > remain)
copy = remain; if (copy > 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 */
rx_pkt_offset += copy;
rx_pkt_len -= copy;
*_offset += copy;
}
if (rx_pkt_len > 0) {
trace_rxrpc_recvdata(call, rxrpc_recvmsg_full, seq,
rx_pkt_offset, rx_pkt_len, 0);
ASSERTCMP(*_offset, ==, len);
ret = 0; break;
}
/* The whole packet has been transferred. */ if (sp->hdr.flags & RXRPC_LAST_PACKET)
ret = 1;
rx_pkt_offset = 0;
rx_pkt_len = 0;
skb = skb_peek_next(skb, &call->recvmsg_queue);
if (!(flags & MSG_PEEK))
rxrpc_rotate_rx_window(call);
/* Return immediately if a client socket has no outstanding calls */ if (RB_EMPTY_ROOT(&rx->calls) &&
list_empty(&rx->recvmsg_q) &&
skb_queue_empty_lockless(&rx->recvmsg_oobq) &&
rx->sk.sk_state != RXRPC_SERVER_LISTENING) {
release_sock(&rx->sk); return -EAGAIN;
}
if (list_empty(&rx->recvmsg_q)) {
ret = -EWOULDBLOCK; if (timeo == 0) {
call = NULL; goto error_no_call;
}
release_sock(&rx->sk);
/* Wait for something to happen */
prepare_to_wait_exclusive(sk_sleep(&rx->sk), &wait,
TASK_INTERRUPTIBLE);
ret = sock_error(&rx->sk); if (ret) goto wait_error;
/* Deal with OOB messages before we consider getting normal data. */ if (!skb_queue_empty_lockless(&rx->recvmsg_oobq)) {
ret = rxrpc_recvmsg_oob(sock, msg, flags);
release_sock(&rx->sk); if (ret == -EAGAIN) goto try_again; goto error_no_call;
}
/* Find the next call and dequeue it if we're not just peeking. If we *dodequeueit,thatcomeswitharefthatwewillneedtorelease. *Wealsowanttoweedoutcallsthatgotrequeuedwhilstwewere *shovellingdataout.
*/
spin_lock_irq(&rx->recvmsg_lock);
l = rx->recvmsg_q.next;
call = list_entry(l, struct rxrpc_call, recvmsg_link);
/* We're going to drop the socket lock, so we need to lock the call *againstinterferencebysendmsg.
*/ if (!mutex_trylock(&call->user_mutex)) {
ret = -EWOULDBLOCK; if (flags & MSG_DONTWAIT) goto error_requeue_call;
ret = -ERESTARTSYS; if (mutex_lock_interruptible(&call->user_mutex) < 0) goto error_requeue_call;
}
release_sock(&rx->sk);
if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) {
rxrpc_see_call(call, rxrpc_call_see_already_released);
mutex_unlock(&call->user_mutex); if (!(flags & MSG_PEEK))
rxrpc_put_call(call, rxrpc_call_put_recvmsg); goto try_again;
}
ret = rxrpc_recvmsg_user_id(call, msg, flags); if (ret < 0) goto error_unlock_call;
if (msg->msg_name && call->peer) {
size_t len = sizeof(call->dest_srx);
ret = rxrpc_recvmsg_data(sock, call, NULL, iter, *_len, 0, &offset);
*_len -= offset; if (ret == -EIO) goto call_failed; if (ret < 0) goto out;
/* We can only reach here with a partially full buffer if we have *reachedtheendofthedata.Wemustotherwisehaveafullbuffer *orhavebeengiven-EAGAIN.
*/ if (ret == 1) { if (iov_iter_count(iter) > 0) goto short_data; if (!want_more) goto read_phase_complete;
ret = 0; goto out;
}
if (!want_more) goto excess_data; goto out;
read_phase_complete:
ret = 1;
out: if (_service)
*_service = call->dest_srx.srx_service;
mutex_unlock(&call->user_mutex);
_leave(" = %d [%zu,%d]", ret, iov_iter_count(iter), *_abort); return ret;
short_data:
trace_rxrpc_abort(call->debug_id, rxrpc_recvmsg_short_data,
call->cid, call->call_id, call->rx_consumed, 0, -EBADMSG);
ret = -EBADMSG; goto out;
excess_data:
trace_rxrpc_abort(call->debug_id, rxrpc_recvmsg_excess_data,
call->cid, call->call_id, call->rx_consumed, 0, -EMSGSIZE);
ret = -EMSGSIZE; goto out;
call_failed:
*_abort = call->abort_code;
ret = call->error; if (call->completion == RXRPC_CALL_SUCCEEDED) {
ret = 1; if (iov_iter_count(iter) > 0)
ret = -ECONNRESET;
} goto out;
}
EXPORT_SYMBOL(rxrpc_kernel_recv_data);
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-09-27)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.