[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] Use RCU for domain_list and domain_hash.



# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1172074429 0
# Node ID 97826d77bd4debec34716c9492aeffefa91b3932
# Parent  3c581edac93accaedde8deacc532dd53e0ffb5c8
Use RCU for domain_list and domain_hash.

Signed-off-by: Jose Renato Santos <jsantos@xxxxxxxxxx>
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 xen/acm/acm_chinesewall_hooks.c             |   15 ++---
 xen/acm/acm_simple_type_enforcement_hooks.c |   76 ++++++++++++++--------------
 xen/arch/ia64/linux-xen/mca.c               |    2 
 xen/arch/ia64/linux-xen/perfmon.c           |   12 +---
 xen/arch/powerpc/audit.c                    |    2 
 xen/arch/x86/hvm/svm/vmcb.c                 |    5 +
 xen/arch/x86/hvm/vmx/vmcs.c                 |    5 +
 xen/arch/x86/mm/shadow/common.c             |    4 +
 xen/arch/x86/time.c                         |    4 -
 xen/common/domain.c                         |   72 ++++++++++++++++----------
 xen/common/domctl.c                         |   11 ++--
 xen/common/keyhandler.c                     |    4 -
 xen/common/sched_sedf.c                     |    8 ++
 xen/common/sysctl.c                         |    4 -
 xen/include/xen/rcupdate.h                  |   53 +++++++++++++++++++
 xen/include/xen/sched.h                     |   17 +++---
 16 files changed, 194 insertions(+), 100 deletions(-)

diff -r 3c581edac93a -r 97826d77bd4d xen/acm/acm_chinesewall_hooks.c
--- a/xen/acm/acm_chinesewall_hooks.c   Wed Feb 21 14:44:09 2007 +0000
+++ b/xen/acm/acm_chinesewall_hooks.c   Wed Feb 21 16:13:49 2007 +0000
@@ -194,19 +194,18 @@ chwall_init_state(struct acm_chwall_poli
     int violation = 0, i, j;
     struct chwall_ssid *chwall_ssid;
     ssidref_t chwall_ssidref;
-    struct domain **pd;
-
-    write_lock(&domlist_lock);
+    struct domain *d;
+
+    spin_lock(&domlist_update_lock);
     /* go through all domains and adjust policy as if this domain was started 
now */
-    pd = &domain_list;
-    for (pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list)
+    for_each_domain ( d )
     {
         chwall_ssid =
             GET_SSIDP(ACM_CHINESE_WALL_POLICY,
-                      (struct acm_ssid_domain *) (*pd)->ssid);
+                      (struct acm_ssid_domain *)d->ssid);
         chwall_ssidref = chwall_ssid->chwall_ssidref;
         traceprintk("%s: validating policy for domain %x (chwall-REF=%x).\n",
-                    __func__, (*pd)->domain_id, chwall_ssidref);
+                    __func__, d->domain_id, chwall_ssidref);
         /* a) adjust types ref-count for running domains */
         for (i = 0; i < chwall_buf->chwall_max_types; i++)
             running_types[i] +=
@@ -247,7 +246,7 @@ chwall_init_state(struct acm_chwall_poli
         }
     }
  out:
