mirror of https://gitee.com/openkylin/linux.git
Merge commit 'v2.6.26-rc8' into core/rcu
This commit is contained in:
commit
9a13150109
|
@ -84,10 +84,9 @@
|
||||||
runs an instance of gdb against the vmlinux file which contains
|
runs an instance of gdb against the vmlinux file which contains
|
||||||
the symbols (not boot image such as bzImage, zImage, uImage...).
|
the symbols (not boot image such as bzImage, zImage, uImage...).
|
||||||
In gdb the developer specifies the connection parameters and
|
In gdb the developer specifies the connection parameters and
|
||||||
connects to kgdb. Depending on which kgdb I/O modules exist in
|
connects to kgdb. The type of connection a developer makes with
|
||||||
the kernel for a given architecture, it may be possible to debug
|
gdb depends on the availability of kgdb I/O modules compiled as
|
||||||
the test machine's kernel with the development machine using a
|
builtin's or kernel modules in the test machine's kernel.
|
||||||
rs232 or ethernet connection.
|
|
||||||
</para>
|
</para>
|
||||||
</chapter>
|
</chapter>
|
||||||
<chapter id="CompilingAKernel">
|
<chapter id="CompilingAKernel">
|
||||||
|
@ -223,7 +222,7 @@
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
IMPORTANT NOTE: Using this option with kgdb over the console
|
IMPORTANT NOTE: Using this option with kgdb over the console
|
||||||
(kgdboc) or kgdb over ethernet (kgdboe) is not supported.
|
(kgdboc) is not supported.
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
@ -249,18 +248,11 @@
|
||||||
(gdb) target remote /dev/ttyS0
|
(gdb) target remote /dev/ttyS0
|
||||||
</programlisting>
|
</programlisting>
|
||||||
<para>
|
<para>
|
||||||
Example (kgdb to a terminal server):
|
Example (kgdb to a terminal server on tcp port 2012):
|
||||||
</para>
|
</para>
|
||||||
<programlisting>
|
<programlisting>
|
||||||
% gdb ./vmlinux
|
% gdb ./vmlinux
|
||||||
(gdb) target remote udp:192.168.2.2:6443
|
(gdb) target remote 192.168.2.2:2012
|
||||||
</programlisting>
|
|
||||||
<para>
|
|
||||||
Example (kgdb over ethernet):
|
|
||||||
</para>
|
|
||||||
<programlisting>
|
|
||||||
% gdb ./vmlinux
|
|
||||||
(gdb) target remote udp:192.168.2.2:6443
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
<para>
|
<para>
|
||||||
Once connected, you can debug a kernel the way you would debug an
|
Once connected, you can debug a kernel the way you would debug an
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -1,7 +1,7 @@
|
||||||
VERSION = 2
|
VERSION = 2
|
||||||
PATCHLEVEL = 6
|
PATCHLEVEL = 6
|
||||||
SUBLEVEL = 26
|
SUBLEVEL = 26
|
||||||
EXTRAVERSION = -rc7
|
EXTRAVERSION = -rc8
|
||||||
NAME = Rotary Wombat
|
NAME = Rotary Wombat
|
||||||
|
|
||||||
# *DOCUMENTATION*
|
# *DOCUMENTATION*
|
||||||
|
|
|
@ -558,8 +558,6 @@ static struct iosapic_rte_info * __init_refok iosapic_alloc_rte (void)
|
||||||
if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) {
|
if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) {
|
||||||
rte = alloc_bootmem(sizeof(struct iosapic_rte_info) *
|
rte = alloc_bootmem(sizeof(struct iosapic_rte_info) *
|
||||||
NR_PREALLOCATE_RTE_ENTRIES);
|
NR_PREALLOCATE_RTE_ENTRIES);
|
||||||
if (!rte)
|
|
||||||
return NULL;
|
|
||||||
for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++)
|
for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++)
|
||||||
list_add(&rte->rte_list, &free_rte_list);
|
list_add(&rte->rte_list, &free_rte_list);
|
||||||
}
|
}
|
||||||
|
|
|
@ -578,8 +578,6 @@ setup_arch (char **cmdline_p)
|
||||||
cpu_init(); /* initialize the bootstrap CPU */
|
cpu_init(); /* initialize the bootstrap CPU */
|
||||||
mmu_context_init(); /* initialize context_id bitmap */
|
mmu_context_init(); /* initialize context_id bitmap */
|
||||||
|
|
||||||
check_sal_cache_flush();
|
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
acpi_boot_init();
|
acpi_boot_init();
|
||||||
#endif
|
#endif
|
||||||
|
@ -607,6 +605,7 @@ setup_arch (char **cmdline_p)
|
||||||
ia64_mca_init();
|
ia64_mca_init();
|
||||||
|
|
||||||
platform_setup(cmdline_p);
|
platform_setup(cmdline_p);
|
||||||
|
check_sal_cache_flush();
|
||||||
paging_init();
|
paging_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -512,7 +512,7 @@ static ssize_t sn2_ptc_proc_write(struct file *file, const char __user *user, si
|
||||||
int cpu;
|
int cpu;
|
||||||
char optstr[64];
|
char optstr[64];
|
||||||
|
|
||||||
if (count > sizeof(optstr))
|
if (count == 0 || count > sizeof(optstr))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (copy_from_user(optstr, user, count))
|
if (copy_from_user(optstr, user, count))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
|
@ -383,6 +383,7 @@ config VMI
|
||||||
config KVM_CLOCK
|
config KVM_CLOCK
|
||||||
bool "KVM paravirtualized clock"
|
bool "KVM paravirtualized clock"
|
||||||
select PARAVIRT
|
select PARAVIRT
|
||||||
|
select PARAVIRT_CLOCK
|
||||||
depends on !(X86_VISWS || X86_VOYAGER)
|
depends on !(X86_VISWS || X86_VOYAGER)
|
||||||
help
|
help
|
||||||
Turning on this option will allow you to run a paravirtualized clock
|
Turning on this option will allow you to run a paravirtualized clock
|
||||||
|
@ -410,6 +411,10 @@ config PARAVIRT
|
||||||
over full virtualization. However, when run without a hypervisor
|
over full virtualization. However, when run without a hypervisor
|
||||||
the kernel is theoretically slower and slightly larger.
|
the kernel is theoretically slower and slightly larger.
|
||||||
|
|
||||||
|
config PARAVIRT_CLOCK
|
||||||
|
bool
|
||||||
|
default n
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
config MEMTEST_BOOTPARAM
|
config MEMTEST_BOOTPARAM
|
||||||
|
|
|
@ -82,6 +82,7 @@ obj-$(CONFIG_VMI) += vmi_32.o vmiclock_32.o
|
||||||
obj-$(CONFIG_KVM_GUEST) += kvm.o
|
obj-$(CONFIG_KVM_GUEST) += kvm.o
|
||||||
obj-$(CONFIG_KVM_CLOCK) += kvmclock.o
|
obj-$(CONFIG_KVM_CLOCK) += kvmclock.o
|
||||||
obj-$(CONFIG_PARAVIRT) += paravirt.o paravirt_patch_$(BITS).o
|
obj-$(CONFIG_PARAVIRT) += paravirt.o paravirt_patch_$(BITS).o
|
||||||
|
obj-$(CONFIG_PARAVIRT_CLOCK) += pvclock.o
|
||||||
|
|
||||||
obj-$(CONFIG_PCSPKR_PLATFORM) += pcspeaker.o
|
obj-$(CONFIG_PCSPKR_PLATFORM) += pcspeaker.o
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include <linux/clocksource.h>
|
#include <linux/clocksource.h>
|
||||||
#include <linux/kvm_para.h>
|
#include <linux/kvm_para.h>
|
||||||
|
#include <asm/pvclock.h>
|
||||||
#include <asm/arch_hooks.h>
|
#include <asm/arch_hooks.h>
|
||||||
#include <asm/msr.h>
|
#include <asm/msr.h>
|
||||||
#include <asm/apic.h>
|
#include <asm/apic.h>
|
||||||
|
@ -36,18 +37,9 @@ static int parse_no_kvmclock(char *arg)
|
||||||
early_param("no-kvmclock", parse_no_kvmclock);
|
early_param("no-kvmclock", parse_no_kvmclock);
|
||||||
|
|
||||||
/* The hypervisor will put information about time periodically here */
|
/* The hypervisor will put information about time periodically here */
|
||||||
static DEFINE_PER_CPU_SHARED_ALIGNED(struct kvm_vcpu_time_info, hv_clock);
|
static DEFINE_PER_CPU_SHARED_ALIGNED(struct pvclock_vcpu_time_info, hv_clock);
|
||||||
#define get_clock(cpu, field) per_cpu(hv_clock, cpu).field
|
static struct pvclock_wall_clock wall_clock;
|
||||||
|
|
||||||
static inline u64 kvm_get_delta(u64 last_tsc)
|
|
||||||
{
|
|
||||||
int cpu = smp_processor_id();
|
|
||||||
u64 delta = native_read_tsc() - last_tsc;
|
|
||||||
return (delta * get_clock(cpu, tsc_to_system_mul)) >> KVM_SCALE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct kvm_wall_clock wall_clock;
|
|
||||||
static cycle_t kvm_clock_read(void);
|
|
||||||
/*
|
/*
|
||||||
* The wallclock is the time of day when we booted. Since then, some time may
|
* The wallclock is the time of day when we booted. Since then, some time may
|
||||||
* have elapsed since the hypervisor wrote the data. So we try to account for
|
* have elapsed since the hypervisor wrote the data. So we try to account for
|
||||||
|
@ -55,64 +47,37 @@ static cycle_t kvm_clock_read(void);
|
||||||
*/
|
*/
|
||||||
static unsigned long kvm_get_wallclock(void)
|
static unsigned long kvm_get_wallclock(void)
|
||||||
{
|
{
|
||||||
u32 wc_sec, wc_nsec;
|
struct pvclock_vcpu_time_info *vcpu_time;
|
||||||
u64 delta;
|
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
int version, nsec;
|
|
||||||
int low, high;
|
int low, high;
|
||||||
|
|
||||||
low = (int)__pa(&wall_clock);
|
low = (int)__pa(&wall_clock);
|
||||||
high = ((u64)__pa(&wall_clock) >> 32);
|
high = ((u64)__pa(&wall_clock) >> 32);
|
||||||
|
|
||||||
delta = kvm_clock_read();
|
|
||||||
|
|
||||||
native_write_msr(MSR_KVM_WALL_CLOCK, low, high);
|
native_write_msr(MSR_KVM_WALL_CLOCK, low, high);
|
||||||
do {
|
|
||||||
version = wall_clock.wc_version;
|
|
||||||
rmb();
|
|
||||||
wc_sec = wall_clock.wc_sec;
|
|
||||||
wc_nsec = wall_clock.wc_nsec;
|
|
||||||
rmb();
|
|
||||||
} while ((wall_clock.wc_version != version) || (version & 1));
|
|
||||||
|
|
||||||
delta = kvm_clock_read() - delta;
|
vcpu_time = &get_cpu_var(hv_clock);
|
||||||
delta += wc_nsec;
|
pvclock_read_wallclock(&wall_clock, vcpu_time, &ts);
|
||||||
nsec = do_div(delta, NSEC_PER_SEC);
|
put_cpu_var(hv_clock);
|
||||||
set_normalized_timespec(&ts, wc_sec + delta, nsec);
|
|
||||||
/*
|
return ts.tv_sec;
|
||||||
* Of all mechanisms of time adjustment I've tested, this one
|
|
||||||
* was the champion!
|
|
||||||
*/
|
|
||||||
return ts.tv_sec + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int kvm_set_wallclock(unsigned long now)
|
static int kvm_set_wallclock(unsigned long now)
|
||||||
{
|
{
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This is our read_clock function. The host puts an tsc timestamp each time
|
|
||||||
* it updates a new time. Without the tsc adjustment, we can have a situation
|
|
||||||
* in which a vcpu starts to run earlier (smaller system_time), but probes
|
|
||||||
* time later (compared to another vcpu), leading to backwards time
|
|
||||||
*/
|
|
||||||
static cycle_t kvm_clock_read(void)
|
static cycle_t kvm_clock_read(void)
|
||||||
{
|
{
|
||||||
u64 last_tsc, now;
|
struct pvclock_vcpu_time_info *src;
|
||||||
int cpu;
|
cycle_t ret;
|
||||||
|
|
||||||
preempt_disable();
|
src = &get_cpu_var(hv_clock);
|
||||||
cpu = smp_processor_id();
|
ret = pvclock_clocksource_read(src);
|
||||||
|
put_cpu_var(hv_clock);
|
||||||
last_tsc = get_clock(cpu, tsc_timestamp);
|
return ret;
|
||||||
now = get_clock(cpu, system_time);
|
|
||||||
|
|
||||||
now += kvm_get_delta(last_tsc);
|
|
||||||
preempt_enable();
|
|
||||||
|
|
||||||
return now;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct clocksource kvm_clock = {
|
static struct clocksource kvm_clock = {
|
||||||
.name = "kvm-clock",
|
.name = "kvm-clock",
|
||||||
.read = kvm_clock_read,
|
.read = kvm_clock_read,
|
||||||
|
@ -123,13 +88,14 @@ static struct clocksource kvm_clock = {
|
||||||
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int kvm_register_clock(void)
|
static int kvm_register_clock(char *txt)
|
||||||
{
|
{
|
||||||
int cpu = smp_processor_id();
|
int cpu = smp_processor_id();
|
||||||
int low, high;
|
int low, high;
|
||||||
low = (int)__pa(&per_cpu(hv_clock, cpu)) | 1;
|
low = (int)__pa(&per_cpu(hv_clock, cpu)) | 1;
|
||||||
high = ((u64)__pa(&per_cpu(hv_clock, cpu)) >> 32);
|
high = ((u64)__pa(&per_cpu(hv_clock, cpu)) >> 32);
|
||||||
|
printk(KERN_INFO "kvm-clock: cpu %d, msr %x:%x, %s\n",
|
||||||
|
cpu, high, low, txt);
|
||||||
return native_write_msr_safe(MSR_KVM_SYSTEM_TIME, low, high);
|
return native_write_msr_safe(MSR_KVM_SYSTEM_TIME, low, high);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,12 +106,20 @@ static void kvm_setup_secondary_clock(void)
|
||||||
* Now that the first cpu already had this clocksource initialized,
|
* Now that the first cpu already had this clocksource initialized,
|
||||||
* we shouldn't fail.
|
* we shouldn't fail.
|
||||||
*/
|
*/
|
||||||
WARN_ON(kvm_register_clock());
|
WARN_ON(kvm_register_clock("secondary cpu clock"));
|
||||||
/* ok, done with our trickery, call native */
|
/* ok, done with our trickery, call native */
|
||||||
setup_secondary_APIC_clock();
|
setup_secondary_APIC_clock();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
void __init kvm_smp_prepare_boot_cpu(void)
|
||||||
|
{
|
||||||
|
WARN_ON(kvm_register_clock("primary cpu clock"));
|
||||||
|
native_smp_prepare_boot_cpu();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* After the clock is registered, the host will keep writing to the
|
* After the clock is registered, the host will keep writing to the
|
||||||
* registered memory location. If the guest happens to shutdown, this memory
|
* registered memory location. If the guest happens to shutdown, this memory
|
||||||
|
@ -174,13 +148,16 @@ void __init kvmclock_init(void)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (kvmclock && kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)) {
|
if (kvmclock && kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)) {
|
||||||
if (kvm_register_clock())
|
if (kvm_register_clock("boot clock"))
|
||||||
return;
|
return;
|
||||||
pv_time_ops.get_wallclock = kvm_get_wallclock;
|
pv_time_ops.get_wallclock = kvm_get_wallclock;
|
||||||
pv_time_ops.set_wallclock = kvm_set_wallclock;
|
pv_time_ops.set_wallclock = kvm_set_wallclock;
|
||||||
pv_time_ops.sched_clock = kvm_clock_read;
|
pv_time_ops.sched_clock = kvm_clock_read;
|
||||||
#ifdef CONFIG_X86_LOCAL_APIC
|
#ifdef CONFIG_X86_LOCAL_APIC
|
||||||
pv_apic_ops.setup_secondary_clock = kvm_setup_secondary_clock;
|
pv_apic_ops.setup_secondary_clock = kvm_setup_secondary_clock;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
smp_ops.smp_prepare_boot_cpu = kvm_smp_prepare_boot_cpu;
|
||||||
#endif
|
#endif
|
||||||
machine_ops.shutdown = kvm_shutdown;
|
machine_ops.shutdown = kvm_shutdown;
|
||||||
#ifdef CONFIG_KEXEC
|
#ifdef CONFIG_KEXEC
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
/* paravirtual clock -- common code used by kvm/xen
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/percpu.h>
|
||||||
|
#include <asm/pvclock.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These are perodically updated
|
||||||
|
* xen: magic shared_info page
|
||||||
|
* kvm: gpa registered via msr
|
||||||
|
* and then copied here.
|
||||||
|
*/
|
||||||
|
struct pvclock_shadow_time {
|
||||||
|
u64 tsc_timestamp; /* TSC at last update of time vals. */
|
||||||
|
u64 system_timestamp; /* Time, in nanosecs, since boot. */
|
||||||
|
u32 tsc_to_nsec_mul;
|
||||||
|
int tsc_shift;
|
||||||
|
u32 version;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
|
||||||
|
* yielding a 64-bit result.
|
||||||
|
*/
|
||||||
|
static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
|
||||||
|
{
|
||||||
|
u64 product;
|
||||||
|
#ifdef __i386__
|
||||||
|
u32 tmp1, tmp2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (shift < 0)
|
||||||
|
delta >>= -shift;
|
||||||
|
else
|
||||||
|
delta <<= shift;
|
||||||
|
|
||||||
|
#ifdef __i386__
|
||||||
|
__asm__ (
|
||||||
|
"mul %5 ; "
|
||||||
|
"mov %4,%%eax ; "
|
||||||
|
"mov %%edx,%4 ; "
|
||||||
|
"mul %5 ; "
|
||||||
|
"xor %5,%5 ; "
|
||||||
|
"add %4,%%eax ; "
|
||||||
|
"adc %5,%%edx ; "
|
||||||
|
: "=A" (product), "=r" (tmp1), "=r" (tmp2)
|
||||||
|
: "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
|
||||||
|
#elif __x86_64__
|
||||||
|
__asm__ (
|
||||||
|
"mul %%rdx ; shrd $32,%%rdx,%%rax"
|
||||||
|
: "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
|
||||||
|
#else
|
||||||
|
#error implement me!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return product;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u64 pvclock_get_nsec_offset(struct pvclock_shadow_time *shadow)
|
||||||
|
{
|
||||||
|
u64 delta = native_read_tsc() - shadow->tsc_timestamp;
|
||||||
|
return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reads a consistent set of time-base values from hypervisor,
|
||||||
|
* into a shadow data area.
|
||||||
|
*/
|
||||||
|
static unsigned pvclock_get_time_values(struct pvclock_shadow_time *dst,
|
||||||
|
struct pvclock_vcpu_time_info *src)
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
dst->version = src->version;
|
||||||
|
rmb(); /* fetch version before data */
|
||||||
|
dst->tsc_timestamp = src->tsc_timestamp;
|
||||||
|
dst->system_timestamp = src->system_time;
|
||||||
|
dst->tsc_to_nsec_mul = src->tsc_to_system_mul;
|
||||||
|
dst->tsc_shift = src->tsc_shift;
|
||||||
|
rmb(); /* test version after fetching data */
|
||||||
|
} while ((src->version & 1) || (dst->version != src->version));
|
||||||
|
|
||||||
|
return dst->version;
|
||||||
|
}
|
||||||
|
|
||||||
|
cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src)
|
||||||
|
{
|
||||||
|
struct pvclock_shadow_time shadow;
|
||||||
|
unsigned version;
|
||||||
|
cycle_t ret, offset;
|
||||||
|
|
||||||
|
do {
|
||||||
|
version = pvclock_get_time_values(&shadow, src);
|
||||||
|
barrier();
|
||||||
|
offset = pvclock_get_nsec_offset(&shadow);
|
||||||
|
ret = shadow.system_timestamp + offset;
|
||||||
|
barrier();
|
||||||
|
} while (version != src->version);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pvclock_read_wallclock(struct pvclock_wall_clock *wall_clock,
|
||||||
|
struct pvclock_vcpu_time_info *vcpu_time,
|
||||||
|
struct timespec *ts)
|
||||||
|
{
|
||||||
|
u32 version;
|
||||||
|
u64 delta;
|
||||||
|
struct timespec now;
|
||||||
|
|
||||||
|
/* get wallclock at system boot */
|
||||||
|
do {
|
||||||
|
version = wall_clock->version;
|
||||||
|
rmb(); /* fetch version before time */
|
||||||
|
now.tv_sec = wall_clock->sec;
|
||||||
|
now.tv_nsec = wall_clock->nsec;
|
||||||
|
rmb(); /* fetch time before checking version */
|
||||||
|
} while ((wall_clock->version & 1) || (version != wall_clock->version));
|
||||||
|
|
||||||
|
delta = pvclock_clocksource_read(vcpu_time); /* time since system boot */
|
||||||
|
delta += now.tv_sec * (u64)NSEC_PER_SEC + now.tv_nsec;
|
||||||
|
|
||||||
|
now.tv_nsec = do_div(delta, NSEC_PER_SEC);
|
||||||
|
now.tv_sec = delta;
|
||||||
|
|
||||||
|
set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);
|
||||||
|
}
|
|
@ -200,9 +200,12 @@ int __pit_timer_fn(struct kvm_kpit_state *ps)
|
||||||
|
|
||||||
atomic_inc(&pt->pending);
|
atomic_inc(&pt->pending);
|
||||||
smp_mb__after_atomic_inc();
|
smp_mb__after_atomic_inc();
|
||||||
if (vcpu0 && waitqueue_active(&vcpu0->wq)) {
|
if (vcpu0) {
|
||||||
vcpu0->arch.mp_state = KVM_MP_STATE_RUNNABLE;
|
set_bit(KVM_REQ_PENDING_TIMER, &vcpu0->requests);
|
||||||
wake_up_interruptible(&vcpu0->wq);
|
if (waitqueue_active(&vcpu0->wq)) {
|
||||||
|
vcpu0->arch.mp_state = KVM_MP_STATE_RUNNABLE;
|
||||||
|
wake_up_interruptible(&vcpu0->wq);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pt->timer.expires = ktime_add_ns(pt->timer.expires, pt->period);
|
pt->timer.expires = ktime_add_ns(pt->timer.expires, pt->period);
|
||||||
|
|
|
@ -940,6 +940,7 @@ static int __apic_timer_fn(struct kvm_lapic *apic)
|
||||||
wait_queue_head_t *q = &apic->vcpu->wq;
|
wait_queue_head_t *q = &apic->vcpu->wq;
|
||||||
|
|
||||||
atomic_inc(&apic->timer.pending);
|
atomic_inc(&apic->timer.pending);
|
||||||
|
set_bit(KVM_REQ_PENDING_TIMER, &apic->vcpu->requests);
|
||||||
if (waitqueue_active(q)) {
|
if (waitqueue_active(q)) {
|
||||||
apic->vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
|
apic->vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
|
||||||
wake_up_interruptible(q);
|
wake_up_interruptible(q);
|
||||||
|
|
|
@ -640,6 +640,7 @@ static void rmap_write_protect(struct kvm *kvm, u64 gfn)
|
||||||
rmap_remove(kvm, spte);
|
rmap_remove(kvm, spte);
|
||||||
--kvm->stat.lpages;
|
--kvm->stat.lpages;
|
||||||
set_shadow_pte(spte, shadow_trap_nonpresent_pte);
|
set_shadow_pte(spte, shadow_trap_nonpresent_pte);
|
||||||
|
spte = NULL;
|
||||||
write_protected = 1;
|
write_protected = 1;
|
||||||
}
|
}
|
||||||
spte = rmap_next(kvm, rmapp, spte);
|
spte = rmap_next(kvm, rmapp, spte);
|
||||||
|
@ -1082,10 +1083,6 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte,
|
||||||
struct kvm_mmu_page *shadow;
|
struct kvm_mmu_page *shadow;
|
||||||
|
|
||||||
spte |= PT_WRITABLE_MASK;
|
spte |= PT_WRITABLE_MASK;
|
||||||
if (user_fault) {
|
|
||||||
mmu_unshadow(vcpu->kvm, gfn);
|
|
||||||
goto unshadowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
shadow = kvm_mmu_lookup_page(vcpu->kvm, gfn);
|
shadow = kvm_mmu_lookup_page(vcpu->kvm, gfn);
|
||||||
if (shadow ||
|
if (shadow ||
|
||||||
|
@ -1102,8 +1099,6 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unshadowed:
|
|
||||||
|
|
||||||
if (pte_access & ACC_WRITE_MASK)
|
if (pte_access & ACC_WRITE_MASK)
|
||||||
mark_page_dirty(vcpu->kvm, gfn);
|
mark_page_dirty(vcpu->kvm, gfn);
|
||||||
|
|
||||||
|
@ -1580,11 +1575,13 @@ static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu,
|
||||||
u64 *spte,
|
u64 *spte,
|
||||||
const void *new)
|
const void *new)
|
||||||
{
|
{
|
||||||
if ((sp->role.level != PT_PAGE_TABLE_LEVEL)
|
if (sp->role.level != PT_PAGE_TABLE_LEVEL) {
|
||||||
&& !vcpu->arch.update_pte.largepage) {
|
if (!vcpu->arch.update_pte.largepage ||
|
||||||
++vcpu->kvm->stat.mmu_pde_zapped;
|
sp->role.glevels == PT32_ROOT_LEVEL) {
|
||||||
return;
|
++vcpu->kvm->stat.mmu_pde_zapped;
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
++vcpu->kvm->stat.mmu_pte_updated;
|
++vcpu->kvm->stat.mmu_pte_updated;
|
||||||
if (sp->role.glevels == PT32_ROOT_LEVEL)
|
if (sp->role.glevels == PT32_ROOT_LEVEL)
|
||||||
|
|
|
@ -566,7 +566,7 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu)
|
||||||
load_transition_efer(vmx);
|
load_transition_efer(vmx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vmx_load_host_state(struct vcpu_vmx *vmx)
|
static void __vmx_load_host_state(struct vcpu_vmx *vmx)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
@ -596,6 +596,13 @@ static void vmx_load_host_state(struct vcpu_vmx *vmx)
|
||||||
reload_host_efer(vmx);
|
reload_host_efer(vmx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void vmx_load_host_state(struct vcpu_vmx *vmx)
|
||||||
|
{
|
||||||
|
preempt_disable();
|
||||||
|
__vmx_load_host_state(vmx);
|
||||||
|
preempt_enable();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Switches to specified vcpu, until a matching vcpu_put(), but assumes
|
* Switches to specified vcpu, until a matching vcpu_put(), but assumes
|
||||||
* vcpu mutex is already taken.
|
* vcpu mutex is already taken.
|
||||||
|
@ -654,7 +661,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
|
||||||
|
|
||||||
static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
|
static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
vmx_load_host_state(to_vmx(vcpu));
|
__vmx_load_host_state(to_vmx(vcpu));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vmx_fpu_activate(struct kvm_vcpu *vcpu)
|
static void vmx_fpu_activate(struct kvm_vcpu *vcpu)
|
||||||
|
@ -884,11 +891,8 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
|
||||||
switch (msr_index) {
|
switch (msr_index) {
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
case MSR_EFER:
|
case MSR_EFER:
|
||||||
|
vmx_load_host_state(vmx);
|
||||||
ret = kvm_set_msr_common(vcpu, msr_index, data);
|
ret = kvm_set_msr_common(vcpu, msr_index, data);
|
||||||
if (vmx->host_state.loaded) {
|
|
||||||
reload_host_efer(vmx);
|
|
||||||
load_transition_efer(vmx);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case MSR_FS_BASE:
|
case MSR_FS_BASE:
|
||||||
vmcs_writel(GUEST_FS_BASE, data);
|
vmcs_writel(GUEST_FS_BASE, data);
|
||||||
|
@ -910,11 +914,10 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
|
||||||
guest_write_tsc(data);
|
guest_write_tsc(data);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
vmx_load_host_state(vmx);
|
||||||
msr = find_msr_entry(vmx, msr_index);
|
msr = find_msr_entry(vmx, msr_index);
|
||||||
if (msr) {
|
if (msr) {
|
||||||
msr->data = data;
|
msr->data = data;
|
||||||
if (vmx->host_state.loaded)
|
|
||||||
load_msrs(vmx->guest_msrs, vmx->save_nmsrs);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ret = kvm_set_msr_common(vcpu, msr_index, data);
|
ret = kvm_set_msr_common(vcpu, msr_index, data);
|
||||||
|
|
|
@ -492,8 +492,8 @@ static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
|
||||||
static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
|
static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
|
||||||
{
|
{
|
||||||
static int version;
|
static int version;
|
||||||
struct kvm_wall_clock wc;
|
struct pvclock_wall_clock wc;
|
||||||
struct timespec wc_ts;
|
struct timespec now, sys, boot;
|
||||||
|
|
||||||
if (!wall_clock)
|
if (!wall_clock)
|
||||||
return;
|
return;
|
||||||
|
@ -502,10 +502,19 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
|
||||||
|
|
||||||
kvm_write_guest(kvm, wall_clock, &version, sizeof(version));
|
kvm_write_guest(kvm, wall_clock, &version, sizeof(version));
|
||||||
|
|
||||||
wc_ts = current_kernel_time();
|
/*
|
||||||
wc.wc_sec = wc_ts.tv_sec;
|
* The guest calculates current wall clock time by adding
|
||||||
wc.wc_nsec = wc_ts.tv_nsec;
|
* system time (updated by kvm_write_guest_time below) to the
|
||||||
wc.wc_version = version;
|
* wall clock specified here. guest system time equals host
|
||||||
|
* system time for us, thus we must fill in host boot time here.
|
||||||
|
*/
|
||||||
|
now = current_kernel_time();
|
||||||
|
ktime_get_ts(&sys);
|
||||||
|
boot = ns_to_timespec(timespec_to_ns(&now) - timespec_to_ns(&sys));
|
||||||
|
|
||||||
|
wc.sec = boot.tv_sec;
|
||||||
|
wc.nsec = boot.tv_nsec;
|
||||||
|
wc.version = version;
|
||||||
|
|
||||||
kvm_write_guest(kvm, wall_clock, &wc, sizeof(wc));
|
kvm_write_guest(kvm, wall_clock, &wc, sizeof(wc));
|
||||||
|
|
||||||
|
@ -513,6 +522,45 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
|
||||||
kvm_write_guest(kvm, wall_clock, &version, sizeof(version));
|
kvm_write_guest(kvm, wall_clock, &version, sizeof(version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t div_frac(uint32_t dividend, uint32_t divisor)
|
||||||
|
{
|
||||||
|
uint32_t quotient, remainder;
|
||||||
|
|
||||||
|
/* Don't try to replace with do_div(), this one calculates
|
||||||
|
* "(dividend << 32) / divisor" */
|
||||||
|
__asm__ ( "divl %4"
|
||||||
|
: "=a" (quotient), "=d" (remainder)
|
||||||
|
: "0" (0), "1" (dividend), "r" (divisor) );
|
||||||
|
return quotient;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kvm_set_time_scale(uint32_t tsc_khz, struct pvclock_vcpu_time_info *hv_clock)
|
||||||
|
{
|
||||||
|
uint64_t nsecs = 1000000000LL;
|
||||||
|
int32_t shift = 0;
|
||||||
|
uint64_t tps64;
|
||||||
|
uint32_t tps32;
|
||||||
|
|
||||||
|
tps64 = tsc_khz * 1000LL;
|
||||||
|
while (tps64 > nsecs*2) {
|
||||||
|
tps64 >>= 1;
|
||||||
|
shift--;
|
||||||
|
}
|
||||||
|
|
||||||
|
tps32 = (uint32_t)tps64;
|
||||||
|
while (tps32 <= (uint32_t)nsecs) {
|
||||||
|
tps32 <<= 1;
|
||||||
|
shift++;
|
||||||
|
}
|
||||||
|
|
||||||
|
hv_clock->tsc_shift = shift;
|
||||||
|
hv_clock->tsc_to_system_mul = div_frac(nsecs, tps32);
|
||||||
|
|
||||||
|
pr_debug("%s: tsc_khz %u, tsc_shift %d, tsc_mul %u\n",
|
||||||
|
__FUNCTION__, tsc_khz, hv_clock->tsc_shift,
|
||||||
|
hv_clock->tsc_to_system_mul);
|
||||||
|
}
|
||||||
|
|
||||||
static void kvm_write_guest_time(struct kvm_vcpu *v)
|
static void kvm_write_guest_time(struct kvm_vcpu *v)
|
||||||
{
|
{
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
|
@ -523,6 +571,11 @@ static void kvm_write_guest_time(struct kvm_vcpu *v)
|
||||||
if ((!vcpu->time_page))
|
if ((!vcpu->time_page))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (unlikely(vcpu->hv_clock_tsc_khz != tsc_khz)) {
|
||||||
|
kvm_set_time_scale(tsc_khz, &vcpu->hv_clock);
|
||||||
|
vcpu->hv_clock_tsc_khz = tsc_khz;
|
||||||
|
}
|
||||||
|
|
||||||
/* Keep irq disabled to prevent changes to the clock */
|
/* Keep irq disabled to prevent changes to the clock */
|
||||||
local_irq_save(flags);
|
local_irq_save(flags);
|
||||||
kvm_get_msr(v, MSR_IA32_TIME_STAMP_COUNTER,
|
kvm_get_msr(v, MSR_IA32_TIME_STAMP_COUNTER,
|
||||||
|
@ -537,14 +590,14 @@ static void kvm_write_guest_time(struct kvm_vcpu *v)
|
||||||
/*
|
/*
|
||||||
* The interface expects us to write an even number signaling that the
|
* The interface expects us to write an even number signaling that the
|
||||||
* update is finished. Since the guest won't see the intermediate
|
* update is finished. Since the guest won't see the intermediate
|
||||||
* state, we just write "2" at the end
|
* state, we just increase by 2 at the end.
|
||||||
*/
|
*/
|
||||||
vcpu->hv_clock.version = 2;
|
vcpu->hv_clock.version += 2;
|
||||||
|
|
||||||
shared_kaddr = kmap_atomic(vcpu->time_page, KM_USER0);
|
shared_kaddr = kmap_atomic(vcpu->time_page, KM_USER0);
|
||||||
|
|
||||||
memcpy(shared_kaddr + vcpu->time_offset, &vcpu->hv_clock,
|
memcpy(shared_kaddr + vcpu->time_offset, &vcpu->hv_clock,
|
||||||
sizeof(vcpu->hv_clock));
|
sizeof(vcpu->hv_clock));
|
||||||
|
|
||||||
kunmap_atomic(shared_kaddr, KM_USER0);
|
kunmap_atomic(shared_kaddr, KM_USER0);
|
||||||
|
|
||||||
|
@ -599,10 +652,6 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
|
||||||
/* ...but clean it before doing the actual write */
|
/* ...but clean it before doing the actual write */
|
||||||
vcpu->arch.time_offset = data & ~(PAGE_MASK | 1);
|
vcpu->arch.time_offset = data & ~(PAGE_MASK | 1);
|
||||||
|
|
||||||
vcpu->arch.hv_clock.tsc_to_system_mul =
|
|
||||||
clocksource_khz2mult(tsc_khz, 22);
|
|
||||||
vcpu->arch.hv_clock.tsc_shift = 22;
|
|
||||||
|
|
||||||
down_read(¤t->mm->mmap_sem);
|
down_read(¤t->mm->mmap_sem);
|
||||||
vcpu->arch.time_page =
|
vcpu->arch.time_page =
|
||||||
gfn_to_page(vcpu->kvm, data >> PAGE_SHIFT);
|
gfn_to_page(vcpu->kvm, data >> PAGE_SHIFT);
|
||||||
|
@ -2759,6 +2808,8 @@ static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
||||||
if (vcpu->requests) {
|
if (vcpu->requests) {
|
||||||
if (test_and_clear_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests))
|
if (test_and_clear_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests))
|
||||||
__kvm_migrate_timers(vcpu);
|
__kvm_migrate_timers(vcpu);
|
||||||
|
if (test_and_clear_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests))
|
||||||
|
kvm_x86_ops->tlb_flush(vcpu);
|
||||||
if (test_and_clear_bit(KVM_REQ_REPORT_TPR_ACCESS,
|
if (test_and_clear_bit(KVM_REQ_REPORT_TPR_ACCESS,
|
||||||
&vcpu->requests)) {
|
&vcpu->requests)) {
|
||||||
kvm_run->exit_reason = KVM_EXIT_TPR_ACCESS;
|
kvm_run->exit_reason = KVM_EXIT_TPR_ACCESS;
|
||||||
|
@ -2772,6 +2823,7 @@ static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clear_bit(KVM_REQ_PENDING_TIMER, &vcpu->requests);
|
||||||
kvm_inject_pending_timer_irqs(vcpu);
|
kvm_inject_pending_timer_irqs(vcpu);
|
||||||
|
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
|
@ -2781,21 +2833,13 @@ static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
||||||
|
|
||||||
local_irq_disable();
|
local_irq_disable();
|
||||||
|
|
||||||
if (need_resched()) {
|
if (vcpu->requests || need_resched()) {
|
||||||
local_irq_enable();
|
local_irq_enable();
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
r = 1;
|
r = 1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vcpu->requests)
|
|
||||||
if (test_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests)) {
|
|
||||||
local_irq_enable();
|
|
||||||
preempt_enable();
|
|
||||||
r = 1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signal_pending(current)) {
|
if (signal_pending(current)) {
|
||||||
local_irq_enable();
|
local_irq_enable();
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
|
@ -2825,9 +2869,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
||||||
|
|
||||||
kvm_guest_enter();
|
kvm_guest_enter();
|
||||||
|
|
||||||
if (vcpu->requests)
|
|
||||||
if (test_and_clear_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests))
|
|
||||||
kvm_x86_ops->tlb_flush(vcpu);
|
|
||||||
|
|
||||||
KVMTRACE_0D(VMENTRY, vcpu, entryexit);
|
KVMTRACE_0D(VMENTRY, vcpu, entryexit);
|
||||||
kvm_x86_ops->run(vcpu, kvm_run);
|
kvm_x86_ops->run(vcpu, kvm_run);
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
config XEN
|
config XEN
|
||||||
bool "Xen guest support"
|
bool "Xen guest support"
|
||||||
select PARAVIRT
|
select PARAVIRT
|
||||||
|
select PARAVIRT_CLOCK
|
||||||
depends on X86_32
|
depends on X86_32
|
||||||
depends on X86_CMPXCHG && X86_TSC && !(X86_VISWS || X86_VOYAGER)
|
depends on X86_CMPXCHG && X86_TSC && X86_PAE && !(X86_VISWS || X86_VOYAGER)
|
||||||
help
|
help
|
||||||
This is the Linux Xen port. Enabling this will allow the
|
This is the Linux Xen port. Enabling this will allow the
|
||||||
kernel to boot in a paravirtualized environment under the
|
kernel to boot in a paravirtualized environment under the
|
||||||
|
|
|
@ -785,38 +785,35 @@ static __init void xen_set_pte_init(pte_t *ptep, pte_t pte)
|
||||||
static __init void xen_pagetable_setup_start(pgd_t *base)
|
static __init void xen_pagetable_setup_start(pgd_t *base)
|
||||||
{
|
{
|
||||||
pgd_t *xen_pgd = (pgd_t *)xen_start_info->pt_base;
|
pgd_t *xen_pgd = (pgd_t *)xen_start_info->pt_base;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* special set_pte for pagetable initialization */
|
/* special set_pte for pagetable initialization */
|
||||||
pv_mmu_ops.set_pte = xen_set_pte_init;
|
pv_mmu_ops.set_pte = xen_set_pte_init;
|
||||||
|
|
||||||
init_mm.pgd = base;
|
init_mm.pgd = base;
|
||||||
/*
|
/*
|
||||||
* copy top-level of Xen-supplied pagetable into place. For
|
* copy top-level of Xen-supplied pagetable into place. This
|
||||||
* !PAE we can use this as-is, but for PAE it is a stand-in
|
* is a stand-in while we copy the pmd pages.
|
||||||
* while we copy the pmd pages.
|
|
||||||
*/
|
*/
|
||||||
memcpy(base, xen_pgd, PTRS_PER_PGD * sizeof(pgd_t));
|
memcpy(base, xen_pgd, PTRS_PER_PGD * sizeof(pgd_t));
|
||||||
|
|
||||||
if (PTRS_PER_PMD > 1) {
|
/*
|
||||||
int i;
|
* For PAE, need to allocate new pmds, rather than
|
||||||
/*
|
* share Xen's, since Xen doesn't like pmd's being
|
||||||
* For PAE, need to allocate new pmds, rather than
|
* shared between address spaces.
|
||||||
* share Xen's, since Xen doesn't like pmd's being
|
*/
|
||||||
* shared between address spaces.
|
for (i = 0; i < PTRS_PER_PGD; i++) {
|
||||||
*/
|
if (pgd_val_ma(xen_pgd[i]) & _PAGE_PRESENT) {
|
||||||
for (i = 0; i < PTRS_PER_PGD; i++) {
|
pmd_t *pmd = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
|
||||||
if (pgd_val_ma(xen_pgd[i]) & _PAGE_PRESENT) {
|
|
||||||
pmd_t *pmd = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
|
|
||||||
|
|
||||||
memcpy(pmd, (void *)pgd_page_vaddr(xen_pgd[i]),
|
memcpy(pmd, (void *)pgd_page_vaddr(xen_pgd[i]),
|
||||||
PAGE_SIZE);
|
PAGE_SIZE);
|
||||||
|
|
||||||
make_lowmem_page_readonly(pmd);
|
make_lowmem_page_readonly(pmd);
|
||||||
|
|
||||||
set_pgd(&base[i], __pgd(1 + __pa(pmd)));
|
set_pgd(&base[i], __pgd(1 + __pa(pmd)));
|
||||||
} else
|
} else
|
||||||
pgd_clear(&base[i]);
|
pgd_clear(&base[i]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make sure zero_page is mapped RO so we can use it in pagetables */
|
/* make sure zero_page is mapped RO so we can use it in pagetables */
|
||||||
|
@ -873,17 +870,7 @@ static __init void xen_pagetable_setup_done(pgd_t *base)
|
||||||
|
|
||||||
/* Actually pin the pagetable down, but we can't set PG_pinned
|
/* Actually pin the pagetable down, but we can't set PG_pinned
|
||||||
yet because the page structures don't exist yet. */
|
yet because the page structures don't exist yet. */
|
||||||
{
|
pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(base)));
|
||||||
unsigned level;
|
|
||||||
|
|
||||||
#ifdef CONFIG_X86_PAE
|
|
||||||
level = MMUEXT_PIN_L3_TABLE;
|
|
||||||
#else
|
|
||||||
level = MMUEXT_PIN_L2_TABLE;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pin_pagetable_pfn(level, PFN_DOWN(__pa(base)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is called once we have the cpu_possible_map */
|
/* This is called once we have the cpu_possible_map */
|
||||||
|
@ -1093,7 +1080,6 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {
|
||||||
.make_pte = xen_make_pte,
|
.make_pte = xen_make_pte,
|
||||||
.make_pgd = xen_make_pgd,
|
.make_pgd = xen_make_pgd,
|
||||||
|
|
||||||
#ifdef CONFIG_X86_PAE
|
|
||||||
.set_pte_atomic = xen_set_pte_atomic,
|
.set_pte_atomic = xen_set_pte_atomic,
|
||||||
.set_pte_present = xen_set_pte_at,
|
.set_pte_present = xen_set_pte_at,
|
||||||
.set_pud = xen_set_pud,
|
.set_pud = xen_set_pud,
|
||||||
|
@ -1102,7 +1088,6 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {
|
||||||
|
|
||||||
.make_pmd = xen_make_pmd,
|
.make_pmd = xen_make_pmd,
|
||||||
.pmd_val = xen_pmd_val,
|
.pmd_val = xen_pmd_val,
|
||||||
#endif /* PAE */
|
|
||||||
|
|
||||||
.activate_mm = xen_activate_mm,
|
.activate_mm = xen_activate_mm,
|
||||||
.dup_mmap = xen_dup_mmap,
|
.dup_mmap = xen_dup_mmap,
|
||||||
|
@ -1228,6 +1213,11 @@ asmlinkage void __init xen_start_kernel(void)
|
||||||
if (xen_feature(XENFEAT_supervisor_mode_kernel))
|
if (xen_feature(XENFEAT_supervisor_mode_kernel))
|
||||||
pv_info.kernel_rpl = 0;
|
pv_info.kernel_rpl = 0;
|
||||||
|
|
||||||
|
/* Prevent unwanted bits from being set in PTEs. */
|
||||||
|
__supported_pte_mask &= ~_PAGE_GLOBAL;
|
||||||
|
if (!is_initial_xendomain())
|
||||||
|
__supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD);
|
||||||
|
|
||||||
/* set the limit of our address space */
|
/* set the limit of our address space */
|
||||||
xen_reserve_top();
|
xen_reserve_top();
|
||||||
|
|
||||||
|
|
|
@ -179,50 +179,56 @@ void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Assume pteval_t is equivalent to all the other *val_t types. */
|
||||||
|
static pteval_t pte_mfn_to_pfn(pteval_t val)
|
||||||
|
{
|
||||||
|
if (val & _PAGE_PRESENT) {
|
||||||
|
unsigned long mfn = (val & PTE_MASK) >> PAGE_SHIFT;
|
||||||
|
pteval_t flags = val & ~PTE_MASK;
|
||||||
|
val = (mfn_to_pfn(mfn) << PAGE_SHIFT) | flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static pteval_t pte_pfn_to_mfn(pteval_t val)
|
||||||
|
{
|
||||||
|
if (val & _PAGE_PRESENT) {
|
||||||
|
unsigned long pfn = (val & PTE_MASK) >> PAGE_SHIFT;
|
||||||
|
pteval_t flags = val & ~PTE_MASK;
|
||||||
|
val = (pfn_to_mfn(pfn) << PAGE_SHIFT) | flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
pteval_t xen_pte_val(pte_t pte)
|
pteval_t xen_pte_val(pte_t pte)
|
||||||
{
|
{
|
||||||
pteval_t ret = pte.pte;
|
return pte_mfn_to_pfn(pte.pte);
|
||||||
|
|
||||||
if (ret & _PAGE_PRESENT)
|
|
||||||
ret = machine_to_phys(XMADDR(ret)).paddr | _PAGE_PRESENT;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pgdval_t xen_pgd_val(pgd_t pgd)
|
pgdval_t xen_pgd_val(pgd_t pgd)
|
||||||
{
|
{
|
||||||
pgdval_t ret = pgd.pgd;
|
return pte_mfn_to_pfn(pgd.pgd);
|
||||||
if (ret & _PAGE_PRESENT)
|
|
||||||
ret = machine_to_phys(XMADDR(ret)).paddr | _PAGE_PRESENT;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pte_t xen_make_pte(pteval_t pte)
|
pte_t xen_make_pte(pteval_t pte)
|
||||||
{
|
{
|
||||||
if (pte & _PAGE_PRESENT) {
|
pte = pte_pfn_to_mfn(pte);
|
||||||
pte = phys_to_machine(XPADDR(pte)).maddr;
|
return native_make_pte(pte);
|
||||||
pte &= ~(_PAGE_PCD | _PAGE_PWT);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (pte_t){ .pte = pte };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pgd_t xen_make_pgd(pgdval_t pgd)
|
pgd_t xen_make_pgd(pgdval_t pgd)
|
||||||
{
|
{
|
||||||
if (pgd & _PAGE_PRESENT)
|
pgd = pte_pfn_to_mfn(pgd);
|
||||||
pgd = phys_to_machine(XPADDR(pgd)).maddr;
|
return native_make_pgd(pgd);
|
||||||
|
|
||||||
return (pgd_t){ pgd };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pmdval_t xen_pmd_val(pmd_t pmd)
|
pmdval_t xen_pmd_val(pmd_t pmd)
|
||||||
{
|
{
|
||||||
pmdval_t ret = native_pmd_val(pmd);
|
return pte_mfn_to_pfn(pmd.pmd);
|
||||||
if (ret & _PAGE_PRESENT)
|
|
||||||
ret = machine_to_phys(XMADDR(ret)).paddr | _PAGE_PRESENT;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_X86_PAE
|
|
||||||
void xen_set_pud(pud_t *ptr, pud_t val)
|
void xen_set_pud(pud_t *ptr, pud_t val)
|
||||||
{
|
{
|
||||||
struct multicall_space mcs;
|
struct multicall_space mcs;
|
||||||
|
@ -267,17 +273,9 @@ void xen_pmd_clear(pmd_t *pmdp)
|
||||||
|
|
||||||
pmd_t xen_make_pmd(pmdval_t pmd)
|
pmd_t xen_make_pmd(pmdval_t pmd)
|
||||||
{
|
{
|
||||||
if (pmd & _PAGE_PRESENT)
|
pmd = pte_pfn_to_mfn(pmd);
|
||||||
pmd = phys_to_machine(XPADDR(pmd)).maddr;
|
|
||||||
|
|
||||||
return native_make_pmd(pmd);
|
return native_make_pmd(pmd);
|
||||||
}
|
}
|
||||||
#else /* !PAE */
|
|
||||||
void xen_set_pte(pte_t *ptep, pte_t pte)
|
|
||||||
{
|
|
||||||
*ptep = pte;
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_X86_PAE */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
(Yet another) pagetable walker. This one is intended for pinning a
|
(Yet another) pagetable walker. This one is intended for pinning a
|
||||||
|
@ -430,8 +428,6 @@ static int pin_page(struct page *page, enum pt_level level)
|
||||||
read-only, and can be pinned. */
|
read-only, and can be pinned. */
|
||||||
void xen_pgd_pin(pgd_t *pgd)
|
void xen_pgd_pin(pgd_t *pgd)
|
||||||
{
|
{
|
||||||
unsigned level;
|
|
||||||
|
|
||||||
xen_mc_batch();
|
xen_mc_batch();
|
||||||
|
|
||||||
if (pgd_walk(pgd, pin_page, TASK_SIZE)) {
|
if (pgd_walk(pgd, pin_page, TASK_SIZE)) {
|
||||||
|
@ -441,14 +437,7 @@ void xen_pgd_pin(pgd_t *pgd)
|
||||||
xen_mc_batch();
|
xen_mc_batch();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_PAE
|
xen_do_pin(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(pgd)));
|
||||||
level = MMUEXT_PIN_L3_TABLE;
|
|
||||||
#else
|
|
||||||
level = MMUEXT_PIN_L2_TABLE;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
xen_do_pin(level, PFN_DOWN(__pa(pgd)));
|
|
||||||
|
|
||||||
xen_mc_issue(0);
|
xen_mc_issue(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,14 +37,13 @@ void xen_exit_mmap(struct mm_struct *mm);
|
||||||
void xen_pgd_pin(pgd_t *pgd);
|
void xen_pgd_pin(pgd_t *pgd);
|
||||||
//void xen_pgd_unpin(pgd_t *pgd);
|
//void xen_pgd_unpin(pgd_t *pgd);
|
||||||
|
|
||||||
#ifdef CONFIG_X86_PAE
|
pteval_t xen_pte_val(pte_t);
|
||||||
unsigned long long xen_pte_val(pte_t);
|
pmdval_t xen_pmd_val(pmd_t);
|
||||||
unsigned long long xen_pmd_val(pmd_t);
|
pgdval_t xen_pgd_val(pgd_t);
|
||||||
unsigned long long xen_pgd_val(pgd_t);
|
|
||||||
|
|
||||||
pte_t xen_make_pte(unsigned long long);
|
pte_t xen_make_pte(pteval_t);
|
||||||
pmd_t xen_make_pmd(unsigned long long);
|
pmd_t xen_make_pmd(pmdval_t);
|
||||||
pgd_t xen_make_pgd(unsigned long long);
|
pgd_t xen_make_pgd(pgdval_t);
|
||||||
|
|
||||||
void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
|
void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
|
||||||
pte_t *ptep, pte_t pteval);
|
pte_t *ptep, pte_t pteval);
|
||||||
|
@ -53,15 +52,4 @@ void xen_set_pud(pud_t *ptr, pud_t val);
|
||||||
void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
|
void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
|
||||||
void xen_pmd_clear(pmd_t *pmdp);
|
void xen_pmd_clear(pmd_t *pmdp);
|
||||||
|
|
||||||
|
|
||||||
#else
|
|
||||||
unsigned long xen_pte_val(pte_t);
|
|
||||||
unsigned long xen_pmd_val(pmd_t);
|
|
||||||
unsigned long xen_pgd_val(pgd_t);
|
|
||||||
|
|
||||||
pte_t xen_make_pte(unsigned long);
|
|
||||||
pmd_t xen_make_pmd(unsigned long);
|
|
||||||
pgd_t xen_make_pgd(unsigned long);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* _XEN_MMU_H */
|
#endif /* _XEN_MMU_H */
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <linux/kernel_stat.h>
|
#include <linux/kernel_stat.h>
|
||||||
#include <linux/math64.h>
|
#include <linux/math64.h>
|
||||||
|
|
||||||
|
#include <asm/pvclock.h>
|
||||||
#include <asm/xen/hypervisor.h>
|
#include <asm/xen/hypervisor.h>
|
||||||
#include <asm/xen/hypercall.h>
|
#include <asm/xen/hypercall.h>
|
||||||
|
|
||||||
|
@ -31,17 +32,6 @@
|
||||||
|
|
||||||
static cycle_t xen_clocksource_read(void);
|
static cycle_t xen_clocksource_read(void);
|
||||||
|
|
||||||
/* These are perodically updated in shared_info, and then copied here. */
|
|
||||||
struct shadow_time_info {
|
|
||||||
u64 tsc_timestamp; /* TSC at last update of time vals. */
|
|
||||||
u64 system_timestamp; /* Time, in nanosecs, since boot. */
|
|
||||||
u32 tsc_to_nsec_mul;
|
|
||||||
int tsc_shift;
|
|
||||||
u32 version;
|
|
||||||
};
|
|
||||||
|
|
||||||
static DEFINE_PER_CPU(struct shadow_time_info, shadow_time);
|
|
||||||
|
|
||||||
/* runstate info updated by Xen */
|
/* runstate info updated by Xen */
|
||||||
static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);
|
static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);
|
||||||
|
|
||||||
|
@ -211,7 +201,7 @@ unsigned long long xen_sched_clock(void)
|
||||||
unsigned long xen_cpu_khz(void)
|
unsigned long xen_cpu_khz(void)
|
||||||
{
|
{
|
||||||
u64 xen_khz = 1000000ULL << 32;
|
u64 xen_khz = 1000000ULL << 32;
|
||||||
const struct vcpu_time_info *info =
|
const struct pvclock_vcpu_time_info *info =
|
||||||
&HYPERVISOR_shared_info->vcpu_info[0].time;
|
&HYPERVISOR_shared_info->vcpu_info[0].time;
|
||||||
|
|
||||||
do_div(xen_khz, info->tsc_to_system_mul);
|
do_div(xen_khz, info->tsc_to_system_mul);
|
||||||
|
@ -223,121 +213,26 @@ unsigned long xen_cpu_khz(void)
|
||||||
return xen_khz;
|
return xen_khz;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Reads a consistent set of time-base values from Xen, into a shadow data
|
|
||||||
* area.
|
|
||||||
*/
|
|
||||||
static unsigned get_time_values_from_xen(void)
|
|
||||||
{
|
|
||||||
struct vcpu_time_info *src;
|
|
||||||
struct shadow_time_info *dst;
|
|
||||||
|
|
||||||
/* src is shared memory with the hypervisor, so we need to
|
|
||||||
make sure we get a consistent snapshot, even in the face of
|
|
||||||
being preempted. */
|
|
||||||
src = &__get_cpu_var(xen_vcpu)->time;
|
|
||||||
dst = &__get_cpu_var(shadow_time);
|
|
||||||
|
|
||||||
do {
|
|
||||||
dst->version = src->version;
|
|
||||||
rmb(); /* fetch version before data */
|
|
||||||
dst->tsc_timestamp = src->tsc_timestamp;
|
|
||||||
dst->system_timestamp = src->system_time;
|
|
||||||
dst->tsc_to_nsec_mul = src->tsc_to_system_mul;
|
|
||||||
dst->tsc_shift = src->tsc_shift;
|
|
||||||
rmb(); /* test version after fetching data */
|
|
||||||
} while ((src->version & 1) | (dst->version ^ src->version));
|
|
||||||
|
|
||||||
return dst->version;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
|
|
||||||
* yielding a 64-bit result.
|
|
||||||
*/
|
|
||||||
static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
|
|
||||||
{
|
|
||||||
u64 product;
|
|
||||||
#ifdef __i386__
|
|
||||||
u32 tmp1, tmp2;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (shift < 0)
|
|
||||||
delta >>= -shift;
|
|
||||||
else
|
|
||||||
delta <<= shift;
|
|
||||||
|
|
||||||
#ifdef __i386__
|
|
||||||
__asm__ (
|
|
||||||
"mul %5 ; "
|
|
||||||
"mov %4,%%eax ; "
|
|
||||||
"mov %%edx,%4 ; "
|
|
||||||
"mul %5 ; "
|
|
||||||
"xor %5,%5 ; "
|
|
||||||
"add %4,%%eax ; "
|
|
||||||
"adc %5,%%edx ; "
|
|
||||||
: "=A" (product), "=r" (tmp1), "=r" (tmp2)
|
|
||||||
: "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
|
|
||||||
#elif __x86_64__
|
|
||||||
__asm__ (
|
|
||||||
"mul %%rdx ; shrd $32,%%rdx,%%rax"
|
|
||||||
: "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
|
|
||||||
#else
|
|
||||||
#error implement me!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return product;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u64 get_nsec_offset(struct shadow_time_info *shadow)
|
|
||||||
{
|
|
||||||
u64 now, delta;
|
|
||||||
now = native_read_tsc();
|
|
||||||
delta = now - shadow->tsc_timestamp;
|
|
||||||
return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
static cycle_t xen_clocksource_read(void)
|
static cycle_t xen_clocksource_read(void)
|
||||||
{
|
{
|
||||||
struct shadow_time_info *shadow = &get_cpu_var(shadow_time);
|
struct pvclock_vcpu_time_info *src;
|
||||||
cycle_t ret;
|
cycle_t ret;
|
||||||
unsigned version;
|
|
||||||
|
|
||||||
do {
|
|
||||||
version = get_time_values_from_xen();
|
|
||||||
barrier();
|
|
||||||
ret = shadow->system_timestamp + get_nsec_offset(shadow);
|
|
||||||
barrier();
|
|
||||||
} while (version != __get_cpu_var(xen_vcpu)->time.version);
|
|
||||||
|
|
||||||
put_cpu_var(shadow_time);
|
|
||||||
|
|
||||||
|
src = &get_cpu_var(xen_vcpu)->time;
|
||||||
|
ret = pvclock_clocksource_read(src);
|
||||||
|
put_cpu_var(xen_vcpu);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xen_read_wallclock(struct timespec *ts)
|
static void xen_read_wallclock(struct timespec *ts)
|
||||||
{
|
{
|
||||||
const struct shared_info *s = HYPERVISOR_shared_info;
|
struct shared_info *s = HYPERVISOR_shared_info;
|
||||||
u32 version;
|
struct pvclock_wall_clock *wall_clock = &(s->wc);
|
||||||
u64 delta;
|
struct pvclock_vcpu_time_info *vcpu_time;
|
||||||
struct timespec now;
|
|
||||||
|
|
||||||
/* get wallclock at system boot */
|
vcpu_time = &get_cpu_var(xen_vcpu)->time;
|
||||||
do {
|
pvclock_read_wallclock(wall_clock, vcpu_time, ts);
|
||||||
version = s->wc_version;
|
put_cpu_var(xen_vcpu);
|
||||||
rmb(); /* fetch version before time */
|
|
||||||
now.tv_sec = s->wc_sec;
|
|
||||||
now.tv_nsec = s->wc_nsec;
|
|
||||||
rmb(); /* fetch time before checking version */
|
|
||||||
} while ((s->wc_version & 1) | (version ^ s->wc_version));
|
|
||||||
|
|
||||||
delta = xen_clocksource_read(); /* time since system boot */
|
|
||||||
delta += now.tv_sec * (u64)NSEC_PER_SEC + now.tv_nsec;
|
|
||||||
|
|
||||||
now.tv_nsec = do_div(delta, NSEC_PER_SEC);
|
|
||||||
now.tv_sec = delta;
|
|
||||||
|
|
||||||
set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long xen_get_wallclock(void)
|
unsigned long xen_get_wallclock(void)
|
||||||
|
@ -345,7 +240,6 @@ unsigned long xen_get_wallclock(void)
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
|
|
||||||
xen_read_wallclock(&ts);
|
xen_read_wallclock(&ts);
|
||||||
|
|
||||||
return ts.tv_sec;
|
return ts.tv_sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,8 +463,6 @@ __init void xen_time_init(void)
|
||||||
{
|
{
|
||||||
int cpu = smp_processor_id();
|
int cpu = smp_processor_id();
|
||||||
|
|
||||||
get_time_values_from_xen();
|
|
||||||
|
|
||||||
clocksource_register(&xen_clocksource);
|
clocksource_register(&xen_clocksource);
|
||||||
|
|
||||||
if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL) == 0) {
|
if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL) == 0) {
|
||||||
|
|
|
@ -17,7 +17,7 @@ ENTRY(startup_xen)
|
||||||
|
|
||||||
__FINIT
|
__FINIT
|
||||||
|
|
||||||
.pushsection .bss.page_aligned
|
.pushsection .text
|
||||||
.align PAGE_SIZE_asm
|
.align PAGE_SIZE_asm
|
||||||
ENTRY(hypercall_page)
|
ENTRY(hypercall_page)
|
||||||
.skip 0x1000
|
.skip 0x1000
|
||||||
|
@ -30,11 +30,7 @@ ENTRY(hypercall_page)
|
||||||
ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .long startup_xen)
|
ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .long startup_xen)
|
||||||
ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .long hypercall_page)
|
ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .long hypercall_page)
|
||||||
ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .asciz "!writable_page_tables|pae_pgdir_above_4gb")
|
ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .asciz "!writable_page_tables|pae_pgdir_above_4gb")
|
||||||
#ifdef CONFIG_X86_PAE
|
|
||||||
ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz "yes")
|
ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz "yes")
|
||||||
#else
|
|
||||||
ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz "no")
|
|
||||||
#endif
|
|
||||||
ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz "generic")
|
ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz "generic")
|
||||||
|
|
||||||
#endif /*CONFIG_XEN */
|
#endif /*CONFIG_XEN */
|
||||||
|
|
|
@ -389,6 +389,7 @@ static int i915_resume(struct drm_device *dev)
|
||||||
pci_restore_state(dev->pdev);
|
pci_restore_state(dev->pdev);
|
||||||
if (pci_enable_device(dev->pdev))
|
if (pci_enable_device(dev->pdev))
|
||||||
return -1;
|
return -1;
|
||||||
|
pci_set_master(dev->pdev);
|
||||||
|
|
||||||
pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB);
|
pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB);
|
||||||
|
|
||||||
|
|
|
@ -981,16 +981,9 @@ EXPORT_SYMBOL_GPL(tty_perform_flush);
|
||||||
int n_tty_ioctl(struct tty_struct *tty, struct file *file,
|
int n_tty_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
unsigned int cmd, unsigned long arg)
|
unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct tty_struct *real_tty;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
|
||||||
tty->driver->subtype == PTY_TYPE_MASTER)
|
|
||||||
real_tty = tty->link;
|
|
||||||
else
|
|
||||||
real_tty = tty;
|
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case TCXONC:
|
case TCXONC:
|
||||||
retval = tty_check_change(tty);
|
retval = tty_check_change(tty);
|
||||||
|
|
|
@ -109,7 +109,11 @@ static int mthca_alloc_icm_pages(struct scatterlist *mem, int order, gfp_t gfp_m
|
||||||
{
|
{
|
||||||
struct page *page;
|
struct page *page;
|
||||||
|
|
||||||
page = alloc_pages(gfp_mask, order);
|
/*
|
||||||
|
* Use __GFP_ZERO because buggy firmware assumes ICM pages are
|
||||||
|
* cleared, and subtle failures are seen if they aren't.
|
||||||
|
*/
|
||||||
|
page = alloc_pages(gfp_mask | __GFP_ZERO, order);
|
||||||
if (!page)
|
if (!page)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
|
|
@ -176,7 +176,7 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
|
||||||
* we set it now, so we can trap and pass that trap to the Guest if it
|
* we set it now, so we can trap and pass that trap to the Guest if it
|
||||||
* uses the FPU. */
|
* uses the FPU. */
|
||||||
if (cpu->ts)
|
if (cpu->ts)
|
||||||
lguest_set_ts();
|
unlazy_fpu(current);
|
||||||
|
|
||||||
/* SYSENTER is an optimized way of doing system calls. We can't allow
|
/* SYSENTER is an optimized way of doing system calls. We can't allow
|
||||||
* it because it always jumps to privilege level 0. A normal Guest
|
* it because it always jumps to privilege level 0. A normal Guest
|
||||||
|
@ -196,6 +196,10 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
|
||||||
* trap made the switcher code come back, and an error code which some
|
* trap made the switcher code come back, and an error code which some
|
||||||
* traps set. */
|
* traps set. */
|
||||||
|
|
||||||
|
/* Restore SYSENTER if it's supposed to be on. */
|
||||||
|
if (boot_cpu_has(X86_FEATURE_SEP))
|
||||||
|
wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
|
||||||
|
|
||||||
/* If the Guest page faulted, then the cr2 register will tell us the
|
/* If the Guest page faulted, then the cr2 register will tell us the
|
||||||
* bad virtual address. We have to grab this now, because once we
|
* bad virtual address. We have to grab this now, because once we
|
||||||
* re-enable interrupts an interrupt could fault and thus overwrite
|
* re-enable interrupts an interrupt could fault and thus overwrite
|
||||||
|
@ -203,13 +207,12 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
|
||||||
if (cpu->regs->trapnum == 14)
|
if (cpu->regs->trapnum == 14)
|
||||||
cpu->arch.last_pagefault = read_cr2();
|
cpu->arch.last_pagefault = read_cr2();
|
||||||
/* Similarly, if we took a trap because the Guest used the FPU,
|
/* Similarly, if we took a trap because the Guest used the FPU,
|
||||||
* we have to restore the FPU it expects to see. */
|
* we have to restore the FPU it expects to see.
|
||||||
|
* math_state_restore() may sleep and we may even move off to
|
||||||
|
* a different CPU. So all the critical stuff should be done
|
||||||
|
* before this. */
|
||||||
else if (cpu->regs->trapnum == 7)
|
else if (cpu->regs->trapnum == 7)
|
||||||
math_state_restore();
|
math_state_restore();
|
||||||
|
|
||||||
/* Restore SYSENTER if it's supposed to be on. */
|
|
||||||
if (boot_cpu_has(X86_FEATURE_SEP))
|
|
||||||
wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*H:130 Now we've examined the hypercall code; our Guest can make requests.
|
/*H:130 Now we've examined the hypercall code; our Guest can make requests.
|
||||||
|
|
|
@ -68,7 +68,6 @@ obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
|
||||||
obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
|
obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
|
||||||
obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o
|
obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o
|
||||||
obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o
|
obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o
|
||||||
CFLAGS_hpwdt.o += -O
|
|
||||||
obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o
|
obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o
|
||||||
obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
|
obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
|
||||||
obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
|
obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
|
||||||
|
|
|
@ -529,7 +529,7 @@ void xen_evtchn_do_upcall(struct pt_regs *regs)
|
||||||
|
|
||||||
#ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */
|
#ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */
|
||||||
/* Clear master flag /before/ clearing selector flag. */
|
/* Clear master flag /before/ clearing selector flag. */
|
||||||
rmb();
|
wmb();
|
||||||
#endif
|
#endif
|
||||||
pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0);
|
pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0);
|
||||||
while (pending_words != 0) {
|
while (pending_words != 0) {
|
||||||
|
|
|
@ -246,15 +246,11 @@ static void find_metapath(const struct gfs2_sbd *sdp, u64 block,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned int zero_metapath_length(const struct metapath *mp,
|
static inline unsigned int metapath_branch_start(const struct metapath *mp)
|
||||||
unsigned height)
|
|
||||||
{
|
{
|
||||||
unsigned int i;
|
if (mp->mp_list[0] == 0)
|
||||||
for (i = 0; i < height - 1; i++) {
|
return 2;
|
||||||
if (mp->mp_list[i] != 0)
|
return 1;
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -436,7 +432,7 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock,
|
||||||
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
||||||
struct buffer_head *dibh = mp->mp_bh[0];
|
struct buffer_head *dibh = mp->mp_bh[0];
|
||||||
u64 bn, dblock = 0;
|
u64 bn, dblock = 0;
|
||||||
unsigned n, i, blks, alloced = 0, iblks = 0, zmpl = 0;
|
unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0;
|
||||||
unsigned dblks = 0;
|
unsigned dblks = 0;
|
||||||
unsigned ptrs_per_blk;
|
unsigned ptrs_per_blk;
|
||||||
const unsigned end_of_metadata = height - 1;
|
const unsigned end_of_metadata = height - 1;
|
||||||
|
@ -471,9 +467,8 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock,
|
||||||
/* Building up tree height */
|
/* Building up tree height */
|
||||||
state = ALLOC_GROW_HEIGHT;
|
state = ALLOC_GROW_HEIGHT;
|
||||||
iblks = height - ip->i_height;
|
iblks = height - ip->i_height;
|
||||||
zmpl = zero_metapath_length(mp, height);
|
branch_start = metapath_branch_start(mp);
|
||||||
iblks -= zmpl;
|
iblks += (height - branch_start);
|
||||||
iblks += height;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,13 +504,13 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock,
|
||||||
sizeof(struct gfs2_meta_header));
|
sizeof(struct gfs2_meta_header));
|
||||||
*ptr = zero_bn;
|
*ptr = zero_bn;
|
||||||
state = ALLOC_GROW_DEPTH;
|
state = ALLOC_GROW_DEPTH;
|
||||||
for(i = zmpl; i < height; i++) {
|
for(i = branch_start; i < height; i++) {
|
||||||
if (mp->mp_bh[i] == NULL)
|
if (mp->mp_bh[i] == NULL)
|
||||||
break;
|
break;
|
||||||
brelse(mp->mp_bh[i]);
|
brelse(mp->mp_bh[i]);
|
||||||
mp->mp_bh[i] = NULL;
|
mp->mp_bh[i] = NULL;
|
||||||
}
|
}
|
||||||
i = zmpl;
|
i = branch_start;
|
||||||
}
|
}
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -195,7 +195,7 @@ static u32 gfs2_bitfit(const u8 *buffer, unsigned int buflen, u32 goal,
|
||||||
depending on architecture. I've experimented with several ways
|
depending on architecture. I've experimented with several ways
|
||||||
of writing this section such as using an else before the goto
|
of writing this section such as using an else before the goto
|
||||||
but this one seems to be the fastest. */
|
but this one seems to be the fastest. */
|
||||||
while ((unsigned char *)plong < end - 1) {
|
while ((unsigned char *)plong < end - sizeof(unsigned long)) {
|
||||||
prefetch(plong + 1);
|
prefetch(plong + 1);
|
||||||
if (((*plong) & LBITMASK) != lskipval)
|
if (((*plong) & LBITMASK) != lskipval)
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -130,10 +130,11 @@ static int xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p,
|
||||||
struct mnt_fhstatus *res)
|
struct mnt_fhstatus *res)
|
||||||
{
|
{
|
||||||
struct nfs_fh *fh = res->fh;
|
struct nfs_fh *fh = res->fh;
|
||||||
|
unsigned size;
|
||||||
|
|
||||||
if ((res->status = ntohl(*p++)) == 0) {
|
if ((res->status = ntohl(*p++)) == 0) {
|
||||||
int size = ntohl(*p++);
|
size = ntohl(*p++);
|
||||||
if (size <= NFS3_FHSIZE) {
|
if (size <= NFS3_FHSIZE && size != 0) {
|
||||||
fh->size = size;
|
fh->size = size;
|
||||||
memcpy(fh->data, p, size);
|
memcpy(fh->data, p, size);
|
||||||
} else
|
} else
|
||||||
|
|
|
@ -1216,8 +1216,6 @@ static int nfs_validate_mount_data(void *options,
|
||||||
{
|
{
|
||||||
struct nfs_mount_data *data = (struct nfs_mount_data *)options;
|
struct nfs_mount_data *data = (struct nfs_mount_data *)options;
|
||||||
|
|
||||||
memset(args, 0, sizeof(*args));
|
|
||||||
|
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
goto out_no_data;
|
goto out_no_data;
|
||||||
|
|
||||||
|
@ -1251,13 +1249,13 @@ static int nfs_validate_mount_data(void *options,
|
||||||
case 5:
|
case 5:
|
||||||
memset(data->context, 0, sizeof(data->context));
|
memset(data->context, 0, sizeof(data->context));
|
||||||
case 6:
|
case 6:
|
||||||
if (data->flags & NFS_MOUNT_VER3)
|
if (data->flags & NFS_MOUNT_VER3) {
|
||||||
|
if (data->root.size > NFS3_FHSIZE || data->root.size == 0)
|
||||||
|
goto out_invalid_fh;
|
||||||
mntfh->size = data->root.size;
|
mntfh->size = data->root.size;
|
||||||
else
|
} else
|
||||||
mntfh->size = NFS2_FHSIZE;
|
mntfh->size = NFS2_FHSIZE;
|
||||||
|
|
||||||
if (mntfh->size > sizeof(mntfh->data))
|
|
||||||
goto out_invalid_fh;
|
|
||||||
|
|
||||||
memcpy(mntfh->data, data->root.data, mntfh->size);
|
memcpy(mntfh->data, data->root.data, mntfh->size);
|
||||||
if (mntfh->size < sizeof(mntfh->data))
|
if (mntfh->size < sizeof(mntfh->data))
|
||||||
|
@ -1585,24 +1583,29 @@ static int nfs_get_sb(struct file_system_type *fs_type,
|
||||||
{
|
{
|
||||||
struct nfs_server *server = NULL;
|
struct nfs_server *server = NULL;
|
||||||
struct super_block *s;
|
struct super_block *s;
|
||||||
struct nfs_fh mntfh;
|
struct nfs_parsed_mount_data *data;
|
||||||
struct nfs_parsed_mount_data data;
|
struct nfs_fh *mntfh;
|
||||||
struct dentry *mntroot;
|
struct dentry *mntroot;
|
||||||
int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
|
int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
|
||||||
struct nfs_sb_mountdata sb_mntdata = {
|
struct nfs_sb_mountdata sb_mntdata = {
|
||||||
.mntflags = flags,
|
.mntflags = flags,
|
||||||
};
|
};
|
||||||
int error;
|
int error = -ENOMEM;
|
||||||
|
|
||||||
security_init_mnt_opts(&data.lsm_opts);
|
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||||
|
mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL);
|
||||||
|
if (data == NULL || mntfh == NULL)
|
||||||
|
goto out_free_fh;
|
||||||
|
|
||||||
|
security_init_mnt_opts(&data->lsm_opts);
|
||||||
|
|
||||||
/* Validate the mount data */
|
/* Validate the mount data */
|
||||||
error = nfs_validate_mount_data(raw_data, &data, &mntfh, dev_name);
|
error = nfs_validate_mount_data(raw_data, data, mntfh, dev_name);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Get a volume representation */
|
/* Get a volume representation */
|
||||||
server = nfs_create_server(&data, &mntfh);
|
server = nfs_create_server(data, mntfh);
|
||||||
if (IS_ERR(server)) {
|
if (IS_ERR(server)) {
|
||||||
error = PTR_ERR(server);
|
error = PTR_ERR(server);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1630,16 +1633,16 @@ static int nfs_get_sb(struct file_system_type *fs_type,
|
||||||
|
|
||||||
if (!s->s_root) {
|
if (!s->s_root) {
|
||||||
/* initial superblock/root creation */
|
/* initial superblock/root creation */
|
||||||
nfs_fill_super(s, &data);
|
nfs_fill_super(s, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
mntroot = nfs_get_root(s, &mntfh);
|
mntroot = nfs_get_root(s, mntfh);
|
||||||
if (IS_ERR(mntroot)) {
|
if (IS_ERR(mntroot)) {
|
||||||
error = PTR_ERR(mntroot);
|
error = PTR_ERR(mntroot);
|
||||||
goto error_splat_super;
|
goto error_splat_super;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = security_sb_set_mnt_opts(s, &data.lsm_opts);
|
error = security_sb_set_mnt_opts(s, &data->lsm_opts);
|
||||||
if (error)
|
if (error)
|
||||||
goto error_splat_root;
|
goto error_splat_root;
|
||||||
|
|
||||||
|
@ -1649,9 +1652,12 @@ static int nfs_get_sb(struct file_system_type *fs_type,
|
||||||
error = 0;
|
error = 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
kfree(data.nfs_server.hostname);
|
kfree(data->nfs_server.hostname);
|
||||||
kfree(data.mount_server.hostname);
|
kfree(data->mount_server.hostname);
|
||||||
security_free_mnt_opts(&data.lsm_opts);
|
security_free_mnt_opts(&data->lsm_opts);
|
||||||
|
out_free_fh:
|
||||||
|
kfree(mntfh);
|
||||||
|
kfree(data);
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
out_err_nosb:
|
out_err_nosb:
|
||||||
|
@ -1800,8 +1806,6 @@ static int nfs4_validate_mount_data(void *options,
|
||||||
struct nfs4_mount_data *data = (struct nfs4_mount_data *)options;
|
struct nfs4_mount_data *data = (struct nfs4_mount_data *)options;
|
||||||
char *c;
|
char *c;
|
||||||
|
|
||||||
memset(args, 0, sizeof(*args));
|
|
||||||
|
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
goto out_no_data;
|
goto out_no_data;
|
||||||
|
|
||||||
|
@ -1959,26 +1963,31 @@ static int nfs4_validate_mount_data(void *options,
|
||||||
static int nfs4_get_sb(struct file_system_type *fs_type,
|
static int nfs4_get_sb(struct file_system_type *fs_type,
|
||||||
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
|
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
|
||||||
{
|
{
|
||||||
struct nfs_parsed_mount_data data;
|
struct nfs_parsed_mount_data *data;
|
||||||
struct super_block *s;
|
struct super_block *s;
|
||||||
struct nfs_server *server;
|
struct nfs_server *server;
|
||||||
struct nfs_fh mntfh;
|
struct nfs_fh *mntfh;
|
||||||
struct dentry *mntroot;
|
struct dentry *mntroot;
|
||||||
int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
|
int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
|
||||||
struct nfs_sb_mountdata sb_mntdata = {
|
struct nfs_sb_mountdata sb_mntdata = {
|
||||||
.mntflags = flags,
|
.mntflags = flags,
|
||||||
};
|
};
|
||||||
int error;
|
int error = -ENOMEM;
|
||||||
|
|
||||||
security_init_mnt_opts(&data.lsm_opts);
|
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||||
|
mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL);
|
||||||
|
if (data == NULL || mntfh == NULL)
|
||||||
|
goto out_free_fh;
|
||||||
|
|
||||||
|
security_init_mnt_opts(&data->lsm_opts);
|
||||||
|
|
||||||
/* Validate the mount data */
|
/* Validate the mount data */
|
||||||
error = nfs4_validate_mount_data(raw_data, &data, dev_name);
|
error = nfs4_validate_mount_data(raw_data, data, dev_name);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Get a volume representation */
|
/* Get a volume representation */
|
||||||
server = nfs4_create_server(&data, &mntfh);
|
server = nfs4_create_server(data, mntfh);
|
||||||
if (IS_ERR(server)) {
|
if (IS_ERR(server)) {
|
||||||
error = PTR_ERR(server);
|
error = PTR_ERR(server);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -2009,13 +2018,13 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
|
||||||
nfs4_fill_super(s);
|
nfs4_fill_super(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
mntroot = nfs4_get_root(s, &mntfh);
|
mntroot = nfs4_get_root(s, mntfh);
|
||||||
if (IS_ERR(mntroot)) {
|
if (IS_ERR(mntroot)) {
|
||||||
error = PTR_ERR(mntroot);
|
error = PTR_ERR(mntroot);
|
||||||
goto error_splat_super;
|
goto error_splat_super;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = security_sb_set_mnt_opts(s, &data.lsm_opts);
|
error = security_sb_set_mnt_opts(s, &data->lsm_opts);
|
||||||
if (error)
|
if (error)
|
||||||
goto error_splat_root;
|
goto error_splat_root;
|
||||||
|
|
||||||
|
@ -2025,10 +2034,13 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
|
||||||
error = 0;
|
error = 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
kfree(data.client_address);
|
kfree(data->client_address);
|
||||||
kfree(data.nfs_server.export_path);
|
kfree(data->nfs_server.export_path);
|
||||||
kfree(data.nfs_server.hostname);
|
kfree(data->nfs_server.hostname);
|
||||||
security_free_mnt_opts(&data.lsm_opts);
|
security_free_mnt_opts(&data->lsm_opts);
|
||||||
|
out_free_fh:
|
||||||
|
kfree(mntfh);
|
||||||
|
kfree(data);
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
out_free:
|
out_free:
|
||||||
|
|
|
@ -739,12 +739,13 @@ int nfs_updatepage(struct file *file, struct page *page,
|
||||||
}
|
}
|
||||||
|
|
||||||
status = nfs_writepage_setup(ctx, page, offset, count);
|
status = nfs_writepage_setup(ctx, page, offset, count);
|
||||||
__set_page_dirty_nobuffers(page);
|
if (status < 0)
|
||||||
|
nfs_set_pageerror(page);
|
||||||
|
else
|
||||||
|
__set_page_dirty_nobuffers(page);
|
||||||
|
|
||||||
dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n",
|
dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n",
|
||||||
status, (long long)i_size_read(inode));
|
status, (long long)i_size_read(inode));
|
||||||
if (status < 0)
|
|
||||||
nfs_set_pageerror(page);
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -249,7 +249,6 @@ int do_select(int n, fd_set_bits *fds, s64 *timeout)
|
||||||
retval++;
|
retval++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cond_resched();
|
|
||||||
}
|
}
|
||||||
if (res_in)
|
if (res_in)
|
||||||
*rinp = res_in;
|
*rinp = res_in;
|
||||||
|
@ -257,6 +256,7 @@ int do_select(int n, fd_set_bits *fds, s64 *timeout)
|
||||||
*routp = res_out;
|
*routp = res_out;
|
||||||
if (res_ex)
|
if (res_ex)
|
||||||
*rexp = res_ex;
|
*rexp = res_ex;
|
||||||
|
cond_resched();
|
||||||
}
|
}
|
||||||
wait = NULL;
|
wait = NULL;
|
||||||
if (retval || !*timeout || signal_pending(current))
|
if (retval || !*timeout || signal_pending(current))
|
||||||
|
|
|
@ -69,6 +69,8 @@ extern unsigned long __per_cpu_offset[NR_CPUS];
|
||||||
#define __get_cpu_var(var) per_cpu_var(var)
|
#define __get_cpu_var(var) per_cpu_var(var)
|
||||||
#define __raw_get_cpu_var(var) per_cpu_var(var)
|
#define __raw_get_cpu_var(var) per_cpu_var(var)
|
||||||
|
|
||||||
|
#define PER_CPU_ATTRIBUTES
|
||||||
|
|
||||||
#endif /* SMP */
|
#endif /* SMP */
|
||||||
|
|
||||||
#define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu_var(name)
|
#define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu_var(name)
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <linux/kvm_para.h>
|
#include <linux/kvm_para.h>
|
||||||
#include <linux/kvm_types.h>
|
#include <linux/kvm_types.h>
|
||||||
|
|
||||||
|
#include <asm/pvclock-abi.h>
|
||||||
#include <asm/desc.h>
|
#include <asm/desc.h>
|
||||||
|
|
||||||
#define KVM_MAX_VCPUS 16
|
#define KVM_MAX_VCPUS 16
|
||||||
|
@ -282,7 +283,8 @@ struct kvm_vcpu_arch {
|
||||||
struct x86_emulate_ctxt emulate_ctxt;
|
struct x86_emulate_ctxt emulate_ctxt;
|
||||||
|
|
||||||
gpa_t time;
|
gpa_t time;
|
||||||
struct kvm_vcpu_time_info hv_clock;
|
struct pvclock_vcpu_time_info hv_clock;
|
||||||
|
unsigned int hv_clock_tsc_khz;
|
||||||
unsigned int time_offset;
|
unsigned int time_offset;
|
||||||
struct page *time_page;
|
struct page *time_page;
|
||||||
};
|
};
|
||||||
|
|
|
@ -48,24 +48,6 @@ struct kvm_mmu_op_release_pt {
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
|
|
||||||
/* xen binary-compatible interface. See xen headers for details */
|
|
||||||
struct kvm_vcpu_time_info {
|
|
||||||
uint32_t version;
|
|
||||||
uint32_t pad0;
|
|
||||||
uint64_t tsc_timestamp;
|
|
||||||
uint64_t system_time;
|
|
||||||
uint32_t tsc_to_system_mul;
|
|
||||||
int8_t tsc_shift;
|
|
||||||
int8_t pad[3];
|
|
||||||
} __attribute__((__packed__)); /* 32 bytes */
|
|
||||||
|
|
||||||
struct kvm_wall_clock {
|
|
||||||
uint32_t wc_version;
|
|
||||||
uint32_t wc_sec;
|
|
||||||
uint32_t wc_nsec;
|
|
||||||
} __attribute__((__packed__));
|
|
||||||
|
|
||||||
|
|
||||||
extern void kvmclock_init(void);
|
extern void kvmclock_init(void);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef _ASM_X86_PVCLOCK_ABI_H_
|
||||||
|
#define _ASM_X86_PVCLOCK_ABI_H_
|
||||||
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These structs MUST NOT be changed.
|
||||||
|
* They are the ABI between hypervisor and guest OS.
|
||||||
|
* Both Xen and KVM are using this.
|
||||||
|
*
|
||||||
|
* pvclock_vcpu_time_info holds the system time and the tsc timestamp
|
||||||
|
* of the last update. So the guest can use the tsc delta to get a
|
||||||
|
* more precise system time. There is one per virtual cpu.
|
||||||
|
*
|
||||||
|
* pvclock_wall_clock references the point in time when the system
|
||||||
|
* time was zero (usually boot time), thus the guest calculates the
|
||||||
|
* current wall clock by adding the system time.
|
||||||
|
*
|
||||||
|
* Protocol for the "version" fields is: hypervisor raises it (making
|
||||||
|
* it uneven) before it starts updating the fields and raises it again
|
||||||
|
* (making it even) when it is done. Thus the guest can make sure the
|
||||||
|
* time values it got are consistent by checking the version before
|
||||||
|
* and after reading them.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct pvclock_vcpu_time_info {
|
||||||
|
u32 version;
|
||||||
|
u32 pad0;
|
||||||
|
u64 tsc_timestamp;
|
||||||
|
u64 system_time;
|
||||||
|
u32 tsc_to_system_mul;
|
||||||
|
s8 tsc_shift;
|
||||||
|
u8 pad[3];
|
||||||
|
} __attribute__((__packed__)); /* 32 bytes */
|
||||||
|
|
||||||
|
struct pvclock_wall_clock {
|
||||||
|
u32 version;
|
||||||
|
u32 sec;
|
||||||
|
u32 nsec;
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
#endif /* __ASSEMBLY__ */
|
||||||
|
#endif /* _ASM_X86_PVCLOCK_ABI_H_ */
|
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef _ASM_X86_PVCLOCK_H_
|
||||||
|
#define _ASM_X86_PVCLOCK_H_
|
||||||
|
|
||||||
|
#include <linux/clocksource.h>
|
||||||
|
#include <asm/pvclock-abi.h>
|
||||||
|
|
||||||
|
/* some helper functions for xen and kvm pv clock sources */
|
||||||
|
cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src);
|
||||||
|
void pvclock_read_wallclock(struct pvclock_wall_clock *wall,
|
||||||
|
struct pvclock_vcpu_time_info *vcpu,
|
||||||
|
struct timespec *ts);
|
||||||
|
|
||||||
|
#endif /* _ASM_X86_PVCLOCK_H_ */
|
|
@ -150,13 +150,9 @@ static inline pte_t __pte_ma(pteval_t x)
|
||||||
return (pte_t) { .pte = x };
|
return (pte_t) { .pte = x };
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_PAE
|
|
||||||
#define pmd_val_ma(v) ((v).pmd)
|
#define pmd_val_ma(v) ((v).pmd)
|
||||||
#define pud_val_ma(v) ((v).pgd.pgd)
|
#define pud_val_ma(v) ((v).pgd.pgd)
|
||||||
#define __pmd_ma(x) ((pmd_t) { (x) } )
|
#define __pmd_ma(x) ((pmd_t) { (x) } )
|
||||||
#else /* !X86_PAE */
|
|
||||||
#define pmd_val_ma(v) ((v).pud.pgd.pgd)
|
|
||||||
#endif /* CONFIG_X86_PAE */
|
|
||||||
|
|
||||||
#define pgd_val_ma(x) ((x).pgd)
|
#define pgd_val_ma(x) ((x).pgd)
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#define KVM_REQ_REPORT_TPR_ACCESS 2
|
#define KVM_REQ_REPORT_TPR_ACCESS 2
|
||||||
#define KVM_REQ_MMU_RELOAD 3
|
#define KVM_REQ_MMU_RELOAD 3
|
||||||
#define KVM_REQ_TRIPLE_FAULT 4
|
#define KVM_REQ_TRIPLE_FAULT 4
|
||||||
|
#define KVM_REQ_PENDING_TIMER 5
|
||||||
|
|
||||||
struct kvm_vcpu;
|
struct kvm_vcpu;
|
||||||
extern struct kmem_cache *kvm_vcpu_cache;
|
extern struct kmem_cache *kvm_vcpu_cache;
|
||||||
|
|
|
@ -27,8 +27,7 @@
|
||||||
* This routine is called by the kernel to write a series of
|
* This routine is called by the kernel to write a series of
|
||||||
* characters to the tty device. The characters may come from
|
* characters to the tty device. The characters may come from
|
||||||
* user space or kernel space. This routine will return the
|
* user space or kernel space. This routine will return the
|
||||||
* number of characters actually accepted for writing. This
|
* number of characters actually accepted for writing.
|
||||||
* routine is mandatory.
|
|
||||||
*
|
*
|
||||||
* Optional: Required for writable devices.
|
* Optional: Required for writable devices.
|
||||||
*
|
*
|
||||||
|
@ -134,7 +133,7 @@
|
||||||
* This routine notifies the tty driver that it should hangup the
|
* This routine notifies the tty driver that it should hangup the
|
||||||
* tty device.
|
* tty device.
|
||||||
*
|
*
|
||||||
* Required:
|
* Optional:
|
||||||
*
|
*
|
||||||
* void (*break_ctl)(struct tty_stuct *tty, int state);
|
* void (*break_ctl)(struct tty_stuct *tty, int state);
|
||||||
*
|
*
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#define __XEN_PUBLIC_XEN_H__
|
#define __XEN_PUBLIC_XEN_H__
|
||||||
|
|
||||||
#include <asm/xen/interface.h>
|
#include <asm/xen/interface.h>
|
||||||
|
#include <asm/pvclock-abi.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XEN "SYSTEM CALLS" (a.k.a. HYPERCALLS).
|
* XEN "SYSTEM CALLS" (a.k.a. HYPERCALLS).
|
||||||
|
@ -336,7 +337,7 @@ struct vcpu_info {
|
||||||
uint8_t evtchn_upcall_mask;
|
uint8_t evtchn_upcall_mask;
|
||||||
unsigned long evtchn_pending_sel;
|
unsigned long evtchn_pending_sel;
|
||||||
struct arch_vcpu_info arch;
|
struct arch_vcpu_info arch;
|
||||||
struct vcpu_time_info time;
|
struct pvclock_vcpu_time_info time;
|
||||||
}; /* 64 bytes (x86) */
|
}; /* 64 bytes (x86) */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -384,9 +385,7 @@ struct shared_info {
|
||||||
* Wallclock time: updated only by control software. Guests should base
|
* Wallclock time: updated only by control software. Guests should base
|
||||||
* their gettimeofday() syscall on this wallclock-base value.
|
* their gettimeofday() syscall on this wallclock-base value.
|
||||||
*/
|
*/
|
||||||
uint32_t wc_version; /* Version counter: see vcpu_time_info_t. */
|
struct pvclock_wall_clock wc;
|
||||||
uint32_t wc_sec; /* Secs 00:00:00 UTC, Jan 1, 1970. */
|
|
||||||
uint32_t wc_nsec; /* Nsecs 00:00:00 UTC, Jan 1, 1970. */
|
|
||||||
|
|
||||||
struct arch_shared_info arch;
|
struct arch_shared_info arch;
|
||||||
|
|
||||||
|
|
|
@ -1096,21 +1096,64 @@ static void unqueue_me_pi(struct futex_q *q)
|
||||||
* private futexes.
|
* private futexes.
|
||||||
*/
|
*/
|
||||||
static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
|
static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
|
||||||
struct task_struct *newowner)
|
struct task_struct *newowner,
|
||||||
|
struct rw_semaphore *fshared)
|
||||||
{
|
{
|
||||||
u32 newtid = task_pid_vnr(newowner) | FUTEX_WAITERS;
|
u32 newtid = task_pid_vnr(newowner) | FUTEX_WAITERS;
|
||||||
struct futex_pi_state *pi_state = q->pi_state;
|
struct futex_pi_state *pi_state = q->pi_state;
|
||||||
|
struct task_struct *oldowner = pi_state->owner;
|
||||||
u32 uval, curval, newval;
|
u32 uval, curval, newval;
|
||||||
int ret;
|
int ret, attempt = 0;
|
||||||
|
|
||||||
/* Owner died? */
|
/* Owner died? */
|
||||||
|
if (!pi_state->owner)
|
||||||
|
newtid |= FUTEX_OWNER_DIED;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are here either because we stole the rtmutex from the
|
||||||
|
* pending owner or we are the pending owner which failed to
|
||||||
|
* get the rtmutex. We have to replace the pending owner TID
|
||||||
|
* in the user space variable. This must be atomic as we have
|
||||||
|
* to preserve the owner died bit here.
|
||||||
|
*
|
||||||
|
* Note: We write the user space value _before_ changing the
|
||||||
|
* pi_state because we can fault here. Imagine swapped out
|
||||||
|
* pages or a fork, which was running right before we acquired
|
||||||
|
* mmap_sem, that marked all the anonymous memory readonly for
|
||||||
|
* cow.
|
||||||
|
*
|
||||||
|
* Modifying pi_state _before_ the user space value would
|
||||||
|
* leave the pi_state in an inconsistent state when we fault
|
||||||
|
* here, because we need to drop the hash bucket lock to
|
||||||
|
* handle the fault. This might be observed in the PID check
|
||||||
|
* in lookup_pi_state.
|
||||||
|
*/
|
||||||
|
retry:
|
||||||
|
if (get_futex_value_locked(&uval, uaddr))
|
||||||
|
goto handle_fault;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
newval = (uval & FUTEX_OWNER_DIED) | newtid;
|
||||||
|
|
||||||
|
curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
|
||||||
|
|
||||||
|
if (curval == -EFAULT)
|
||||||
|
goto handle_fault;
|
||||||
|
if (curval == uval)
|
||||||
|
break;
|
||||||
|
uval = curval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We fixed up user space. Now we need to fix the pi_state
|
||||||
|
* itself.
|
||||||
|
*/
|
||||||
if (pi_state->owner != NULL) {
|
if (pi_state->owner != NULL) {
|
||||||
spin_lock_irq(&pi_state->owner->pi_lock);
|
spin_lock_irq(&pi_state->owner->pi_lock);
|
||||||
WARN_ON(list_empty(&pi_state->list));
|
WARN_ON(list_empty(&pi_state->list));
|
||||||
list_del_init(&pi_state->list);
|
list_del_init(&pi_state->list);
|
||||||
spin_unlock_irq(&pi_state->owner->pi_lock);
|
spin_unlock_irq(&pi_state->owner->pi_lock);
|
||||||
} else
|
}
|
||||||
newtid |= FUTEX_OWNER_DIED;
|
|
||||||
|
|
||||||
pi_state->owner = newowner;
|
pi_state->owner = newowner;
|
||||||
|
|
||||||
|
@ -1118,26 +1161,35 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
|
||||||
WARN_ON(!list_empty(&pi_state->list));
|
WARN_ON(!list_empty(&pi_state->list));
|
||||||
list_add(&pi_state->list, &newowner->pi_state_list);
|
list_add(&pi_state->list, &newowner->pi_state_list);
|
||||||
spin_unlock_irq(&newowner->pi_lock);
|
spin_unlock_irq(&newowner->pi_lock);
|
||||||
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We own it, so we have to replace the pending owner
|
* To handle the page fault we need to drop the hash bucket
|
||||||
* TID. This must be atomic as we have preserve the
|
* lock here. That gives the other task (either the pending
|
||||||
* owner died bit here.
|
* owner itself or the task which stole the rtmutex) the
|
||||||
|
* chance to try the fixup of the pi_state. So once we are
|
||||||
|
* back from handling the fault we need to check the pi_state
|
||||||
|
* after reacquiring the hash bucket lock and before trying to
|
||||||
|
* do another fixup. When the fixup has been done already we
|
||||||
|
* simply return.
|
||||||
*/
|
*/
|
||||||
ret = get_futex_value_locked(&uval, uaddr);
|
handle_fault:
|
||||||
|
spin_unlock(q->lock_ptr);
|
||||||
|
|
||||||
while (!ret) {
|
ret = futex_handle_fault((unsigned long)uaddr, fshared, attempt++);
|
||||||
newval = (uval & FUTEX_OWNER_DIED) | newtid;
|
|
||||||
|
|
||||||
curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
|
spin_lock(q->lock_ptr);
|
||||||
|
|
||||||
if (curval == -EFAULT)
|
/*
|
||||||
ret = -EFAULT;
|
* Check if someone else fixed it for us:
|
||||||
if (curval == uval)
|
*/
|
||||||
break;
|
if (pi_state->owner != oldowner)
|
||||||
uval = curval;
|
return 0;
|
||||||
}
|
|
||||||
return ret;
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1507,7 +1559,7 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
|
||||||
* that case:
|
* that case:
|
||||||
*/
|
*/
|
||||||
if (q.pi_state->owner != curr)
|
if (q.pi_state->owner != curr)
|
||||||
ret = fixup_pi_state_owner(uaddr, &q, curr);
|
ret = fixup_pi_state_owner(uaddr, &q, curr, fshared);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Catch the rare case, where the lock was released
|
* Catch the rare case, where the lock was released
|
||||||
|
@ -1539,7 +1591,8 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
owner = rt_mutex_owner(&q.pi_state->pi_mutex);
|
owner = rt_mutex_owner(&q.pi_state->pi_mutex);
|
||||||
res = fixup_pi_state_owner(uaddr, &q, owner);
|
res = fixup_pi_state_owner(uaddr, &q, owner,
|
||||||
|
fshared);
|
||||||
|
|
||||||
/* propagate -EFAULT, if the fixup failed */
|
/* propagate -EFAULT, if the fixup failed */
|
||||||
if (res)
|
if (res)
|
||||||
|
|
|
@ -1499,7 +1499,8 @@ int kgdb_nmicallback(int cpu, void *regs)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void kgdb_console_write(struct console *co, const char *s, unsigned count)
|
static void kgdb_console_write(struct console *co, const char *s,
|
||||||
|
unsigned count)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
|
|
@ -4398,22 +4398,20 @@ do_wait_for_common(struct completion *x, long timeout, int state)
|
||||||
signal_pending(current)) ||
|
signal_pending(current)) ||
|
||||||
(state == TASK_KILLABLE &&
|
(state == TASK_KILLABLE &&
|
||||||
fatal_signal_pending(current))) {
|
fatal_signal_pending(current))) {
|
||||||
__remove_wait_queue(&x->wait, &wait);
|
timeout = -ERESTARTSYS;
|
||||||
return -ERESTARTSYS;
|
break;
|
||||||
}
|
}
|
||||||
__set_current_state(state);
|
__set_current_state(state);
|
||||||
spin_unlock_irq(&x->wait.lock);
|
spin_unlock_irq(&x->wait.lock);
|
||||||
timeout = schedule_timeout(timeout);
|
timeout = schedule_timeout(timeout);
|
||||||
spin_lock_irq(&x->wait.lock);
|
spin_lock_irq(&x->wait.lock);
|
||||||
if (!timeout) {
|
} while (!x->done && timeout);
|
||||||
__remove_wait_queue(&x->wait, &wait);
|
|
||||||
return timeout;
|
|
||||||
}
|
|
||||||
} while (!x->done);
|
|
||||||
__remove_wait_queue(&x->wait, &wait);
|
__remove_wait_queue(&x->wait, &wait);
|
||||||
|
if (!x->done)
|
||||||
|
return timeout;
|
||||||
}
|
}
|
||||||
x->done--;
|
x->done--;
|
||||||
return timeout;
|
return timeout ?: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long __sched
|
static long __sched
|
||||||
|
|
|
@ -250,7 +250,8 @@ static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun)
|
||||||
if (rt_rq->rt_time || rt_rq->rt_nr_running)
|
if (rt_rq->rt_time || rt_rq->rt_nr_running)
|
||||||
idle = 0;
|
idle = 0;
|
||||||
spin_unlock(&rt_rq->rt_runtime_lock);
|
spin_unlock(&rt_rq->rt_runtime_lock);
|
||||||
}
|
} else if (rt_rq->rt_nr_running)
|
||||||
|
idle = 0;
|
||||||
|
|
||||||
if (enqueue)
|
if (enqueue)
|
||||||
sched_rt_rq_enqueue(rt_rq);
|
sched_rt_rq_enqueue(rt_rq);
|
||||||
|
|
50
mm/memory.c
50
mm/memory.c
|
@ -1045,6 +1045,26 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address,
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Can we do the FOLL_ANON optimization? */
|
||||||
|
static inline int use_zero_page(struct vm_area_struct *vma)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We don't want to optimize FOLL_ANON for make_pages_present()
|
||||||
|
* when it tries to page in a VM_LOCKED region. As to VM_SHARED,
|
||||||
|
* we want to get the page from the page tables to make sure
|
||||||
|
* that we serialize and update with any other user of that
|
||||||
|
* mapping.
|
||||||
|
*/
|
||||||
|
if (vma->vm_flags & (VM_LOCKED | VM_SHARED))
|
||||||
|
return 0;
|
||||||
|
/*
|
||||||
|
* And if we have a fault or a nopfn routine, it's not an
|
||||||
|
* anonymous region.
|
||||||
|
*/
|
||||||
|
return !vma->vm_ops ||
|
||||||
|
(!vma->vm_ops->fault && !vma->vm_ops->nopfn);
|
||||||
|
}
|
||||||
|
|
||||||
int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
|
int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
|
||||||
unsigned long start, int len, int write, int force,
|
unsigned long start, int len, int write, int force,
|
||||||
struct page **pages, struct vm_area_struct **vmas)
|
struct page **pages, struct vm_area_struct **vmas)
|
||||||
|
@ -1119,8 +1139,7 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
|
||||||
foll_flags = FOLL_TOUCH;
|
foll_flags = FOLL_TOUCH;
|
||||||
if (pages)
|
if (pages)
|
||||||
foll_flags |= FOLL_GET;
|
foll_flags |= FOLL_GET;
|
||||||
if (!write && !(vma->vm_flags & VM_LOCKED) &&
|
if (!write && use_zero_page(vma))
|
||||||
(!vma->vm_ops || !vma->vm_ops->fault))
|
|
||||||
foll_flags |= FOLL_ANON;
|
foll_flags |= FOLL_ANON;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -1766,7 +1785,6 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
|
||||||
page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
|
page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
|
||||||
if (likely(pte_same(*page_table, orig_pte))) {
|
if (likely(pte_same(*page_table, orig_pte))) {
|
||||||
if (old_page) {
|
if (old_page) {
|
||||||
page_remove_rmap(old_page, vma);
|
|
||||||
if (!PageAnon(old_page)) {
|
if (!PageAnon(old_page)) {
|
||||||
dec_mm_counter(mm, file_rss);
|
dec_mm_counter(mm, file_rss);
|
||||||
inc_mm_counter(mm, anon_rss);
|
inc_mm_counter(mm, anon_rss);
|
||||||
|
@ -1788,6 +1806,32 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
|
||||||
lru_cache_add_active(new_page);
|
lru_cache_add_active(new_page);
|
||||||
page_add_new_anon_rmap(new_page, vma, address);
|
page_add_new_anon_rmap(new_page, vma, address);
|
||||||
|
|
||||||
|
if (old_page) {
|
||||||
|
/*
|
||||||
|
* Only after switching the pte to the new page may
|
||||||
|
* we remove the mapcount here. Otherwise another
|
||||||
|
* process may come and find the rmap count decremented
|
||||||
|
* before the pte is switched to the new page, and
|
||||||
|
* "reuse" the old page writing into it while our pte
|
||||||
|
* here still points into it and can be read by other
|
||||||
|
* threads.
|
||||||
|
*
|
||||||
|
* The critical issue is to order this
|
||||||
|
* page_remove_rmap with the ptp_clear_flush above.
|
||||||
|
* Those stores are ordered by (if nothing else,)
|
||||||
|
* the barrier present in the atomic_add_negative
|
||||||
|
* in page_remove_rmap.
|
||||||
|
*
|
||||||
|
* Then the TLB flush in ptep_clear_flush ensures that
|
||||||
|
* no process can access the old page before the
|
||||||
|
* decremented mapcount is visible. And the old page
|
||||||
|
* cannot be reused until after the decremented
|
||||||
|
* mapcount is visible. So transitively, TLBs to
|
||||||
|
* old page will be flushed before it can be reused.
|
||||||
|
*/
|
||||||
|
page_remove_rmap(old_page, vma);
|
||||||
|
}
|
||||||
|
|
||||||
/* Free the old page.. */
|
/* Free the old page.. */
|
||||||
new_page = old_page;
|
new_page = old_page;
|
||||||
ret |= VM_FAULT_WRITE;
|
ret |= VM_FAULT_WRITE;
|
||||||
|
|
|
@ -925,7 +925,7 @@ static unsigned char als4000_saved_regs[] = {
|
||||||
static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
|
static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
|
||||||
{
|
{
|
||||||
unsigned char *val = chip->saved_regs;
|
unsigned char *val = chip->saved_regs;
|
||||||
snd_assert(num_regs > ARRAY_SIZE(chip->saved_regs), return);
|
snd_assert(num_regs <= ARRAY_SIZE(chip->saved_regs), return);
|
||||||
for (; num_regs; num_regs--)
|
for (; num_regs; num_regs--)
|
||||||
*val++ = snd_sbmixer_read(chip, *regs++);
|
*val++ = snd_sbmixer_read(chip, *regs++);
|
||||||
}
|
}
|
||||||
|
@ -933,7 +933,7 @@ static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
|
||||||
static void restore_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
|
static void restore_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
|
||||||
{
|
{
|
||||||
unsigned char *val = chip->saved_regs;
|
unsigned char *val = chip->saved_regs;
|
||||||
snd_assert(num_regs > ARRAY_SIZE(chip->saved_regs), return);
|
snd_assert(num_regs <= ARRAY_SIZE(chip->saved_regs), return);
|
||||||
for (; num_regs; num_regs--)
|
for (; num_regs; num_regs--)
|
||||||
snd_sbmixer_write(chip, *regs++, *val++);
|
snd_sbmixer_write(chip, *regs++, *val++);
|
||||||
}
|
}
|
||||||
|
|
|
@ -316,6 +316,8 @@ static int __devinit snd_aw2_create(struct snd_card *card,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (2) initialization of the chip hardware */
|
||||||
|
snd_aw2_saa7146_setup(&chip->saa7146, chip->iobase_virt);
|
||||||
|
|
||||||
if (request_irq(pci->irq, snd_aw2_saa7146_interrupt,
|
if (request_irq(pci->irq, snd_aw2_saa7146_interrupt,
|
||||||
IRQF_SHARED, "Audiowerk2", chip)) {
|
IRQF_SHARED, "Audiowerk2", chip)) {
|
||||||
|
@ -329,8 +331,6 @@ static int __devinit snd_aw2_create(struct snd_card *card,
|
||||||
}
|
}
|
||||||
chip->irq = pci->irq;
|
chip->irq = pci->irq;
|
||||||
|
|
||||||
/* (2) initialization of the chip hardware */
|
|
||||||
snd_aw2_saa7146_setup(&chip->saa7146, chip->iobase_virt);
|
|
||||||
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
|
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
free_irq(chip->irq, (void *)chip);
|
free_irq(chip->irq, (void *)chip);
|
||||||
|
|
|
@ -269,28 +269,9 @@ void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_eoi_gsi(struct kvm_ioapic *ioapic, int vector)
|
static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int gsi)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < IOAPIC_NUM_PINS; i++)
|
|
||||||
if (ioapic->redirtbl[i].fields.vector == vector)
|
|
||||||
return i;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void kvm_ioapic_update_eoi(struct kvm *kvm, int vector)
|
|
||||||
{
|
|
||||||
struct kvm_ioapic *ioapic = kvm->arch.vioapic;
|
|
||||||
union ioapic_redir_entry *ent;
|
union ioapic_redir_entry *ent;
|
||||||
int gsi;
|
|
||||||
|
|
||||||
gsi = get_eoi_gsi(ioapic, vector);
|
|
||||||
if (gsi == -1) {
|
|
||||||
printk(KERN_WARNING "Can't find redir item for %d EOI\n",
|
|
||||||
vector);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ent = &ioapic->redirtbl[gsi];
|
ent = &ioapic->redirtbl[gsi];
|
||||||
ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
|
ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
|
||||||
|
@ -300,6 +281,16 @@ void kvm_ioapic_update_eoi(struct kvm *kvm, int vector)
|
||||||
ioapic_deliver(ioapic, gsi);
|
ioapic_deliver(ioapic, gsi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void kvm_ioapic_update_eoi(struct kvm *kvm, int vector)
|
||||||
|
{
|
||||||
|
struct kvm_ioapic *ioapic = kvm->arch.vioapic;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < IOAPIC_NUM_PINS; i++)
|
||||||
|
if (ioapic->redirtbl[i].fields.vector == vector)
|
||||||
|
__kvm_ioapic_update_eoi(ioapic, i);
|
||||||
|
}
|
||||||
|
|
||||||
static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr)
|
static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr)
|
||||||
{
|
{
|
||||||
struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
|
struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
|
||||||
|
|
Loading…
Reference in New Issue