mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
[XEN] Separate domain creation from vcpu creation.
Creating a domain no longer creates vcpu0 -- that is now done later. Signed-off-by: Keir Fraser <keir@xensource.com>
This commit is contained in:
1 parent
78c851da09
commit
ecf0bebefa
10 files changed
+150
-104
No files matched your search
@@ -425,8 +425,9 @@ void start_kernel(void)
|
||||
|
||||
scheduler_init();
|
||||
idle_vcpu[0] = (struct vcpu*) ia64_r13;
|
||||
idle_domain = domain_create(IDLE_DOMAIN_ID, 0);
|
||||
BUG_ON(idle_domain == NULL);
|
||||
idle_domain = domain_create(IDLE_DOMAIN_ID);
|
||||
if ( (idle_domain == NULL) || (alloc_vcpu(idle_domain, 0, 0) == NULL) )
|
||||
BUG();
|
||||
|
||||
late_setup_arch(&cmdline);
|
||||
alloc_dom_xen_and_dom_io();
|
||||
@@ -503,9 +504,8 @@ printk("num_online_cpus=%d, max_cpus=%d\n",num_online_cpus(),max_cpus);
|
||||
}
|
||||
|
||||
/* Create initial domain 0. */
|
||||
dom0 = domain_create(0, 0);
|
||||
|
||||
if ( dom0 == NULL )
|
||||
dom0 = domain_create(0);
|
||||
if ( (dom0 == NULL) || (alloc_vcpu(dom0, 0, 0) == NULL) )
|
||||
panic("Error creating domain 0\n");
|
||||
|
||||
set_bit(_DOMF_privileged, &dom0->domain_flags);
|
||||
|
||||
@@ -951,7 +951,7 @@ void domain_relinquish_resources(struct domain *d)
|
||||
}
|
||||
}
|
||||
|
||||
if ( hvm_guest(d->vcpu[0]) )
|
||||
if ( d->vcpu[0] && hvm_guest(d->vcpu[0]) )
|
||||
hvm_relinquish_guest_resources(d);
|
||||
|
||||
shadow_mode_disable(d);
|
||||
|
||||
@@ -439,8 +439,9 @@ void __init __start_xen(multiboot_info_t *mbi)
|
||||
|
||||
scheduler_init();
|
||||
|
||||
idle_domain = domain_create(IDLE_DOMAIN_ID, 0);
|
||||
BUG_ON(idle_domain == NULL);
|
||||
idle_domain = domain_create(IDLE_DOMAIN_ID);
|
||||
if ( (idle_domain == NULL) || (alloc_vcpu(idle_domain, 0, 0) == NULL) )
|
||||
BUG();
|
||||
|
||||
set_current(idle_domain->vcpu[0]);
|
||||
this_cpu(curr_vcpu) = idle_domain->vcpu[0];
|
||||
@@ -537,8 +538,8 @@ void __init __start_xen(multiboot_info_t *mbi)
|
||||
acm_init(&initrdidx, mbi, initial_images_start);
|
||||
|
||||
/* Create initial domain 0. */
|
||||
dom0 = domain_create(0, 0);
|
||||
if ( dom0 == NULL )
|
||||
dom0 = domain_create(0);
|
||||
if ( (dom0 == NULL) || (alloc_vcpu(dom0, 0, 0) == NULL) )
|
||||
panic("Error creating domain 0\n");
|
||||
|
||||
set_bit(_DOMF_privileged, &dom0->domain_flags);
|
||||
|
||||
@@ -1397,13 +1397,14 @@ static void nmi_softirq(void)
|
||||
static void nmi_dom0_report(unsigned int reason_idx)
|
||||
{
|
||||
struct domain *d;
|
||||
struct vcpu *v;
|
||||
|
||||
if ( (d = dom0) == NULL )
|
||||
if ( ((d = dom0) == NULL) || ((v = d->vcpu[0]) == NULL) )
|
||||
return;
|
||||
|
||||
set_bit(reason_idx, &d->shared_info->arch.nmi_reason);
|
||||
|
||||
if ( test_and_set_bit(_VCPUF_nmi_pending, &d->vcpu[0]->vcpu_flags) )
|
||||
if ( test_and_set_bit(_VCPUF_nmi_pending, &v->vcpu_flags) )
|
||||
raise_softirq(NMI_SOFTIRQ); /* not safe to wake up a vcpu here */
|
||||
}
|
||||
|
||||
|
||||
+52
-48
@@ -90,6 +90,44 @@ static void getdomaininfo(struct domain *d, dom0_getdomaininfo_t *info)
|
||||
memcpy(info->handle, d->handle, sizeof(xen_domain_handle_t));
|
||||
}
|
||||
|
||||
static unsigned int default_vcpu0_location(void)
|
||||
{
|
||||
struct domain *d;
|
||||
struct vcpu *v;
|
||||
unsigned int i, cpu, cnt[NR_CPUS] = { 0 };
|
||||
cpumask_t cpu_exclude_map;
|
||||
|
||||
/* Do an initial CPU placement. Pick the least-populated CPU. */
|
||||
read_lock(&domlist_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);
|
||||
|
||||
/*
|
||||
* If we're on a HT system, we only auto-allocate to a non-primary HT. We
|
||||
* favour high numbered CPUs in the event of a tie.
|
||||
*/
|
||||
cpu = first_cpu(cpu_sibling_map[0]);
|
||||
if ( cpus_weight(cpu_sibling_map[0]) > 1 )
|
||||
cpu = next_cpu(cpu, cpu_sibling_map[0]);
|
||||
cpu_exclude_map = cpu_sibling_map[0];
|
||||
for_each_online_cpu ( i )
|
||||
{
|
||||
if ( cpu_isset(i, cpu_exclude_map) )
|
||||
continue;
|
||||
if ( (i == first_cpu(cpu_sibling_map[i])) &&
|
||||
(cpus_weight(cpu_sibling_map[i]) > 1) )
|
||||
continue;
|
||||
cpus_or(cpu_exclude_map, cpu_exclude_map, cpu_sibling_map[i]);
|
||||
if ( cnt[i] <= cnt[cpu] )
|
||||
cpu = i;
|
||||
}
|
||||
|
||||
return cpu;
|
||||
}
|
||||
|
||||
long do_dom0_op(XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op)
|
||||
{
|
||||
long ret = 0;
|
||||
@@ -150,7 +188,7 @@ long do_dom0_op(XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op)
|
||||
if ( d != NULL )
|
||||
{
|
||||
ret = -EINVAL;
|
||||
if ( (d != current->domain) &&
|
||||
if ( (d != current->domain) && (d->vcpu[0] != NULL) &&
|
||||
test_bit(_VCPUF_initialised, &d->vcpu[0]->vcpu_flags) )
|
||||
{
|
||||
domain_unpause_by_systemcontroller(d);
|
||||
@@ -164,11 +202,7 @@ long do_dom0_op(XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op)
|
||||
case DOM0_CREATEDOMAIN:
|
||||
{
|
||||
struct domain *d;
|
||||
unsigned int pro;
|
||||
domid_t dom;
|
||||
struct vcpu *v;
|
||||
unsigned int i, cnt[NR_CPUS] = { 0 };
|
||||
cpumask_t cpu_exclude_map;
|
||||
static domid_t rover = 0;
|
||||
|
||||
/*
|
||||
@@ -202,36 +236,8 @@ long do_dom0_op(XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op)
|
||||
rover = dom;
|
||||
}
|
||||
|
||||
/* Do an initial CPU placement. Pick the least-populated CPU. */
|
||||
read_lock(&domlist_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);
|
||||
|
||||
/*
|
||||
* If we're on a HT system, we only auto-allocate to a non-primary HT.
|
||||
* We favour high numbered CPUs in the event of a tie.
|
||||
*/
|
||||
pro = first_cpu(cpu_sibling_map[0]);
|
||||
if ( cpus_weight(cpu_sibling_map[0]) > 1 )
|
||||
pro = next_cpu(pro, cpu_sibling_map[0]);
|
||||
cpu_exclude_map = cpu_sibling_map[0];
|
||||
for_each_online_cpu ( i )
|
||||
{
|
||||
if ( cpu_isset(i, cpu_exclude_map) )
|
||||
continue;
|
||||
if ( (i == first_cpu(cpu_sibling_map[i])) &&
|
||||
(cpus_weight(cpu_sibling_map[i]) > 1) )
|
||||
continue;
|
||||
cpus_or(cpu_exclude_map, cpu_exclude_map, cpu_sibling_map[i]);
|
||||
if ( cnt[i] <= cnt[pro] )
|
||||
pro = i;
|
||||
}
|
||||
|
||||
ret = -ENOMEM;
|
||||
if ( (d = domain_create(dom, pro)) == NULL )
|
||||
if ( (d = domain_create(dom)) == NULL )
|
||||
break;
|
||||
|
||||
memcpy(d->handle, op->u.createdomain.handle,
|
||||
@@ -258,14 +264,8 @@ long do_dom0_op(XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op)
|
||||
if ( (d = find_domain_by_id(op->u.max_vcpus.domain)) == NULL )
|
||||
break;
|
||||
|
||||
/*
|
||||
* Can only create new VCPUs while the domain is not fully constructed
|
||||
* (and hence not runnable). Xen needs auditing for races before
|
||||
* removing this check.
|
||||
*/
|
||||
ret = -EINVAL;
|
||||
if ( test_bit(_VCPUF_initialised, &d->vcpu[0]->vcpu_flags) )
|
||||
goto maxvcpu_out;
|
||||
/* Needed, for example, to ensure writable p.t. state is synced. */
|
||||
domain_pause(d);
|
||||
|
||||
/* We cannot reduce maximum VCPUs. */
|
||||
ret = -EINVAL;
|
||||
@@ -275,17 +275,21 @@ long do_dom0_op(XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op)
|
||||
ret = -ENOMEM;
|
||||
for ( i = 0; i < max; i++ )
|
||||
{
|
||||
if ( d->vcpu[i] == NULL )
|
||||
{
|
||||
cpu = (d->vcpu[i-1]->processor + 1) % num_online_cpus();
|
||||
if ( alloc_vcpu(d, i, cpu) == NULL )
|
||||
goto maxvcpu_out;
|
||||
}
|
||||
if ( d->vcpu[i] != NULL )
|
||||
continue;
|
||||
|
||||
cpu = (i == 0) ?
|
||||
default_vcpu0_location() :
|
||||
(d->vcpu[i-1]->processor + 1) % num_online_cpus();
|
||||
|
||||
if ( alloc_vcpu(d, i, cpu) == NULL )
|
||||
goto maxvcpu_out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
maxvcpu_out:
|
||||
domain_unpause(d);
|
||||
put_domain(d);
|
||||
}
|
||||
break;
|
||||
|
||||
+57
-35
@@ -46,6 +46,7 @@ struct domain *alloc_domain(domid_t domid)
|
||||
atomic_set(&d->refcnt, 1);
|
||||
spin_lock_init(&d->big_lock);
|
||||
spin_lock_init(&d->page_alloc_lock);
|
||||
spin_lock_init(&d->pause_lock);
|
||||
INIT_LIST_HEAD(&d->page_list);
|
||||
INIT_LIST_HEAD(&d->xenpage_list);
|
||||
|
||||
@@ -81,8 +82,8 @@ struct vcpu *alloc_vcpu(
|
||||
v->domain = d;
|
||||
v->vcpu_id = vcpu_id;
|
||||
v->processor = cpu_id;
|
||||
atomic_set(&v->pausecnt, 0);
|
||||
v->vcpu_info = &d->shared_info->vcpu_info[vcpu_id];
|
||||
spin_lock_init(&v->pause_lock);
|
||||
|
||||
v->cpu_affinity = is_idle_domain(d) ?
|
||||
cpumask_of_cpu(cpu_id) : CPU_MASK_ALL;
|
||||
@@ -110,30 +111,22 @@ struct vcpu *alloc_idle_vcpu(unsigned int cpu_id)
|
||||
{
|
||||
struct domain *d;
|
||||
struct vcpu *v;
|
||||
unsigned int vcpu_id;
|
||||
unsigned int vcpu_id = cpu_id % MAX_VIRT_CPUS;
|
||||
|
||||
if ((vcpu_id = cpu_id % MAX_VIRT_CPUS) == 0)
|
||||
{
|
||||
d = domain_create(IDLE_DOMAIN_ID, cpu_id);
|
||||
BUG_ON(d == NULL);
|
||||
v = d->vcpu[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
d = idle_vcpu[cpu_id - vcpu_id]->domain;
|
||||
BUG_ON(d == NULL);
|
||||
v = alloc_vcpu(d, vcpu_id, cpu_id);
|
||||
}
|
||||
d = (vcpu_id == 0) ?
|
||||
domain_create(IDLE_DOMAIN_ID) :
|
||||
idle_vcpu[cpu_id - vcpu_id]->domain;
|
||||
BUG_ON(d == NULL);
|
||||
|
||||
v = alloc_vcpu(d, vcpu_id, cpu_id);
|
||||
idle_vcpu[cpu_id] = v;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
struct domain *domain_create(domid_t domid, unsigned int cpu)
|
||||
struct domain *domain_create(domid_t domid)
|
||||
{
|
||||
struct domain *d, **pd;
|
||||
struct vcpu *v;
|
||||
|
||||
if ( (d = alloc_domain(domid)) == NULL )
|
||||
return NULL;
|
||||
@@ -152,13 +145,10 @@ struct domain *domain_create(domid_t domid, unsigned int cpu)
|
||||
if ( arch_domain_create(d) != 0 )
|
||||
goto fail3;
|
||||
|
||||
if ( (v = alloc_vcpu(d, 0, cpu)) == NULL )
|
||||
goto fail4;
|
||||
|
||||
d->iomem_caps = rangeset_new(d, "I/O Memory", RANGESETF_prettyprint_hex);
|
||||
d->irq_caps = rangeset_new(d, "Interrupts", 0);
|
||||
if ( (d->iomem_caps == NULL) || (d->irq_caps == NULL) )
|
||||
goto fail4; /* NB. alloc_vcpu() is undone in free_domain() */
|
||||
goto fail4;
|
||||
|
||||
if ( !is_idle_domain(d) )
|
||||
{
|
||||
@@ -327,11 +317,12 @@ void domain_shutdown(struct domain *d, u8 reason)
|
||||
d->shutdown_code = reason;
|
||||
|
||||
/* Put every vcpu to sleep, but don't wait (avoids inter-vcpu deadlock). */
|
||||
spin_lock(&d->pause_lock);
|
||||
d->pause_count++;
|
||||
set_bit(_DOMF_paused, &d->domain_flags);
|
||||
spin_unlock(&d->pause_lock);
|
||||
for_each_vcpu ( d, v )
|
||||
{
|
||||
atomic_inc(&v->pausecnt);
|
||||
vcpu_sleep_nosync(v);
|
||||
}
|
||||
|
||||
get_knownalive_domain(d);
|
||||
domain_shuttingdown[smp_processor_id()] = d;
|
||||
@@ -398,34 +389,65 @@ void domain_destroy(struct domain *d)
|
||||
|
||||
void vcpu_pause(struct vcpu *v)
|
||||
{
|
||||
BUG_ON(v == current);
|
||||
atomic_inc(&v->pausecnt);
|
||||
ASSERT(v != current);
|
||||
|
||||
spin_lock(&v->pause_lock);
|
||||
if ( v->pause_count++ == 0 )
|
||||
set_bit(_VCPUF_paused, &v->vcpu_flags);
|
||||
spin_unlock(&v->pause_lock);
|
||||
|
||||
vcpu_sleep_sync(v);
|
||||
}
|
||||
|
||||
void vcpu_unpause(struct vcpu *v)
|
||||
{
|
||||
int wake;
|
||||
|
||||
ASSERT(v != current);
|
||||
|
||||
spin_lock(&v->pause_lock);
|
||||
wake = (--v->pause_count == 0);
|
||||
if ( wake )
|
||||
clear_bit(_VCPUF_paused, &v->vcpu_flags);
|
||||
spin_unlock(&v->pause_lock);
|
||||
|
||||
if ( wake )
|
||||
vcpu_wake(v);
|
||||
}
|
||||
|
||||
void domain_pause(struct domain *d)
|
||||
{
|
||||
struct vcpu *v;
|
||||
|
||||
ASSERT(d != current->domain);
|
||||
|
||||
spin_lock(&d->pause_lock);
|
||||
if ( d->pause_count++ == 0 )
|
||||
set_bit(_DOMF_paused, &d->domain_flags);
|
||||
spin_unlock(&d->pause_lock);
|
||||
|
||||
for_each_vcpu( d, v )
|
||||
vcpu_pause(v);
|
||||
vcpu_sleep_sync(v);
|
||||
|
||||
sync_pagetable_state(d);
|
||||
}
|
||||
|
||||
void vcpu_unpause(struct vcpu *v)
|
||||
{
|
||||
BUG_ON(v == current);
|
||||
if ( atomic_dec_and_test(&v->pausecnt) )
|
||||
vcpu_wake(v);
|
||||
}
|
||||
|
||||
void domain_unpause(struct domain *d)
|
||||
{
|
||||
struct vcpu *v;
|
||||
int wake;
|
||||
|
||||
for_each_vcpu( d, v )
|
||||
vcpu_unpause(v);
|
||||
ASSERT(d != current->domain);
|
||||
|
||||
spin_lock(&d->pause_lock);
|
||||
wake = (--d->pause_count == 0);
|
||||
if ( wake )
|
||||
clear_bit(_DOMF_paused, &d->domain_flags);
|
||||
spin_unlock(&d->pause_lock);
|
||||
|
||||
if ( wake )
|
||||
for_each_vcpu( d, v )
|
||||
vcpu_wake(v);
|
||||
}
|
||||
|
||||
void domain_pause_by_systemcontroller(struct domain *d)
|
||||
|
||||
@@ -525,11 +525,16 @@ void send_guest_vcpu_virq(struct vcpu *v, int virq)
|
||||
void send_guest_global_virq(struct domain *d, int virq)
|
||||
{
|
||||
int port;
|
||||
struct vcpu *v;
|
||||
struct evtchn *chn;
|
||||
|
||||
ASSERT(virq_is_global(virq));
|
||||
|
||||
port = d->vcpu[0]->virq_to_evtchn[virq];
|
||||
v = d->vcpu[0];
|
||||
if ( unlikely(v == NULL) )
|
||||
return;
|
||||
|
||||
port = v->virq_to_evtchn[virq];
|
||||
if ( unlikely(port == 0) )
|
||||
return;
|
||||
|
||||
|
||||
@@ -1429,6 +1429,8 @@ static int sedf_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd)
|
||||
}
|
||||
else if ( cmd->direction == SCHED_INFO_GET )
|
||||
{
|
||||
if ( p->vcpu[0] == NULL )
|
||||
return -EINVAL;
|
||||
cmd->u.sedf.period = EDOM_INFO(p->vcpu[0])->period;
|
||||
cmd->u.sedf.slice = EDOM_INFO(p->vcpu[0])->slice;
|
||||
cmd->u.sedf.extratime = EDOM_INFO(p->vcpu[0])->status & EXTRA_AWARE;
|
||||
|
||||
@@ -279,7 +279,7 @@ static void switch_serial_input(void)
|
||||
{
|
||||
static char *input_str[2] = { "DOM0", "Xen" };
|
||||
xen_rx = !xen_rx;
|
||||
if ( SWITCH_CODE != 0 )
|
||||
if ( (SWITCH_CODE != 0) && (dom0 != NULL) )
|
||||
{
|
||||
printk("*** Serial input -> %s "
|
||||
"(type 'CTRL-%c' three times to switch input to %s).\n",
|
||||
|
||||
+18
-7
@@ -78,9 +78,10 @@ struct vcpu
|
||||
|
||||
unsigned long vcpu_flags;
|
||||
|
||||
u16 virq_to_evtchn[NR_VIRQS];
|
||||
spinlock_t pause_lock;
|
||||
unsigned int pause_count;
|
||||
|
||||
atomic_t pausecnt;
|
||||
u16 virq_to_evtchn[NR_VIRQS];
|
||||
|
||||
/* Bitmask of CPUs on which this VCPU may run. */
|
||||
cpumask_t cpu_affinity;
|
||||
@@ -141,6 +142,10 @@ struct domain
|
||||
struct rangeset *irq_caps;
|
||||
|
||||
unsigned long domain_flags;
|
||||
|
||||
spinlock_t pause_lock;
|
||||
unsigned int pause_count;
|
||||
|
||||
unsigned long vm_assist;
|
||||
|
||||
atomic_t refcnt;
|
||||
@@ -220,8 +225,7 @@ static inline void get_knownalive_domain(struct domain *d)
|
||||
ASSERT(!(atomic_read(&d->refcnt) & DOMAIN_DESTROYED));
|
||||
}
|
||||
|
||||
extern struct domain *domain_create(
|
||||
domid_t domid, unsigned int cpu);
|
||||
extern struct domain *domain_create(domid_t domid);
|
||||
extern int construct_dom0(
|
||||
struct domain *d,
|
||||
unsigned long image_start, unsigned long image_len,
|
||||
@@ -368,6 +372,9 @@ extern struct domain *domain_list;
|
||||
/* VCPU is polling a set of event channels (SCHEDOP_poll). */
|
||||
#define _VCPUF_polling 10
|
||||
#define VCPUF_polling (1UL<<_VCPUF_polling)
|
||||
/* VCPU is paused by the hypervisor? */
|
||||
#define _VCPUF_paused 11
|
||||
#define VCPUF_paused (1UL<<_VCPUF_paused)
|
||||
|
||||
/*
|
||||
* Per-domain flags (domain_flags).
|
||||
@@ -390,12 +397,16 @@ extern struct domain *domain_list;
|
||||
/* Are any VCPUs polling event channels (SCHEDOP_poll)? */
|
||||
#define _DOMF_polling 5
|
||||
#define DOMF_polling (1UL<<_DOMF_polling)
|
||||
/* Domain is paused by the hypervisor? */
|
||||
#define _DOMF_paused 6
|
||||
#define DOMF_paused (1UL<<_DOMF_paused)
|
||||
|
||||
static inline int vcpu_runnable(struct vcpu *v)
|
||||
{
|
||||
return ( (atomic_read(&v->pausecnt) == 0) &&
|
||||
!(v->vcpu_flags & (VCPUF_blocked|VCPUF_down)) &&
|
||||
!(v->domain->domain_flags & (DOMF_shutdown|DOMF_ctrl_pause)) );
|
||||
return ( !(v->vcpu_flags &
|
||||
(VCPUF_blocked|VCPUF_down|VCPUF_paused)) &&
|
||||
!(v->domain->domain_flags &
|
||||
(DOMF_shutdown|DOMF_ctrl_pause|DOMF_paused)) );
|
||||
}
|
||||
|
||||
void vcpu_pause(struct vcpu *v);
|
||||
|
||||