-    write_unlock(&domlist_lock);
+    spin_unlock(&domlist_update_lock);
     return violation;
     /* returning "violation != 0" means that the currently running set of 
domains would
      * not be possible if the new policy had been enforced before starting 
them; for chinese
diff -r 3c581edac93a -r 97826d77bd4d xen/acm/acm_simple_type_enforcement_hooks.c
--- a/xen/acm/acm_simple_type_enforcement_hooks.c       Wed Feb 21 14:44:09 
2007 +0000
+++ b/xen/acm/acm_simple_type_enforcement_hooks.c       Wed Feb 21 16:13:49 
2007 +0000
@@ -175,36 +175,37 @@ ste_init_state(struct acm_ste_policy_buf
     int violation = 1;
     struct ste_ssid *ste_ssid, *ste_rssid;
     ssidref_t ste_ssidref, ste_rssidref;
-    struct domain **pd, *rdom;
+    struct domain *d, *rdom;
     domid_t rdomid;
     struct grant_entry sha_copy;
     int port, i;
 
-    read_lock(&domlist_lock); /* go by domain? or directly by global? 
event/grant list */
+    rcu_read_lock(&domlist_read_lock);
+    /* go by domain? or directly by global? event/grant list */
     /* go through all domains and adjust policy as if this domain was started 
now */
-    pd = &domain_list;
-    for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
+    for_each_domain ( d )
+    {
         ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
-                             (struct acm_ssid_domain *)(*pd)->ssid);
+                             (struct acm_ssid_domain *)d->ssid);
         ste_ssidref = ste_ssid->ste_ssidref;
         traceprintk("%s: validating policy for eventch domain %x 
(ste-Ref=%x).\n",
-                    __func__, (*pd)->domain_id, ste_ssidref);
+                    __func__, d->domain_id, ste_ssidref);
         /* a) check for event channel conflicts */
         for (port=0; port < NR_EVTCHN_BUCKETS; port++) {
-            spin_lock(&(*pd)->evtchn_lock);
-            if ((*pd)->evtchn[port] == NULL) {
-                spin_unlock(&(*pd)->evtchn_lock);
+            spin_lock(&d->evtchn_lock);
+            if (d->evtchn[port] == NULL) {
+                spin_unlock(&d->evtchn_lock);
                 continue;
             }
-            if ((*pd)->evtchn[port]->state == ECS_INTERDOMAIN) {
-                rdom = (*pd)->evtchn[port]->u.interdomain.remote_dom;
+            if (d->evtchn[port]->state == ECS_INTERDOMAIN) {
+                rdom = d->evtchn[port]->u.interdomain.remote_dom;
                 rdomid = rdom->domain_id;
                 /* rdom now has remote domain */
                 ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
                                       (struct acm_ssid_domain *)(rdom->ssid));
                 ste_rssidref = ste_rssid->ste_ssidref;
-            } else if ((*pd)->evtchn[port]->state == ECS_UNBOUND) {
-                rdomid = (*pd)->evtchn[port]->u.unbound.remote_domid;
+            } else if (d->evtchn[port]->state == ECS_UNBOUND) {
+                rdomid = d->evtchn[port]->u.unbound.remote_domid;
                 if ((rdom = get_domain_by_id(rdomid)) == NULL) {
                     printk("%s: Error finding domain to id %x!\n", __func__, 
rdomid);
                     goto out;
@@ -215,36 +216,36 @@ ste_init_state(struct acm_ste_policy_buf
                 ste_rssidref = ste_rssid->ste_ssidref;
                 put_domain(rdom);
             } else {
-                spin_unlock(&(*pd)->evtchn_lock);
+                spin_unlock(&d->evtchn_lock);
                 continue; /* port unused */
             }
-            spin_unlock(&(*pd)->evtchn_lock);
+            spin_unlock(&d->evtchn_lock);
 
             /* rdom now has remote domain */
             ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
                                   (struct acm_ssid_domain *)(rdom->ssid));
             ste_rssidref = ste_rssid->ste_ssidref;
             traceprintk("%s: eventch: domain %x (ssidref %x) --> domain %x 
(rssidref %x) used (port %x).\n", 
-                        __func__, (*pd)->domain_id, ste_ssidref, 
rdom->domain_id, ste_rssidref, port);  
+                        __func__, d->domain_id, ste_ssidref, rdom->domain_id, 
ste_rssidref, port);  
             /* check whether on subj->ssid, obj->ssid share a common type*/
             if (!have_common_type(ste_ssidref, ste_rssidref)) {
                 printkd("%s: Policy violation in event channel domain %x -> 
domain %x.\n",
-                        __func__, (*pd)->domain_id, rdomid);
+                        __func__, d->domain_id, rdomid);
                 goto out;
             }
         } 
         /* b) check for grant table conflicts on shared pages */
