Skip to content

Commit

Permalink
lguest: per-vcpu lguest task management
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Glauber de Oliveira Costa authored and rustyrussell committed Jan 30, 2008
1 parent fc708b3 commit 66686c2
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 39 deletions.
4 changes: 2 additions & 2 deletions drivers/lguest/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
return -ERESTARTSYS;

/* If Waker set break_out, return to Launcher. */
if (lg->break_out)
if (cpu->break_out)
return -EAGAIN;

/* Check if there are any interrupts which can be delivered
Expand All @@ -217,7 +217,7 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)

/* If the Guest asked to be stopped, we sleep. The Guest's
* clock timer or LHCALL_BREAK from the Waker will wake us. */
if (lg->halted) {
if (cpu->halted) {
set_current_state(TASK_INTERRUPTIBLE);
schedule();
continue;
Expand Down
2 changes: 1 addition & 1 deletion drivers/lguest/hypercalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ static void do_hcall(struct lg_cpu *cpu, struct hcall_args *args)
break;
case LHCALL_HALT:
/* Similarly, this sets the halted flag for run_guest(). */
lg->halted = 1;
cpu->halted = 1;
break;
case LHCALL_NOTIFY:
lg->pending_notify = args->arg1;
Expand Down
8 changes: 4 additions & 4 deletions drivers/lguest/interrupts_and_traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,11 @@ void maybe_do_interrupt(struct lg_cpu *cpu)
return;

/* If they're halted, interrupts restart them. */
if (lg->halted) {
if (cpu->halted) {
/* Re-enable interrupts. */
if (put_user(X86_EFLAGS_IF, &lg->lguest_data->irq_enabled))
kill_guest(lg, "Re-enabling interrupts");
lg->halted = 0;
cpu->halted = 0;
} else {
/* Otherwise we check if they have interrupts disabled. */
u32 irq_enabled;
Expand Down Expand Up @@ -497,8 +497,8 @@ static enum hrtimer_restart clockdev_fn(struct hrtimer *timer)
/* Remember the first interrupt is the timer interrupt. */
set_bit(0, cpu->irqs_pending);
/* If the Guest is actually stopped, we need to wake it up. */
if (cpu->lg->halted)
wake_up_process(cpu->lg->tsk);
if (cpu->halted)
wake_up_process(cpu->tsk);
return HRTIMER_NORESTART;
}

Expand Down
14 changes: 7 additions & 7 deletions drivers/lguest/lg.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ struct lguest;
struct lg_cpu {
unsigned int id;
struct lguest *lg;
struct task_struct *tsk;
struct mm_struct *mm; /* == tsk->mm, but that becomes NULL on exit */

/* At end of a page shared mapped over lguest_pages in guest. */
unsigned long regs_page;
Expand All @@ -55,6 +57,11 @@ struct lg_cpu {
/* Virtual clock device */
struct hrtimer hrt;

/* Do we need to stop what we're doing and return to userspace? */
int break_out;
wait_queue_head_t break_wq;
int halted;

/* Pending virtual interrupts */
DECLARE_BITMAP(irqs_pending, LGUEST_IRQS);

Expand All @@ -65,8 +72,6 @@ struct lg_cpu {
struct lguest
{
struct lguest_data __user *lguest_data;
struct task_struct *tsk;
struct mm_struct *mm; /* == tsk->mm, but that becomes NULL on exit */
struct lg_cpu cpus[NR_CPUS];
unsigned int nr_cpus;

Expand All @@ -76,15 +81,10 @@ struct lguest
void __user *mem_base;
unsigned long kernel_address;
u32 cr2;
int halted;
int ts;
u32 esp1;
u8 ss1;

/* Do we need to stop what we're doing and return to userspace? */
int break_out;
wait_queue_head_t break_wq;

/* Bitmap of what has changed: see CHANGED_* above. */
int changed;
struct lguest_pages *last_pages;
Expand Down
53 changes: 28 additions & 25 deletions drivers/lguest/lguest_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* LHREQ_BREAK and the value "1" to /dev/lguest to do this. Once the Launcher
* has done whatever needs attention, it writes LHREQ_BREAK and "0" to release
* the Waker. */
static int break_guest_out(struct lguest *lg, const unsigned long __user *input)
static int break_guest_out(struct lg_cpu *cpu, const unsigned long __user*input)
{
unsigned long on;

Expand All @@ -22,14 +22,14 @@ static int break_guest_out(struct lguest *lg, const unsigned long __user *input)
return -EFAULT;

if (on) {
lg->break_out = 1;
cpu->break_out = 1;
/* Pop it out of the Guest (may be running on different CPU) */
wake_up_process(lg->tsk);
wake_up_process(cpu->tsk);
/* Wait for them to reset it */
return wait_event_interruptible(lg->break_wq, !lg->break_out);
return wait_event_interruptible(cpu->break_wq, !cpu->break_out);
} else {
lg->break_out = 0;
wake_up(&lg->break_wq);
cpu->break_out = 0;
wake_up(&cpu->break_wq);
return 0;
}
}
Expand Down Expand Up @@ -69,7 +69,7 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
cpu = &lg->cpus[cpu_id];

/* If you're not the task which owns the Guest, go away. */
if (current != lg->tsk)
if (current != cpu->tsk)
return -EPERM;

/* If the guest is already dead, we indicate why */
Expand Down Expand Up @@ -119,6 +119,18 @@ static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
* address. */
lguest_arch_setup_regs(cpu, start_ip);

/* Initialize the queue for the waker to wait on */
init_waitqueue_head(&cpu->break_wq);

/* We keep a pointer to the Launcher task (ie. current task) for when
* other Guests want to wake this one (inter-Guest I/O). */
cpu->tsk = current;

/* We need to keep a pointer to the Launcher's memory map, because if
* the Launcher dies we need to clean it up. If we don't keep a
* reference, it is destroyed before close() is called. */
cpu->mm = get_task_mm(cpu->tsk);

return 0;
}

Expand Down Expand Up @@ -180,17 +192,6 @@ static int initialize(struct file *file, const unsigned long __user *input)
if (err)
goto free_regs;

/* We keep a pointer to the Launcher task (ie. current task) for when
* other Guests want to wake this one (inter-Guest I/O). */
lg->tsk = current;
/* We need to keep a pointer to the Launcher's memory map, because if
* the Launcher dies we need to clean it up. If we don't keep a
* reference, it is destroyed before close() is called. */
lg->mm = get_task_mm(lg->tsk);

/* Initialize the queue for the waker to wait on */
init_waitqueue_head(&lg->break_wq);

/* We remember which CPU's pages this Guest used last, for optimization
* when the same Guest runs on the same CPU twice. */
lg->last_pages = NULL;
Expand Down Expand Up @@ -246,7 +247,7 @@ static ssize_t write(struct file *file, const char __user *in,
return -ENOENT;

/* If you're not the task which owns the Guest, you can only break */
if (lg && current != lg->tsk && req != LHREQ_BREAK)
if (lg && current != cpu->tsk && req != LHREQ_BREAK)
return -EPERM;

switch (req) {
Expand All @@ -255,7 +256,7 @@ static ssize_t write(struct file *file, const char __user *in,
case LHREQ_IRQ:
return user_send_irq(cpu, input);
case LHREQ_BREAK:
return break_guest_out(lg, input);
return break_guest_out(cpu, input);
default:
return -EINVAL;
}
Expand All @@ -280,17 +281,19 @@ static int close(struct inode *inode, struct file *file)
/* We need the big lock, to protect from inter-guest I/O and other
* Launchers initializing guests. */
mutex_lock(&lguest_lock);

/* Free up the shadow page tables for the Guest. */
free_guest_pagetable(lg);

for (i = 0; i < lg->nr_cpus; i++) {
/* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
hrtimer_cancel(&lg->cpus[i].hrt);
/* We can free up the register page we allocated. */
free_page(lg->cpus[i].regs_page);
/* Now all the memory cleanups are done, it's safe to release
* the Launcher's memory management structure. */
mmput(lg->cpus[i].mm);
}
/* Free up the shadow page tables for the Guest. */
free_guest_pagetable(lg);
/* Now all the memory cleanups are done, it's safe to release the
* Launcher's memory management structure. */
mmput(lg->mm);
/* If lg->dead doesn't contain an error code it will be NULL or a
* kmalloc()ed string, either of which is ok to hand to kfree(). */
if (!IS_ERR(lg->dead))
Expand Down

0 comments on commit 66686c2

Please sign in to comment.