aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorJulian Anastasov <ja@ssi.bg>2010-09-21 12:12:30 -0400
committerPatrick McHardy <kaber@trash.net>2010-09-21 12:12:30 -0400
commit26c15cfd291f8b4ee40b4bbdf5e3772adfd704f5 (patch)
tree7ac3dc5c55b30ab85d599e945abd5f718a97c3c3 /net/netfilter
parent99f07e91bef34db0fc8b1a224096e97f02dc0d56 (diff)
ipvs: changes related to service usecnt
Change the usage of svc usecnt during command execution: - we check if svc is registered but we do not need to hold usecnt reference while under __ip_vs_mutex, only the packet handling needs it during scheduling - change __ip_vs_service_get to __ip_vs_service_find and __ip_vs_svc_fwm_get to __ip_vs_svc_fwm_find because now caller will increase svc->usecnt - put common code that calls update_service in __ip_vs_update_dest - put common code in ip_vs_unlink_service() and use it to unregister the service - add comment that svc should not be accessed after ip_vs_del_service anymore - all IP_VS_WAIT_WHILE calls are now unified: usecnt > 0 - Properly log the app ports As result, some problems are fixed: - possible use-after-free of svc in ip_vs_genl_set_cmd after ip_vs_del_service because our usecnt reference does not guarantee that svc is not freed on refcnt==0, eg. when no dests are moved to trash - possible usecnt leak in do_ip_vs_set_ctl after ip_vs_del_service when the service is not freed now, for example, when some destionations are moved into trash and svc->refcnt remains above 0. It is harmless because svc is not in hash anymore. Signed-off-by: Julian Anastasov <ja@ssi.bg> Acked-by: Simon Horman <horms@verge.net.au> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/ipvs/ip_vs_app.c6
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c250
2 files changed, 102 insertions, 154 deletions
diff --git a/net/netfilter/ipvs/ip_vs_app.c b/net/netfilter/ipvs/ip_vs_app.c
index e76f87f4aca..a475edee091 100644
--- a/net/netfilter/ipvs/ip_vs_app.c
+++ b/net/netfilter/ipvs/ip_vs_app.c
@@ -103,8 +103,8 @@ ip_vs_app_inc_new(struct ip_vs_app *app, __u16 proto, __u16 port)
103 goto out; 103 goto out;
104 104
105 list_add(&inc->a_list, &app->incs_list); 105 list_add(&inc->a_list, &app->incs_list);
106 IP_VS_DBG(9, "%s application %s:%u registered\n", 106 IP_VS_DBG(9, "%s App %s:%u registered\n",
107 pp->name, inc->name, inc->port); 107 pp->name, inc->name, ntohs(inc->port));
108 108
109 return 0; 109 return 0;
110 110
@@ -130,7 +130,7 @@ ip_vs_app_inc_release(struct ip_vs_app *inc)
130 pp->unregister_app(inc); 130 pp->unregister_app(inc);
131 131
132 IP_VS_DBG(9, "%s App %s:%u unregistered\n", 132 IP_VS_DBG(9, "%s App %s:%u unregistered\n",
133 pp->name, inc->name, inc->port); 133 pp->name, inc->name, ntohs(inc->port));
134 134
135 list_del(&inc->a_list); 135 list_del(&inc->a_list);
136 136
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index e637cd0384b..e4ec8f364f8 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -405,7 +405,7 @@ static int ip_vs_svc_unhash(struct ip_vs_service *svc)
405 * Get service by {proto,addr,port} in the service table. 405 * Get service by {proto,addr,port} in the service table.
406 */ 406 */
407static inline struct ip_vs_service * 407static inline struct ip_vs_service *
408__ip_vs_service_get(int af, __u16 protocol, const union nf_inet_addr *vaddr, 408__ip_vs_service_find(int af, __u16 protocol, const union nf_inet_addr *vaddr,
409 __be16 vport) 409 __be16 vport)
410{ 410{
411 unsigned hash; 411 unsigned hash;
@@ -420,7 +420,6 @@ __ip_vs_service_get(int af, __u16 protocol, const union nf_inet_addr *vaddr,
420 && (svc->port == vport) 420 && (svc->port == vport)
421 && (svc->protocol == protocol)) { 421 && (svc->protocol == protocol)) {
422 /* HIT */ 422 /* HIT */
423 atomic_inc(&svc->usecnt);
424 return svc; 423 return svc;
425 } 424 }
426 } 425 }
@@ -433,7 +432,7 @@ __ip_vs_service_get(int af, __u16 protocol, const union nf_inet_addr *vaddr,
433 * Get service by {fwmark} in the service table. 432 * Get service by {fwmark} in the service table.
434 */ 433 */
435static inline struct ip_vs_service * 434static inline struct ip_vs_service *
436__ip_vs_svc_fwm_get(int af, __u32 fwmark) 435__ip_vs_svc_fwm_find(int af, __u32 fwmark)
437{ 436{
438 unsigned hash; 437 unsigned hash;
439 struct ip_vs_service *svc; 438 struct ip_vs_service *svc;
@@ -444,7 +443,6 @@ __ip_vs_svc_fwm_get(int af, __u32 fwmark)
444 list_for_each_entry(svc, &ip_vs_svc_fwm_table[hash], f_list) { 443 list_for_each_entry(svc, &ip_vs_svc_fwm_table[hash], f_list) {
445 if (svc->fwmark == fwmark && svc->af == af) { 444 if (svc->fwmark == fwmark && svc->af == af) {
446 /* HIT */ 445 /* HIT */
447 atomic_inc(&svc->usecnt);
448 return svc; 446 return svc;
449 } 447 }
450 } 448 }
@@ -463,14 +461,14 @@ ip_vs_service_get(int af, __u32 fwmark, __u16 protocol,
463 /* 461 /*
464 * Check the table hashed by fwmark first 462 * Check the table hashed by fwmark first
465 */ 463 */
466 if (fwmark && (svc = __ip_vs_svc_fwm_get(af, fwmark))) 464 if (fwmark && (svc = __ip_vs_svc_fwm_find(af, fwmark)))
467 goto out; 465 goto out;
468 466
469 /* 467 /*
470 * Check the table hashed by <protocol,addr,port> 468 * Check the table hashed by <protocol,addr,port>
471 * for "full" addressed entries 469 * for "full" addressed entries
472 */ 470 */
473 svc = __ip_vs_service_get(af, protocol, vaddr, vport); 471 svc = __ip_vs_service_find(af, protocol, vaddr, vport);
474 472
475 if (svc == NULL 473 if (svc == NULL
476 && protocol == IPPROTO_TCP 474 && protocol == IPPROTO_TCP
@@ -480,7 +478,7 @@ ip_vs_service_get(int af, __u32 fwmark, __u16 protocol,
480 * Check if ftp service entry exists, the packet 478 * Check if ftp service entry exists, the packet
481 * might belong to FTP data connections. 479 * might belong to FTP data connections.
482 */ 480 */
483 svc = __ip_vs_service_get(af, protocol, vaddr, FTPPORT); 481 svc = __ip_vs_service_find(af, protocol, vaddr, FTPPORT);
484 } 482 }
485 483
486 if (svc == NULL 484 if (svc == NULL
@@ -488,10 +486,12 @@ ip_vs_service_get(int af, __u32 fwmark, __u16 protocol,
488 /* 486 /*
489 * Check if the catch-all port (port zero) exists 487 * Check if the catch-all port (port zero) exists
490 */ 488 */
491 svc = __ip_vs_service_get(af, protocol, vaddr, 0); 489 svc = __ip_vs_service_find(af, protocol, vaddr, 0);
492 } 490 }
493 491
494 out: 492 out:
493 if (svc)
494 atomic_inc(&svc->usecnt);
495 read_unlock(&__ip_vs_svc_lock); 495 read_unlock(&__ip_vs_svc_lock);
496 496
497 IP_VS_DBG_BUF(9, "lookup service: fwm %u %s %s:%u %s\n", 497 IP_VS_DBG_BUF(9, "lookup service: fwm %u %s %s:%u %s\n",
@@ -510,14 +510,19 @@ __ip_vs_bind_svc(struct ip_vs_dest *dest, struct ip_vs_service *svc)
510 dest->svc = svc; 510 dest->svc = svc;
511} 511}
512 512
513static inline void 513static void
514__ip_vs_unbind_svc(struct ip_vs_dest *dest) 514__ip_vs_unbind_svc(struct ip_vs_dest *dest)
515{ 515{
516 struct ip_vs_service *svc = dest->svc; 516 struct ip_vs_service *svc = dest->svc;
517 517
518 dest->svc = NULL; 518 dest->svc = NULL;
519 if (atomic_dec_and_test(&svc->refcnt)) 519 if (atomic_dec_and_test(&svc->refcnt)) {
520 IP_VS_DBG_BUF(3, "Removing service %u/%s:%u usecnt=%d\n",
521 svc->fwmark,
522 IP_VS_DBG_ADDR(svc->af, &svc->addr),
523 ntohs(svc->port), atomic_read(&svc->usecnt));
520 kfree(svc); 524 kfree(svc);
525 }
521} 526}
522 527
523 528
@@ -762,8 +767,8 @@ ip_vs_zero_stats(struct ip_vs_stats *stats)
762 * Update a destination in the given service 767 * Update a destination in the given service
763 */ 768 */
764static void 769static void
765__ip_vs_update_dest(struct ip_vs_service *svc, 770__ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
766 struct ip_vs_dest *dest, struct ip_vs_dest_user_kern *udest) 771 struct ip_vs_dest_user_kern *udest, int add)
767{ 772{
768 int conn_flags; 773 int conn_flags;
769 774
@@ -818,6 +823,25 @@ __ip_vs_update_dest(struct ip_vs_service *svc,
818 dest->flags &= ~IP_VS_DEST_F_OVERLOAD; 823 dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
819 dest->u_threshold = udest->u_threshold; 824 dest->u_threshold = udest->u_threshold;
820 dest->l_threshold = udest->l_threshold; 825 dest->l_threshold = udest->l_threshold;
826
827 if (add)
828 ip_vs_new_estimator(&dest->stats);
829
830 write_lock_bh(&__ip_vs_svc_lock);
831
832 /* Wait until all other svc users go away */
833 IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
834
835 if (add) {
836 list_add(&dest->n_list, &svc->destinations);
837 svc->num_dests++;
838 }
839
840 /* call the update_service, because server weight may be changed */
841 if (svc->scheduler->update_service)
842 svc->scheduler->update_service(svc);
843
844 write_unlock_bh(&__ip_vs_svc_lock);
821} 845}
822 846
823 847
@@ -865,13 +889,12 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest,
865 atomic_set(&dest->activeconns, 0); 889 atomic_set(&dest->activeconns, 0);
866 atomic_set(&dest->inactconns, 0); 890 atomic_set(&dest->inactconns, 0);
867 atomic_set(&dest->persistconns, 0); 891 atomic_set(&dest->persistconns, 0);
868 atomic_set(&dest->refcnt, 0); 892 atomic_set(&dest->refcnt, 1);
869 893
870 INIT_LIST_HEAD(&dest->d_list); 894 INIT_LIST_HEAD(&dest->d_list);
871 spin_lock_init(&dest->dst_lock); 895 spin_lock_init(&dest->dst_lock);
872 spin_lock_init(&dest->stats.lock); 896 spin_lock_init(&dest->stats.lock);
873 __ip_vs_update_dest(svc, dest, udest); 897 __ip_vs_update_dest(svc, dest, udest, 1);
874 ip_vs_new_estimator(&dest->stats);
875 898
876 *dest_p = dest; 899 *dest_p = dest;
877 900
@@ -931,65 +954,22 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
931 IP_VS_DBG_ADDR(svc->af, &dest->vaddr), 954 IP_VS_DBG_ADDR(svc->af, &dest->vaddr),
932 ntohs(dest->vport)); 955 ntohs(dest->vport));
933 956
934 __ip_vs_update_dest(svc, dest, udest);
935
936 /* 957 /*
937 * Get the destination from the trash 958 * Get the destination from the trash
938 */ 959 */
939 list_del(&dest->n_list); 960 list_del(&dest->n_list);
940 961
941 ip_vs_new_estimator(&dest->stats); 962 __ip_vs_update_dest(svc, dest, udest, 1);
942 963 ret = 0;
943 write_lock_bh(&__ip_vs_svc_lock); 964 } else {
944
945 /* 965 /*
946 * Wait until all other svc users go away. 966 * Allocate and initialize the dest structure
947 */ 967 */
948 IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1); 968 ret = ip_vs_new_dest(svc, udest, &dest);
949
950 list_add(&dest->n_list, &svc->destinations);
951 svc->num_dests++;
952
953 /* call the update_service function of its scheduler */
954 if (svc->scheduler->update_service)
955 svc->scheduler->update_service(svc);
956
957 write_unlock_bh(&__ip_vs_svc_lock);
958 return 0;
959 }
960
961 /*
962 * Allocate and initialize the dest structure
963 */
964 ret = ip_vs_new_dest(svc, udest, &dest);
965 if (ret) {
966 return ret;
967 } 969 }
968
969 /*
970 * Add the dest entry into the list
971 */
972 atomic_inc(&dest->refcnt);
973
974 write_lock_bh(&__ip_vs_svc_lock);
975
976 /*
977 * Wait until all other svc users go away.
978 */
979 IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
980
981 list_add(&dest->n_list, &svc->destinations);
982 svc->num_dests++;
983
984 /* call the update_service function of its scheduler */
985 if (svc->scheduler->update_service)
986 svc->scheduler->update_service(svc);
987
988 write_unlock_bh(&__ip_vs_svc_lock);
989
990 LeaveFunction(2); 970 LeaveFunction(2);
991 971
992 return 0; 972 return ret;
993} 973}
994 974
995 975
@@ -1028,19 +1008,7 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
1028 return -ENOENT; 1008 return -ENOENT;
1029 } 1009 }
1030 1010
1031 __ip_vs_update_dest(svc, dest, udest); 1011 __ip_vs_update_dest(svc, dest, udest, 0);
1032
1033 write_lock_bh(&__ip_vs_svc_lock);
1034
1035 /* Wait until all other svc users go away */
1036 IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
1037
1038 /* call the update_service, because server weight may be changed */
1039 if (svc->scheduler->update_service)
1040 svc->scheduler->update_service(svc);
1041
1042 write_unlock_bh(&__ip_vs_svc_lock);
1043
1044 LeaveFunction(2); 1012 LeaveFunction(2);
1045 1013
1046 return 0; 1014 return 0;
@@ -1067,6 +1035,10 @@ static void __ip_vs_del_dest(struct ip_vs_dest *dest)
1067 * the destination into the trash. 1035 * the destination into the trash.
1068 */ 1036 */
1069 if (atomic_dec_and_test(&dest->refcnt)) { 1037 if (atomic_dec_and_test(&dest->refcnt)) {
1038 IP_VS_DBG_BUF(3, "Removing destination %u/%s:%u\n",
1039 dest->vfwmark,
1040 IP_VS_DBG_ADDR(dest->af, &dest->addr),
1041 ntohs(dest->port));
1070 ip_vs_dst_reset(dest); 1042 ip_vs_dst_reset(dest);
1071 /* simply decrease svc->refcnt here, let the caller check 1043 /* simply decrease svc->refcnt here, let the caller check
1072 and release the service if nobody refers to it. 1044 and release the service if nobody refers to it.
@@ -1133,7 +1105,7 @@ ip_vs_del_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
1133 /* 1105 /*
1134 * Wait until all other svc users go away. 1106 * Wait until all other svc users go away.
1135 */ 1107 */
1136 IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1); 1108 IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
1137 1109
1138 /* 1110 /*
1139 * Unlink dest from the service 1111 * Unlink dest from the service
@@ -1190,7 +1162,7 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u,
1190 } 1162 }
1191 1163
1192 /* I'm the first user of the service */ 1164 /* I'm the first user of the service */
1193 atomic_set(&svc->usecnt, 1); 1165 atomic_set(&svc->usecnt, 0);
1194 atomic_set(&svc->refcnt, 0); 1166 atomic_set(&svc->refcnt, 0);
1195 1167
1196 svc->af = u->af; 1168 svc->af = u->af;
@@ -1284,7 +1256,7 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
1284 /* 1256 /*
1285 * Wait until all other svc users go away. 1257 * Wait until all other svc users go away.
1286 */ 1258 */
1287 IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1); 1259 IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
1288 1260
1289 /* 1261 /*
1290 * Set the flags and timeout value 1262 * Set the flags and timeout value
@@ -1383,21 +1355,23 @@ static void __ip_vs_del_service(struct ip_vs_service *svc)
1383 /* 1355 /*
1384 * Free the service if nobody refers to it 1356 * Free the service if nobody refers to it
1385 */ 1357 */
1386 if (atomic_read(&svc->refcnt) == 0) 1358 if (atomic_read(&svc->refcnt) == 0) {
1359 IP_VS_DBG_BUF(3, "Removing service %u/%s:%u usecnt=%d\n",
1360 svc->fwmark,
1361 IP_VS_DBG_ADDR(svc->af, &svc->addr),
1362 ntohs(svc->port), atomic_read(&svc->usecnt));
1387 kfree(svc); 1363 kfree(svc);
1364 }
1388 1365
1389 /* decrease the module use count */ 1366 /* decrease the module use count */
1390 ip_vs_use_count_dec(); 1367 ip_vs_use_count_dec();
1391} 1368}
1392 1369
1393/* 1370/*
1394 * Delete a service from the service list 1371 * Unlink a service from list and try to delete it if its refcnt reached 0
1395 */ 1372 */
1396static int ip_vs_del_service(struct ip_vs_service *svc) 1373static void ip_vs_unlink_service(struct ip_vs_service *svc)
1397{ 1374{
1398 if (svc == NULL)
1399 return -EEXIST;
1400
1401 /* 1375 /*
1402 * Unhash it from the service table 1376 * Unhash it from the service table
1403 */ 1377 */
@@ -1408,11 +1382,21 @@ static int ip_vs_del_service(struct ip_vs_service *svc)
1408 /* 1382 /*
1409 * Wait until all the svc users go away. 1383 * Wait until all the svc users go away.
1410 */ 1384 */
1411 IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1); 1385 IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
1412 1386
1413 __ip_vs_del_service(svc); 1387 __ip_vs_del_service(svc);
1414 1388
1415 write_unlock_bh(&__ip_vs_svc_lock); 1389 write_unlock_bh(&__ip_vs_svc_lock);
1390}
1391
1392/*
1393 * Delete a service from the service list
1394 */
1395static int ip_vs_del_service(struct ip_vs_service *svc)
1396{
1397 if (svc == NULL)
1398 return -EEXIST;
1399 ip_vs_unlink_service(svc);
1416 1400
1417 return 0; 1401 return 0;
1418} 1402}
@@ -1431,14 +1415,7 @@ static int ip_vs_flush(void)
1431 */ 1415 */
1432 for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) { 1416 for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
1433 list_for_each_entry_safe(svc, nxt, &ip_vs_svc_table[idx], s_list) { 1417 list_for_each_entry_safe(svc, nxt, &ip_vs_svc_table[idx], s_list) {
1434 write_lock_bh(&__ip_vs_svc_lock); 1418 ip_vs_unlink_service(svc);
1435 ip_vs_svc_unhash(svc);
1436 /*
1437 * Wait until all the svc users go away.
1438 */
1439 IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
1440 __ip_vs_del_service(svc);
1441 write_unlock_bh(&__ip_vs_svc_lock);
1442 } 1419 }
1443 } 1420 }
1444 1421
@@ -1448,14 +1425,7 @@ static int ip_vs_flush(void)
1448 for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) { 1425 for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
1449 list_for_each_entry_safe(svc, nxt, 1426 list_for_each_entry_safe(svc, nxt,
1450 &ip_vs_svc_fwm_table[idx], f_list) { 1427 &ip_vs_svc_fwm_table[idx], f_list) {
1451 write_lock_bh(&__ip_vs_svc_lock); 1428 ip_vs_unlink_service(svc);
1452 ip_vs_svc_unhash(svc);
1453 /*
1454 * Wait until all the svc users go away.
1455 */
1456 IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
1457 __ip_vs_del_service(svc);
1458 write_unlock_bh(&__ip_vs_svc_lock);
1459 } 1429 }
1460 } 1430 }
1461 1431
@@ -2168,15 +2138,15 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2168 2138
2169 /* Lookup the exact service by <protocol, addr, port> or fwmark */ 2139 /* Lookup the exact service by <protocol, addr, port> or fwmark */
2170 if (usvc.fwmark == 0) 2140 if (usvc.fwmark == 0)
2171 svc = __ip_vs_service_get(usvc.af, usvc.protocol, 2141 svc = __ip_vs_service_find(usvc.af, usvc.protocol,
2172 &usvc.addr, usvc.port); 2142 &usvc.addr, usvc.port);
2173 else 2143 else
2174 svc = __ip_vs_svc_fwm_get(usvc.af, usvc.fwmark); 2144 svc = __ip_vs_svc_fwm_find(usvc.af, usvc.fwmark);
2175 2145
2176 if (cmd != IP_VS_SO_SET_ADD 2146 if (cmd != IP_VS_SO_SET_ADD
2177 && (svc == NULL || svc->protocol != usvc.protocol)) { 2147 && (svc == NULL || svc->protocol != usvc.protocol)) {
2178 ret = -ESRCH; 2148 ret = -ESRCH;
2179 goto out_drop_service; 2149 goto out_unlock;
2180 } 2150 }
2181 2151
2182 switch (cmd) { 2152 switch (cmd) {
@@ -2210,10 +2180,6 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2210 ret = -EINVAL; 2180 ret = -EINVAL;
2211 } 2181 }
2212 2182
2213out_drop_service:
2214 if (svc)
2215 ip_vs_service_put(svc);
2216
2217 out_unlock: 2183 out_unlock:
2218 mutex_unlock(&__ip_vs_mutex); 2184 mutex_unlock(&__ip_vs_mutex);
2219 out_dec: 2185 out_dec:
@@ -2306,10 +2272,10 @@ __ip_vs_get_dest_entries(const struct ip_vs_get_dests *get,
2306 int ret = 0; 2272 int ret = 0;
2307 2273
2308 if (get->fwmark) 2274 if (get->fwmark)
2309 svc = __ip_vs_svc_fwm_get(AF_INET, get->fwmark); 2275 svc = __ip_vs_svc_fwm_find(AF_INET, get->fwmark);
2310 else 2276 else
2311 svc = __ip_vs_service_get(AF_INET, get->protocol, &addr, 2277 svc = __ip_vs_service_find(AF_INET, get->protocol, &addr,
2312 get->port); 2278 get->port);
2313 2279
2314 if (svc) { 2280 if (svc) {
2315 int count = 0; 2281 int count = 0;
@@ -2337,7 +2303,6 @@ __ip_vs_get_dest_entries(const struct ip_vs_get_dests *get,
2337 } 2303 }
2338 count++; 2304 count++;
2339 } 2305 }
2340 ip_vs_service_put(svc);
2341 } else 2306 } else
2342 ret = -ESRCH; 2307 ret = -ESRCH;
2343 return ret; 2308 return ret;
@@ -2458,15 +2423,14 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2458 entry = (struct ip_vs_service_entry *)arg; 2423 entry = (struct ip_vs_service_entry *)arg;
2459 addr.ip = entry->addr; 2424 addr.ip = entry->addr;
2460 if (entry->fwmark) 2425 if (entry->fwmark)
2461 svc = __ip_vs_svc_fwm_get(AF_INET, entry->fwmark); 2426 svc = __ip_vs_svc_fwm_find(AF_INET, entry->fwmark);
2462 else 2427 else
2463 svc = __ip_vs_service_get(AF_INET, entry->protocol, 2428 svc = __ip_vs_service_find(AF_INET, entry->protocol,
2464 &addr, entry->port); 2429 &addr, entry->port);
2465 if (svc) { 2430 if (svc) {
2466 ip_vs_copy_service(entry, svc); 2431 ip_vs_copy_service(entry, svc);
2467 if (copy_to_user(user, entry, sizeof(*entry)) != 0) 2432 if (copy_to_user(user, entry, sizeof(*entry)) != 0)
2468 ret = -EFAULT; 2433 ret = -EFAULT;
2469 ip_vs_service_put(svc);
2470 } else 2434 } else
2471 ret = -ESRCH; 2435 ret = -ESRCH;
2472 } 2436 }
@@ -2733,10 +2697,12 @@ nla_put_failure:
2733} 2697}
2734 2698
2735static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc, 2699static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc,
2736 struct nlattr *nla, int full_entry) 2700 struct nlattr *nla, int full_entry,
2701 struct ip_vs_service **ret_svc)
2737{ 2702{
2738 struct nlattr *attrs[IPVS_SVC_ATTR_MAX + 1]; 2703 struct nlattr *attrs[IPVS_SVC_ATTR_MAX + 1];
2739 struct nlattr *nla_af, *nla_port, *nla_fwmark, *nla_protocol, *nla_addr; 2704 struct nlattr *nla_af, *nla_port, *nla_fwmark, *nla_protocol, *nla_addr;
2705 struct ip_vs_service *svc;
2740 2706
2741 /* Parse mandatory identifying service fields first */ 2707 /* Parse mandatory identifying service fields first */
2742 if (nla == NULL || 2708 if (nla == NULL ||
@@ -2772,12 +2738,18 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc,
2772 usvc->fwmark = 0; 2738 usvc->fwmark = 0;
2773 } 2739 }
2774 2740
2741 if (usvc->fwmark)
2742 svc = __ip_vs_svc_fwm_find(usvc->af, usvc->fwmark);
2743 else
2744 svc = __ip_vs_service_find(usvc->af, usvc->protocol,
2745 &usvc->addr, usvc->port);
2746 *ret_svc = svc;
2747
2775 /* If a full entry was requested, check for the additional fields */ 2748 /* If a full entry was requested, check for the additional fields */
2776 if (full_entry) { 2749 if (full_entry) {
2777 struct nlattr *nla_sched, *nla_flags, *nla_timeout, 2750 struct nlattr *nla_sched, *nla_flags, *nla_timeout,
2778 *nla_netmask; 2751 *nla_netmask;
2779 struct ip_vs_flags flags; 2752 struct ip_vs_flags flags;
2780 struct ip_vs_service *svc;
2781 2753
2782 nla_sched = attrs[IPVS_SVC_ATTR_SCHED_NAME]; 2754 nla_sched = attrs[IPVS_SVC_ATTR_SCHED_NAME];
2783 nla_flags = attrs[IPVS_SVC_ATTR_FLAGS]; 2755 nla_flags = attrs[IPVS_SVC_ATTR_FLAGS];
@@ -2790,16 +2762,8 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc,
2790 nla_memcpy(&flags, nla_flags, sizeof(flags)); 2762 nla_memcpy(&flags, nla_flags, sizeof(flags));
2791 2763
2792 /* prefill flags from service if it already exists */ 2764 /* prefill flags from service if it already exists */
2793 if (usvc->fwmark) 2765 if (svc)
2794 svc = __ip_vs_svc_fwm_get(usvc->af, usvc->fwmark);
2795 else
2796 svc = __ip_vs_service_get(usvc->af, usvc->protocol,
2797 &usvc->addr, usvc->port);
2798 if (svc) {
2799 usvc->flags = svc->flags; 2766 usvc->flags = svc->flags;
2800 ip_vs_service_put(svc);
2801 } else
2802 usvc->flags = 0;
2803 2767
2804 /* set new flags from userland */ 2768 /* set new flags from userland */
2805 usvc->flags = (usvc->flags & ~flags.mask) | 2769 usvc->flags = (usvc->flags & ~flags.mask) |
@@ -2815,17 +2779,11 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc,
2815static struct ip_vs_service *ip_vs_genl_find_service(struct nlattr *nla) 2779static struct ip_vs_service *ip_vs_genl_find_service(struct nlattr *nla)
2816{ 2780{
2817 struct ip_vs_service_user_kern usvc; 2781 struct ip_vs_service_user_kern usvc;
2782 struct ip_vs_service *svc;
2818 int ret; 2783 int ret;
2819 2784
2820 ret = ip_vs_genl_parse_service(&usvc, nla, 0); 2785 ret = ip_vs_genl_parse_service(&usvc, nla, 0, &svc);
2821 if (ret) 2786 return ret ? ERR_PTR(ret) : svc;
2822 return ERR_PTR(ret);
2823
2824 if (usvc.fwmark)
2825 return __ip_vs_svc_fwm_get(usvc.af, usvc.fwmark);
2826 else
2827 return __ip_vs_service_get(usvc.af, usvc.protocol,
2828 &usvc.addr, usvc.port);
2829} 2787}
2830 2788
2831static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest) 2789static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest)
@@ -2916,7 +2874,6 @@ static int ip_vs_genl_dump_dests(struct sk_buff *skb,
2916 2874
2917nla_put_failure: 2875nla_put_failure:
2918 cb->args[0] = idx; 2876 cb->args[0] = idx;
2919 ip_vs_service_put(svc);
2920 2877
2921out_err: 2878out_err:
2922 mutex_unlock(&__ip_vs_mutex); 2879 mutex_unlock(&__ip_vs_mutex);
@@ -3129,17 +3086,10 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
3129 3086
3130 ret = ip_vs_genl_parse_service(&usvc, 3087 ret = ip_vs_genl_parse_service(&usvc,
3131 info->attrs[IPVS_CMD_ATTR_SERVICE], 3088 info->attrs[IPVS_CMD_ATTR_SERVICE],
3132 need_full_svc); 3089 need_full_svc, &svc);
3133 if (ret) 3090 if (ret)
3134 goto out; 3091 goto out;
3135 3092
3136 /* Lookup the exact service by <protocol, addr, port> or fwmark */
3137 if (usvc.fwmark == 0)
3138 svc = __ip_vs_service_get(usvc.af, usvc.protocol,
3139 &usvc.addr, usvc.port);
3140 else
3141 svc = __ip_vs_svc_fwm_get(usvc.af, usvc.fwmark);
3142
3143 /* Unless we're adding a new service, the service must already exist */ 3093 /* Unless we're adding a new service, the service must already exist */
3144 if ((cmd != IPVS_CMD_NEW_SERVICE) && (svc == NULL)) { 3094 if ((cmd != IPVS_CMD_NEW_SERVICE) && (svc == NULL)) {
3145 ret = -ESRCH; 3095 ret = -ESRCH;
@@ -3173,6 +3123,7 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
3173 break; 3123 break;
3174 case IPVS_CMD_DEL_SERVICE: 3124 case IPVS_CMD_DEL_SERVICE:
3175 ret = ip_vs_del_service(svc); 3125 ret = ip_vs_del_service(svc);
3126 /* do not use svc, it can be freed */
3176 break; 3127 break;
3177 case IPVS_CMD_NEW_DEST: 3128 case IPVS_CMD_NEW_DEST:
3178 ret = ip_vs_add_dest(svc, &udest); 3129 ret = ip_vs_add_dest(svc, &udest);
@@ -3191,8 +3142,6 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
3191 } 3142 }
3192 3143
3193out: 3144out:
3194 if (svc)
3195 ip_vs_service_put(svc);
3196 mutex_unlock(&__ip_vs_mutex); 3145 mutex_unlock(&__ip_vs_mutex);
3197 3146
3198 return ret; 3147 return ret;
@@ -3238,7 +3187,6 @@ static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info)
3238 goto out_err; 3187 goto out_err;
3239 } else if (svc) { 3188 } else if (svc) {
3240 ret = ip_vs_genl_fill_service(msg, svc); 3189 ret = ip_vs_genl_fill_service(msg, svc);
3241 ip_vs_service_put(svc);
3242 if (ret) 3190 if (ret)
3243 goto nla_put_failure; 3191 goto nla_put_failure;
3244 } else { 3192 } else {