-        spin_lock(&(*pd)->grant_table->lock);
-        for ( i = 0; i < nr_grant_entries((*pd)->grant_table); i++ ) {
+        spin_lock(&d->grant_table->lock);
+        for ( i = 0; i < nr_grant_entries(d->grant_table); i++ ) {
 #define SPP (PAGE_SIZE / sizeof(struct grant_entry))
-            sha_copy = (*pd)->grant_table->shared[i/SPP][i%SPP];
+            sha_copy = d->grant_table->shared[i/SPP][i%SPP];
             if ( sha_copy.flags ) {
                 printkd("%s: grant dom (%hu) SHARED (%d) flags:(%hx) dom:(%hu) 
frame:(%lx)\n",
-                        __func__, (*pd)->domain_id, i, sha_copy.flags, 
sha_copy.domid, 
+                        __func__, d->domain_id, i, sha_copy.flags, 
sha_copy.domid, 
                         (unsigned long)sha_copy.frame);
                 rdomid = sha_copy.domid;
                 if ((rdom = get_domain_by_id(rdomid)) == NULL) {
-                    spin_unlock(&(*pd)->grant_table->lock);
+                    spin_unlock(&d->grant_table->lock);
                     printkd("%s: domain not found ERROR!\n", __func__);
                     goto out;
                 };
@@ -254,18 +255,18 @@ ste_init_state(struct acm_ste_policy_buf
                 ste_rssidref = ste_rssid->ste_ssidref;
                 put_domain(rdom);
                 if (!have_common_type(ste_ssidref, ste_rssidref)) {
-                    spin_unlock(&(*pd)->grant_table->lock);
+                    spin_unlock(&d->grant_table->lock);
                     printkd("%s: Policy violation in grant table sharing 
domain %x -> domain %x.\n",
-                            __func__, (*pd)->domain_id, rdomid);
+                            __func__, d->domain_id, rdomid);
                     goto out;
                 }
             }
         }
-        spin_unlock(&(*pd)->grant_table->lock);
+        spin_unlock(&d->grant_table->lock);
     }
     violation = 0;
  out:
-    read_unlock(&domlist_lock);
+    rcu_read_unlock(&domlist_read_lock);
     return violation;
     /* returning "violation != 0" means that existing sharing between domains 
would not 
      * have been allowed if the new policy had been enforced before the 
sharing; for ste, 
@@ -281,7 +282,7 @@ ste_set_policy(u8 *buf, u32 buf_size)
     struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer 
*)buf;
     void *ssidrefsbuf;
     struct ste_ssid *ste_ssid;
-    struct domain **pd;
+    struct domain *d;
     int i;
 
     if (buf_size < sizeof(struct acm_ste_policy_buffer))
@@ -326,15 +327,14 @@ ste_set_policy(u8 *buf, u32 buf_size)
     ste_bin_pol.ssidrefs = (domaintype_t *)ssidrefsbuf;
 
     /* clear all ste caches */
-    read_lock(&domlist_lock);
-    pd = &domain_list;
-    for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
+    rcu_read_lock(&domlist_read_lock);
+    for_each_domain ( d ) {
         ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
-                             (struct acm_ssid_domain *)(*pd)->ssid);
+                             (struct acm_ssid_domain *)(d)->ssid);
         for (i=0; i<ACM_TE_CACHE_SIZE; i++)
             ste_ssid->ste_cache[i].valid = ACM_STE_free;
     }
-    read_unlock(&domlist_lock);
+    rcu_read_unlock(&domlist_read_lock);
     return ACM_OK;
 
  error_free:
