debuggers.hg

view xen/common/domain.c @ 2633:fe2f4bbcf869

bitkeeper revision 1.1159.99.4 (41626f06VquclgVVpIeHy9z2K3jW-A)

Rationalise scheduler locking. A bit more conservative now, but much
simpler! I only applied this to the basic BVT scheduler -- the others
are still unsafe and have been removed from the basic build.
author kaf24@freefall.cl.cam.ac.uk
date Tue Oct 05 09:53:10 2004 +0000 (2004-10-05)
parents ed44deec5fb6
children 92fff25bf21e
line source
1 /******************************************************************************
2 * domain.c
3 *
4 * Generic domain-handling functions.
5 */
7 #include <xen/config.h>
8 #include <xen/init.h>
9 #include <xen/lib.h>
10 #include <xen/errno.h>
11 #include <xen/sched.h>
12 #include <xen/mm.h>
13 #include <xen/event.h>
14 #include <xen/time.h>
15 #include <xen/console.h>
16 #include <asm/shadow.h>
17 #include <hypervisor-ifs/dom0_ops.h>
18 #include <asm/domain_page.h>
20 /* Both these structures are protected by the tasklist_lock. */
21 rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED;
22 struct domain *task_hash[TASK_HASH_SIZE];
23 struct domain *task_list;
25 struct domain *do_createdomain(domid_t dom_id, unsigned int cpu)
26 {
27 char buf[100];
28 struct domain *d, **pd;
29 unsigned long flags;
31 if ( (d = alloc_domain_struct()) == NULL )
32 return NULL;
34 atomic_set(&d->refcnt, 1);
35 atomic_set(&d->pausecnt, 0);
37 shadow_lock_init(d);
39 d->domain = dom_id;
40 d->processor = cpu;
41 d->create_time = NOW();
43 memcpy(&d->thread, &idle0_task.thread, sizeof(d->thread));
45 spin_lock_init(&d->page_alloc_lock);
46 INIT_LIST_HEAD(&d->page_list);
47 INIT_LIST_HEAD(&d->xenpage_list);
49 /* Per-domain PCI-device list. */
50 spin_lock_init(&d->pcidev_lock);
51 INIT_LIST_HEAD(&d->pcidev_list);
53 if ( d->domain != IDLE_DOMAIN_ID )
54 {
55 if ( (init_event_channels(d) != 0) || (grant_table_create(d) != 0) )
56 {
57 destroy_event_channels(d);
58 free_domain_struct(d);
59 return NULL;
60 }
62 /* We use a large intermediate to avoid overflow in sprintf. */
63 sprintf(buf, "Domain-%u", dom_id);
64 strncpy(d->name, buf, MAX_DOMAIN_NAME);
65 d->name[MAX_DOMAIN_NAME-1] = '\0';
67 arch_do_createdomain(d);
69 sched_add_domain(d);
71 write_lock_irqsave(&tasklist_lock, flags);
72 pd = &task_list; /* NB. task_list is maintained in order of dom_id. */
73 for ( pd = &task_list; *pd != NULL; pd = &(*pd)->next_list )
74 if ( (*pd)->domain > d->domain )
75 break;
76 d->next_list = *pd;
77 *pd = d;
78 d->next_hash = task_hash[TASK_HASH(dom_id)];
79 task_hash[TASK_HASH(dom_id)] = d;
80 write_unlock_irqrestore(&tasklist_lock, flags);
81 }
82 else
83 {
84 sprintf(d->name, "Idle-%d", cpu);
85 sched_add_domain(d);
86 }
88 return d;
89 }
92 struct domain *find_domain_by_id(domid_t dom)
93 {
94 struct domain *d;
95 unsigned long flags;
97 read_lock_irqsave(&tasklist_lock, flags);
98 d = task_hash[TASK_HASH(dom)];
99 while ( d != NULL )
100 {
101 if ( d->domain == dom )
102 {
103 if ( unlikely(!get_domain(d)) )
104 d = NULL;
105 break;
106 }
107 d = d->next_hash;
108 }
109 read_unlock_irqrestore(&tasklist_lock, flags);
111 return d;
112 }
115 /* Return the most recently created domain. */
116 struct domain *find_last_domain(void)
117 {
118 struct domain *d, *dlast;
119 unsigned long flags;
121 read_lock_irqsave(&tasklist_lock, flags);
122 dlast = task_list;
123 d = dlast->next_list;
124 while ( d != NULL )
125 {
126 if ( d->create_time > dlast->create_time )
127 dlast = d;
128 d = d->next_list;
129 }
130 if ( !get_domain(dlast) )
131 dlast = NULL;
132 read_unlock_irqrestore(&tasklist_lock, flags);
134 return dlast;
135 }
138 void domain_kill(struct domain *d)
139 {
140 domain_pause(d);
141 if ( !test_and_set_bit(DF_DYING, &d->flags) )
142 {
143 sched_rem_domain(d);
144 domain_relinquish_memory(d);
145 put_domain(d);
146 }
147 }
150 void domain_crash(void)
151 {
152 struct domain *d;
154 if ( current->domain == 0 )
155 BUG();
157 set_bit(DF_CRASHED, &current->flags);
159 d = find_domain_by_id(0);
160 send_guest_virq(d, VIRQ_DOM_EXC);
161 put_domain(d);
163 __enter_scheduler();
164 BUG();
165 }
167 void domain_shutdown(u8 reason)
168 {
169 struct domain *d;
171 if ( current->domain == 0 )
172 {
173 extern void machine_restart(char *);
174 extern void machine_halt(void);
176 if ( reason == 0 )
177 {
178 printk("Domain 0 halted: Our work here is done.\n");
179 machine_halt();
180 }
181 else
182 {
183 printk("Domain 0 shutdown: rebooting machine!\n");
184 machine_restart(0);
185 }
186 }
188 current->shutdown_code = reason;
189 set_bit(DF_SHUTDOWN, &current->flags);
191 d = find_domain_by_id(0);
192 send_guest_virq(d, VIRQ_DOM_EXC);
193 put_domain(d);
195 __enter_scheduler();
196 }
198 unsigned int alloc_new_dom_mem(struct domain *d, unsigned int kbytes)
199 {
200 unsigned int alloc_pfns, nr_pages;
201 struct pfn_info *page;
203 nr_pages = (kbytes + ((PAGE_SIZE-1)>>10)) >> (PAGE_SHIFT - 10);
204 d->max_pages = nr_pages; /* this can now be controlled independently */
206 /* Grow the allocation if necessary. */
207 for ( alloc_pfns = d->tot_pages; alloc_pfns < nr_pages; alloc_pfns++ )
208 {
209 if ( unlikely((page = alloc_domheap_page(d)) == NULL) )
210 {
211 domain_relinquish_memory(d);
212 return -ENOMEM;
213 }
215 /* initialise to machine_to_phys_mapping table to likely pfn */
216 machine_to_phys_mapping[page-frame_table] = alloc_pfns;
218 #ifndef NDEBUG
219 {
220 /* Initialise with magic marker if in DEBUG mode. */
221 void *a = map_domain_mem((page-frame_table)<<PAGE_SHIFT);
222 memset(a, 0x80 | (char)d->domain, PAGE_SIZE);
223 unmap_domain_mem(a);
224 }
225 #endif
226 }
228 return 0;
229 }
232 /* Release resources belonging to task @p. */
233 void domain_destruct(struct domain *d)
234 {
235 struct domain **pd;
236 unsigned long flags;
237 atomic_t old, new;
239 if ( !test_bit(DF_DYING, &d->flags) )
240 BUG();
242 /* May be already destructed, or get_domain() can race us. */
243 _atomic_set(old, 0);
244 _atomic_set(new, DOMAIN_DESTRUCTED);
245 old = atomic_compareandswap(old, new, &d->refcnt);
246 if ( _atomic_read(old) != 0 )
247 return;
249 DPRINTK("Releasing task %u\n", d->domain);
251 /* Delete from task list and task hashtable. */
252 write_lock_irqsave(&tasklist_lock, flags);
253 pd = &task_list;
254 while ( *pd != d )
255 pd = &(*pd)->next_list;
256 *pd = d->next_list;
257 pd = &task_hash[TASK_HASH(d->domain)];
258 while ( *pd != d )
259 pd = &(*pd)->next_hash;
260 *pd = d->next_hash;
261 write_unlock_irqrestore(&tasklist_lock, flags);
263 destroy_event_channels(d);
264 grant_table_destroy(d);
266 free_perdomain_pt(d);
267 free_xenheap_page((unsigned long)d->shared_info);
269 free_domain_struct(d);
270 }
273 /*
274 * final_setup_guestos is used for final setup and launching of domains other
275 * than domain 0. ie. the domains that are being built by the userspace dom0
276 * domain builder.
277 */
278 int final_setup_guestos(struct domain *p, dom0_builddomain_t *builddomain)
279 {
280 int rc = 0;
281 full_execution_context_t *c;
283 if ( (c = xmalloc(sizeof(*c))) == NULL )
284 return -ENOMEM;
286 if ( test_bit(DF_CONSTRUCTED, &p->flags) )
287 {
288 rc = -EINVAL;
289 goto out;
290 }
292 if ( copy_from_user(c, builddomain->ctxt, sizeof(*c)) )
293 {
294 rc = -EFAULT;
295 goto out;
296 }
298 if ( (rc = arch_final_setup_guestos(p,c)) != 0 )
299 goto out;
301 /* Set up the shared info structure. */
302 update_dom_time(p->shared_info);
304 set_bit(DF_CONSTRUCTED, &p->flags);
306 out:
307 if ( c != NULL )
308 xfree(c);
309 return rc;
310 }
312 long vm_assist(struct domain *p, unsigned int cmd, unsigned int type)
313 {
314 if ( type > MAX_VMASST_TYPE )
315 return -EINVAL;
317 switch ( cmd )
318 {
319 case VMASST_CMD_enable:
320 set_bit(type, &p->vm_assist);
321 if (vm_assist_info[type].enable)
322 (*vm_assist_info[type].enable)(p);
323 return 0;
324 case VMASST_CMD_disable:
325 clear_bit(type, &p->vm_assist);
326 if (vm_assist_info[type].disable)
327 (*vm_assist_info[type].disable)(p);
328 return 0;
329 }
331 return -ENOSYS;
332 }