aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/netfilter/ipvs/ip_vs_lblcr.c44
1 files changed, 21 insertions, 23 deletions
diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c
index f7476b95ab46..caa58fa1438a 100644
--- a/net/netfilter/ipvs/ip_vs_lblcr.c
+++ b/net/netfilter/ipvs/ip_vs_lblcr.c
@@ -45,6 +45,7 @@
45#include <linux/kernel.h> 45#include <linux/kernel.h>
46#include <linux/skbuff.h> 46#include <linux/skbuff.h>
47#include <linux/jiffies.h> 47#include <linux/jiffies.h>
48#include <linux/list.h>
48 49
49/* for sysctl */ 50/* for sysctl */
50#include <linux/fs.h> 51#include <linux/fs.h>
@@ -85,25 +86,25 @@ static int sysctl_ip_vs_lblcr_expiration = 24*60*60*HZ;
85/* 86/*
86 * IPVS destination set structure and operations 87 * IPVS destination set structure and operations
87 */ 88 */
88struct ip_vs_dest_list { 89struct ip_vs_dest_set_elem {
89 struct ip_vs_dest_list *next; /* list link */ 90 struct list_head list; /* list link */
90 struct ip_vs_dest *dest; /* destination server */ 91 struct ip_vs_dest *dest; /* destination server */
91}; 92};
92 93
93struct ip_vs_dest_set { 94struct ip_vs_dest_set {
94 atomic_t size; /* set size */ 95 atomic_t size; /* set size */
95 unsigned long lastmod; /* last modified time */ 96 unsigned long lastmod; /* last modified time */
96 struct ip_vs_dest_list *list; /* destination list */ 97 struct list_head list; /* destination list */
97 rwlock_t lock; /* lock for this list */ 98 rwlock_t lock; /* lock for this list */
98}; 99};
99 100
100 101
101static struct ip_vs_dest_list * 102static struct ip_vs_dest_set_elem *
102ip_vs_dest_set_insert(struct ip_vs_dest_set *set, struct ip_vs_dest *dest) 103ip_vs_dest_set_insert(struct ip_vs_dest_set *set, struct ip_vs_dest *dest)
103{ 104{
104 struct ip_vs_dest_list *e; 105 struct ip_vs_dest_set_elem *e;
105 106
106 for (e=set->list; e!=NULL; e=e->next) { 107 list_for_each_entry(e, &set->list, list) {
107 if (e->dest == dest) 108 if (e->dest == dest)
108 /* already existed */ 109 /* already existed */
109 return NULL; 110 return NULL;
@@ -118,9 +119,7 @@ ip_vs_dest_set_insert(struct ip_vs_dest_set *set, struct ip_vs_dest *dest)
118 atomic_inc(&dest->refcnt); 119 atomic_inc(&dest->refcnt);
119 e->dest = dest; 120 e->dest = dest;
120 121
121 /* link it to the list */ 122 list_add(&e->list, &set->list);
122 e->next = set->list;
123 set->list = e;
124 atomic_inc(&set->size); 123 atomic_inc(&set->size);
125 124
126 set->lastmod = jiffies; 125 set->lastmod = jiffies;
@@ -130,34 +129,33 @@ ip_vs_dest_set_insert(struct ip_vs_dest_set *set, struct ip_vs_dest *dest)
130static void 129static void
131ip_vs_dest_set_erase(struct ip_vs_dest_set *set, struct ip_vs_dest *dest) 130ip_vs_dest_set_erase(struct ip_vs_dest_set *set, struct ip_vs_dest *dest)
132{ 131{
133 struct ip_vs_dest_list *e, **ep; 132 struct ip_vs_dest_set_elem *e;
134 133
135 for (ep=&set->list, e=*ep; e!=NULL; e=*ep) { 134 list_for_each_entry(e, &set->list, list) {
136 if (e->dest == dest) { 135 if (e->dest == dest) {
137 /* HIT */ 136 /* HIT */
138 *ep = e->next;
139 atomic_dec(&set->size); 137 atomic_dec(&set->size);
140 set->lastmod = jiffies; 138 set->lastmod = jiffies;
141 atomic_dec(&e->dest->refcnt); 139 atomic_dec(&e->dest->refcnt);
140 list_del(&e->list);
142 kfree(e); 141 kfree(e);
143 break; 142 break;
144 } 143 }
145 ep = &e->next;
146 } 144 }
147} 145}
148 146
149static void ip_vs_dest_set_eraseall(struct ip_vs_dest_set *set) 147static void ip_vs_dest_set_eraseall(struct ip_vs_dest_set *set)
150{ 148{
151 struct ip_vs_dest_list *e, **ep; 149 struct ip_vs_dest_set_elem *e, *ep;
152 150
153 write_lock(&set->lock); 151 write_lock(&set->lock);
154 for (ep=&set->list, e=*ep; e!=NULL; e=*ep) { 152 list_for_each_entry_safe(e, ep, &set->list, list) {
155 *ep = e->next;
156 /* 153 /*
157 * We don't kfree dest because it is refered either 154 * We don't kfree dest because it is refered either
158 * by its service or by the trash dest list. 155 * by its service or by the trash dest list.
159 */ 156 */
160 atomic_dec(&e->dest->refcnt); 157 atomic_dec(&e->dest->refcnt);
158 list_del(&e->list);
161 kfree(e); 159 kfree(e);
162 } 160 }
163 write_unlock(&set->lock); 161 write_unlock(&set->lock);
@@ -166,7 +164,7 @@ static void ip_vs_dest_set_eraseall(struct ip_vs_dest_set *set)
166/* get weighted least-connection node in the destination set */ 164/* get weighted least-connection node in the destination set */
167static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set) 165static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
168{ 166{
169 register struct ip_vs_dest_list *e; 167 register struct ip_vs_dest_set_elem *e;
170 struct ip_vs_dest *dest, *least; 168 struct ip_vs_dest *dest, *least;
171 int loh, doh; 169 int loh, doh;
172 170
@@ -174,7 +172,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
174 return NULL; 172 return NULL;
175 173
176 /* select the first destination server, whose weight > 0 */ 174 /* select the first destination server, whose weight > 0 */
177 for (e=set->list; e!=NULL; e=e->next) { 175 list_for_each_entry(e, &set->list, list) {
178 least = e->dest; 176 least = e->dest;
179 if (least->flags & IP_VS_DEST_F_OVERLOAD) 177 if (least->flags & IP_VS_DEST_F_OVERLOAD)
180 continue; 178 continue;
@@ -190,7 +188,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
190 188
191 /* find the destination with the weighted least load */ 189 /* find the destination with the weighted least load */
192 nextstage: 190 nextstage:
193 for (e=e->next; e!=NULL; e=e->next) { 191 list_for_each_entry(e, &set->list, list) {
194 dest = e->dest; 192 dest = e->dest;
195 if (dest->flags & IP_VS_DEST_F_OVERLOAD) 193 if (dest->flags & IP_VS_DEST_F_OVERLOAD)
196 continue; 194 continue;
@@ -220,7 +218,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
220/* get weighted most-connection node in the destination set */ 218/* get weighted most-connection node in the destination set */
221static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set) 219static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set)
222{ 220{
223 register struct ip_vs_dest_list *e; 221 register struct ip_vs_dest_set_elem *e;
224 struct ip_vs_dest *dest, *most; 222 struct ip_vs_dest *dest, *most;
225 int moh, doh; 223 int moh, doh;
226 224
@@ -228,7 +226,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set)
228 return NULL; 226 return NULL;
229 227
230 /* select the first destination server, whose weight > 0 */ 228 /* select the first destination server, whose weight > 0 */
231 for (e=set->list; e!=NULL; e=e->next) { 229 list_for_each_entry(e, &set->list, list) {
232 most = e->dest; 230 most = e->dest;
233 if (atomic_read(&most->weight) > 0) { 231 if (atomic_read(&most->weight) > 0) {
234 moh = atomic_read(&most->activeconns) * 50 232 moh = atomic_read(&most->activeconns) * 50
@@ -240,7 +238,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set)
240 238
241 /* find the destination with the weighted most load */ 239 /* find the destination with the weighted most load */
242 nextstage: 240 nextstage:
243 for (e=e->next; e!=NULL; e=e->next) { 241 list_for_each_entry(e, &set->list, list) {
244 dest = e->dest; 242 dest = e->dest;
245 doh = atomic_read(&dest->activeconns) * 50 243 doh = atomic_read(&dest->activeconns) * 50
246 + atomic_read(&dest->inactconns); 244 + atomic_read(&dest->inactconns);
@@ -389,7 +387,7 @@ ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl, const union nf_inet_addr *daddr,
389 387
390 /* initilize its dest set */ 388 /* initilize its dest set */
391 atomic_set(&(en->set.size), 0); 389 atomic_set(&(en->set.size), 0);
392 en->set.list = NULL; 390 INIT_LIST_HEAD(&en->set.list);
393 rwlock_init(&en->set.lock); 391 rwlock_init(&en->set.lock);
394 392
395 ip_vs_lblcr_hash(tbl, en); 393 ip_vs_lblcr_hash(tbl, en);