@@ -436,14 +436,14 @@ clean_id_from_cache(domid_t id)
 {
     struct ste_ssid *ste_ssid;
     int i;
-    struct domain **pd;
+    struct domain *d;
     struct acm_ssid_domain *ssid;
 
     printkd("deleting cache for dom %x.\n", id);
-    read_lock(&domlist_lock); /* look through caches of all domains */
-    pd = &domain_list;
-    for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
-        ssid = (struct acm_ssid_domain *)((*pd)->ssid);
+    rcu_read_lock(&domlist_read_lock);
+    /* look through caches of all domains */
+    for_each_domain ( d ) {
+        ssid = (struct acm_ssid_domain *)(d->ssid);
 
         if (ssid == NULL)
             continue; /* hanging domain structure, no ssid any more ... */
@@ -459,7 +459,7 @@ clean_id_from_cache(domid_t id)
                 ste_ssid->ste_cache[i].valid = ACM_STE_free;
     }
  out:
-    read_unlock(&domlist_lock);
+    rcu_read_unlock(&domlist_read_lock);
 }
 
 /***************************
diff -r 3c581edac93a -r 97826d77bd4d xen/arch/ia64/linux-xen/mca.c
--- a/xen/arch/ia64/linux-xen/mca.c     Wed Feb 21 14:44:09 2007 +0000
+++ b/xen/arch/ia64/linux-xen/mca.c     Wed Feb 21 16:13:49 2007 +0000
@@ -790,6 +790,7 @@ init_handler_platform (pal_min_state_are
                        /* this route is for dump routine */
                        unw_init_running(try_crashdump, pt);
                } else {
+                       rcu_read_lock(&domlist_read_lock);
                        for_each_domain(d) {
                                for_each_vcpu(d, v) {
                                        printk("Backtrace of current vcpu "
@@ -798,6 +799,7 @@ init_handler_platform (pal_min_state_are
                                        show_stack(v, NULL);
                                }
                        }
+                       rcu_read_unlock(&domlist_read_lock);
                }
        }
        unw_init_running(freeze_cpu_osinit, NULL);
diff -r 3c581edac93a -r 97826d77bd4d xen/arch/ia64/linux-xen/perfmon.c
--- a/xen/arch/ia64/linux-xen/perfmon.c Wed Feb 21 14:44:09 2007 +0000
+++ b/xen/arch/ia64/linux-xen/perfmon.c Wed Feb 21 16:13:49 2007 +0000
@@ -7225,7 +7225,6 @@ DEFINE_PER_CPU(pfm_context_t*, xenpfm_co
 /*
  * note: some functions mask interrupt with this lock held
  * so that this lock can't be locked from interrupt handler.
- * lock order domlist_lock => xenpfm_context_lock
  */
 DEFINE_SPINLOCK(xenpfm_context_lock);
 
@@ -7507,10 +7506,8 @@ xenpfm_context_unload(void)
                arg.error[cpu] = 0;
 
        BUG_ON(in_irq());
-       read_lock(&domlist_lock);
        spin_lock(&xenpfm_context_lock);
        error = xenpfm_start_stop_locked(0);
-       read_unlock(&domlist_lock);
        if (error) {
                spin_unlock(&xenpfm_context_lock);
                return error;
@@ -7688,10 +7685,11 @@ xenpfm_start_stop_locked(int is_start)
        while (atomic_read(&arg.started) != cpus)
                cpu_relax();
 
-       for_each_domain(d) {
+       rcu_read_lock(&domlist_read_lock);
+       for_each_domain(d)
                for_each_vcpu(d, v)
                        xenpfm_start_stop_vcpu(v, is_start);
-       }
+       rcu_read_unlock(&domlist_read_lock);
 
        arg.error[smp_processor_id()] = __xenpfm_start_stop(is_start);
        atomic_inc(&arg.finished);
@@ -7716,11 +7714,9 @@ xenpfm_start_stop(int is_start)
        int error;
        
        BUG_ON(in_irq());
-       read_lock(&domlist_lock);
        spin_lock(&xenpfm_context_lock);
-       error =xenpfm_start_stop_locked(is_start);
+       error = xenpfm_start_stop_locked(is_start);
        spin_unlock(&xenpfm_context_lock);
-       read_unlock(&domlist_lock);
 
        return error;
 }
diff -r 3c581edac93a -r 97826d77bd4d xen/arch/powerpc/audit.c
--- a/xen/arch/powerpc/audit.c  Wed Feb 21 14:44:09 2007 +0000
+++ b/xen/arch/powerpc/audit.c  Wed Feb 21 16:13:49 2007 +0000
@@ -34,8 +34,10 @@ void audit_domains(void)
 void audit_domains(void)
 {
     struct domain *d;
+    rcu_read_lock(&domlist_read_lock);
     for_each_domain ( d )
         audit_domain(d);
+    rcu_read_unlock(&domlist_read_lock);
 }
 
 void audit_domains_key(unsigned char key)
diff -r 3c581edac93a -r 97826d77bd4d xen/arch/x86/hvm/svm/vmcb.c
--- a/xen/arch/x86/hvm/svm/vmcb.c       Wed Feb 21 14:44:09 2007 +0000
+++ b/xen/arch/x86/hvm/svm/vmcb.c       Wed Feb 21 16:13:49 2007 +0000
@@ -330,6 +330,9 @@ static void vmcb_dump(unsigned char ch)
     struct vcpu *v;
     
     printk("*********** VMCB Areas **************\n");
+
+    rcu_read_lock(&domlist_read_lock);
+
     for_each_domain ( d )
     {
         if ( !is_hvm_domain(d) )
@@ -341,6 +344,8 @@ static void vmcb_dump(unsigned char ch)
             svm_dump_vmcb("key_handler", v->arch.hvm_svm.vmcb);
         }
     }
+
+    rcu_read_unlock(&domlist_read_lock);
 
     printk("**************************************\n");
 }
