Skip to content

Commit f4919ff

Browse files
lxindavem330
authored andcommitted
tipc: keep the skb in rcv queue until the whole data is read
Currently, when userspace reads a datagram with a buffer that is smaller than this datagram, the data will be truncated and only part of it can be received by users. It doesn't seem right that users don't know the datagram size and have to use a huge buffer to read it to avoid the truncation. This patch to fix it by keeping the skb in rcv queue until the whole data is read by users. Only the last msg of the datagram will be marked with MSG_EOR, just as TCP/SCTP does. Note that this will work as above only when MSG_EOR is set in the flags parameter of recvmsg(), so that it won't break any old user applications. Signed-off-by: Xin Long <[email protected]> Acked-by: Jon Maloy <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 5242b0c commit f4919ff

File tree

1 file changed

+27
-9
lines changed

1 file changed

+27
-9
lines changed

net/tipc/socket.c

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1880,6 +1880,7 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m,
18801880
bool connected = !tipc_sk_type_connectionless(sk);
18811881
struct tipc_sock *tsk = tipc_sk(sk);
18821882
int rc, err, hlen, dlen, copy;
1883+
struct tipc_skb_cb *skb_cb;
18831884
struct sk_buff_head xmitq;
18841885
struct tipc_msg *hdr;
18851886
struct sk_buff *skb;
@@ -1903,6 +1904,7 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m,
19031904
if (unlikely(rc))
19041905
goto exit;
19051906
skb = skb_peek(&sk->sk_receive_queue);
1907+
skb_cb = TIPC_SKB_CB(skb);
19061908
hdr = buf_msg(skb);
19071909
dlen = msg_data_sz(hdr);
19081910
hlen = msg_hdr_sz(hdr);
@@ -1922,18 +1924,33 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m,
19221924

19231925
/* Capture data if non-error msg, otherwise just set return value */
19241926
if (likely(!err)) {
1925-
copy = min_t(int, dlen, buflen);
1926-
if (unlikely(copy != dlen))
1927-
m->msg_flags |= MSG_TRUNC;
1928-
rc = skb_copy_datagram_msg(skb, hlen, m, copy);
1927+
int offset = skb_cb->bytes_read;
1928+
1929+
copy = min_t(int, dlen - offset, buflen);
1930+
rc = skb_copy_datagram_msg(skb, hlen + offset, m, copy);
1931+
if (unlikely(rc))
1932+
goto exit;
1933+
if (unlikely(offset + copy < dlen)) {
1934+
if (flags & MSG_EOR) {
1935+
if (!(flags & MSG_PEEK))
1936+
skb_cb->bytes_read = offset + copy;
1937+
} else {
1938+
m->msg_flags |= MSG_TRUNC;
1939+
skb_cb->bytes_read = 0;
1940+
}
1941+
} else {
1942+
if (flags & MSG_EOR)
1943+
m->msg_flags |= MSG_EOR;
1944+
skb_cb->bytes_read = 0;
1945+
}
19291946
} else {
19301947
copy = 0;
19311948
rc = 0;
1932-
if (err != TIPC_CONN_SHUTDOWN && connected && !m->msg_control)
1949+
if (err != TIPC_CONN_SHUTDOWN && connected && !m->msg_control) {
19331950
rc = -ECONNRESET;
1951+
goto exit;
1952+
}
19341953
}
1935-
if (unlikely(rc))
1936-
goto exit;
19371954

19381955
/* Mark message as group event if applicable */
19391956
if (unlikely(grp_evt)) {
@@ -1956,9 +1973,10 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m,
19561973
tipc_node_distr_xmit(sock_net(sk), &xmitq);
19571974
}
19581975

1959-
tsk_advance_rx_queue(sk);
1976+
if (!skb_cb->bytes_read)
1977+
tsk_advance_rx_queue(sk);
19601978

1961-
if (likely(!connected))
1979+
if (likely(!connected) || skb_cb->bytes_read)
19621980
goto exit;
19631981

19641982
/* Send connection flow control advertisement when applicable */

0 commit comments

Comments
 (0)