diff options
author | kfraser@localhost.localdomain <kfraser@localhost.localdomain> | 2007-02-21 16:13:49 +0000 |
---|---|---|
committer | kfraser@localhost.localdomain <kfraser@localhost.localdomain> | 2007-02-21 16:13:49 +0000 |
commit | c6c62d99d860ff01493f1aa3530e517f6ba7de6d (patch) | |
tree | 8bb47c79f7ff771896089a6adeebd3a3fa8bbcd6 /xen/common | |
parent | 39475b429d06a097bc528468a80c1bee2eb38a5b (diff) | |
download | xen-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.c | 68 | ||||
-rw-r--r-- | xen/common/domctl.c | 11 | ||||
-rw-r--r-- | xen/common/keyhandler.c | 4 | ||||
-rw-r--r-- | xen/common/sched_sedf.c | 8 | ||||
-rw-r--r-- | xen/common/sysctl.c | 4 |
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; |