diff -r 3c581edac93a -r 97826d77bd4d xen/arch/x86/hvm/vmx/vmcs.c
--- a/xen/arch/x86/hvm/vmx/vmcs.c       Wed Feb 21 14:44:09 2007 +0000
+++ b/xen/arch/x86/hvm/vmx/vmcs.c       Wed Feb 21 16:13:49 2007 +0000
@@ -567,6 +567,9 @@ static void vmcs_dump(unsigned char ch)
     struct vcpu *v;
     
     printk("*********** VMCS Areas **************\n");
+
+    rcu_read_lock(&domlist_read_lock);
+
     for_each_domain ( d )
     {
         if ( !is_hvm_domain(d) )
@@ -581,6 +584,8 @@ static void vmcs_dump(unsigned char ch)
         }
     }
 
+    rcu_read_unlock(&domlist_read_lock);
+
     printk("**************************************\n");
 }
 
diff -r 3c581edac93a -r 97826d77bd4d xen/arch/x86/mm/shadow/common.c
--- a/xen/arch/x86/mm/shadow/common.c   Wed Feb 21 14:44:09 2007 +0000
+++ b/xen/arch/x86/mm/shadow/common.c   Wed Feb 21 16:13:49 2007 +0000
@@ -890,13 +890,17 @@ static void shadow_blow_all_tables(unsig
 {
     struct domain *d;
     printk("'%c' pressed -> blowing all shadow tables\n", c);
+    rcu_read_lock(&domlist_read_lock);
     for_each_domain(d)
+    {
         if ( shadow_mode_enabled(d) && d->vcpu[0] != NULL )
         {
             shadow_lock(d);
             shadow_blow_tables(d);
             shadow_unlock(d);
         }
+    }
+    rcu_read_unlock(&domlist_read_lock);
 }
 
 /* Register this function in the Xen console keypress table */
diff -r 3c581edac93a -r 97826d77bd4d xen/arch/x86/time.c
--- a/xen/arch/x86/time.c       Wed Feb 21 14:44:09 2007 +0000
+++ b/xen/arch/x86/time.c       Wed Feb 21 16:13:49 2007 +0000
@@ -720,10 +720,10 @@ void do_settime(unsigned long secs, unsi
     wc_nsec = _wc_nsec = (u32)y;
     spin_unlock(&wc_lock);
 
-    read_lock(&domlist_lock);
+    rcu_read_lock(&domlist_read_lock);
     for_each_domain ( d )
         update_domain_wallclock_time(d);
-    read_unlock(&domlist_lock);
+    rcu_read_unlock(&domlist_read_lock);
 }
 
 static void local_time_calibration(void *unused)
diff -r 3c581edac93a -r 97826d77bd4d xen/common/domain.c
--- a/xen/common/domain.c       Wed Feb 21 14:44:09 2007 +0000
+++ b/xen/common/domain.c       Wed Feb 21 16:13:49 2007 +0000
@@ -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 dom
 
     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 
 {
     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 
                 d = NULL;
             break;
         }
-        d = d->next_in_hashbucket;
-    }
-    read_unlock(&domlist_lock);
+        d = rcu_dereference(d->next_in_hashbucket);
+    }
+    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);
-
-    free_domain(d);
-
-    send_guest_global_virq(dom0, VIRQ_DOM_EXC);
+    rcu_assign_pointer(*pd, d->next_in_hashbucket);
+    spin_unlock(&domlist_update_lock);
+
+    /* schedule RCU asynchronous completion of domain destroy */
+    call_rcu(&d->rcu, complete_domain_destroy);
 }
 
 static void vcpu_pause_setup(struct vcpu *v)
