tipc: fix retrans failure due to wrong destination
commitabc9b4e054
upstream. When a user message is sent, TIPC will check if the socket has faced a congestion at link layer. If that happens, it will make a sleep to wait for the congestion to disappear. This leaves a gap for other users to take over the socket (e.g. multi threads) since the socket is released as well. Also, in case of connectionless (e.g. SOCK_RDM), user is free to send messages to various destinations (e.g. via 'sendto()'), then the socket's preformatted header has to be updated correspondingly prior to the actual payload message building. Unfortunately, the latter action is done before the first action which causes a condition issue that the destination of a certain message can be modified incorrectly in the middle, leading to wrong destination when that message is built. Consequently, when the message is sent to the link layer, it gets stuck there forever because the peer node will simply reject it. After a number of retransmission attempts, the link is eventually taken down and the retransmission failure is reported. This commit fixes the problem by rearranging the order of actions to prevent the race condition from occurring, so the message building is 'atomic' and its header will not be modified by anyone. Fixes:365ad353c2
("tipc: reduce risk of user starvation during link congestion") Acked-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: Tuong Lien <tuong.t.lien@dektech.com.au> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
f83b957029
commit
4e7c55aabf
@ -1306,8 +1306,8 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen)
|
||||
struct tipc_msg *hdr = &tsk->phdr;
|
||||
struct tipc_name_seq *seq;
|
||||
struct sk_buff_head pkts;
|
||||
u32 dport, dnode = 0;
|
||||
u32 type, inst;
|
||||
u32 dport = 0, dnode = 0;
|
||||
u32 type = 0, inst = 0;
|
||||
int mtu, rc;
|
||||
|
||||
if (unlikely(dlen > TIPC_MAX_USER_MSG_SIZE))
|
||||
@ -1360,23 +1360,11 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen)
|
||||
type = dest->addr.name.name.type;
|
||||
inst = dest->addr.name.name.instance;
|
||||
dnode = dest->addr.name.domain;
|
||||
msg_set_type(hdr, TIPC_NAMED_MSG);
|
||||
msg_set_hdr_sz(hdr, NAMED_H_SIZE);
|
||||
msg_set_nametype(hdr, type);
|
||||
msg_set_nameinst(hdr, inst);
|
||||
msg_set_lookup_scope(hdr, tipc_node2scope(dnode));
|
||||
dport = tipc_nametbl_translate(net, type, inst, &dnode);
|
||||
msg_set_destnode(hdr, dnode);
|
||||
msg_set_destport(hdr, dport);
|
||||
if (unlikely(!dport && !dnode))
|
||||
return -EHOSTUNREACH;
|
||||
} else if (dest->addrtype == TIPC_ADDR_ID) {
|
||||
dnode = dest->addr.id.node;
|
||||
msg_set_type(hdr, TIPC_DIRECT_MSG);
|
||||
msg_set_lookup_scope(hdr, 0);
|
||||
msg_set_destnode(hdr, dnode);
|
||||
msg_set_destport(hdr, dest->addr.id.ref);
|
||||
msg_set_hdr_sz(hdr, BASIC_H_SIZE);
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1387,6 +1375,22 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen)
|
||||
if (unlikely(rc))
|
||||
return rc;
|
||||
|
||||
if (dest->addrtype == TIPC_ADDR_NAME) {
|
||||
msg_set_type(hdr, TIPC_NAMED_MSG);
|
||||
msg_set_hdr_sz(hdr, NAMED_H_SIZE);
|
||||
msg_set_nametype(hdr, type);
|
||||
msg_set_nameinst(hdr, inst);
|
||||
msg_set_lookup_scope(hdr, tipc_node2scope(dnode));
|
||||
msg_set_destnode(hdr, dnode);
|
||||
msg_set_destport(hdr, dport);
|
||||
} else { /* TIPC_ADDR_ID */
|
||||
msg_set_type(hdr, TIPC_DIRECT_MSG);
|
||||
msg_set_lookup_scope(hdr, 0);
|
||||
msg_set_destnode(hdr, dnode);
|
||||
msg_set_destport(hdr, dest->addr.id.ref);
|
||||
msg_set_hdr_sz(hdr, BASIC_H_SIZE);
|
||||
}
|
||||
|
||||
__skb_queue_head_init(&pkts);
|
||||
mtu = tipc_node_get_mtu(net, dnode, tsk->portid);
|
||||
rc = tipc_msg_build(hdr, m, 0, dlen, mtu, &pkts);
|
||||
|
Loading…
Reference in New Issue
Block a user