Skip to content

Commit

Permalink
ipvs: convert locks used in persistence engines
Browse files Browse the repository at this point in the history
Allow the readers to use RCU lock and for
PE module registrations use global mutex instead of
spinlock. All PE modules need to use synchronize_rcu
in their module exit handler.

Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off by: Hans Schillstrom <hans@schillstrom.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
  • Loading branch information
Julian Anastasov authored and Pablo Neira Ayuso committed Apr 1, 2013
1 parent 276472e commit 60b6aa3
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 30 deletions.
43 changes: 13 additions & 30 deletions net/netfilter/ipvs/ip_vs_pe.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
/* IPVS pe list */
static LIST_HEAD(ip_vs_pe);

/* lock for service table */
static DEFINE_SPINLOCK(ip_vs_pe_lock);
/* semaphore for IPVS PEs. */
static DEFINE_MUTEX(ip_vs_pe_mutex);

/* Bind a service with a pe */
void ip_vs_bind_pe(struct ip_vs_service *svc, struct ip_vs_pe *pe)
Expand All @@ -36,9 +36,8 @@ struct ip_vs_pe *__ip_vs_pe_getbyname(const char *pe_name)
IP_VS_DBG(10, "%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) {
rcu_read_lock();
list_for_each_entry_rcu(pe, &ip_vs_pe, n_list) {
/* Test and get the modules atomically */
if (pe->module &&
!try_module_get(pe->module)) {
Expand All @@ -47,14 +46,14 @@ struct ip_vs_pe *__ip_vs_pe_getbyname(const char *pe_name)
}
if (strcmp(pe_name, pe->name)==0) {
/* HIT */
spin_unlock_bh(&ip_vs_pe_lock);
rcu_read_unlock();
return pe;
}
if (pe->module)
module_put(pe->module);
}
rcu_read_unlock();

spin_unlock_bh(&ip_vs_pe_lock);
return NULL;
}

Expand Down Expand Up @@ -83,31 +82,22 @@ int register_ip_vs_pe(struct ip_vs_pe *pe)
/* 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;
}

mutex_lock(&ip_vs_pe_mutex);
/* 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);
mutex_unlock(&ip_vs_pe_mutex);
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);
list_add_rcu(&pe->n_list, &ip_vs_pe);
mutex_unlock(&ip_vs_pe_mutex);

pr_info("[%s] pe registered.\n", pe->name);

Expand All @@ -118,17 +108,10 @@ 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;
}

mutex_lock(&ip_vs_pe_mutex);
/* Remove it from the d-linked pe list */
list_del(&pe->n_list);
spin_unlock_bh(&ip_vs_pe_lock);
list_del_rcu(&pe->n_list);
mutex_unlock(&ip_vs_pe_mutex);

/* decrease the module use count */
ip_vs_use_count_dec();
Expand Down
1 change: 1 addition & 0 deletions net/netfilter/ipvs/ip_vs_pe_sip.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ static int __init ip_vs_sip_init(void)
static void __exit ip_vs_sip_cleanup(void)
{
unregister_ip_vs_pe(&ip_vs_sip_pe);
synchronize_rcu();
}

module_init(ip_vs_sip_init);
Expand Down

0 comments on commit 60b6aa3

Please sign in to comment.