diff -r 3c581edac93a -r 97826d77bd4d xen/common/domctl.c
--- a/xen/common/domctl.c       Wed Feb 21 14:44:09 2007 +0000
+++ b/xen/common/domctl.c       Wed Feb 21 16:13:49 2007 +0000
@@ -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_locati
     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_domc
         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_domc
 
         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 -r 3c581edac93a -r 97826d77bd4d xen/common/keyhandler.c
--- a/xen/common/keyhandler.c   Wed Feb 21 14:44:09 2007 +0000
+++ b/xen/common/keyhandler.c   Wed Feb 21 16:13:49 2007 +0000
@@ -145,7 +145,7 @@ static void dump_domains(unsigned char k
     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 k
         }
     }
 
-    read_unlock(&domlist_lock);
+    rcu_read_unlock(&domlist_read_lock);
 }
 
 static cpumask_t read_clocks_cpumask = CPU_MASK_NONE;
diff -r 3c581edac93a -r 97826d77bd4d xen/common/sched_sedf.c
--- a/xen/common/sched_sedf.c   Wed Feb 21 14:44:09 2007 +0000
+++ b/xen/common/sched_sedf.c   Wed Feb 21 16:13:49 2007 +0000
@@ -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 xe
     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 xe
             }
         }
     }
+    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 xe
             }
         }
     }
+    rcu_read_unlock(&domlist_read_lock);
 
     return 0;
 }
diff -r 3c581edac93a -r 97826d77bd4d xen/common/sysctl.c
--- a/xen/common/sysctl.c       Wed Feb 21 14:44:09 2007 +0000
+++ b/xen/common/sysctl.c       Wed Feb 21 16:13:49 2007 +0000
@@ -78,7 +78,7 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysc
         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_sysc
             num_domains++;
         }
         
-        read_unlock(&domlist_lock);
+        rcu_read_unlock(&domlist_read_lock);
         
         if ( ret != 0 )
             break;
diff -r 3c581edac93a -r 97826d77bd4d xen/include/xen/rcupdate.h
--- a/xen/include/xen/rcupdate.h        Wed Feb 21 14:44:09 2007 +0000
+++ b/xen/include/xen/rcupdate.h        Wed Feb 21 16:13:49 2007 +0000
@@ -111,6 +111,59 @@ int rcu_pending(int cpu);
 int rcu_pending(int cpu);
 int rcu_needs_cpu(int cpu);
 
