[PATCH 13/16] per-vcpu lguest task management

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

 



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 <[email protected]>
---
 drivers/lguest/core.c                 |    4 +-
 drivers/lguest/hypercalls.c           |    2 +-
 drivers/lguest/interrupts_and_traps.c |    8 ++--
 drivers/lguest/lg.h                   |   14 ++++----
 drivers/lguest/lguest_user.c          |   56 ++++++++++++++++++--------------
 5 files changed, 45 insertions(+), 39 deletions(-)

diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c
index 4d0102d..285a465 100644
--- a/drivers/lguest/core.c
+++ b/drivers/lguest/core.c
@@ -197,7 +197,7 @@ int run_guest(struct lguest_vcpu *vcpu, unsigned long __user *user)
 			return -ERESTARTSYS;
 
 		/* If Waker set break_out, return to Launcher. */
-		if (lg->break_out)
+		if (vcpu->break_out)
 			return -EAGAIN;
 
 		/* Check if there are any interrupts which can be delivered
@@ -217,7 +217,7 @@ int run_guest(struct lguest_vcpu *vcpu, 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 (vcpu->halted) {
 			set_current_state(TASK_INTERRUPTIBLE);
 			schedule();
 			continue;
diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c
index 4364bc2..41ea2e2 100644
--- a/drivers/lguest/hypercalls.c
+++ b/drivers/lguest/hypercalls.c
@@ -86,7 +86,7 @@ static void do_hcall(struct lguest_vcpu *vcpu, struct hcall_args *args)
 		break;
 	case LHCALL_HALT:
 		/* Similarly, this sets the halted flag for run_guest(). */
-		lg->halted = 1;
+		vcpu->halted = 1;
 		break;
 	case LHCALL_NOTIFY:
 		lg->pending_notify = args->arg1;
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c
index b3d444a..10c9aea 100644
--- a/drivers/lguest/interrupts_and_traps.c
+++ b/drivers/lguest/interrupts_and_traps.c
@@ -163,11 +163,11 @@ void maybe_do_interrupt(struct lguest_vcpu *vcpu)
 		return;
 
 	/* If they're halted, interrupts restart them. */
-	if (lg->halted) {
+	if (vcpu->halted) {
 		/* Re-enable interrupts. */
 		if (put_user(X86_EFLAGS_IF, &lg->lguest_data->irq_enabled))
 			kill_guest(lg, "Re-enabling interrupts");
-		lg->halted = 0;
+		vcpu->halted = 0;
 	} else {
 		/* Otherwise we check if they have interrupts disabled. */
 		u32 irq_enabled;
@@ -500,8 +500,8 @@ static enum hrtimer_restart clockdev_fn(struct hrtimer *timer)
 	/* Remember the first interrupt is the timer interrupt. */
 	set_bit(0, vcpu->irqs_pending);
 	/* If the Guest is actually stopped, we need to wake it up. */
-	if (vcpu->lg->halted)
-		wake_up_process(vcpu->lg->tsk);
+	if (vcpu->halted)
+		wake_up_process(vcpu->tsk);
 	return HRTIMER_NORESTART;
 }
 
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h
index f9429ff..b23694e 100644
--- a/drivers/lguest/lg.h
+++ b/drivers/lguest/lg.h
@@ -43,6 +43,8 @@ struct lguest;
 struct lguest_vcpu {
 	int vcpu_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;
@@ -55,6 +57,11 @@ struct lguest_vcpu {
 	/* 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);
 
@@ -65,8 +72,6 @@ struct lguest_vcpu {
 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 lguest_vcpu vcpus[NR_CPUS];
 	unsigned int nr_vcpus;
 
@@ -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;
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c
index 4f51e25..d081db4 100644
--- a/drivers/lguest/lguest_user.c
+++ b/drivers/lguest/lguest_user.c
@@ -13,7 +13,8 @@
  * 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 lguest_vcpu *vcpu,
+			   const unsigned long __user *input)
 {
 	unsigned long on;
 
@@ -22,14 +23,15 @@ static int break_guest_out(struct lguest *lg, const unsigned long __user *input)
 		return -EFAULT;
 
 	if (on) {
-		lg->break_out = 1;
+		vcpu->break_out = 1;
 		/* Pop it out of the Guest (may be running on different CPU) */
-		wake_up_process(lg->tsk);
+		wake_up_process(vcpu->tsk);
 		/* Wait for them to reset it */
-		return wait_event_interruptible(lg->break_wq, !lg->break_out);
+		return wait_event_interruptible(vcpu->break_wq,
+						!vcpu->break_out);
 	} else {
-		lg->break_out = 0;
-		wake_up(&lg->break_wq);
+		vcpu->break_out = 0;
+		wake_up(&vcpu->break_wq);
 		return 0;
 	}
 }
@@ -66,7 +68,7 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
 	vcpu = &lg->vcpus[vcpu_id];
 
 	/* If you're not the task which owns the Guest, go away. */
-	if (current != lg->tsk)
+	if (current != vcpu->tsk)
 		return -EPERM;
 
 	/* If the guest is already dead, we indicate why */
@@ -114,6 +116,19 @@ static int vcpu_start(struct lguest_vcpu *vcpu, int vcpu_id,
 	 * address. */
 	lguest_arch_setup_regs(vcpu, start_ip);
 
+	/* Initialize the queue for the waker to wait on */
+	init_waitqueue_head(&vcpu->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). */
+	vcpu->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. */
+	vcpu->mm = get_task_mm(vcpu->tsk);
+
+
 	vcpu->lg = container_of((vcpu - vcpu_id), struct lguest, vcpus[0]);
 	vcpu->lg->nr_vcpus++;
 
@@ -179,17 +194,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;
@@ -244,7 +248,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 != vcpu->tsk && req != LHREQ_BREAK)
 		return -EPERM;
 
 	switch (req) {
@@ -253,7 +257,7 @@ static ssize_t write(struct file *file, const char __user *in,
 	case LHREQ_IRQ:
 		return user_send_irq(vcpu, input);
 	case LHREQ_BREAK:
-		return break_guest_out(lg, input);
+		return break_guest_out(vcpu, input);
 	default:
 		return -EINVAL;
 	}
@@ -278,17 +282,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_vcpus; i++) {
 		/* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
 		hrtimer_cancel(&lg->vcpus[i].hrt);
 		/* We can free up the register page we allocated. */
 		free_page(lg->vcpus[i].regs_page);
+		/* Now all the memory cleanups are done, it's safe to release
+		 * the Launcher's memory management structure. */
+		mmput(lg->vcpus[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))
-- 
1.5.0.6

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux