lguest: per-vcpu lguest timers
Here, I introduce per-vcpu timers. With this, we can have local expiries, needed for accounting time in smp guests Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
73044f05a4
commit
ad8d8f3bc6
|
@ -80,7 +80,7 @@ static void do_hcall(struct lg_cpu *cpu, struct hcall_args *args)
|
||||||
guest_set_pmd(lg, args->arg1, args->arg2);
|
guest_set_pmd(lg, args->arg1, args->arg2);
|
||||||
break;
|
break;
|
||||||
case LHCALL_SET_CLOCKEVENT:
|
case LHCALL_SET_CLOCKEVENT:
|
||||||
guest_set_clockevent(lg, args->arg1);
|
guest_set_clockevent(cpu, args->arg1);
|
||||||
break;
|
break;
|
||||||
case LHCALL_TS:
|
case LHCALL_TS:
|
||||||
/* This sets the TS flag, as we saw used in run_guest(). */
|
/* This sets the TS flag, as we saw used in run_guest(). */
|
||||||
|
|
|
@ -470,13 +470,13 @@ void copy_traps(const struct lguest *lg, struct desc_struct *idt,
|
||||||
* infrastructure to set a callback at that time.
|
* infrastructure to set a callback at that time.
|
||||||
*
|
*
|
||||||
* 0 means "turn off the clock". */
|
* 0 means "turn off the clock". */
|
||||||
void guest_set_clockevent(struct lguest *lg, unsigned long delta)
|
void guest_set_clockevent(struct lg_cpu *cpu, unsigned long delta)
|
||||||
{
|
{
|
||||||
ktime_t expires;
|
ktime_t expires;
|
||||||
|
|
||||||
if (unlikely(delta == 0)) {
|
if (unlikely(delta == 0)) {
|
||||||
/* Clock event device is shutting down. */
|
/* Clock event device is shutting down. */
|
||||||
hrtimer_cancel(&lg->hrt);
|
hrtimer_cancel(&cpu->hrt);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,25 +484,25 @@ void guest_set_clockevent(struct lguest *lg, unsigned long delta)
|
||||||
* all the time between now and the timer interrupt it asked for. This
|
* all the time between now and the timer interrupt it asked for. This
|
||||||
* is almost always the right thing to do. */
|
* is almost always the right thing to do. */
|
||||||
expires = ktime_add_ns(ktime_get_real(), delta);
|
expires = ktime_add_ns(ktime_get_real(), delta);
|
||||||
hrtimer_start(&lg->hrt, expires, HRTIMER_MODE_ABS);
|
hrtimer_start(&cpu->hrt, expires, HRTIMER_MODE_ABS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is the function called when the Guest's timer expires. */
|
/* This is the function called when the Guest's timer expires. */
|
||||||
static enum hrtimer_restart clockdev_fn(struct hrtimer *timer)
|
static enum hrtimer_restart clockdev_fn(struct hrtimer *timer)
|
||||||
{
|
{
|
||||||
struct lguest *lg = container_of(timer, struct lguest, hrt);
|
struct lg_cpu *cpu = container_of(timer, struct lg_cpu, hrt);
|
||||||
|
|
||||||
/* Remember the first interrupt is the timer interrupt. */
|
/* Remember the first interrupt is the timer interrupt. */
|
||||||
set_bit(0, lg->irqs_pending);
|
set_bit(0, cpu->lg->irqs_pending);
|
||||||
/* If the Guest is actually stopped, we need to wake it up. */
|
/* If the Guest is actually stopped, we need to wake it up. */
|
||||||
if (lg->halted)
|
if (cpu->lg->halted)
|
||||||
wake_up_process(lg->tsk);
|
wake_up_process(cpu->lg->tsk);
|
||||||
return HRTIMER_NORESTART;
|
return HRTIMER_NORESTART;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This sets up the timer for this Guest. */
|
/* This sets up the timer for this Guest. */
|
||||||
void init_clockdev(struct lguest *lg)
|
void init_clockdev(struct lg_cpu *cpu)
|
||||||
{
|
{
|
||||||
hrtimer_init(&lg->hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS);
|
hrtimer_init(&cpu->hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS);
|
||||||
lg->hrt.function = clockdev_fn;
|
cpu->hrt.function = clockdev_fn;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,9 @@ struct lg_cpu {
|
||||||
/* If a hypercall was asked for, this points to the arguments. */
|
/* If a hypercall was asked for, this points to the arguments. */
|
||||||
struct hcall_args *hcall;
|
struct hcall_args *hcall;
|
||||||
u32 next_hcall;
|
u32 next_hcall;
|
||||||
|
|
||||||
|
/* Virtual clock device */
|
||||||
|
struct hrtimer hrt;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The private info the thread maintains about the guest. */
|
/* The private info the thread maintains about the guest. */
|
||||||
|
@ -95,9 +98,6 @@ struct lguest
|
||||||
|
|
||||||
struct lguest_arch arch;
|
struct lguest_arch arch;
|
||||||
|
|
||||||
/* Virtual clock device */
|
|
||||||
struct hrtimer hrt;
|
|
||||||
|
|
||||||
/* Pending virtual interrupts */
|
/* Pending virtual interrupts */
|
||||||
DECLARE_BITMAP(irqs_pending, LGUEST_IRQS);
|
DECLARE_BITMAP(irqs_pending, LGUEST_IRQS);
|
||||||
};
|
};
|
||||||
|
@ -145,8 +145,8 @@ void setup_default_idt_entries(struct lguest_ro_state *state,
|
||||||
const unsigned long *def);
|
const unsigned long *def);
|
||||||
void copy_traps(const struct lguest *lg, struct desc_struct *idt,
|
void copy_traps(const struct lguest *lg, struct desc_struct *idt,
|
||||||
const unsigned long *def);
|
const unsigned long *def);
|
||||||
void guest_set_clockevent(struct lguest *lg, unsigned long delta);
|
void guest_set_clockevent(struct lg_cpu *cpu, unsigned long delta);
|
||||||
void init_clockdev(struct lguest *lg);
|
void init_clockdev(struct lg_cpu *cpu);
|
||||||
bool check_syscall_vector(struct lguest *lg);
|
bool check_syscall_vector(struct lguest *lg);
|
||||||
int init_interrupts(void);
|
int init_interrupts(void);
|
||||||
void free_interrupts(void);
|
void free_interrupts(void);
|
||||||
|
|
|
@ -104,6 +104,7 @@ static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
|
||||||
cpu->id = id;
|
cpu->id = id;
|
||||||
cpu->lg = container_of((cpu - id), struct lguest, cpus[0]);
|
cpu->lg = container_of((cpu - id), struct lguest, cpus[0]);
|
||||||
cpu->lg->nr_cpus++;
|
cpu->lg->nr_cpus++;
|
||||||
|
init_clockdev(cpu);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -180,9 +181,6 @@ static int initialize(struct file *file, const unsigned long __user *input)
|
||||||
* address. */
|
* address. */
|
||||||
lguest_arch_setup_regs(lg, args[3]);
|
lguest_arch_setup_regs(lg, args[3]);
|
||||||
|
|
||||||
/* The timer for lguest's clock needs initialization. */
|
|
||||||
init_clockdev(lg);
|
|
||||||
|
|
||||||
/* We keep a pointer to the Launcher task (ie. current task) for when
|
/* We keep a pointer to the Launcher task (ie. current task) for when
|
||||||
* other Guests want to wake this one (inter-Guest I/O). */
|
* other Guests want to wake this one (inter-Guest I/O). */
|
||||||
lg->tsk = current;
|
lg->tsk = current;
|
||||||
|
@ -273,6 +271,7 @@ static ssize_t write(struct file *file, const char __user *in,
|
||||||
static int close(struct inode *inode, struct file *file)
|
static int close(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct lguest *lg = file->private_data;
|
struct lguest *lg = file->private_data;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
/* If we never successfully initialized, there's nothing to clean up */
|
/* If we never successfully initialized, there's nothing to clean up */
|
||||||
if (!lg)
|
if (!lg)
|
||||||
|
@ -281,8 +280,9 @@ static int close(struct inode *inode, struct file *file)
|
||||||
/* We need the big lock, to protect from inter-guest I/O and other
|
/* We need the big lock, to protect from inter-guest I/O and other
|
||||||
* Launchers initializing guests. */
|
* Launchers initializing guests. */
|
||||||
mutex_lock(&lguest_lock);
|
mutex_lock(&lguest_lock);
|
||||||
/* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
|
for (i = 0; i < lg->nr_cpus; i++)
|
||||||
hrtimer_cancel(&lg->hrt);
|
/* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
|
||||||
|
hrtimer_cancel(&lg->cpus[i].hrt);
|
||||||
/* Free up the shadow page tables for the Guest. */
|
/* Free up the shadow page tables for the Guest. */
|
||||||
free_guest_pagetable(lg);
|
free_guest_pagetable(lg);
|
||||||
/* Now all the memory cleanups are done, it's safe to release the
|
/* Now all the memory cleanups are done, it's safe to release the
|
||||||
|
|
Loading…
Reference in New Issue