aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common
diff options
context:
space:
mode:
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>2007-02-21 16:13:49 +0000
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>2007-02-21 16:13:49 +0000
commitc6c62d99d860ff01493f1aa3530e517f6ba7de6d (patch)
tree8bb47c79f7ff771896089a6adeebd3a3fa8bbcd6 /xen/common
parent39475b429d06a097bc528468a80c1bee2eb38a5b (diff)
downloadxen-c6c62d99d860ff01493f1aa3530e517f6ba7de6d.tar.gz
xen-c6c62d99d860ff01493f1aa3530e517f6ba7de6d.tar.bz2
xen-c6c62d99d860ff01493f1aa3530e517f6ba7de6d.zip
Use RCU for domain_list and domain_hash.
Signed-off-by: Jose Renato Santos <jsantos@hpl.hp.com> Signed-off-by: Keir Fraser <keir@xensource.com>
Diffstat (limited to 'xen/common')
-rw-r--r--xen/common/domain.c68
-rw-r--r--xen/common/domctl.c11
-rw-r--r--xen/common/keyhandler.c4
-rw-r--r--xen/common/sched_sedf.c8
-rw-r--r--xen/common/sysctl.c4
5 files changed, 60 insertions, 35 deletions
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 7ec09b9d81..b911525006 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -24,13 +24,18 @@
#include <xen/shutdown.h>
#include <xen/percpu.h>
#include <xen/multicall.h>
+#include <xen/rcupdate.h>
#include <asm/debugger.h>
#include <public/sched.h>
#include <public/vcpu.h>
-/* Both these structures are protected by the domlist_lock. */
-DEFINE_RWLOCK(domlist_lock);
-struct domain *domain_hash[DOMAIN_HASH_SIZE];
+/* Protect updates/reads (resp.) of domain_list and domain_hash. */
+DEFINE_SPINLOCK(domlist_update_lock);
+DEFINE_RCU_READ_LOCK(domlist_read_lock);
+
+#define DOMAIN_HASH_SIZE 256
+#define DOMAIN_HASH(_id) ((int)(_id)&(DOMAIN_HASH_SIZE-1))
+static struct domain *domain_hash[DOMAIN_HASH_SIZE];
struct domain *domain_list;
struct domain *dom0;
@@ -174,16 +179,20 @@ struct domain *domain_create(domid_t domid, unsigned int domcr_flags)
if ( !is_idle_domain(d) )
{
- write_lock(&domlist_lock);
+ spin_lock(&domlist_update_lock);
pd = &domain_list; /* NB. domain_list maintained in order of domid. */
for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list )
if ( (*pd)->domain_id > d->domain_id )
break;
d->next_in_list = *pd;
- *pd = d;
d->next_in_hashbucket = domain_hash[DOMAIN_HASH(domid)];
- domain_hash[DOMAIN_HASH(domid)] = d;
- write_unlock(&domlist_lock);
+ /* Two rcu assignments are not atomic
+ * Readers may see inconsistent domlist and hash table
+ * That is OK as long as each RCU reader-side critical section uses
+ * only one or them */
+ rcu_assign_pointer(*pd, d);
+ rcu_assign_pointer(domain_hash[DOMAIN_HASH(domid)], d);
+ spin_unlock(&domlist_update_lock);
}
return d;
@@ -207,8 +216,8 @@ struct domain *get_domain_by_id(domid_t dom)
{
struct domain *d;
- read_lock(&domlist_lock);
- d = domain_hash[DOMAIN_HASH(dom)];
+ rcu_read_lock(&domlist_read_lock);
+ d = rcu_dereference(domain_hash[DOMAIN_HASH(dom)]);
while ( d != NULL )
{
if ( d->domain_id == dom )
@@ -217,9 +226,9 @@ struct domain *get_domain_by_id(domid_t dom)
d = NULL;
break;
}
- d = d->next_in_hashbucket;
+ d = rcu_dereference(d->next_in_hashbucket);
}
- read_unlock(&domlist_lock);
+ rcu_read_unlock(&domlist_read_lock);
return d;
}
@@ -314,6 +323,23 @@ void domain_pause_for_debugger(void)
send_guest_global_virq(dom0, VIRQ_DEBUGGER);
}
+/* Complete domain destroy after RCU readers are not holding
+ old references */
+static void complete_domain_destroy(struct rcu_head *head)
+{
+ struct domain *d = container_of(head, struct domain, rcu);
+
+ rangeset_domain_destroy(d);
+
+ evtchn_destroy(d);
+ grant_table_destroy(d);
+
+ arch_domain_destroy(d);
+
+ free_domain(d);
+
+ send_guest_global_virq(dom0, VIRQ_DOM_EXC);
+}
/* Release resources belonging to task @p. */
void domain_destroy(struct domain *d)
@@ -331,27 +357,19 @@ void domain_destroy(struct domain *d)
return;
/* Delete from task list and task hashtable. */
- write_lock(&domlist_lock);
+ spin_lock(&domlist_update_lock);
pd = &domain_list;
while ( *pd != d )
pd = &(*pd)->next_in_list;
- *pd = d->next_in_list;
+ rcu_assign_pointer(*pd, d->next_in_list);
pd = &domain_hash[DOMAIN_HASH(d->domain_id)];
while ( *pd != d )
pd = &(*pd)->next_in_hashbucket;
- *pd = d->next_in_hashbucket;
- write_unlock(&domlist_lock);
-
- rangeset_domain_destroy(d);
-
- evtchn_destroy(d);
- grant_table_destroy(d);
-
- arch_domain_destroy(d);
+ rcu_assign_pointer(*pd, d->next_in_hashbucket);
+ spin_unlock(&domlist_update_lock);
- free_domain(d);
-
- send_guest_global_virq(dom0, VIRQ_DOM_EXC);
+ /* schedule RCU asynchronous completion of domain destroy */
+ call_rcu(&d->rcu, complete_domain_destroy);
}
static void vcpu_pause_setup(struct vcpu *v)
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index b3df79ba53..f7fe2d61ba 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -17,6 +17,7 @@
#include <xen/trace.h>
#include <xen/console.h>
#include <xen/iocap.h>
+#include <xen/rcupdate.h>
#include <xen/guest_access.h>
#include <xen/bitmap.h>
#include <asm/current.h>
@@ -140,12 +141,12 @@ static unsigned int default_vcpu0_location(void)
cpumask_t cpu_exclude_map;
/* Do an initial CPU placement. Pick the least-populated CPU. */
- read_lock(&domlist_lock);
+ rcu_read_lock(&domlist_read_lock);
for_each_domain ( d )
for_each_vcpu ( d, v )
if ( !test_bit(_VCPUF_down, &v->vcpu_flags) )
cnt[v->processor]++;
- read_unlock(&domlist_lock);
+ rcu_read_unlock(&domlist_read_lock);
/*
* If we're on a HT system, we only auto-allocate to a non-primary HT. We
@@ -480,7 +481,7 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
if ( dom == DOMID_SELF )
dom = current->domain->domain_id;
- read_lock(&domlist_lock);
+ rcu_read_lock(&domlist_read_lock);
for_each_domain ( d )
{
@@ -490,12 +491,12 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
if ( (d == NULL) || !get_domain(d) )
{
- read_unlock(&domlist_lock);
+ rcu_read_unlock(&domlist_read_lock);
ret = -ESRCH;
break;
}
- read_unlock(&domlist_lock);
+ rcu_read_unlock(&domlist_read_lock);
getdomaininfo(d, &op->u.getdomaininfo);
diff --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c
index 6568407bb2..b99d396399 100644
--- a/xen/common/keyhandler.c
+++ b/xen/common/keyhandler.c
@@ -145,7 +145,7 @@ static void dump_domains(unsigned char key)
printk("'%c' pressed -> dumping domain info (now=0x%X:%08X)\n", key,
(u32)(now>>32), (u32)now);
- read_lock(&domlist_lock);
+ rcu_read_lock(&domlist_read_lock);
for_each_domain ( d )
{
@@ -196,7 +196,7 @@ static void dump_domains(unsigned char key)
}
}
- read_unlock(&domlist_lock);
+ rcu_read_unlock(&domlist_read_lock);
}
static cpumask_t read_clocks_cpumask = CPU_MASK_NONE;
diff --git a/xen/common/sched_sedf.c b/xen/common/sched_sedf.c
index 5381fcb3ca..8f79dd23b4 100644
--- a/xen/common/sched_sedf.c
+++ b/xen/common/sched_sedf.c
@@ -1277,6 +1277,7 @@ static void sedf_dump_cpu_state(int i)
loop = 0;
printk("\nnot on Q\n");
+ rcu_read_lock(&domlist_read_lock);
for_each_domain ( d )
{
for_each_vcpu(d, ed)
@@ -1288,6 +1289,7 @@ static void sedf_dump_cpu_state(int i)
}
}
}
+ rcu_read_unlock(&domlist_read_lock);
}
@@ -1298,8 +1300,9 @@ static int sedf_adjust_weights(struct xen_domctl_scheduler_op *cmd)
struct domain *d;
int sumw[NR_CPUS] = { 0 };
s_time_t sumt[NR_CPUS] = { 0 };
-
+
/* Sum across all weights. */
+ rcu_read_lock(&domlist_read_lock);
for_each_domain( d )
{
for_each_vcpu( d, p )
@@ -1323,8 +1326,10 @@ static int sedf_adjust_weights(struct xen_domctl_scheduler_op *cmd)
}
}
}
+ rcu_read_unlock(&domlist_read_lock);
/* Adjust all slices (and periods) to the new weight. */
+ rcu_read_lock(&domlist_read_lock);
for_each_domain( d )
{
for_each_vcpu ( d, p )
@@ -1341,6 +1346,7 @@ static int sedf_adjust_weights(struct xen_domctl_scheduler_op *cmd)
}
}
}
+ rcu_read_unlock(&domlist_read_lock);
return 0;
}
diff --git a/xen/common/sysctl.c b/xen/common/sysctl.c
index 69c4d7a6ab..399523ecfd 100644
--- a/xen/common/sysctl.c
+++ b/xen/common/sysctl.c
@@ -78,7 +78,7 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl)
struct xen_domctl_getdomaininfo info;
u32 num_domains = 0;
- read_lock(&domlist_lock);
+ rcu_read_lock(&domlist_read_lock);
for_each_domain ( d )
{
@@ -106,7 +106,7 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl)
num_domains++;
}
- read_unlock(&domlist_lock);
+ rcu_read_unlock(&domlist_read_lock);
if ( ret != 0 )
break;