diff options
| author | Jon Maloy <jon.maloy@ericsson.com> | 2017-10-13 05:04:22 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2017-10-13 11:46:00 -0400 |
| commit | a80ae5306a7346d4e52f59462878beb8362f4bbd (patch) | |
| tree | c81696b3bf35b844513994379571f954e0d631e8 /net/tipc | |
| parent | f70d37b796241f617107d5585ee96a7e1b660b63 (diff) | |
tipc: improve destination linked list
We often see a need for a linked list of destination identities,
sometimes containing a port number, sometimes a node identity, and
sometimes both. The currently defined struct u32_list is not generic
enough to cover all cases, so we extend it to contain two u32 integers
and rename it to struct tipc_dest_list.
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc')
| -rw-r--r-- | net/tipc/bcast.c | 18 | ||||
| -rw-r--r-- | net/tipc/name_table.c | 89 | ||||
| -rw-r--r-- | net/tipc/name_table.h | 22 | ||||
| -rw-r--r-- | net/tipc/socket.c | 12 |
4 files changed, 74 insertions, 67 deletions
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index a140dd4a84af..329325bd553e 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c | |||
| @@ -258,20 +258,20 @@ static int tipc_bcast_xmit(struct net *net, struct sk_buff_head *pkts, | |||
| 258 | static int tipc_rcast_xmit(struct net *net, struct sk_buff_head *pkts, | 258 | static int tipc_rcast_xmit(struct net *net, struct sk_buff_head *pkts, |
| 259 | struct tipc_nlist *dests, u16 *cong_link_cnt) | 259 | struct tipc_nlist *dests, u16 *cong_link_cnt) |
| 260 | { | 260 | { |
| 261 | struct tipc_dest *dst, *tmp; | ||
| 261 | struct sk_buff_head _pkts; | 262 | struct sk_buff_head _pkts; |
| 262 | struct u32_item *n, *tmp; | 263 | u32 dnode, selector; |
| 263 | u32 dst, selector; | ||
| 264 | 264 | ||
| 265 | selector = msg_link_selector(buf_msg(skb_peek(pkts))); | 265 | selector = msg_link_selector(buf_msg(skb_peek(pkts))); |
| 266 | skb_queue_head_init(&_pkts); | 266 | skb_queue_head_init(&_pkts); |
| 267 | 267 | ||
| 268 | list_for_each_entry_safe(n, tmp, &dests->list, list) { | 268 | list_for_each_entry_safe(dst, tmp, &dests->list, list) { |
| 269 | dst = n->value; | 269 | dnode = dst->node; |
| 270 | if (!tipc_msg_pskb_copy(dst, pkts, &_pkts)) | 270 | if (!tipc_msg_pskb_copy(dnode, pkts, &_pkts)) |
| 271 | return -ENOMEM; | 271 | return -ENOMEM; |
| 272 | 272 | ||
| 273 | /* Any other return value than -ELINKCONG is ignored */ | 273 | /* Any other return value than -ELINKCONG is ignored */ |
| 274 | if (tipc_node_xmit(net, &_pkts, dst, selector) == -ELINKCONG) | 274 | if (tipc_node_xmit(net, &_pkts, dnode, selector) == -ELINKCONG) |
| 275 | (*cong_link_cnt)++; | 275 | (*cong_link_cnt)++; |
| 276 | } | 276 | } |
| 277 | return 0; | 277 | return 0; |
| @@ -554,7 +554,7 @@ void tipc_nlist_add(struct tipc_nlist *nl, u32 node) | |||
| 554 | { | 554 | { |
| 555 | if (node == nl->self) | 555 | if (node == nl->self) |
| 556 | nl->local = true; | 556 | nl->local = true; |
| 557 | else if (u32_push(&nl->list, node)) | 557 | else if (tipc_dest_push(&nl->list, node, 0)) |
| 558 | nl->remote++; | 558 | nl->remote++; |
| 559 | } | 559 | } |
| 560 | 560 | ||
| @@ -562,13 +562,13 @@ void tipc_nlist_del(struct tipc_nlist *nl, u32 node) | |||
| 562 | { | 562 | { |
| 563 | if (node == nl->self) | 563 | if (node == nl->self) |
| 564 | nl->local = false; | 564 | nl->local = false; |
| 565 | else if (u32_del(&nl->list, node)) | 565 | else if (tipc_dest_del(&nl->list, node, 0)) |
| 566 | nl->remote--; | 566 | nl->remote--; |
| 567 | } | 567 | } |
| 568 | 568 | ||
| 569 | void tipc_nlist_purge(struct tipc_nlist *nl) | 569 | void tipc_nlist_purge(struct tipc_nlist *nl) |
| 570 | { | 570 | { |
| 571 | u32_list_purge(&nl->list); | 571 | tipc_dest_list_purge(&nl->list); |
| 572 | nl->remote = 0; | 572 | nl->remote = 0; |
| 573 | nl->local = 0; | 573 | nl->local = 0; |
| 574 | } | 574 | } |
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index bd0aac87b41a..76bd2777baaf 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c | |||
| @@ -634,7 +634,7 @@ int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper, | |||
| 634 | info = sseq->info; | 634 | info = sseq->info; |
| 635 | list_for_each_entry(publ, &info->node_list, node_list) { | 635 | list_for_each_entry(publ, &info->node_list, node_list) { |
| 636 | if (publ->scope <= limit) | 636 | if (publ->scope <= limit) |
| 637 | u32_push(dports, publ->ref); | 637 | tipc_dest_push(dports, 0, publ->ref); |
| 638 | } | 638 | } |
| 639 | 639 | ||
| 640 | if (info->cluster_list_size != info->node_list_size) | 640 | if (info->cluster_list_size != info->node_list_size) |
| @@ -1057,78 +1057,79 @@ int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 1057 | return skb->len; | 1057 | return skb->len; |
| 1058 | } | 1058 | } |
| 1059 | 1059 | ||
| 1060 | bool u32_find(struct list_head *l, u32 value) | 1060 | struct tipc_dest *tipc_dest_find(struct list_head *l, u32 node, u32 port) |
| 1061 | { | 1061 | { |
| 1062 | struct u32_item *item; | 1062 | u64 value = (u64)node << 32 | port; |
| 1063 | struct tipc_dest *dst; | ||
| 1063 | 1064 | ||
| 1064 | list_for_each_entry(item, l, list) { | 1065 | list_for_each_entry(dst, l, list) { |
| 1065 | if (item->value == value) | 1066 | if (dst->value != value) |
| 1066 | return true; | 1067 | continue; |
| 1068 | return dst; | ||
| 1067 | } | 1069 | } |
| 1068 | return false; | 1070 | return NULL; |
| 1069 | } | 1071 | } |
| 1070 | 1072 | ||
| 1071 | bool u32_push(struct list_head *l, u32 value) | 1073 | bool tipc_dest_push(struct list_head *l, u32 node, u32 port) |
| 1072 | { | 1074 | { |
| 1073 | struct u32_item *item; | 1075 | u64 value = (u64)node << 32 | port; |
| 1076 | struct tipc_dest *dst; | ||
| 1074 | 1077 | ||
| 1075 | list_for_each_entry(item, l, list) { | 1078 | if (tipc_dest_find(l, node, port)) |
| 1076 | if (item->value == value) | ||
| 1077 | return false; | ||
| 1078 | } | ||
| 1079 | item = kmalloc(sizeof(*item), GFP_ATOMIC); | ||
| 1080 | if (unlikely(!item)) | ||
| 1081 | return false; | 1079 | return false; |
| 1082 | 1080 | ||
| 1083 | item->value = value; | 1081 | dst = kmalloc(sizeof(*dst), GFP_ATOMIC); |
| 1084 | list_add(&item->list, l); | 1082 | if (unlikely(!dst)) |
| 1083 | return false; | ||
| 1084 | dst->value = value; | ||
| 1085 | list_add(&dst->list, l); | ||
| 1085 | return true; | 1086 | return true; |
| 1086 | } | 1087 | } |
| 1087 | 1088 | ||
| 1088 | u32 u32_pop(struct list_head *l) | 1089 | bool tipc_dest_pop(struct list_head *l, u32 *node, u32 *port) |
| 1089 | { | 1090 | { |
| 1090 | struct u32_item *item; | 1091 | struct tipc_dest *dst; |
| 1091 | u32 value = 0; | ||
| 1092 | 1092 | ||
| 1093 | if (list_empty(l)) | 1093 | if (list_empty(l)) |
| 1094 | return 0; | 1094 | return false; |
| 1095 | item = list_first_entry(l, typeof(*item), list); | 1095 | dst = list_first_entry(l, typeof(*dst), list); |
| 1096 | value = item->value; | 1096 | if (port) |
| 1097 | list_del(&item->list); | 1097 | *port = dst->port; |
| 1098 | kfree(item); | 1098 | if (node) |
| 1099 | return value; | 1099 | *node = dst->node; |
| 1100 | list_del(&dst->list); | ||
| 1101 | kfree(dst); | ||
| 1102 | return true; | ||
| 1100 | } | 1103 | } |
| 1101 | 1104 | ||
| 1102 | bool u32_del(struct list_head *l, u32 value) | 1105 | bool tipc_dest_del(struct list_head *l, u32 node, u32 port) |
| 1103 | { | 1106 | { |
| 1104 | struct u32_item *item, *tmp; | 1107 | struct tipc_dest *dst; |
| 1105 | 1108 | ||
| 1106 | list_for_each_entry_safe(item, tmp, l, list) { | 1109 | dst = tipc_dest_find(l, node, port); |
| 1107 | if (item->value != value) | 1110 | if (!dst) |
| 1108 | continue; | 1111 | return false; |
| 1109 | list_del(&item->list); | 1112 | list_del(&dst->list); |
| 1110 | kfree(item); | 1113 | kfree(dst); |
| 1111 | return true; | 1114 | return true; |
| 1112 | } | ||
| 1113 | return false; | ||
| 1114 | } | 1115 | } |
| 1115 | 1116 | ||
| 1116 | void u32_list_purge(struct list_head *l) | 1117 | void tipc_dest_list_purge(struct list_head *l) |
| 1117 | { | 1118 | { |
| 1118 | struct u32_item *item, *tmp; | 1119 | struct tipc_dest *dst, *tmp; |
| 1119 | 1120 | ||
| 1120 | list_for_each_entry_safe(item, tmp, l, list) { | 1121 | list_for_each_entry_safe(dst, tmp, l, list) { |
| 1121 | list_del(&item->list); | 1122 | list_del(&dst->list); |
| 1122 | kfree(item); | 1123 | kfree(dst); |
| 1123 | } | 1124 | } |
| 1124 | } | 1125 | } |
| 1125 | 1126 | ||
| 1126 | int u32_list_len(struct list_head *l) | 1127 | int tipc_dest_list_len(struct list_head *l) |
| 1127 | { | 1128 | { |
| 1128 | struct u32_item *item; | 1129 | struct tipc_dest *dst; |
| 1129 | int i = 0; | 1130 | int i = 0; |
| 1130 | 1131 | ||
| 1131 | list_for_each_entry(item, l, list) { | 1132 | list_for_each_entry(dst, l, list) { |
| 1132 | i++; | 1133 | i++; |
| 1133 | } | 1134 | } |
| 1134 | return i; | 1135 | return i; |
diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h index 6ebdeb1d84a5..d121175a92b5 100644 --- a/net/tipc/name_table.h +++ b/net/tipc/name_table.h | |||
| @@ -120,16 +120,22 @@ void tipc_nametbl_unsubscribe(struct tipc_subscription *s); | |||
| 120 | int tipc_nametbl_init(struct net *net); | 120 | int tipc_nametbl_init(struct net *net); |
| 121 | void tipc_nametbl_stop(struct net *net); | 121 | void tipc_nametbl_stop(struct net *net); |
| 122 | 122 | ||
| 123 | struct u32_item { | 123 | struct tipc_dest { |
| 124 | struct list_head list; | 124 | struct list_head list; |
| 125 | u32 value; | 125 | union { |
| 126 | struct { | ||
| 127 | u32 port; | ||
| 128 | u32 node; | ||
| 129 | }; | ||
| 130 | u64 value; | ||
| 131 | }; | ||
| 126 | }; | 132 | }; |
| 127 | 133 | ||
| 128 | bool u32_push(struct list_head *l, u32 value); | 134 | struct tipc_dest *tipc_dest_find(struct list_head *l, u32 node, u32 port); |
| 129 | u32 u32_pop(struct list_head *l); | 135 | bool tipc_dest_push(struct list_head *l, u32 node, u32 port); |
| 130 | bool u32_find(struct list_head *l, u32 value); | 136 | bool tipc_dest_pop(struct list_head *l, u32 *node, u32 *port); |
| 131 | bool u32_del(struct list_head *l, u32 value); | 137 | bool tipc_dest_del(struct list_head *l, u32 node, u32 port); |
| 132 | void u32_list_purge(struct list_head *l); | 138 | void tipc_dest_list_purge(struct list_head *l); |
| 133 | int u32_list_len(struct list_head *l); | 139 | int tipc_dest_list_len(struct list_head *l); |
| 134 | 140 | ||
| 135 | #endif | 141 | #endif |
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index c7c674934474..daf7c4df4531 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
| @@ -565,7 +565,7 @@ static int tipc_release(struct socket *sock) | |||
| 565 | 565 | ||
| 566 | /* Reject any messages that accumulated in backlog queue */ | 566 | /* Reject any messages that accumulated in backlog queue */ |
| 567 | release_sock(sk); | 567 | release_sock(sk); |
| 568 | u32_list_purge(&tsk->cong_links); | 568 | tipc_dest_list_purge(&tsk->cong_links); |
| 569 | tsk->cong_link_cnt = 0; | 569 | tsk->cong_link_cnt = 0; |
| 570 | call_rcu(&tsk->rcu, tipc_sk_callback); | 570 | call_rcu(&tsk->rcu, tipc_sk_callback); |
| 571 | sock->sk = NULL; | 571 | sock->sk = NULL; |
| @@ -826,8 +826,7 @@ void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq, | |||
| 826 | tipc_nametbl_mc_translate(net, | 826 | tipc_nametbl_mc_translate(net, |
| 827 | msg_nametype(msg), msg_namelower(msg), | 827 | msg_nametype(msg), msg_namelower(msg), |
| 828 | msg_nameupper(msg), scope, &dports); | 828 | msg_nameupper(msg), scope, &dports); |
| 829 | portid = u32_pop(&dports); | 829 | while (tipc_dest_pop(&dports, NULL, &portid)) { |
| 830 | for (; portid; portid = u32_pop(&dports)) { | ||
| 831 | _skb = __pskb_copy(skb, hsz, GFP_ATOMIC); | 830 | _skb = __pskb_copy(skb, hsz, GFP_ATOMIC); |
| 832 | if (_skb) { | 831 | if (_skb) { |
| 833 | msg_set_destport(buf_msg(_skb), portid); | 832 | msg_set_destport(buf_msg(_skb), portid); |
| @@ -1000,7 +999,8 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen) | |||
| 1000 | } | 999 | } |
| 1001 | 1000 | ||
| 1002 | /* Block or return if destination link is congested */ | 1001 | /* Block or return if destination link is congested */ |
| 1003 | rc = tipc_wait_for_cond(sock, &timeout, !u32_find(clinks, dnode)); | 1002 | rc = tipc_wait_for_cond(sock, &timeout, |
| 1003 | !tipc_dest_find(clinks, dnode, 0)); | ||
| 1004 | if (unlikely(rc)) | 1004 | if (unlikely(rc)) |
| 1005 | return rc; | 1005 | return rc; |
| 1006 | 1006 | ||
| @@ -1012,7 +1012,7 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen) | |||
| 1012 | 1012 | ||
| 1013 | rc = tipc_node_xmit(net, &pkts, dnode, tsk->portid); | 1013 | rc = tipc_node_xmit(net, &pkts, dnode, tsk->portid); |
| 1014 | if (unlikely(rc == -ELINKCONG)) { | 1014 | if (unlikely(rc == -ELINKCONG)) { |
| 1015 | u32_push(clinks, dnode); | 1015 | tipc_dest_push(clinks, dnode, 0); |
| 1016 | tsk->cong_link_cnt++; | 1016 | tsk->cong_link_cnt++; |
| 1017 | rc = 0; | 1017 | rc = 0; |
| 1018 | } | 1018 | } |
| @@ -1549,7 +1549,7 @@ static void tipc_sk_proto_rcv(struct sock *sk, | |||
| 1549 | tipc_sk_conn_proto_rcv(tsk, skb, xmitq); | 1549 | tipc_sk_conn_proto_rcv(tsk, skb, xmitq); |
| 1550 | return; | 1550 | return; |
| 1551 | case SOCK_WAKEUP: | 1551 | case SOCK_WAKEUP: |
| 1552 | u32_del(&tsk->cong_links, msg_orignode(hdr)); | 1552 | tipc_dest_del(&tsk->cong_links, msg_orignode(hdr), 0); |
| 1553 | tsk->cong_link_cnt--; | 1553 | tsk->cong_link_cnt--; |
| 1554 | sk->sk_write_space(sk); | 1554 | sk->sk_write_space(sk); |
| 1555 | break; | 1555 | break; |
