Commit 1b4e3e1d authored by David S. Miller's avatar David S. Miller

[IPV4]: Kill slow timers from IPVS, they are superfluous and inefficient these days.

parent 08dbab2c
......@@ -407,17 +407,6 @@ union ip_vs_tphdr {
};
/*
* Slow timer for IPVS connections
*/
struct sltimer_list {
struct list_head list;
unsigned long expires;
unsigned long data;
void (*function)(unsigned long);
};
/*
* Delta sequence info structure
* Each ip_vs_conn has 2 (output AND input seq. changes).
......@@ -535,7 +524,7 @@ struct ip_vs_conn {
/* counter and timer */
atomic_t refcnt; /* reference count */
struct sltimer_list timer; /* Expiration timer */
struct timer_list timer; /* Expiration timer */
volatile unsigned long timeout; /* timeout */
/* Flags and state transition */
......@@ -939,27 +928,6 @@ extern int ip_vs_new_estimator(struct ip_vs_stats *stats);
extern void ip_vs_kill_estimator(struct ip_vs_stats *stats);
extern void ip_vs_zero_estimator(struct ip_vs_stats *stats);
/*
* Slow timer functions for IPVS
* (from ip_vs_timer.c)
*/
extern void add_sltimer(struct sltimer_list *timer);
extern int del_sltimer(struct sltimer_list *timer);
extern void mod_sltimer(struct sltimer_list *timer, unsigned long expires);
extern void ip_vs_sltimer_init(void);
extern void ip_vs_sltimer_cleanup(void);
static inline void init_sltimer(struct sltimer_list *timer)
{
timer->list.next = timer->list.prev = NULL;
}
static inline int sltimer_pending(const struct sltimer_list *timer)
{
return timer->list.next != NULL;
}
/*
* Various IPVS packet transmitters (from ip_vs_xmit.c)
*/
......
......@@ -16,7 +16,7 @@ ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_ESP) += ip_vs_proto_esp.o
ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_AH) += ip_vs_proto_ah.o
ip_vs-objs := ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o \
ip_vs_xmit.o ip_vs_timer.o ip_vs_app.o ip_vs_sync.o \
ip_vs_xmit.o ip_vs_app.o ip_vs_sync.o \
ip_vs_est.o ip_vs_proto.o ip_vs_proto_icmp.o \
$(ip_vs_proto-objs-y)
......
......@@ -282,7 +282,7 @@ struct ip_vs_conn *ip_vs_conn_out_get
void ip_vs_conn_put(struct ip_vs_conn *cp)
{
/* reset it expire in its timeout */
mod_sltimer(&cp->timer, jiffies+cp->timeout);
mod_timer(&cp->timer, jiffies+cp->timeout);
__ip_vs_conn_put(cp);
}
......@@ -508,8 +508,7 @@ static void ip_vs_conn_expire(unsigned long data)
*/
if (likely(atomic_read(&cp->refcnt) == 1)) {
/* make sure that there is no timer on it now */
if (sltimer_pending(&cp->timer))
del_sltimer(&cp->timer);
del_timer_sync(&cp->timer);
/* does anybody control me? */
if (cp->control)
......@@ -542,7 +541,7 @@ static void ip_vs_conn_expire(unsigned long data)
void ip_vs_conn_expire_now(struct ip_vs_conn *cp)
{
cp->timeout = 0;
mod_sltimer(&cp->timer, jiffies);
mod_timer(&cp->timer, jiffies);
__ip_vs_conn_put(cp);
}
......@@ -566,7 +565,7 @@ ip_vs_conn_new(int proto, __u32 caddr, __u16 cport, __u32 vaddr, __u16 vport,
memset(cp, 0, sizeof(*cp));
INIT_LIST_HEAD(&cp->c_list);
init_sltimer(&cp->timer);
init_timer(&cp->timer);
cp->timer.data = (unsigned long)cp;
cp->timer.function = ip_vs_conn_expire;
cp->protocol = proto;
......
......@@ -1092,7 +1092,6 @@ static int __init ip_vs_init(void)
goto cleanup_nothing;
}
ip_vs_sltimer_init();
ip_vs_protocol_init();
ret = ip_vs_app_init();
......@@ -1144,7 +1143,6 @@ static int __init ip_vs_init(void)
ip_vs_app_cleanup();
cleanup_protocol:
ip_vs_protocol_cleanup();
ip_vs_sltimer_cleanup();
ip_vs_control_cleanup();
cleanup_nothing:
return ret;
......@@ -1159,7 +1157,6 @@ static void __exit ip_vs_cleanup(void)
ip_vs_conn_cleanup();
ip_vs_app_cleanup();
ip_vs_protocol_cleanup();
ip_vs_sltimer_cleanup();
ip_vs_control_cleanup();
IP_VS_INFO("ipvs unloaded.\n");
}
......
/*
* IPVS An implementation of the IP virtual server support for the
* LINUX operating system. IPVS is now implemented as a module
* over the Netfilter framework. IPVS can be used to build a
* high-performance and highly available server based on a
* cluster of servers.
*
* Version: $Id: ip_vs_timer.c,v 1.11 2003/06/08 09:31:19 wensong Exp $
*
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Julian Anastasov <ja@ssi.bg>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Changes:
*
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <net/ip_vs.h>
/*
* The following block implements slow timers for IPVS, most code is stolen
* from linux/kernel/timer.c.
* Slow timer is used to avoid the overhead of cascading timers, when lots
* of connection entries (>50,000) are cluttered in the system.
*/
#define SHIFT_BITS 6
#define TVN_BITS 8
#define TVR_BITS 10
#define TVN_SIZE (1 << TVN_BITS)
#define TVR_SIZE (1 << TVR_BITS)
#define TVN_MASK (TVN_SIZE - 1)
#define TVR_MASK (TVR_SIZE - 1)
struct sltimer_vec {
int index;
struct list_head vec[TVN_SIZE];
};
struct sltimer_vec_root {
int index;
struct list_head vec[TVR_SIZE];
};
static struct sltimer_vec sltv3 = { 0 };
static struct sltimer_vec sltv2 = { 0 };
static struct sltimer_vec_root sltv1 = { 0 };
static struct sltimer_vec * const sltvecs[] = {
(struct sltimer_vec *)&sltv1, &sltv2, &sltv3
};
#define NOOF_SLTVECS (sizeof(sltvecs) / sizeof(sltvecs[0]))
static void init_sltimervecs(void)
{
int i;
for (i = 0; i < TVN_SIZE; i++) {
INIT_LIST_HEAD(sltv3.vec + i);
INIT_LIST_HEAD(sltv2.vec + i);
}
for (i = 0; i < TVR_SIZE; i++)
INIT_LIST_HEAD(sltv1.vec + i);
}
static unsigned long sltimer_jiffies = 0;
static inline void internal_add_sltimer(struct sltimer_list *timer)
{
/*
* must hold the sltimer lock when calling this
*/
unsigned long expires = timer->expires;
unsigned long idx = expires - sltimer_jiffies;
struct list_head * vec;
if (idx < 1 << (SHIFT_BITS + TVR_BITS)) {
int i = (expires >> SHIFT_BITS) & TVR_MASK;
vec = sltv1.vec + i;
} else if (idx < 1 << (SHIFT_BITS + TVR_BITS + TVN_BITS)) {
int i = (expires >> (SHIFT_BITS+TVR_BITS)) & TVN_MASK;
vec = sltv2.vec + i;
} else if ((signed long) idx < 0) {
/*
* can happen if you add a timer with expires == jiffies,
* or you set a timer to go off in the past
*/
vec = sltv1.vec + sltv1.index;
} else if (idx <= 0xffffffffUL) {
int i = (expires >> (SHIFT_BITS+TVR_BITS+TVN_BITS)) & TVN_MASK;
vec = sltv3.vec + i;
} else {
/* Can only get here on architectures with 64-bit jiffies */
INIT_LIST_HEAD(&timer->list);
}
/*
* Timers are FIFO!
*/
list_add(&timer->list, vec->prev);
}
static spinlock_t __ip_vs_sltimerlist_lock = SPIN_LOCK_UNLOCKED;
void add_sltimer(struct sltimer_list *timer)
{
spin_lock(&__ip_vs_sltimerlist_lock);
if (timer->list.next)
goto bug;
internal_add_sltimer(timer);
out:
spin_unlock(&__ip_vs_sltimerlist_lock);
return;
bug:
printk("bug: kernel sltimer added twice at %p.\n",
__builtin_return_address(0));
goto out;
}
static inline int detach_sltimer(struct sltimer_list *timer)
{
if (!sltimer_pending(timer))
return 0;
list_del(&timer->list);
return 1;
}
void mod_sltimer(struct sltimer_list *timer, unsigned long expires)
{
int ret;
spin_lock(&__ip_vs_sltimerlist_lock);
timer->expires = expires;
ret = detach_sltimer(timer);
internal_add_sltimer(timer);
spin_unlock(&__ip_vs_sltimerlist_lock);
}
int del_sltimer(struct sltimer_list * timer)
{
int ret;
spin_lock(&__ip_vs_sltimerlist_lock);
ret = detach_sltimer(timer);
timer->list.next = timer->list.prev = 0;
spin_unlock(&__ip_vs_sltimerlist_lock);
return ret;
}
static inline void cascade_sltimers(struct sltimer_vec *tv)
{
/*
* cascade all the timers from tv up one level
*/
struct list_head *head, *curr, *next;
head = tv->vec + tv->index;
curr = head->next;
/*
* We are removing _all_ timers from the list, so we don't have to
* detach them individually, just clear the list afterwards.
*/
while (curr != head) {
struct sltimer_list *tmp;
tmp = list_entry(curr, struct sltimer_list, list);
next = curr->next;
list_del(curr); // not needed
internal_add_sltimer(tmp);
curr = next;
}
INIT_LIST_HEAD(head);
tv->index = (tv->index + 1) & TVN_MASK;
}
static inline void run_sltimer_list(void)
{
spin_lock(&__ip_vs_sltimerlist_lock);
while ((long)(jiffies - sltimer_jiffies) >= 0) {
struct list_head *head, *curr;
if (!sltv1.index) {
int n = 1;
do {
cascade_sltimers(sltvecs[n]);
} while (sltvecs[n]->index == 1 && ++n < NOOF_SLTVECS);
}
repeat:
head = sltv1.vec + sltv1.index;
curr = head->next;
if (curr != head) {
struct sltimer_list *timer;
void (*fn)(unsigned long);
unsigned long data;
timer = list_entry(curr, struct sltimer_list, list);
fn = timer->function;
data= timer->data;
detach_sltimer(timer);
timer->list.next = timer->list.prev = NULL;
spin_unlock(&__ip_vs_sltimerlist_lock);
fn(data);
spin_lock(&__ip_vs_sltimerlist_lock);
goto repeat;
}
sltimer_jiffies += 1<<SHIFT_BITS;
sltv1.index = (sltv1.index + 1) & TVR_MASK;
}
spin_unlock(&__ip_vs_sltimerlist_lock);
}
static struct timer_list slow_timer;
/*
* Slow timer handler is activated every second
*/
#define SLTIMER_PERIOD 1*HZ
static void sltimer_handler(unsigned long data)
{
run_sltimer_list();
update_defense_level();
if (atomic_read(&ip_vs_dropentry))
ip_vs_random_dropentry();
mod_timer(&slow_timer, (jiffies + SLTIMER_PERIOD));
}
void ip_vs_sltimer_init(void)
{
/* initialize the slow timer vectors */
init_sltimervecs();
/* initialize the slow timer jiffies and the vector indexes */
sltimer_jiffies = jiffies;
sltv1.index = (sltimer_jiffies >> SHIFT_BITS) & TVR_MASK;
sltv2.index = (sltimer_jiffies >> (SHIFT_BITS + TVR_BITS)) & TVN_MASK;
sltv3.index = (sltimer_jiffies >> (SHIFT_BITS + TVR_BITS + TVN_BITS))
& TVN_MASK;
/* Hook the slow_timer handler in the system timer */
init_timer(&slow_timer);
slow_timer.function = sltimer_handler;
slow_timer.expires = jiffies+SLTIMER_PERIOD;
add_timer(&slow_timer);
}
void ip_vs_sltimer_cleanup(void)
{
del_timer_sync(&slow_timer);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment