diff options
Diffstat (limited to 'net/tipc/link.c')
| -rw-r--r-- | net/tipc/link.c | 104 |
1 files changed, 60 insertions, 44 deletions
diff --git a/net/tipc/link.c b/net/tipc/link.c index ebf338f7b14e..5ed4b4f7452d 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c | |||
| @@ -92,7 +92,8 @@ static int link_recv_changeover_msg(struct link **l_ptr, struct sk_buff **buf); | |||
| 92 | static void link_set_supervision_props(struct link *l_ptr, u32 tolerance); | 92 | static void link_set_supervision_props(struct link *l_ptr, u32 tolerance); |
| 93 | static int link_send_sections_long(struct tipc_port *sender, | 93 | static int link_send_sections_long(struct tipc_port *sender, |
| 94 | struct iovec const *msg_sect, | 94 | struct iovec const *msg_sect, |
| 95 | u32 num_sect, u32 destnode); | 95 | u32 num_sect, unsigned int total_len, |
| 96 | u32 destnode); | ||
| 96 | static void link_check_defragm_bufs(struct link *l_ptr); | 97 | static void link_check_defragm_bufs(struct link *l_ptr); |
| 97 | static void link_state_event(struct link *l_ptr, u32 event); | 98 | static void link_state_event(struct link *l_ptr, u32 event); |
| 98 | static void link_reset_statistics(struct link *l_ptr); | 99 | static void link_reset_statistics(struct link *l_ptr); |
| @@ -842,6 +843,25 @@ static void link_add_to_outqueue(struct link *l_ptr, | |||
| 842 | l_ptr->stats.max_queue_sz = l_ptr->out_queue_size; | 843 | l_ptr->stats.max_queue_sz = l_ptr->out_queue_size; |
| 843 | } | 844 | } |
| 844 | 845 | ||
| 846 | static void link_add_chain_to_outqueue(struct link *l_ptr, | ||
| 847 | struct sk_buff *buf_chain, | ||
| 848 | u32 long_msgno) | ||
| 849 | { | ||
| 850 | struct sk_buff *buf; | ||
| 851 | struct tipc_msg *msg; | ||
| 852 | |||
| 853 | if (!l_ptr->next_out) | ||
| 854 | l_ptr->next_out = buf_chain; | ||
| 855 | while (buf_chain) { | ||
| 856 | buf = buf_chain; | ||
| 857 | buf_chain = buf_chain->next; | ||
| 858 | |||
| 859 | msg = buf_msg(buf); | ||
| 860 | msg_set_long_msgno(msg, long_msgno); | ||
| 861 | link_add_to_outqueue(l_ptr, buf, msg); | ||
| 862 | } | ||
| 863 | } | ||
| 864 | |||
| 845 | /* | 865 | /* |
| 846 | * tipc_link_send_buf() is the 'full path' for messages, called from | 866 | * tipc_link_send_buf() is the 'full path' for messages, called from |
| 847 | * inside TIPC when the 'fast path' in tipc_send_buf | 867 | * inside TIPC when the 'fast path' in tipc_send_buf |
| @@ -864,8 +884,9 @@ int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf) | |||
| 864 | 884 | ||
| 865 | if (unlikely(queue_size >= queue_limit)) { | 885 | if (unlikely(queue_size >= queue_limit)) { |
| 866 | if (imp <= TIPC_CRITICAL_IMPORTANCE) { | 886 | if (imp <= TIPC_CRITICAL_IMPORTANCE) { |
| 867 | return link_schedule_port(l_ptr, msg_origport(msg), | 887 | link_schedule_port(l_ptr, msg_origport(msg), size); |
| 868 | size); | 888 | buf_discard(buf); |
| 889 | return -ELINKCONG; | ||
| 869 | } | 890 | } |
| 870 | buf_discard(buf); | 891 | buf_discard(buf); |
| 871 | if (imp > CONN_MANAGER) { | 892 | if (imp > CONN_MANAGER) { |
| @@ -1042,6 +1063,7 @@ int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode) | |||
| 1042 | int tipc_link_send_sections_fast(struct tipc_port *sender, | 1063 | int tipc_link_send_sections_fast(struct tipc_port *sender, |
| 1043 | struct iovec const *msg_sect, | 1064 | struct iovec const *msg_sect, |
| 1044 | const u32 num_sect, | 1065 | const u32 num_sect, |
| 1066 | unsigned int total_len, | ||
| 1045 | u32 destaddr) | 1067 | u32 destaddr) |
| 1046 | { | 1068 | { |
| 1047 | struct tipc_msg *hdr = &sender->phdr; | 1069 | struct tipc_msg *hdr = &sender->phdr; |
| @@ -1057,8 +1079,8 @@ again: | |||
| 1057 | * (Must not hold any locks while building message.) | 1079 | * (Must not hold any locks while building message.) |
| 1058 | */ | 1080 | */ |
| 1059 | 1081 | ||
| 1060 | res = tipc_msg_build(hdr, msg_sect, num_sect, sender->max_pkt, | 1082 | res = tipc_msg_build(hdr, msg_sect, num_sect, total_len, |
| 1061 | !sender->user_port, &buf); | 1083 | sender->max_pkt, !sender->user_port, &buf); |
| 1062 | 1084 | ||
| 1063 | read_lock_bh(&tipc_net_lock); | 1085 | read_lock_bh(&tipc_net_lock); |
| 1064 | node = tipc_node_find(destaddr); | 1086 | node = tipc_node_find(destaddr); |
| @@ -1069,8 +1091,6 @@ again: | |||
| 1069 | if (likely(buf)) { | 1091 | if (likely(buf)) { |
| 1070 | res = link_send_buf_fast(l_ptr, buf, | 1092 | res = link_send_buf_fast(l_ptr, buf, |
| 1071 | &sender->max_pkt); | 1093 | &sender->max_pkt); |
| 1072 | if (unlikely(res < 0)) | ||
| 1073 | buf_discard(buf); | ||
| 1074 | exit: | 1094 | exit: |
| 1075 | tipc_node_unlock(node); | 1095 | tipc_node_unlock(node); |
| 1076 | read_unlock_bh(&tipc_net_lock); | 1096 | read_unlock_bh(&tipc_net_lock); |
| @@ -1105,7 +1125,8 @@ exit: | |||
| 1105 | goto again; | 1125 | goto again; |
| 1106 | 1126 | ||
| 1107 | return link_send_sections_long(sender, msg_sect, | 1127 | return link_send_sections_long(sender, msg_sect, |
| 1108 | num_sect, destaddr); | 1128 | num_sect, total_len, |
| 1129 | destaddr); | ||
| 1109 | } | 1130 | } |
| 1110 | tipc_node_unlock(node); | 1131 | tipc_node_unlock(node); |
| 1111 | } | 1132 | } |
| @@ -1117,7 +1138,7 @@ exit: | |||
| 1117 | return tipc_reject_msg(buf, TIPC_ERR_NO_NODE); | 1138 | return tipc_reject_msg(buf, TIPC_ERR_NO_NODE); |
| 1118 | if (res >= 0) | 1139 | if (res >= 0) |
| 1119 | return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect, | 1140 | return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect, |
| 1120 | TIPC_ERR_NO_NODE); | 1141 | total_len, TIPC_ERR_NO_NODE); |
| 1121 | return res; | 1142 | return res; |
| 1122 | } | 1143 | } |
| 1123 | 1144 | ||
| @@ -1138,12 +1159,13 @@ exit: | |||
| 1138 | static int link_send_sections_long(struct tipc_port *sender, | 1159 | static int link_send_sections_long(struct tipc_port *sender, |
| 1139 | struct iovec const *msg_sect, | 1160 | struct iovec const *msg_sect, |
| 1140 | u32 num_sect, | 1161 | u32 num_sect, |
| 1162 | unsigned int total_len, | ||
| 1141 | u32 destaddr) | 1163 | u32 destaddr) |
| 1142 | { | 1164 | { |
| 1143 | struct link *l_ptr; | 1165 | struct link *l_ptr; |
| 1144 | struct tipc_node *node; | 1166 | struct tipc_node *node; |
| 1145 | struct tipc_msg *hdr = &sender->phdr; | 1167 | struct tipc_msg *hdr = &sender->phdr; |
| 1146 | u32 dsz = msg_data_sz(hdr); | 1168 | u32 dsz = total_len; |
| 1147 | u32 max_pkt, fragm_sz, rest; | 1169 | u32 max_pkt, fragm_sz, rest; |
| 1148 | struct tipc_msg fragm_hdr; | 1170 | struct tipc_msg fragm_hdr; |
| 1149 | struct sk_buff *buf, *buf_chain, *prev; | 1171 | struct sk_buff *buf, *buf_chain, *prev; |
| @@ -1169,7 +1191,6 @@ again: | |||
| 1169 | 1191 | ||
| 1170 | tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, | 1192 | tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, |
| 1171 | INT_H_SIZE, msg_destnode(hdr)); | 1193 | INT_H_SIZE, msg_destnode(hdr)); |
| 1172 | msg_set_link_selector(&fragm_hdr, sender->ref); | ||
| 1173 | msg_set_size(&fragm_hdr, max_pkt); | 1194 | msg_set_size(&fragm_hdr, max_pkt); |
| 1174 | msg_set_fragm_no(&fragm_hdr, 1); | 1195 | msg_set_fragm_no(&fragm_hdr, 1); |
| 1175 | 1196 | ||
| @@ -1271,28 +1292,15 @@ reject: | |||
| 1271 | buf_discard(buf_chain); | 1292 | buf_discard(buf_chain); |
| 1272 | } | 1293 | } |
| 1273 | return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect, | 1294 | return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect, |
| 1274 | TIPC_ERR_NO_NODE); | 1295 | total_len, TIPC_ERR_NO_NODE); |
| 1275 | } | 1296 | } |
| 1276 | 1297 | ||
| 1277 | /* Append whole chain to send queue: */ | 1298 | /* Append chain of fragments to send queue & send them */ |
| 1278 | 1299 | ||
| 1279 | buf = buf_chain; | 1300 | l_ptr->long_msg_seq_no++; |
| 1280 | l_ptr->long_msg_seq_no = mod(l_ptr->long_msg_seq_no + 1); | 1301 | link_add_chain_to_outqueue(l_ptr, buf_chain, l_ptr->long_msg_seq_no); |
| 1281 | if (!l_ptr->next_out) | 1302 | l_ptr->stats.sent_fragments += fragm_no; |
| 1282 | l_ptr->next_out = buf_chain; | ||
| 1283 | l_ptr->stats.sent_fragmented++; | 1303 | l_ptr->stats.sent_fragmented++; |
| 1284 | while (buf) { | ||
| 1285 | struct sk_buff *next = buf->next; | ||
| 1286 | struct tipc_msg *msg = buf_msg(buf); | ||
| 1287 | |||
| 1288 | l_ptr->stats.sent_fragments++; | ||
| 1289 | msg_set_long_msgno(msg, l_ptr->long_msg_seq_no); | ||
| 1290 | link_add_to_outqueue(l_ptr, buf, msg); | ||
| 1291 | buf = next; | ||
| 1292 | } | ||
| 1293 | |||
| 1294 | /* Send it, if possible: */ | ||
| 1295 | |||
| 1296 | tipc_link_push_queue(l_ptr); | 1304 | tipc_link_push_queue(l_ptr); |
| 1297 | tipc_node_unlock(node); | 1305 | tipc_node_unlock(node); |
| 1298 | return dsz; | 1306 | return dsz; |
| @@ -2407,6 +2415,8 @@ void tipc_link_recv_bundle(struct sk_buff *buf) | |||
| 2407 | */ | 2415 | */ |
| 2408 | static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) | 2416 | static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) |
| 2409 | { | 2417 | { |
| 2418 | struct sk_buff *buf_chain = NULL; | ||
| 2419 | struct sk_buff *buf_chain_tail = (struct sk_buff *)&buf_chain; | ||
| 2410 | struct tipc_msg *inmsg = buf_msg(buf); | 2420 | struct tipc_msg *inmsg = buf_msg(buf); |
| 2411 | struct tipc_msg fragm_hdr; | 2421 | struct tipc_msg fragm_hdr; |
| 2412 | u32 insize = msg_size(inmsg); | 2422 | u32 insize = msg_size(inmsg); |
| @@ -2415,7 +2425,7 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) | |||
| 2415 | u32 rest = insize; | 2425 | u32 rest = insize; |
| 2416 | u32 pack_sz = l_ptr->max_pkt; | 2426 | u32 pack_sz = l_ptr->max_pkt; |
| 2417 | u32 fragm_sz = pack_sz - INT_H_SIZE; | 2427 | u32 fragm_sz = pack_sz - INT_H_SIZE; |
| 2418 | u32 fragm_no = 1; | 2428 | u32 fragm_no = 0; |
| 2419 | u32 destaddr; | 2429 | u32 destaddr; |
| 2420 | 2430 | ||
| 2421 | if (msg_short(inmsg)) | 2431 | if (msg_short(inmsg)) |
| @@ -2427,10 +2437,6 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) | |||
| 2427 | 2437 | ||
| 2428 | tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, | 2438 | tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, |
| 2429 | INT_H_SIZE, destaddr); | 2439 | INT_H_SIZE, destaddr); |
| 2430 | msg_set_link_selector(&fragm_hdr, msg_link_selector(inmsg)); | ||
| 2431 | msg_set_long_msgno(&fragm_hdr, mod(l_ptr->long_msg_seq_no++)); | ||
| 2432 | msg_set_fragm_no(&fragm_hdr, fragm_no); | ||
| 2433 | l_ptr->stats.sent_fragmented++; | ||
| 2434 | 2440 | ||
| 2435 | /* Chop up message: */ | 2441 | /* Chop up message: */ |
| 2436 | 2442 | ||
| @@ -2443,27 +2449,37 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) | |||
| 2443 | } | 2449 | } |
| 2444 | fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE); | 2450 | fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE); |
| 2445 | if (fragm == NULL) { | 2451 | if (fragm == NULL) { |
| 2446 | warn("Link unable to fragment message\n"); | 2452 | buf_discard(buf); |
| 2447 | dsz = -ENOMEM; | 2453 | while (buf_chain) { |
| 2448 | goto exit; | 2454 | buf = buf_chain; |
| 2455 | buf_chain = buf_chain->next; | ||
| 2456 | buf_discard(buf); | ||
| 2457 | } | ||
| 2458 | return -ENOMEM; | ||
| 2449 | } | 2459 | } |
| 2450 | msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE); | 2460 | msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE); |
| 2461 | fragm_no++; | ||
| 2462 | msg_set_fragm_no(&fragm_hdr, fragm_no); | ||
| 2451 | skb_copy_to_linear_data(fragm, &fragm_hdr, INT_H_SIZE); | 2463 | skb_copy_to_linear_data(fragm, &fragm_hdr, INT_H_SIZE); |
| 2452 | skb_copy_to_linear_data_offset(fragm, INT_H_SIZE, crs, | 2464 | skb_copy_to_linear_data_offset(fragm, INT_H_SIZE, crs, |
| 2453 | fragm_sz); | 2465 | fragm_sz); |
| 2454 | /* Send queued messages first, if any: */ | 2466 | buf_chain_tail->next = fragm; |
| 2467 | buf_chain_tail = fragm; | ||
| 2455 | 2468 | ||
| 2456 | l_ptr->stats.sent_fragments++; | ||
| 2457 | tipc_link_send_buf(l_ptr, fragm); | ||
| 2458 | if (!tipc_link_is_up(l_ptr)) | ||
| 2459 | return dsz; | ||
| 2460 | msg_set_fragm_no(&fragm_hdr, ++fragm_no); | ||
| 2461 | rest -= fragm_sz; | 2469 | rest -= fragm_sz; |
| 2462 | crs += fragm_sz; | 2470 | crs += fragm_sz; |
| 2463 | msg_set_type(&fragm_hdr, FRAGMENT); | 2471 | msg_set_type(&fragm_hdr, FRAGMENT); |
| 2464 | } | 2472 | } |
| 2465 | exit: | ||
| 2466 | buf_discard(buf); | 2473 | buf_discard(buf); |
| 2474 | |||
| 2475 | /* Append chain of fragments to send queue & send them */ | ||
| 2476 | |||
| 2477 | l_ptr->long_msg_seq_no++; | ||
| 2478 | link_add_chain_to_outqueue(l_ptr, buf_chain, l_ptr->long_msg_seq_no); | ||
| 2479 | l_ptr->stats.sent_fragments += fragm_no; | ||
| 2480 | l_ptr->stats.sent_fragmented++; | ||
| 2481 | tipc_link_push_queue(l_ptr); | ||
| 2482 | |||
| 2467 | return dsz; | 2483 | return dsz; |
| 2468 | } | 2484 | } |
| 2469 | 2485 | ||
