-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
IPVS: management of persistence engine modules
This is based heavily on the scheduler management code Signed-off-by: Simon Horman <horms@verge.net.au> Acked-by: Julian Anastasov <ja@ssi.bg>
- Loading branch information
Simon Horman
committed
Oct 4, 2010
1 parent
a3c918a
commit 8be67a6
Showing
3 changed files
with
154 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
#define KMSG_COMPONENT "IPVS" | ||
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
|
||
#include <linux/module.h> | ||
#include <linux/spinlock.h> | ||
#include <linux/interrupt.h> | ||
#include <asm/string.h> | ||
#include <linux/kmod.h> | ||
#include <linux/sysctl.h> | ||
|
||
#include <net/ip_vs.h> | ||
|
||
/* IPVS pe list */ | ||
static LIST_HEAD(ip_vs_pe); | ||
|
||
/* lock for service table */ | ||
static DEFINE_SPINLOCK(ip_vs_pe_lock); | ||
|
||
/* Bind a service with a pe */ | ||
void ip_vs_bind_pe(struct ip_vs_service *svc, struct ip_vs_pe *pe) | ||
{ | ||
svc->pe = pe; | ||
} | ||
|
||
/* Unbind a service from its pe */ | ||
void ip_vs_unbind_pe(struct ip_vs_service *svc) | ||
{ | ||
svc->pe = NULL; | ||
} | ||
|
||
/* Get pe in the pe list by name */ | ||
static struct ip_vs_pe * | ||
ip_vs_pe_getbyname(const char *pe_name) | ||
{ | ||
struct ip_vs_pe *pe; | ||
|
||
IP_VS_DBG(2, "%s(): pe_name \"%s\"\n", __func__, | ||
pe_name); | ||
|
||
spin_lock_bh(&ip_vs_pe_lock); | ||
|
||
list_for_each_entry(pe, &ip_vs_pe, n_list) { | ||
/* Test and get the modules atomically */ | ||
if (pe->module && | ||
!try_module_get(pe->module)) { | ||
/* This pe is just deleted */ | ||
continue; | ||
} | ||
if (strcmp(pe_name, pe->name)==0) { | ||
/* HIT */ | ||
spin_unlock_bh(&ip_vs_pe_lock); | ||
return pe; | ||
} | ||
if (pe->module) | ||
module_put(pe->module); | ||
} | ||
|
||
spin_unlock_bh(&ip_vs_pe_lock); | ||
return NULL; | ||
} | ||
|
||
/* Lookup pe and try to load it if it doesn't exist */ | ||
struct ip_vs_pe *ip_vs_pe_get(const char *name) | ||
{ | ||
struct ip_vs_pe *pe; | ||
|
||
/* Search for the pe by name */ | ||
pe = ip_vs_pe_getbyname(name); | ||
|
||
/* If pe not found, load the module and search again */ | ||
if (!pe) { | ||
request_module("ip_vs_pe_%s", name); | ||
pe = ip_vs_pe_getbyname(name); | ||
} | ||
|
||
return pe; | ||
} | ||
|
||
void ip_vs_pe_put(struct ip_vs_pe *pe) | ||
{ | ||
if (pe && pe->module) | ||
module_put(pe->module); | ||
} | ||
|
||
/* Register a pe in the pe list */ | ||
int register_ip_vs_pe(struct ip_vs_pe *pe) | ||
{ | ||
struct ip_vs_pe *tmp; | ||
|
||
/* increase the module use count */ | ||
ip_vs_use_count_inc(); | ||
|
||
spin_lock_bh(&ip_vs_pe_lock); | ||
|
||
if (!list_empty(&pe->n_list)) { | ||
spin_unlock_bh(&ip_vs_pe_lock); | ||
ip_vs_use_count_dec(); | ||
pr_err("%s(): [%s] pe already linked\n", | ||
__func__, pe->name); | ||
return -EINVAL; | ||
} | ||
|
||
/* Make sure that the pe with this name doesn't exist | ||
* in the pe list. | ||
*/ | ||
list_for_each_entry(tmp, &ip_vs_pe, n_list) { | ||
if (strcmp(tmp->name, pe->name) == 0) { | ||
spin_unlock_bh(&ip_vs_pe_lock); | ||
ip_vs_use_count_dec(); | ||
pr_err("%s(): [%s] pe already existed " | ||
"in the system\n", __func__, pe->name); | ||
return -EINVAL; | ||
} | ||
} | ||
/* Add it into the d-linked pe list */ | ||
list_add(&pe->n_list, &ip_vs_pe); | ||
spin_unlock_bh(&ip_vs_pe_lock); | ||
|
||
pr_info("[%s] pe registered.\n", pe->name); | ||
|
||
return 0; | ||
} | ||
EXPORT_SYMBOL_GPL(register_ip_vs_pe); | ||
|
||
/* Unregister a pe from the pe list */ | ||
int unregister_ip_vs_pe(struct ip_vs_pe *pe) | ||
{ | ||
spin_lock_bh(&ip_vs_pe_lock); | ||
if (list_empty(&pe->n_list)) { | ||
spin_unlock_bh(&ip_vs_pe_lock); | ||
pr_err("%s(): [%s] pe is not in the list. failed\n", | ||
__func__, pe->name); | ||
return -EINVAL; | ||
} | ||
|
||
/* Remove it from the d-linked pe list */ | ||
list_del(&pe->n_list); | ||
spin_unlock_bh(&ip_vs_pe_lock); | ||
|
||
/* decrease the module use count */ | ||
ip_vs_use_count_dec(); | ||
|
||
pr_info("[%s] pe unregistered.\n", pe->name); | ||
|
||
return 0; | ||
} | ||
EXPORT_SYMBOL_GPL(unregister_ip_vs_pe); |