+/*
+ * Dummy lock type for passing to rcu_read_{lock,unlock}. Currently exists
+ * only to document the reason for rcu_read_lock() critical sections.
+ */
+struct _rcu_read_lock {};
+typedef struct _rcu_read_lock rcu_read_lock_t;
+#define DEFINE_RCU_READ_LOCK(x) rcu_read_lock_t x
+
+/**
+ * rcu_read_lock - mark the beginning of an RCU read-side critical section.
+ *
+ * When call_rcu() is invoked
+ * on one CPU while other CPUs are within RCU read-side critical
+ * sections, invocation of the corresponding RCU callback is deferred
+ * until after the all the other CPUs exit their critical sections.
+ *
+ * Note, however, that RCU callbacks are permitted to run concurrently
+ * with RCU read-side critical sections.  One way that this can happen
+ * is via the following sequence of events: (1) CPU 0 enters an RCU
+ * read-side critical section, (2) CPU 1 invokes call_rcu() to register
+ * an RCU callback, (3) CPU 0 exits the RCU read-side critical section,
+ * (4) CPU 2 enters a RCU read-side critical section, (5) the RCU
+ * callback is invoked.  This is legal, because the RCU read-side critical
+ * section that was running concurrently with the call_rcu() (and which
+ * therefore might be referencing something that the corresponding RCU
+ * callback would free up) has completed before the corresponding
+ * RCU callback is invoked.
+ *
+ * RCU read-side critical sections may be nested.  Any deferred actions
+ * will be deferred until the outermost RCU read-side critical section
+ * completes.
+ *
+ * It is illegal to block while in an RCU read-side critical section.
+ */
+#define rcu_read_lock(x)       do { } while (0)
+
+/**
+ * rcu_read_unlock - marks the end of an RCU read-side critical section.
+ *
+ * See rcu_read_lock() for more information.
+ */
+#define rcu_read_unlock(x)     do { } while (0)
+
+/*
+ * So where is rcu_write_lock()?  It does not exist, as there is no
+ * way for writers to lock out RCU readers.  This is a feature, not
+ * a bug -- this property is what provides RCU's performance benefits.
+ * Of course, writers must coordinate with each other.  The normal
+ * spinlock primitives work well for this, but any other technique may be
+ * used as well.  RCU does not care how the writers keep out of each
+ * others' way, as long as they do so.
+ */
+
 /**
  * rcu_dereference - fetch an RCU-protected pointer in an
  * RCU read-side critical section.  This pointer may later
diff -r 3c581edac93a -r 97826d77bd4d xen/include/xen/sched.h
--- a/xen/include/xen/sched.h   Wed Feb 21 14:44:09 2007 +0000
+++ b/xen/include/xen/sched.h   Wed Feb 21 16:13:49 2007 +0000
@@ -16,6 +16,7 @@
 #include <xen/rangeset.h>
 #include <asm/domain.h>
 #include <xen/xenoprof.h>
+#include <xen/rcupdate.h>
 #include <xen/irq.h>
 
 #ifdef CONFIG_COMPAT
@@ -24,7 +25,6 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_runstate_in
 #endif
 
 extern unsigned long volatile jiffies;
-extern rwlock_t domlist_lock;
 
 /* A global pointer to the initial domain (DOM0). */
 extern struct domain *dom0;
@@ -193,6 +193,8 @@ struct domain
     /* OProfile support. */
     struct xenoprof *xenoprof;
     int32_t time_offset_seconds;
+
+    struct rcu_head rcu;
 };
 
 struct domain_setup_info
@@ -356,16 +358,17 @@ unsigned long hypercall_create_continuat
         local_events_need_delivery()            \
     ))
 
-/* This domain_hash and domain_list are protected by the domlist_lock. */
-#define DOMAIN_HASH_SIZE 256
-#define DOMAIN_HASH(_id) ((int)(_id)&(DOMAIN_HASH_SIZE-1))
-extern struct domain *domain_hash[DOMAIN_HASH_SIZE];
+/* Protect updates/reads (resp.) of domain_list and domain_hash. */
+extern spinlock_t domlist_update_lock;
+extern rcu_read_lock_t domlist_read_lock;
+
 extern struct domain *domain_list;
 
+/* Caller must hold the domlist_read_lock or domlist_update_lock. */
 #define for_each_domain(_d)                     \
- for ( (_d) = domain_list;                      \
+ for ( (_d) = rcu_dereference(domain_list);     \
        (_d) != NULL;                            \
-       (_d) = (_d)->next_in_list )
+       (_d) = rcu_dereference((_d)->next_in_list )) \
 
 #define for_each_vcpu(_d,_v)                    \
  for ( (_v) = (_d)->vcpu[0];                    \

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.