aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlauber de Oliveira Costa <gcosta@redhat.com>2008-01-07 08:05:34 -0500
committerRusty Russell <rusty@rustcorp.com.au>2008-01-30 06:50:12 -0500
commit66686c2ab08feb721ca4d98285fba64acdf6017f (patch)
treebae76c0e0dc78809abc83b8f0dc9f84dca702de0
parentfc708b3e407dfd2e12ba9a6cf35bd0bffad1796d (diff)
lguest: per-vcpu lguest task management
lguest uses tasks to control its running behaviour (like sending breaks, controlling halted state, etc). In a per-vcpu environment, each vcpu will have its own underlying task. So this patch makes the infrastructure for that possible Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r--drivers/lguest/core.c4
-rw-r--r--drivers/lguest/hypercalls.c2
-rw-r--r--drivers/lguest/interrupts_and_traps.c8
-rw-r--r--drivers/lguest/lg.h14
-rw-r--r--drivers/lguest/lguest_user.c53
5 files changed, 42 insertions, 39 deletions
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c
index d8e1ac305dc6..66c3d3b17fe4 100644
--- a/drivers/lguest/core.c
+++ b/drivers/lguest/core.c
@@ -197,7 +197,7 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
197 return -ERESTARTSYS; 197 return -ERESTARTSYS;
198 198
199 /* If Waker set break_out, return to Launcher. */ 199 /* If Waker set break_out, return to Launcher. */
200 if (lg->break_out) 200 if (cpu->break_out)
201 return -EAGAIN; 201 return -EAGAIN;
202 202
203 /* Check if there are any interrupts which can be delivered 203 /* Check if there are any interrupts which can be delivered
@@ -217,7 +217,7 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
217 217
218 /* If the Guest asked to be stopped, we sleep. The Guest's 218 /* If the Guest asked to be stopped, we sleep. The Guest's
219 * clock timer or LHCALL_BREAK from the Waker will wake us. */ 219 * clock timer or LHCALL_BREAK from the Waker will wake us. */
220 if (lg->halted) { 220 if (cpu->halted) {
221 set_current_state(TASK_INTERRUPTIBLE); 221 set_current_state(TASK_INTERRUPTIBLE);
222 schedule(); 222 schedule();
223 continue; 223 continue;
diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c
index 6f8c70ae380d..83323b1cc0b2 100644
--- a/drivers/lguest/hypercalls.c
+++ b/drivers/lguest/hypercalls.c
@@ -88,7 +88,7 @@ static void do_hcall(struct lg_cpu *cpu, struct hcall_args *args)
88 break; 88 break;
89 case LHCALL_HALT: 89 case LHCALL_HALT:
90 /* Similarly, this sets the halted flag for run_guest(). */ 90 /* Similarly, this sets the halted flag for run_guest(). */
91 lg->halted = 1; 91 cpu->halted = 1;
92 break; 92 break;
93 case LHCALL_NOTIFY: 93 case LHCALL_NOTIFY:
94 lg->pending_notify = args->arg1; 94 lg->pending_notify = args->arg1;
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c
index 306b93c71dcc..9c1c479e8c62 100644
--- a/drivers/lguest/interrupts_and_traps.c
+++ b/drivers/lguest/interrupts_and_traps.c
@@ -161,11 +161,11 @@ void maybe_do_interrupt(struct lg_cpu *cpu)
161 return; 161 return;
162 162
163 /* If they're halted, interrupts restart them. */ 163 /* If they're halted, interrupts restart them. */
164 if (lg->halted) { 164 if (cpu->halted) {
165 /* Re-enable interrupts. */ 165 /* Re-enable interrupts. */
166 if (put_user(X86_EFLAGS_IF, &lg->lguest_data->irq_enabled)) 166 if (put_user(X86_EFLAGS_IF, &lg->lguest_data->irq_enabled))
167 kill_guest(lg, "Re-enabling interrupts"); 167 kill_guest(lg, "Re-enabling interrupts");
168 lg->halted = 0; 168 cpu->halted = 0;
169 } else { 169 } else {
170 /* Otherwise we check if they have interrupts disabled. */ 170 /* Otherwise we check if they have interrupts disabled. */
171 u32 irq_enabled; 171 u32 irq_enabled;
@@ -497,8 +497,8 @@ static enum hrtimer_restart clockdev_fn(struct hrtimer *timer)
497 /* Remember the first interrupt is the timer interrupt. */ 497 /* Remember the first interrupt is the timer interrupt. */
498 set_bit(0, cpu->irqs_pending); 498 set_bit(0, cpu->irqs_pending);
499 /* If the Guest is actually stopped, we need to wake it up. */ 499 /* If the Guest is actually stopped, we need to wake it up. */
500 if (cpu->lg->halted) 500 if (cpu->halted)
501 wake_up_process(cpu->lg->tsk); 501 wake_up_process(cpu->tsk);
502 return HRTIMER_NORESTART; 502 return HRTIMER_NORESTART;
503} 503}
504 504
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h
index d08b85342b92..e7123fa6127f 100644
--- a/drivers/lguest/lg.h
+++ b/drivers/lguest/lg.h
@@ -43,6 +43,8 @@ struct lguest;
43struct lg_cpu { 43struct lg_cpu {
44 unsigned int id; 44 unsigned int id;
45 struct lguest *lg; 45 struct lguest *lg;
46 struct task_struct *tsk;
47 struct mm_struct *mm; /* == tsk->mm, but that becomes NULL on exit */
46 48
47 /* At end of a page shared mapped over lguest_pages in guest. */ 49 /* At end of a page shared mapped over lguest_pages in guest. */
48 unsigned long regs_page; 50 unsigned long regs_page;
@@ -55,6 +57,11 @@ struct lg_cpu {
55 /* Virtual clock device */ 57 /* Virtual clock device */
56 struct hrtimer hrt; 58 struct hrtimer hrt;
57 59
60 /* Do we need to stop what we're doing and return to userspace? */
61 int break_out;
62 wait_queue_head_t break_wq;
63 int halted;
64
58 /* Pending virtual interrupts */ 65 /* Pending virtual interrupts */
59 DECLARE_BITMAP(irqs_pending, LGUEST_IRQS); 66 DECLARE_BITMAP(irqs_pending, LGUEST_IRQS);
60 67
@@ -65,8 +72,6 @@ struct lg_cpu {
65struct lguest 72struct lguest
66{ 73{
67 struct lguest_data __user *lguest_data; 74 struct lguest_data __user *lguest_data;
68 struct task_struct *tsk;
69 struct mm_struct *mm; /* == tsk->mm, but that becomes NULL on exit */
70 struct lg_cpu cpus[NR_CPUS]; 75 struct lg_cpu cpus[NR_CPUS];
71 unsigned int nr_cpus; 76 unsigned int nr_cpus;
72 77
@@ -76,15 +81,10 @@ struct lguest
76 void __user *mem_base; 81 void __user *mem_base;
77 unsigned long kernel_address; 82 unsigned long kernel_address;
78 u32 cr2; 83 u32 cr2;
79 int halted;
80 int ts; 84 int ts;
81 u32 esp1; 85 u32 esp1;
82 u8 ss1; 86 u8 ss1;
83 87
84 /* Do we need to stop what we're doing and return to userspace? */
85 int break_out;
86 wait_queue_head_t break_wq;
87
88 /* Bitmap of what has changed: see CHANGED_* above. */ 88 /* Bitmap of what has changed: see CHANGED_* above. */
89 int changed; 89 int changed;
90 struct lguest_pages *last_pages; 90 struct lguest_pages *last_pages;
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c
index d21d95b2b1fc..980b3550db7f 100644
--- a/drivers/lguest/lguest_user.c
+++ b/drivers/lguest/lguest_user.c
@@ -13,7 +13,7 @@
13 * LHREQ_BREAK and the value "1" to /dev/lguest to do this. Once the Launcher 13 * LHREQ_BREAK and the value "1" to /dev/lguest to do this. Once the Launcher
14 * has done whatever needs attention, it writes LHREQ_BREAK and "0" to release 14 * has done whatever needs attention, it writes LHREQ_BREAK and "0" to release
15 * the Waker. */ 15 * the Waker. */
16static int break_guest_out(struct lguest *lg, const unsigned long __user *input) 16static int break_guest_out(struct lg_cpu *cpu, const unsigned long __user*input)
17{ 17{
18 unsigned long on; 18 unsigned long on;
19 19
@@ -22,14 +22,14 @@ static int break_guest_out(struct lguest *lg, const unsigned long __user *input)
22 return -EFAULT; 22 return -EFAULT;
23 23
24 if (on) { 24 if (on) {
25 lg->break_out = 1; 25 cpu->break_out = 1;
26 /* Pop it out of the Guest (may be running on different CPU) */ 26 /* Pop it out of the Guest (may be running on different CPU) */
27 wake_up_process(lg->tsk); 27 wake_up_process(cpu->tsk);
28 /* Wait for them to reset it */ 28 /* Wait for them to reset it */
29 return wait_event_interruptible(lg->break_wq, !lg->break_out); 29 return wait_event_interruptible(cpu->break_wq, !cpu->break_out);
30 } else { 30 } else {
31 lg->break_out = 0; 31 cpu->break_out = 0;
32 wake_up(&lg->break_wq); 32 wake_up(&cpu->break_wq);
33 return 0; 33 return 0;
34 } 34 }
35} 35}
@@ -69,7 +69,7 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
69 cpu = &lg->cpus[cpu_id]; 69 cpu = &lg->cpus[cpu_id];
70 70
71 /* If you're not the task which owns the Guest, go away. */ 71 /* If you're not the task which owns the Guest, go away. */
72 if (current != lg->tsk) 72 if (current != cpu->tsk)
73 return -EPERM; 73 return -EPERM;
74 74
75 /* If the guest is already dead, we indicate why */ 75 /* If the guest is already dead, we indicate why */
@@ -119,6 +119,18 @@ static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
119 * address. */ 119 * address. */
120 lguest_arch_setup_regs(cpu, start_ip); 120 lguest_arch_setup_regs(cpu, start_ip);
121 121
122 /* Initialize the queue for the waker to wait on */
123 init_waitqueue_head(&cpu->break_wq);
124
125 /* We keep a pointer to the Launcher task (ie. current task) for when
126 * other Guests want to wake this one (inter-Guest I/O). */
127 cpu->tsk = current;
128
129 /* We need to keep a pointer to the Launcher's memory map, because if
130 * the Launcher dies we need to clean it up. If we don't keep a
131 * reference, it is destroyed before close() is called. */
132 cpu->mm = get_task_mm(cpu->tsk);
133
122 return 0; 134 return 0;
123} 135}
124 136
@@ -180,17 +192,6 @@ static int initialize(struct file *file, const unsigned long __user *input)
180 if (err) 192 if (err)
181 goto free_regs; 193 goto free_regs;
182 194
183 /* We keep a pointer to the Launcher task (ie. current task) for when
184 * other Guests want to wake this one (inter-Guest I/O). */
185 lg->tsk = current;
186 /* We need to keep a pointer to the Launcher's memory map, because if
187 * the Launcher dies we need to clean it up. If we don't keep a
188 * reference, it is destroyed before close() is called. */
189 lg->mm = get_task_mm(lg->tsk);
190
191 /* Initialize the queue for the waker to wait on */
192 init_waitqueue_head(&lg->break_wq);
193
194 /* We remember which CPU's pages this Guest used last, for optimization 195 /* We remember which CPU's pages this Guest used last, for optimization
195 * when the same Guest runs on the same CPU twice. */ 196 * when the same Guest runs on the same CPU twice. */
196 lg->last_pages = NULL; 197 lg->last_pages = NULL;
@@ -246,7 +247,7 @@ static ssize_t write(struct file *file, const char __user *in,
246 return -ENOENT; 247 return -ENOENT;
247 248
248 /* If you're not the task which owns the Guest, you can only break */ 249 /* If you're not the task which owns the Guest, you can only break */
249 if (lg && current != lg->tsk && req != LHREQ_BREAK) 250 if (lg && current != cpu->tsk && req != LHREQ_BREAK)
250 return -EPERM; 251 return -EPERM;
251 252
252 switch (req) { 253 switch (req) {
@@ -255,7 +256,7 @@ static ssize_t write(struct file *file, const char __user *in,
255 case LHREQ_IRQ: 256 case LHREQ_IRQ:
256 return user_send_irq(cpu, input); 257 return user_send_irq(cpu, input);
257 case LHREQ_BREAK: 258 case LHREQ_BREAK:
258 return break_guest_out(lg, input); 259 return break_guest_out(cpu, input);
259 default: 260 default:
260 return -EINVAL; 261 return -EINVAL;
261 } 262 }
@@ -280,17 +281,19 @@ static int close(struct inode *inode, struct file *file)
280 /* We need the big lock, to protect from inter-guest I/O and other 281 /* We need the big lock, to protect from inter-guest I/O and other
281 * Launchers initializing guests. */ 282 * Launchers initializing guests. */
282 mutex_lock(&lguest_lock); 283 mutex_lock(&lguest_lock);
284
285 /* Free up the shadow page tables for the Guest. */
286 free_guest_pagetable(lg);
287
283 for (i = 0; i < lg->nr_cpus; i++) { 288 for (i = 0; i < lg->nr_cpus; i++) {
284 /* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */ 289 /* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
285 hrtimer_cancel(&lg->cpus[i].hrt); 290 hrtimer_cancel(&lg->cpus[i].hrt);
286 /* We can free up the register page we allocated. */ 291 /* We can free up the register page we allocated. */
287 free_page(lg->cpus[i].regs_page); 292 free_page(lg->cpus[i].regs_page);
293 /* Now all the memory cleanups are done, it's safe to release
294 * the Launcher's memory management structure. */
295 mmput(lg->cpus[i].mm);
288 } 296 }
289 /* Free up the shadow page tables for the Guest. */
290 free_guest_pagetable(lg);
291 /* Now all the memory cleanups are done, it's safe to release the
292 * Launcher's memory management structure. */
293 mmput(lg->mm);
294 /* If lg->dead doesn't contain an error code it will be NULL or a 297 /* If lg->dead doesn't contain an error code it will be NULL or a
295 * kmalloc()ed string, either of which is ok to hand to kfree(). */ 298 * kmalloc()ed string, either of which is ok to hand to kfree(). */
296 if (!IS_ERR(lg->dead)) 299 if (!IS_ERR(lg->dead))