mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
bitkeeper revision 1.1159.170.59 (41b4c2fdJ2gj_BWy27Vj3ptayZp_yg)
sync w/ head.
This commit is contained in:
commit
3776bbe6f6
42 files changed
+1043
-899
No files matched your search
@@ -253,6 +253,8 @@
|
||||
410a94a4KT6I6X0LVc7djB39tRDp4g linux-2.6.10-rc2-xen-sparse/mm/page_alloc.c
|
||||
41505c572m-s9ATiO1LiD1GPznTTIg linux-2.6.10-rc2-xen-sparse/net/core/skbuff.c
|
||||
4149ec79wMpIHdvbntxqVGLRZZjPxw linux-2.6.10-rc2-xen-sparse/net/ipv4/raw.c
|
||||
41ab6fa06JdF7jxUsuDcjN3UhuIAxg linux-2.6.9-xen-sparse/arch/xen/kernel/devmem.c
|
||||
41af4017PDMuSmMWtSRU5UC9Vylw5g linux-2.6.9-xen-sparse/include/asm-xen/balloon.h
|
||||
413cb1e4zst25MDYjg63Y-NGC5_pLg netbsd-2.0-xen-sparse/Makefile
|
||||
413cb1e5c_Mkxf_X0zimEhTKI_l4DA netbsd-2.0-xen-sparse/mkbuildtree
|
||||
413cb1e5kY_Zil7-b0kI6hvCIxBEYg netbsd-2.0-xen-sparse/nbconfig-xen
|
||||
@@ -378,6 +380,7 @@
|
||||
3f5ef5a2dTZP0nnsFoeq2jRf3mWDDg tools/misc/xen-clone.README
|
||||
405eedf6_nnNhFQ1I85lhCkLK6jFGA tools/misc/xencons
|
||||
40c9c4697z76HDfkCLdMhmaEwzFoNQ tools/misc/xend
|
||||
41adc641dV-0cDLSyzMs5BT8nL7v3Q tools/misc/xenperf.c
|
||||
4107986eMWVdBoz4tXYoOscpN_BCYg tools/misc/xensv
|
||||
4056f5155QYZdsk-1fLdjsZPFTnlhg tools/misc/xensymoops
|
||||
40cf2937dqM1jWW87O5OoOYND8leuA tools/misc/xm
|
||||
|
||||
@@ -58,7 +58,7 @@ tools/balloon/balloon
|
||||
tools/check/.*
|
||||
tools/libxc/xen/*
|
||||
tools/misc/miniterm/miniterm
|
||||
tools/misc/xen_cpuperf
|
||||
tools/misc/xenperf
|
||||
tools/vnet/gc
|
||||
tools/vnet/gc*/*
|
||||
tools/vnet/vnet-module/.tmp_versions/*
|
||||
|
||||
@@ -19,10 +19,30 @@ export INSTALL_DIR
|
||||
include buildconfigs/Rules.mk
|
||||
|
||||
.PHONY: all dist install xen tools kernels docs world clean mkpatches mrproper
|
||||
.PHONY: kbuild kdelete kclean
|
||||
.PHONY: kbuild kdelete kclean install-tools install-xen install-docs
|
||||
.PHONY: install-kernels
|
||||
|
||||
all: dist
|
||||
|
||||
# install everything into the standard system directories
|
||||
# NB: install explicitly does not check that everything is up to date!
|
||||
install: install-tools install-xen install-kernels install-docs
|
||||
|
||||
install-xen:
|
||||
$(MAKE) -C xen install
|
||||
|
||||
install-tools:
|
||||
$(MAKE) -C tools install
|
||||
|
||||
install-kernels:
|
||||
$(shell cp -a $(INSTALL_DIR)/boot/* /boot/)
|
||||
$(shell cp -a $(INSTALL_DIR)/lib/modules/* /lib/modules/)
|
||||
$(shell cp -dR $(INSTALL_DIR)/boot/*$(LINUX_VER)* $(prefix)/boot/)
|
||||
$(shell cp -dR $(INSTALL_DIR)/lib/modules/* $(prefix)/lib/modules/)
|
||||
|
||||
install-docs:
|
||||
sh ./docs/check_pkgs && $(MAKE) -C docs install || true
|
||||
|
||||
# build and install everything into local dist directory
|
||||
dist: xen tools kernels docs
|
||||
install -m0644 ./COPYING $(DIST_DIR)
|
||||
@@ -31,17 +51,6 @@ dist: xen tools kernels docs
|
||||
mkdir -p $(DIST_DIR)/check
|
||||
install -m0755 tools/check/chk tools/check/check_* $(DIST_DIR)/check
|
||||
|
||||
# install everything into the standard system directories
|
||||
# NB: install explicitly does not check that everything is up to date!
|
||||
install:
|
||||
$(MAKE) -C xen install
|
||||
$(MAKE) -C tools install
|
||||
$(shell cp -a $(INSTALL_DIR)/boot/* /boot/)
|
||||
$(shell cp -a $(INSTALL_DIR)/lib/modules/* /lib/modules/)
|
||||
sh ./docs/check_pkgs && $(MAKE) -C docs install || true
|
||||
$(shell cp -dR $(INSTALL_DIR)/boot/*$(LINUX_VER)* $(prefix)/boot/)
|
||||
$(shell cp -dR $(INSTALL_DIR)/lib/modules/* $(prefix)/lib/modules/)
|
||||
|
||||
xen:
|
||||
$(MAKE) prefix=$(INSTALL_DIR) dist=yes -C xen install
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
O_TARGET := drv.o
|
||||
export-objs := balloon.o
|
||||
obj-y := balloon.o
|
||||
include $(TOPDIR)/Rules.make
|
||||
@@ -6,7 +6,7 @@ all: kernel.o head.o init_task.o
|
||||
|
||||
O_TARGET := kernel.o
|
||||
|
||||
export-objs := i386_ksyms.o gnttab.o skbuff.o
|
||||
export-objs := i386_ksyms.o gnttab.o skbuff.o ctrl_if.o
|
||||
|
||||
obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \
|
||||
ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o \
|
||||
|
||||
@@ -275,7 +275,8 @@ void __init setup_arch(char **cmdline_p)
|
||||
* arch/xen/drivers/balloon/balloon.c
|
||||
*/
|
||||
mem_param = parse_mem_cmdline(cmdline_p);
|
||||
if (!mem_param) mem_param = xen_start_info.nr_pages;
|
||||
if (mem_param < xen_start_info.nr_pages)
|
||||
mem_param = xen_start_info.nr_pages;
|
||||
|
||||
#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
|
||||
#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
|
||||
@@ -303,6 +304,7 @@ void __init setup_arch(char **cmdline_p)
|
||||
printk(KERN_WARNING "Use a PAE enabled kernel.\n");
|
||||
else
|
||||
printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
|
||||
max_pfn = lmax_low_pfn;
|
||||
#else /* !CONFIG_HIGHMEM */
|
||||
#ifndef CONFIG_X86_PAE
|
||||
if (max_pfn > MAX_NONPAE_PFN) {
|
||||
@@ -350,8 +352,6 @@ void __init setup_arch(char **cmdline_p)
|
||||
*/
|
||||
max_low_pfn = lmax_low_pfn;
|
||||
|
||||
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
if ( xen_start_info.mod_start != 0 )
|
||||
{
|
||||
@@ -375,6 +375,20 @@ void __init setup_arch(char **cmdline_p)
|
||||
|
||||
paging_init();
|
||||
|
||||
/* Make sure we have a large enough P->M table. */
|
||||
if ( max_pfn > xen_start_info.nr_pages )
|
||||
{
|
||||
phys_to_machine_mapping = alloc_bootmem_low_pages(
|
||||
max_pfn * sizeof(unsigned long));
|
||||
memset(phys_to_machine_mapping, ~0, max_pfn * sizeof(unsigned long));
|
||||
memcpy(phys_to_machine_mapping,
|
||||
(unsigned long *)xen_start_info.mfn_list,
|
||||
xen_start_info.nr_pages * sizeof(unsigned long));
|
||||
free_bootmem(__pa(xen_start_info.mfn_list),
|
||||
PFN_PHYS(PFN_UP(xen_start_info.nr_pages *
|
||||
sizeof(unsigned long))));
|
||||
}
|
||||
|
||||
pfn_to_mfn_frame_list = alloc_bootmem_low_pages(PAGE_SIZE);
|
||||
for ( i=0, j=0; i < max_pfn; i+=(PAGE_SIZE/sizeof(unsigned long)), j++ )
|
||||
{
|
||||
|
||||
@@ -213,23 +213,16 @@ static void __init fixrange_init (unsigned long start,
|
||||
|
||||
static void __init pagetable_init (void)
|
||||
{
|
||||
unsigned long vaddr, end;
|
||||
unsigned long vaddr, end, ram_end;
|
||||
pgd_t *kpgd, *pgd, *pgd_base;
|
||||
int i, j, k;
|
||||
pmd_t *kpmd, *pmd;
|
||||
pte_t *kpte, *pte, *pte_base;
|
||||
|
||||
/* create tables only for boot_pfn frames. max_low_pfn may be sized for
|
||||
* pages yet to be allocated from the hypervisor, or it may be set
|
||||
* to override the xen_start_info amount of memory
|
||||
*/
|
||||
int boot_pfn = min(xen_start_info.nr_pages,max_low_pfn);
|
||||
|
||||
/*
|
||||
* This can be zero as well - no problem, in that case we exit
|
||||
* the loops anyway due to the PTRS_PER_* conditions.
|
||||
*/
|
||||
end = (unsigned long)__va(boot_pfn *PAGE_SIZE);
|
||||
end = (unsigned long)__va(max_low_pfn * PAGE_SIZE);
|
||||
ram_end = (unsigned long)__va(xen_start_info.nr_pages * PAGE_SIZE);
|
||||
if ( ram_end > end )
|
||||
ram_end = end;
|
||||
|
||||
pgd_base = init_mm.pgd;
|
||||
i = __pgd_offset(PAGE_OFFSET);
|
||||
@@ -237,12 +230,12 @@ static void __init pagetable_init (void)
|
||||
|
||||
for (; i < PTRS_PER_PGD; pgd++, i++) {
|
||||
vaddr = i*PGDIR_SIZE;
|
||||
if (end && (vaddr >= end))
|
||||
if (vaddr >= end)
|
||||
break;
|
||||
pmd = (pmd_t *)pgd;
|
||||
for (j = 0; j < PTRS_PER_PMD; pmd++, j++) {
|
||||
vaddr = i*PGDIR_SIZE + j*PMD_SIZE;
|
||||
if (end && (vaddr >= end))
|
||||
if (vaddr >= end)
|
||||
break;
|
||||
|
||||
/* Filled in for us already? */
|
||||
@@ -250,10 +243,11 @@ static void __init pagetable_init (void)
|
||||
continue;
|
||||
|
||||
pte_base = pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
|
||||
clear_page(pte_base);
|
||||
|
||||
for (k = 0; k < PTRS_PER_PTE; pte++, k++) {
|
||||
vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE;
|
||||
if (end && (vaddr >= end))
|
||||
if (vaddr >= ram_end)
|
||||
break;
|
||||
*pte = mk_pte_phys(__pa(vaddr), PAGE_KERNEL);
|
||||
}
|
||||
@@ -329,28 +323,14 @@ static inline int page_is_ram (unsigned long pagenr)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int page_kills_ppro(unsigned long pagenr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HIGHMEM
|
||||
void __init one_highpage_init(struct page *page, int pfn, int bad_ppro)
|
||||
void __init one_highpage_init(struct page *page, int free_page)
|
||||
{
|
||||
if (!page_is_ram(pfn)) {
|
||||
SetPageReserved(page);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bad_ppro && page_kills_ppro(pfn)) {
|
||||
SetPageReserved(page);
|
||||
return;
|
||||
}
|
||||
|
||||
ClearPageReserved(page);
|
||||
set_bit(PG_highmem, &page->flags);
|
||||
atomic_set(&page->count, 1);
|
||||
__free_page(page);
|
||||
if ( free_page )
|
||||
__free_page(page);
|
||||
totalhigh_pages++;
|
||||
}
|
||||
#endif /* CONFIG_HIGHMEM */
|
||||
@@ -392,8 +372,9 @@ static int __init free_pages_init(void)
|
||||
reservedpages++;
|
||||
}
|
||||
#ifdef CONFIG_HIGHMEM
|
||||
for (pfn = xen_start_info.nr_pages-1; pfn >= highstart_pfn; pfn--)
|
||||
one_highpage_init((struct page *) (mem_map + pfn), pfn, bad_ppro);
|
||||
for (pfn = highend_pfn-1; pfn >= highstart_pfn; pfn--)
|
||||
one_highpage_init((struct page *) (mem_map + pfn), pfn,
|
||||
(pfn < xen_start_info.nr_pages));
|
||||
totalram_pages += totalhigh_pages;
|
||||
#endif
|
||||
return reservedpages;
|
||||
|
||||
@@ -204,6 +204,7 @@ ln -sf ../asm-i386/unaligned.h
|
||||
ln -sf ../asm-i386/unistd.h
|
||||
ln -sf ../asm-i386/user.h
|
||||
ln -sf ../asm-i386/vm86.h
|
||||
ln -sf ../../${LINUX_26}/include/asm-xen/balloon.h
|
||||
ln -sf ../../${LINUX_26}/include/asm-xen/ctrl_if.h
|
||||
ln -sf ../../${LINUX_26}/include/asm-xen/evtchn.h
|
||||
ln -sf ../../${LINUX_26}/include/asm-xen/gnttab.h
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Automatically generated make config: don't edit
|
||||
# Linux kernel version: 2.6.10-rc2-xen0
|
||||
# Fri Nov 19 20:16:38 2004
|
||||
# Wed Dec 1 09:22:49 2004
|
||||
#
|
||||
CONFIG_XEN=y
|
||||
CONFIG_ARCH_XEN=y
|
||||
@@ -152,10 +152,10 @@ CONFIG_DEBUG_KERNEL=y
|
||||
CONFIG_EARLY_PRINTK=y
|
||||
# CONFIG_DEBUG_STACKOVERFLOW is not set
|
||||
# CONFIG_DEBUG_STACK_USAGE is not set
|
||||
# CONFIG_DEBUG_SLAB is not set
|
||||
CONFIG_DEBUG_SLAB=y
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
# CONFIG_DEBUG_SPINLOCK is not set
|
||||
# CONFIG_DEBUG_PAGEALLOC is not set
|
||||
CONFIG_DEBUG_PAGEALLOC=y
|
||||
# CONFIG_DEBUG_INFO is not set
|
||||
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
|
||||
# CONFIG_FRAME_POINTER is not set
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Automatically generated make config: don't edit
|
||||
# Linux kernel version: 2.6.10-rc2-xenU
|
||||
# Fri Nov 19 20:16:52 2004
|
||||
# Wed Dec 1 09:22:09 2004
|
||||
#
|
||||
CONFIG_XEN=y
|
||||
CONFIG_ARCH_XEN=y
|
||||
@@ -47,6 +47,7 @@ CONFIG_KOBJECT_UEVENT=y
|
||||
# CONFIG_IKCONFIG is not set
|
||||
# CONFIG_EMBEDDED is not set
|
||||
CONFIG_KALLSYMS=y
|
||||
# CONFIG_KALLSYMS_ALL is not set
|
||||
# CONFIG_KALLSYMS_EXTRA_PASS is not set
|
||||
CONFIG_FUTEX=y
|
||||
CONFIG_EPOLL=y
|
||||
@@ -118,8 +119,15 @@ CONFIG_HAVE_DEC_LOCK=y
|
||||
#
|
||||
# Kernel hacking
|
||||
#
|
||||
# CONFIG_DEBUG_KERNEL is not set
|
||||
CONFIG_DEBUG_KERNEL=y
|
||||
CONFIG_EARLY_PRINTK=y
|
||||
# CONFIG_DEBUG_STACKOVERFLOW is not set
|
||||
# CONFIG_DEBUG_STACK_USAGE is not set
|
||||
CONFIG_DEBUG_SLAB=y
|
||||
# CONFIG_MAGIC_SYSRQ is not set
|
||||
# CONFIG_DEBUG_SPINLOCK is not set
|
||||
CONFIG_DEBUG_PAGEALLOC=y
|
||||
# CONFIG_DEBUG_INFO is not set
|
||||
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
|
||||
# CONFIG_FRAME_POINTER is not set
|
||||
# CONFIG_4KSTACKS is not set
|
||||
@@ -145,6 +153,7 @@ CONFIG_BINFMT_ELF=y
|
||||
CONFIG_STANDALONE=y
|
||||
CONFIG_PREVENT_FIRMWARE_BUILD=y
|
||||
# CONFIG_FW_LOADER is not set
|
||||
# CONFIG_DEBUG_DRIVER is not set
|
||||
|
||||
#
|
||||
# Block devices
|
||||
|
||||
@@ -513,7 +513,7 @@ void __init cpu_gdt_init(struct Xgt_desc_struct *gdt_descr)
|
||||
va < gdt_descr->address + gdt_descr->size;
|
||||
va += PAGE_SIZE, f++) {
|
||||
frames[f] = virt_to_machine(va) >> PAGE_SHIFT;
|
||||
protect_page(swapper_pg_dir, (void *)va, PROT_ON);
|
||||
make_page_readonly((void *)va);
|
||||
}
|
||||
flush_page_update_queue();
|
||||
if (HYPERVISOR_set_gdt(frames, gdt_descr->size / 8))
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <linux/pci.h>
|
||||
#include <linux/version.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm-xen/balloon.h>
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
|
||||
#define pte_offset_kernel pte_offset
|
||||
@@ -37,9 +38,12 @@ xen_contig_memory(unsigned long vstart, unsigned int order)
|
||||
pgd_t *pgd;
|
||||
pmd_t *pmd;
|
||||
pte_t *pte;
|
||||
unsigned long pfn, i;
|
||||
unsigned long pfn, i, flags;
|
||||
|
||||
scrub_pages(vstart, 1 << order);
|
||||
|
||||
balloon_lock(flags);
|
||||
|
||||
/* 1. Zap current PTEs, giving away the underlying pages. */
|
||||
for (i = 0; i < (1<<order); i++) {
|
||||
pgd = pgd_offset_k( (vstart + (i*PAGE_SIZE)));
|
||||
@@ -70,6 +74,8 @@ xen_contig_memory(unsigned long vstart, unsigned int order)
|
||||
}
|
||||
/* Flush updates through and flush the TLB. */
|
||||
xen_tlb_flush();
|
||||
|
||||
balloon_unlock(flags);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
|
||||
|
||||
@@ -52,6 +52,9 @@
|
||||
#include "setup_arch_pre.h"
|
||||
#include <bios_ebda.h>
|
||||
|
||||
/* Allows setting of maximum possible memory size */
|
||||
static unsigned long xen_override_max_pfn;
|
||||
|
||||
int disable_pse __initdata = 0;
|
||||
|
||||
/*
|
||||
@@ -718,8 +721,13 @@ static void __init parse_cmdline_early (char ** cmdline_p)
|
||||
unsigned long long mem_size;
|
||||
|
||||
mem_size = memparse(from+4, &from);
|
||||
#if 0
|
||||
limit_regions(mem_size);
|
||||
userdef=1;
|
||||
#else
|
||||
xen_override_max_pfn =
|
||||
(unsigned long)(mem_size>>PAGE_SHIFT);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -857,6 +865,7 @@ static void __init parse_cmdline_early (char ** cmdline_p)
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 /* !XEN */
|
||||
/*
|
||||
* Callback for efi_memory_walk.
|
||||
*/
|
||||
@@ -873,7 +882,6 @@ efi_find_max_pfn(unsigned long start, unsigned long end, void *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Find the highest page frame number we have available
|
||||
*/
|
||||
@@ -900,6 +908,15 @@ void __init find_max_pfn(void)
|
||||
max_pfn = end;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* We don't use the fake e820 because we need to respond to user override. */
|
||||
void __init find_max_pfn(void)
|
||||
{
|
||||
if ( xen_override_max_pfn < xen_start_info.nr_pages )
|
||||
xen_override_max_pfn = xen_start_info.nr_pages;
|
||||
max_pfn = xen_override_max_pfn;
|
||||
}
|
||||
#endif /* XEN */
|
||||
|
||||
/*
|
||||
* Determine low and high memory ranges:
|
||||
@@ -1414,6 +1431,21 @@ void __init setup_arch(char **cmdline_p)
|
||||
#endif
|
||||
paging_init();
|
||||
|
||||
/* Make sure we have a large enough P->M table. */
|
||||
if (max_pfn > xen_start_info.nr_pages) {
|
||||
phys_to_machine_mapping = alloc_bootmem_low_pages(
|
||||
max_pfn * sizeof(unsigned long));
|
||||
memset(phys_to_machine_mapping, ~0,
|
||||
max_pfn * sizeof(unsigned long));
|
||||
memcpy(phys_to_machine_mapping,
|
||||
(unsigned long *)xen_start_info.mfn_list,
|
||||
xen_start_info.nr_pages * sizeof(unsigned long));
|
||||
free_bootmem(
|
||||
__pa(xen_start_info.mfn_list),
|
||||
PFN_PHYS(PFN_UP(xen_start_info.nr_pages *
|
||||
sizeof(unsigned long))));
|
||||
}
|
||||
|
||||
pfn_to_mfn_frame_list = alloc_bootmem_low_pages(PAGE_SIZE);
|
||||
for ( i=0, j=0; i < max_pfn; i+=(PAGE_SIZE/sizeof(unsigned long)), j++ )
|
||||
{
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm-xen/hypervisor.h>
|
||||
#include <asm-xen/multicall.h>
|
||||
#include <asm-xen/balloon.h>
|
||||
|
||||
/*
|
||||
* This suffices to protect us if we ever move to SMP domains.
|
||||
@@ -352,7 +353,6 @@ unsigned long allocate_empty_lowmem_region(unsigned long pages)
|
||||
unsigned long *pfn_array;
|
||||
unsigned long vstart;
|
||||
unsigned long i;
|
||||
int ret;
|
||||
unsigned int order = get_order(pages*PAGE_SIZE);
|
||||
|
||||
vstart = __get_free_pages(GFP_KERNEL, order);
|
||||
@@ -378,57 +378,11 @@ unsigned long allocate_empty_lowmem_region(unsigned long pages)
|
||||
/* Flush updates through and flush the TLB. */
|
||||
xen_tlb_flush();
|
||||
|
||||
ret = HYPERVISOR_dom_mem_op(MEMOP_decrease_reservation,
|
||||
pfn_array, 1<<order, 0);
|
||||
if ( unlikely(ret != (1<<order)) )
|
||||
{
|
||||
printk(KERN_WARNING "Unable to reduce memory reservation (%d)\n", ret);
|
||||
BUG();
|
||||
}
|
||||
balloon_put_pages(pfn_array, 1 << order);
|
||||
|
||||
vfree(pfn_array);
|
||||
|
||||
return vstart;
|
||||
}
|
||||
|
||||
void deallocate_lowmem_region(unsigned long vstart, unsigned long pages)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
pmd_t *pmd;
|
||||
pte_t *pte;
|
||||
unsigned long *pfn_array;
|
||||
unsigned long i;
|
||||
int ret;
|
||||
unsigned int order = get_order(pages*PAGE_SIZE);
|
||||
|
||||
pfn_array = vmalloc((1<<order) * sizeof(*pfn_array));
|
||||
if ( pfn_array == NULL )
|
||||
BUG();
|
||||
|
||||
ret = HYPERVISOR_dom_mem_op(MEMOP_increase_reservation,
|
||||
pfn_array, 1<<order, 0);
|
||||
if ( unlikely(ret != (1<<order)) )
|
||||
{
|
||||
printk(KERN_WARNING "Unable to increase memory reservation (%d)\n",
|
||||
ret);
|
||||
BUG();
|
||||
}
|
||||
|
||||
for ( i = 0; i < (1<<order); i++ )
|
||||
{
|
||||
pgd = pgd_offset_k( (vstart + (i*PAGE_SIZE)));
|
||||
pmd = pmd_offset(pgd, (vstart + (i*PAGE_SIZE)));
|
||||
pte = pte_offset_kernel(pmd, (vstart + (i*PAGE_SIZE)));
|
||||
queue_l1_entry_update(pte, (pfn_array[i]<<PAGE_SHIFT)|__PAGE_KERNEL);
|
||||
queue_machphys_update(pfn_array[i], __pa(vstart)>>PAGE_SHIFT);
|
||||
phys_to_machine_mapping[__pa(vstart)>>PAGE_SHIFT] = pfn_array[i];
|
||||
}
|
||||
|
||||
flush_page_update_queue();
|
||||
|
||||
vfree(pfn_array);
|
||||
|
||||
free_pages(vstart, order);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_XEN_PHYSDEV_ACCESS */
|
||||
@@ -77,6 +77,7 @@ static pte_t * __init one_page_table_init(pmd_t *pmd)
|
||||
{
|
||||
if (pmd_none(*pmd)) {
|
||||
pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
|
||||
make_page_readonly(page_table);
|
||||
set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));
|
||||
if (page_table != pte_offset_kernel(pmd, 0))
|
||||
BUG();
|
||||
@@ -125,41 +126,6 @@ static void __init page_table_range_init (unsigned long start, unsigned long end
|
||||
}
|
||||
}
|
||||
|
||||
void __init protect_page(pgd_t *pgd, void *page, int mode)
|
||||
{
|
||||
pmd_t *pmd;
|
||||
pte_t *pte;
|
||||
unsigned long addr;
|
||||
|
||||
addr = (unsigned long)page;
|
||||
pgd += pgd_index(addr);
|
||||
pmd = pmd_offset(pgd, addr);
|
||||
pte = pte_offset_kernel(pmd, addr);
|
||||
if (!pte_present(*pte))
|
||||
return;
|
||||
queue_l1_entry_update(pte, mode ? pte_val_ma(*pte) & ~_PAGE_RW :
|
||||
pte_val_ma(*pte) | _PAGE_RW);
|
||||
}
|
||||
|
||||
void __init protect_pagetable(pgd_t *dpgd, pgd_t *spgd, int mode)
|
||||
{
|
||||
pmd_t *pmd;
|
||||
pte_t *pte;
|
||||
int pgd_idx, pmd_idx;
|
||||
|
||||
protect_page(dpgd, spgd, mode);
|
||||
|
||||
for (pgd_idx = 0; pgd_idx < PTRS_PER_PGD_NO_HV; spgd++, pgd_idx++) {
|
||||
pmd = pmd_offset(spgd, 0);
|
||||
if (pmd_none(*pmd))
|
||||
continue;
|
||||
for (pmd_idx = 0; pmd_idx < PTRS_PER_PMD; pmd++, pmd_idx++) {
|
||||
pte = pte_offset_kernel(pmd, 0);
|
||||
protect_page(dpgd, pte, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline int is_kernel_text(unsigned long addr)
|
||||
{
|
||||
if (addr >= (unsigned long)_stext && addr <= (unsigned long)__init_end)
|
||||
@@ -180,6 +146,10 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
|
||||
pte_t *pte;
|
||||
int pgd_idx, pmd_idx, pte_ofs;
|
||||
|
||||
unsigned long max_ram_pfn = xen_start_info.nr_pages;
|
||||
if (max_ram_pfn > max_low_pfn)
|
||||
max_ram_pfn = max_low_pfn;
|
||||
|
||||
pgd_idx = pgd_index(PAGE_OFFSET);
|
||||
pgd = pgd_base + pgd_idx;
|
||||
pfn = 0;
|
||||
@@ -207,7 +177,10 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
|
||||
pte = one_page_table_init(pmd);
|
||||
|
||||
pte += pte_ofs;
|
||||
for (; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) {
|
||||
/* XEN: Only map initial RAM allocation. */
|
||||
for (; pte_ofs < PTRS_PER_PTE && pfn < max_ram_pfn; pte++, pfn++, pte_ofs++) {
|
||||
if (pte_present(*pte))
|
||||
continue;
|
||||
if (is_kernel_text(address))
|
||||
set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
|
||||
else
|
||||
@@ -311,7 +284,8 @@ void __init one_highpage_init(struct page *page, int pfn, int bad_ppro)
|
||||
ClearPageReserved(page);
|
||||
set_bit(PG_highmem, &page->flags);
|
||||
set_page_count(page, 1);
|
||||
__free_page(page);
|
||||
if (pfn < xen_start_info.nr_pages)
|
||||
__free_page(page);
|
||||
totalhigh_pages++;
|
||||
} else
|
||||
SetPageReserved(page);
|
||||
@@ -347,7 +321,8 @@ extern void __init remap_numa_kva(void);
|
||||
static void __init pagetable_init (void)
|
||||
{
|
||||
unsigned long vaddr;
|
||||
pgd_t *pgd_base = swapper_pg_dir;
|
||||
pgd_t *old_pgd = (pgd_t *)xen_start_info.pt_base;
|
||||
pgd_t *new_pgd = swapper_pg_dir;
|
||||
|
||||
#ifdef CONFIG_X86_PAE
|
||||
int i;
|
||||
@@ -368,7 +343,22 @@ static void __init pagetable_init (void)
|
||||
__PAGE_KERNEL_EXEC |= _PAGE_GLOBAL;
|
||||
}
|
||||
|
||||
kernel_physical_mapping_init(pgd_base);
|
||||
/*
|
||||
* Switch to proper mm_init page directory. Initialise from the current
|
||||
* page directory, write-protect the new page directory, then switch to
|
||||
* it. We clean up by write-enabling and then freeing the old page dir.
|
||||
*/
|
||||
memcpy(new_pgd, old_pgd, PTRS_PER_PGD_NO_HV*sizeof(pgd_t));
|
||||
make_page_readonly(new_pgd);
|
||||
queue_pgd_pin(__pa(new_pgd));
|
||||
load_cr3(new_pgd);
|
||||
queue_pgd_unpin(__pa(old_pgd));
|
||||
__flush_tlb_all(); /* implicit flush */
|
||||
make_page_writable(old_pgd);
|
||||
flush_page_update_queue();
|
||||
free_bootmem(__pa(old_pgd), PAGE_SIZE);
|
||||
|
||||
kernel_physical_mapping_init(new_pgd);
|
||||
remap_numa_kva();
|
||||
|
||||
/*
|
||||
@@ -376,9 +366,9 @@ static void __init pagetable_init (void)
|
||||
* created - mappings will be set by set_fixmap():
|
||||
*/
|
||||
vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
|
||||
page_table_range_init(vaddr, 0, pgd_base);
|
||||
page_table_range_init(vaddr, 0, new_pgd);
|
||||
|
||||
permanent_kmaps_init(pgd_base);
|
||||
permanent_kmaps_init(new_pgd);
|
||||
|
||||
#ifdef CONFIG_X86_PAE
|
||||
/*
|
||||
@@ -388,7 +378,7 @@ static void __init pagetable_init (void)
|
||||
* All user-space mappings are explicitly cleared after
|
||||
* SMP startup.
|
||||
*/
|
||||
pgd_base[0] = pgd_base[USER_PTRS_PER_PGD];
|
||||
new_pgd[0] = new_pgd[USER_PTRS_PER_PGD];
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -545,8 +535,6 @@ out:
|
||||
*/
|
||||
void __init paging_init(void)
|
||||
{
|
||||
pgd_t *old_pgd = (pgd_t *)xen_start_info.pt_base;
|
||||
pgd_t *new_pgd = swapper_pg_dir;
|
||||
#ifdef CONFIG_XEN_PHYSDEV_ACCESS
|
||||
int i;
|
||||
#endif
|
||||
@@ -559,25 +547,6 @@ void __init paging_init(void)
|
||||
|
||||
pagetable_init();
|
||||
|
||||
/*
|
||||
* Write-protect both page tables within both page tables.
|
||||
* That's three ops, as the old p.t. is already protected
|
||||
* within the old p.t. Then pin the new table, switch tables,
|
||||
* and unprotect the old table.
|
||||
*/
|
||||
protect_pagetable(new_pgd, old_pgd, PROT_ON);
|
||||
protect_pagetable(new_pgd, new_pgd, PROT_ON);
|
||||
protect_pagetable(old_pgd, new_pgd, PROT_ON);
|
||||
queue_pgd_pin(__pa(new_pgd));
|
||||
load_cr3(new_pgd);
|
||||
queue_pgd_unpin(__pa(old_pgd));
|
||||
__flush_tlb_all(); /* implicit flush */
|
||||
protect_pagetable(new_pgd, old_pgd, PROT_OFF);
|
||||
flush_page_update_queue();
|
||||
|
||||
/* Completely detached from old tables, so free them. */
|
||||
free_bootmem(__pa(old_pgd), xen_start_info.nr_pt_frames << PAGE_SHIFT);
|
||||
|
||||
#ifdef CONFIG_X86_PAE
|
||||
/*
|
||||
* We will bail out later - printk doesn't work right now so
|
||||
|
||||
@@ -11,16 +11,18 @@
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/pgalloc.h>
|
||||
|
||||
#ifndef CONFIG_XEN_PHYSDEV_ACCESS
|
||||
|
||||
void * __ioremap(unsigned long phys_addr, unsigned long size,
|
||||
unsigned long flags)
|
||||
unsigned long flags)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@@ -59,86 +61,6 @@ static inline int is_local_lowmem(unsigned long address)
|
||||
return ((pfn < max_low_pfn) && (pfn_to_mfn(pfn) == mfn));
|
||||
}
|
||||
|
||||
static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
|
||||
unsigned long phys_addr, unsigned long flags)
|
||||
{
|
||||
unsigned long end;
|
||||
unsigned long pfn;
|
||||
|
||||
address &= ~PMD_MASK;
|
||||
end = address + size;
|
||||
if (end > PMD_SIZE)
|
||||
end = PMD_SIZE;
|
||||
if (address >= end)
|
||||
BUG();
|
||||
pfn = phys_addr >> PAGE_SHIFT;
|
||||
do {
|
||||
if (!pte_none(*pte)) {
|
||||
printk("remap_area_pte: page already exists\n");
|
||||
BUG();
|
||||
}
|
||||
set_pte(pte, pfn_pte_ma(pfn, __pgprot(_PAGE_PRESENT | _PAGE_RW |
|
||||
_PAGE_DIRTY | _PAGE_ACCESSED | flags)));
|
||||
address += PAGE_SIZE;
|
||||
pfn++;
|
||||
pte++;
|
||||
} while (address && (address < end));
|
||||
}
|
||||
|
||||
static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
|
||||
unsigned long phys_addr, unsigned long flags)
|
||||
{
|
||||
unsigned long end;
|
||||
|
||||
address &= ~PGDIR_MASK;
|
||||
end = address + size;
|
||||
if (end > PGDIR_SIZE)
|
||||
end = PGDIR_SIZE;
|
||||
phys_addr -= address;
|
||||
if (address >= end)
|
||||
BUG();
|
||||
do {
|
||||
pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address);
|
||||
if (!pte)
|
||||
return -ENOMEM;
|
||||
remap_area_pte(pte, address, end - address, address + phys_addr, flags);
|
||||
address = (address + PMD_SIZE) & PMD_MASK;
|
||||
pmd++;
|
||||
} while (address && (address < end));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int remap_area_pages(unsigned long address, unsigned long phys_addr,
|
||||
unsigned long size, unsigned long flags)
|
||||
{
|
||||
int error;
|
||||
pgd_t * dir;
|
||||
unsigned long end = address + size;
|
||||
|
||||
phys_addr -= address;
|
||||
dir = pgd_offset(&init_mm, address);
|
||||
flush_cache_all();
|
||||
if (address >= end)
|
||||
BUG();
|
||||
spin_lock(&init_mm.page_table_lock);
|
||||
do {
|
||||
pmd_t *pmd;
|
||||
pmd = pmd_alloc(&init_mm, dir, address);
|
||||
error = -ENOMEM;
|
||||
if (!pmd)
|
||||
break;
|
||||
if (remap_area_pmd(pmd, address, end - address,
|
||||
phys_addr + address, flags))
|
||||
break;
|
||||
error = 0;
|
||||
address = (address + PGDIR_SIZE) & PGDIR_MASK;
|
||||
dir++;
|
||||
} while (address && (address < end));
|
||||
spin_unlock(&init_mm.page_table_lock);
|
||||
flush_tlb_all();
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic mapping function (not visible outside):
|
||||
*/
|
||||
@@ -201,7 +123,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l
|
||||
return NULL;
|
||||
area->phys_addr = phys_addr;
|
||||
addr = (void __iomem *) area->addr;
|
||||
if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
|
||||
if (direct_remap_area_pages(&init_mm, (unsigned long) addr, phys_addr, size, __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | flags), DOMID_IO)) {
|
||||
vunmap((void __force *) addr);
|
||||
return NULL;
|
||||
}
|
||||
@@ -406,7 +328,9 @@ static inline int direct_remap_area_pmd(struct mm_struct *mm,
|
||||
if (address >= end)
|
||||
BUG();
|
||||
do {
|
||||
pte_t *pte = pte_alloc_map(mm, pmd, address);
|
||||
pte_t *pte = (mm == &init_mm) ?
|
||||
pte_alloc_kernel(mm, pmd, address) :
|
||||
pte_alloc_map(mm, pmd, address);
|
||||
if (!pte)
|
||||
return -ENOMEM;
|
||||
direct_remap_area_pte(pte, address, end - address, v);
|
||||
@@ -426,7 +350,6 @@ int __direct_remap_area_pages(struct mm_struct *mm,
|
||||
unsigned long end = address + size;
|
||||
|
||||
dir = pgd_offset(mm, address);
|
||||
flush_cache_all();
|
||||
if (address >= end)
|
||||
BUG();
|
||||
spin_lock(&mm->page_table_lock);
|
||||
@@ -440,7 +363,6 @@ int __direct_remap_area_pages(struct mm_struct *mm,
|
||||
|
||||
} while (address && (address < end));
|
||||
spin_unlock(&mm->page_table_lock);
|
||||
flush_tlb_all();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -464,16 +386,18 @@ int direct_remap_area_pages(struct mm_struct *mm,
|
||||
|
||||
start_address = address;
|
||||
|
||||
for(i = 0; i < size; i += PAGE_SIZE) {
|
||||
flush_cache_all();
|
||||
|
||||
for (i = 0; i < size; i += PAGE_SIZE) {
|
||||
if ((v - u) == MAX_DIRECTMAP_MMU_QUEUE) {
|
||||
/* Fill in the PTE pointers. */
|
||||
__direct_remap_area_pages(mm,
|
||||
start_address,
|
||||
address-start_address,
|
||||
w);
|
||||
|
||||
|
||||
if (HYPERVISOR_mmu_update(u, v - u, NULL) < 0)
|
||||
return -EFAULT;
|
||||
return -EFAULT;
|
||||
v = w;
|
||||
start_address = address;
|
||||
}
|
||||
@@ -494,10 +418,14 @@ int direct_remap_area_pages(struct mm_struct *mm,
|
||||
__direct_remap_area_pages(mm,
|
||||
start_address,
|
||||
address-start_address,
|
||||
w);
|
||||
w);
|
||||
if (unlikely(HYPERVISOR_mmu_update(u, v - u, NULL) < 0))
|
||||
return -EFAULT;
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
|
||||
flush_tlb_all();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(direct_remap_area_pages);
|
||||
@@ -11,4 +11,4 @@ $(obj)/vmlinux.lds.S:
|
||||
|
||||
extra-y += vmlinux.lds
|
||||
|
||||
obj-y := ctrl_if.o evtchn.o fixup.o reboot.o xen_proc.o gnttab.o skbuff.o
|
||||
obj-y := ctrl_if.o evtchn.o fixup.o reboot.o xen_proc.o gnttab.o skbuff.o devmem.o
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm-xen/ctrl_if.h>
|
||||
#include <asm-xen/evtchn.h>
|
||||
|
||||
@@ -539,3 +540,10 @@ void ctrl_if_discard_responses(void)
|
||||
ctrl_if_tx_resp_cons = get_ctrl_if()->tx_resp_prod;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(ctrl_if_send_message_noblock);
|
||||
EXPORT_SYMBOL(ctrl_if_send_message_block);
|
||||
EXPORT_SYMBOL(ctrl_if_send_message_and_get_response);
|
||||
EXPORT_SYMBOL(ctrl_if_enqueue_space_callback);
|
||||
EXPORT_SYMBOL(ctrl_if_send_response);
|
||||
EXPORT_SYMBOL(ctrl_if_register_receiver);
|
||||
EXPORT_SYMBOL(ctrl_if_unregister_receiver);
|
||||
@@ -42,12 +42,7 @@ extern void tapechar_init(void);
|
||||
*/
|
||||
static inline int uncached_access(struct file *file, unsigned long addr)
|
||||
{
|
||||
#ifdef CONFIG_XEN
|
||||
if (file->f_flags & O_SYNC)
|
||||
return 1;
|
||||
/* Xen sets correct MTRR type on non-RAM for us. */
|
||||
return 0;
|
||||
#elif defined(__i386__)
|
||||
#if defined(__i386__)
|
||||
/*
|
||||
* On the PPro and successors, the MTRRs are used to set
|
||||
* memory types for physical addresses outside main memory,
|
||||
@@ -148,7 +143,7 @@ static ssize_t do_write_mem(void *p, unsigned long realp,
|
||||
return written;
|
||||
}
|
||||
|
||||
|
||||
#ifndef ARCH_HAS_DEV_MEM
|
||||
/*
|
||||
* This funcion reads the *physical* memory. The f_pos points directly to the
|
||||
* memory location.
|
||||
@@ -194,8 +189,9 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
|
||||
return -EFAULT;
|
||||
return do_write_mem(__va(p), p, buf, count, ppos);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int mmap_mem(struct file * file, struct vm_area_struct * vma)
|
||||
static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
|
||||
{
|
||||
#ifdef pgprot_noncached
|
||||
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
|
||||
@@ -206,22 +202,18 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma)
|
||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_XEN)
|
||||
if (io_remap_page_range(vma,
|
||||
vma->vm_start,
|
||||
vma->vm_pgoff << PAGE_SHIFT,
|
||||
vma->vm_end-vma->vm_start,
|
||||
vma->vm_page_prot))
|
||||
/* Don't try to swap out physical pages.. */
|
||||
vma->vm_flags |= VM_RESERVED;
|
||||
|
||||
/*
|
||||
* Don't dump addresses that are not real memory to a core file.
|
||||
*/
|
||||
if (uncached)
|
||||
vma->vm_flags |= VM_IO;
|
||||
|
||||
if (remap_page_range(vma, vma->vm_start, offset, vma->vm_end-vma->vm_start,
|
||||
vma->vm_page_prot))
|
||||
return -EAGAIN;
|
||||
#else
|
||||
/* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */
|
||||
if (remap_pfn_range(vma,
|
||||
vma->vm_start,
|
||||
vma->vm_pgoff,
|
||||
vma->vm_end-vma->vm_start,
|
||||
vma->vm_page_prot))
|
||||
return -EAGAIN;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -581,7 +573,7 @@ static int open_port(struct inode * inode, struct file * filp)
|
||||
return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
|
||||
}
|
||||
|
||||
#define mmap_kmem mmap_mem
|
||||
#define mmap_mem mmap_kmem
|
||||
#define zero_lseek null_lseek
|
||||
#define full_lseek null_lseek
|
||||
#define write_zero write_null
|
||||
@@ -589,6 +581,7 @@ static int open_port(struct inode * inode, struct file * filp)
|
||||
#define open_mem open_port
|
||||
#define open_kmem open_mem
|
||||
|
||||
#ifndef ARCH_HAS_DEV_MEM
|
||||
static struct file_operations mem_fops = {
|
||||
.llseek = memory_lseek,
|
||||
.read = read_mem,
|
||||
@@ -596,6 +589,9 @@ static struct file_operations mem_fops = {
|
||||
.mmap = mmap_mem,
|
||||
.open = open_mem,
|
||||
};
|
||||
#else
|
||||
extern struct file_operations mem_fops;
|
||||
#endif
|
||||
|
||||
static struct file_operations kmem_fops = {
|
||||
.llseek = memory_lseek,
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
obj-y += console/
|
||||
obj-y += evtchn/
|
||||
obj-y += privcmd/
|
||||
obj-y += balloon/
|
||||
obj-y += balloon/
|
||||
|
||||
obj-$(CONFIG_XEN_PRIVILEGED_GUEST) += privcmd/
|
||||
obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/
|
||||
obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/
|
||||
obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blkfront/
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* Xen balloon driver - enables returning/claiming memory to/from Xen.
|
||||
*
|
||||
* Copyright (c) 2003, B Dragovic
|
||||
* Copyright (c) 2003-2004, M Williamson, K Fraser
|
||||
*
|
||||
* This file may be distributed separately from the Linux kernel, or
|
||||
* incorporated into other software packages, subject to the following license:
|
||||
@@ -28,8 +29,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mm.h>
|
||||
@@ -42,25 +43,39 @@
|
||||
#include <asm-xen/xen_proc.h>
|
||||
#include <asm-xen/hypervisor.h>
|
||||
#include <asm-xen/ctrl_if.h>
|
||||
#include <asm-xen/balloon.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/tlb.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
/* USER DEFINES -- THESE SHOULD BE COPIED TO USER-SPACE TOOLS */
|
||||
#define USER_INFLATE_BALLOON 1 /* return mem to hypervisor */
|
||||
#define USER_DEFLATE_BALLOON 2 /* claim mem from hypervisor */
|
||||
typedef struct user_balloon_op {
|
||||
unsigned int op;
|
||||
unsigned long size;
|
||||
} user_balloon_op_t;
|
||||
/* END OF USER DEFINE */
|
||||
|
||||
static struct proc_dir_entry *balloon_pde;
|
||||
|
||||
unsigned long credit;
|
||||
static unsigned long current_pages, most_seen_pages;
|
||||
static DECLARE_MUTEX(balloon_mutex);
|
||||
spinlock_t balloon_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
/* We aim for 'current allocation' == 'target allocation'. */
|
||||
static unsigned long current_pages;
|
||||
static unsigned long target_pages;
|
||||
|
||||
/* We may hit the hard limit in Xen. If we do then we remember it. */
|
||||
static unsigned long hard_limit;
|
||||
|
||||
/*
|
||||
* Drivers may alter the memory reservation independently, but they must
|
||||
* inform the balloon driver so that we can avoid hitting the hard limit.
|
||||
*/
|
||||
static unsigned long driver_pages;
|
||||
|
||||
/* List of ballooned pages, threaded through the mem_map array. */
|
||||
static LIST_HEAD(ballooned_pages);
|
||||
static unsigned long balloon_low, balloon_high;
|
||||
|
||||
/* Main work function, always executed in process context. */
|
||||
static void balloon_process(void *unused);
|
||||
static DECLARE_WORK(balloon_worker, balloon_process, NULL);
|
||||
static struct timer_list balloon_timer;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
/* Use the private and mapping fields of struct page as a list. */
|
||||
@@ -76,452 +91,223 @@ static unsigned long current_pages, most_seen_pages;
|
||||
#define LIST_TO_PAGE(l) ( list_entry(l, struct page, list) )
|
||||
#define UNLIST_PAGE(p) ( list_del(&p->list) )
|
||||
#define pte_offset_kernel pte_offset
|
||||
#define subsys_initcall(_fn) __initcall(_fn)
|
||||
#endif
|
||||
|
||||
/* List of ballooned pages, threaded through the mem_map array. */
|
||||
LIST_HEAD(ballooned_pages);
|
||||
#define IPRINTK(fmt, args...) \
|
||||
printk(KERN_INFO "xen_mem: " fmt, ##args)
|
||||
#define WPRINTK(fmt, args...) \
|
||||
printk(KERN_WARNING "xen_mem: " fmt, ##args)
|
||||
|
||||
/** add_ballooned_page - remember we've ballooned a pfn */
|
||||
void add_ballooned_page(unsigned long pfn)
|
||||
/* balloon_append: add the given page to the balloon. */
|
||||
static void balloon_append(struct page *page)
|
||||
{
|
||||
struct page *p = mem_map + pfn;
|
||||
|
||||
list_add(PAGE_TO_LIST(p), &ballooned_pages);
|
||||
}
|
||||
|
||||
/* rem_ballooned_page - recall a ballooned page and remove from list. */
|
||||
struct page *rem_ballooned_page(void)
|
||||
{
|
||||
if(!list_empty(&ballooned_pages))
|
||||
/* Low memory is re-populated first, so highmem pages go at list tail. */
|
||||
if ( PageHighMem(page) )
|
||||
{
|
||||
struct page *ret;
|
||||
|
||||
ret = LIST_TO_PAGE(ballooned_pages.next);
|
||||
UNLIST_PAGE(ret);
|
||||
|
||||
return ret;
|
||||
list_add_tail(PAGE_TO_LIST(page), &ballooned_pages);
|
||||
balloon_high++;
|
||||
}
|
||||
else
|
||||
{
|
||||
list_add(PAGE_TO_LIST(page), &ballooned_pages);
|
||||
balloon_low++;
|
||||
}
|
||||
}
|
||||
|
||||
/* balloon_retrieve: rescue a page from the balloon, if it is not empty. */
|
||||
static struct page *balloon_retrieve(void)
|
||||
{
|
||||
struct page *page;
|
||||
|
||||
if ( list_empty(&ballooned_pages) )
|
||||
return NULL;
|
||||
|
||||
page = LIST_TO_PAGE(ballooned_pages.next);
|
||||
UNLIST_PAGE(page);
|
||||
|
||||
if ( PageHighMem(page) )
|
||||
balloon_high--;
|
||||
else
|
||||
balloon_low--;
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
static inline pte_t *get_ptep(unsigned long addr)
|
||||
{
|
||||
pgd_t *pgd; pmd_t *pmd; pte_t *ptep;
|
||||
pgd = pgd_offset_k(addr);
|
||||
pgd_t *pgd;
|
||||
pmd_t *pmd;
|
||||
|
||||
pgd = pgd_offset_k(addr);
|
||||
if ( pgd_none(*pgd) || pgd_bad(*pgd) ) BUG();
|
||||
|
||||
pmd = pmd_offset(pgd, addr);
|
||||
if ( pmd_none(*pmd) || pmd_bad(*pmd) ) BUG();
|
||||
|
||||
ptep = pte_offset_kernel(pmd, addr);
|
||||
|
||||
return ptep;
|
||||
return pte_offset_kernel(pmd, addr);
|
||||
}
|
||||
|
||||
/* Main function for relinquishing memory. */
|
||||
static unsigned long inflate_balloon(unsigned long num_pages)
|
||||
|
||||
static void balloon_alarm(unsigned long unused)
|
||||
{
|
||||
unsigned long *parray;
|
||||
unsigned long *currp;
|
||||
unsigned long curraddr;
|
||||
unsigned long ret = 0;
|
||||
unsigned long i, j;
|
||||
schedule_work(&balloon_worker);
|
||||
}
|
||||
|
||||
parray = (unsigned long *)vmalloc(num_pages * sizeof(unsigned long));
|
||||
if ( parray == NULL )
|
||||
{
|
||||
printk(KERN_ERR "inflate_balloon: Unable to vmalloc parray\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
currp = parray;
|
||||
|
||||
for ( i = 0; i < num_pages; i++, currp++ )
|
||||
{
|
||||
struct page *page = alloc_page(GFP_HIGHUSER);
|
||||
unsigned long pfn = page - mem_map;
|
||||
|
||||
/* If allocation fails then free all reserved pages. */
|
||||
if ( page == NULL )
|
||||
{
|
||||
printk(KERN_ERR "Unable to inflate balloon by %ld, only"
|
||||
" %ld pages free.", num_pages, i);
|
||||
currp = parray;
|
||||
for ( j = 0; j < i; j++, currp++ )
|
||||
__free_page((struct page *) (mem_map + *currp));
|
||||
|
||||
ret = -EFAULT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
*currp = pfn;
|
||||
}
|
||||
|
||||
|
||||
for ( i = 0, currp = parray; i < num_pages; i++, currp++ )
|
||||
{
|
||||
unsigned long mfn = phys_to_machine_mapping[*currp];
|
||||
curraddr = (unsigned long)page_address(mem_map + *currp);
|
||||
/* Blow away page contents for security, and also p.t. ref if any. */
|
||||
if ( curraddr != 0 )
|
||||
{
|
||||
scrub_pages(curraddr, 1);
|
||||
queue_l1_entry_update(get_ptep(curraddr), 0);
|
||||
}
|
||||
#ifdef CONFIG_XEN_SCRUB_PAGES
|
||||
else
|
||||
{
|
||||
void *p = kmap(&mem_map[*currp]);
|
||||
scrub_pages(p, 1);
|
||||
kunmap(&mem_map[*currp]);
|
||||
}
|
||||
#endif
|
||||
|
||||
add_ballooned_page(*currp);
|
||||
|
||||
phys_to_machine_mapping[*currp] = INVALID_P2M_ENTRY;
|
||||
*currp = mfn;
|
||||
}
|
||||
|
||||
/* Flush updates through and flush the TLB. */
|
||||
xen_tlb_flush();
|
||||
|
||||
ret = HYPERVISOR_dom_mem_op(MEMOP_decrease_reservation,
|
||||
parray, num_pages, 0);
|
||||
if ( unlikely(ret != num_pages) )
|
||||
{
|
||||
printk(KERN_ERR "Unable to inflate balloon, error %lx\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
credit += num_pages;
|
||||
ret = num_pages;
|
||||
|
||||
cleanup:
|
||||
vfree(parray);
|
||||
|
||||
return ret;
|
||||
static unsigned long current_target(void)
|
||||
{
|
||||
unsigned long target = min(target_pages, hard_limit);
|
||||
if ( target > (current_pages + balloon_low + balloon_high) )
|
||||
target = current_pages + balloon_low + balloon_high;
|
||||
return target;
|
||||
}
|
||||
|
||||
/*
|
||||
* Install new mem pages obtained by deflate_balloon. function walks
|
||||
* phys->machine mapping table looking for DEAD entries and populates
|
||||
* them.
|
||||
* We avoid multiple worker processes conflicting via the balloon mutex.
|
||||
* We may of course race updates of the target counts (which are protected
|
||||
* by the balloon lock), or with changes to the Xen hard limit, but we will
|
||||
* recover from these in time.
|
||||
*/
|
||||
static unsigned long process_returned_pages(unsigned long * parray,
|
||||
unsigned long num)
|
||||
static void balloon_process(void *unused)
|
||||
{
|
||||
/* currently, this function is rather simplistic as
|
||||
* it is assumed that domain reclaims only number of
|
||||
* pages previously released. this is to change soon
|
||||
* and the code to extend page tables etc. will be
|
||||
* incorporated here.
|
||||
*/
|
||||
|
||||
unsigned long * curr = parray;
|
||||
unsigned long num_installed;
|
||||
unsigned long *mfn_list, pfn, i, flags;
|
||||
struct page *page;
|
||||
long credit, debt, rc;
|
||||
void *v;
|
||||
|
||||
struct page *page;
|
||||
down(&balloon_mutex);
|
||||
|
||||
num_installed = 0;
|
||||
while ( (page = rem_ballooned_page()) != NULL )
|
||||
retry:
|
||||
mfn_list = NULL;
|
||||
|
||||
if ( (credit = current_target() - current_pages) > 0 )
|
||||
{
|
||||
unsigned long pfn;
|
||||
mfn_list = (unsigned long *)vmalloc(credit * sizeof(*mfn_list));
|
||||
if ( mfn_list == NULL )
|
||||
goto out;
|
||||
|
||||
if ( num_installed == num )
|
||||
break;
|
||||
|
||||
pfn = page - mem_map;
|
||||
|
||||
if(phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY)
|
||||
balloon_lock(flags);
|
||||
rc = HYPERVISOR_dom_mem_op(
|
||||
MEMOP_increase_reservation, mfn_list, credit, 0);
|
||||
balloon_unlock(flags);
|
||||
if ( rc < credit )
|
||||
{
|
||||
printk("BUG: Tried to unballoon existing page!");
|
||||
BUG();
|
||||
/* We hit the Xen hard limit: reprobe. */
|
||||
if ( HYPERVISOR_dom_mem_op(
|
||||
MEMOP_decrease_reservation, mfn_list, rc, 0) != rc )
|
||||
BUG();
|
||||
hard_limit = current_pages + rc - driver_pages;
|
||||
vfree(mfn_list);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
phys_to_machine_mapping[pfn] = *curr;
|
||||
queue_machphys_update(*curr, pfn);
|
||||
if (pfn<max_low_pfn)
|
||||
queue_l1_entry_update(
|
||||
get_ptep((unsigned long)__va(pfn << PAGE_SHIFT)),
|
||||
((*curr) << PAGE_SHIFT) | pgprot_val(PAGE_KERNEL));
|
||||
|
||||
__free_page(mem_map + pfn);
|
||||
for ( i = 0; i < credit; i++ )
|
||||
{
|
||||
if ( (page = balloon_retrieve()) == NULL )
|
||||
BUG();
|
||||
|
||||
curr++;
|
||||
num_installed++;
|
||||
pfn = page - mem_map;
|
||||
if ( phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY )
|
||||
BUG();
|
||||
|
||||
/* Update P->M and M->P tables. */
|
||||
phys_to_machine_mapping[pfn] = mfn_list[i];
|
||||
queue_machphys_update(mfn_list[i], pfn);
|
||||
|
||||
/* Link back into the page tables if it's not a highmem page. */
|
||||
if ( pfn < max_low_pfn )
|
||||
queue_l1_entry_update(
|
||||
get_ptep((unsigned long)__va(pfn << PAGE_SHIFT)),
|
||||
(mfn_list[i] << PAGE_SHIFT) | pgprot_val(PAGE_KERNEL));
|
||||
|
||||
/* Finally, relinquish the memory back to the system allocator. */
|
||||
ClearPageReserved(page);
|
||||
set_page_count(page, 1);
|
||||
__free_page(page);
|
||||
}
|
||||
|
||||
current_pages += credit;
|
||||
}
|
||||
|
||||
return num_installed;
|
||||
}
|
||||
|
||||
unsigned long deflate_balloon(unsigned long num_pages)
|
||||
{
|
||||
unsigned long ret;
|
||||
unsigned long * parray;
|
||||
|
||||
if ( num_pages > credit )
|
||||
else if ( credit < 0 )
|
||||
{
|
||||
printk(KERN_ERR "deflate_balloon: %lu pages > %lu credit.\n",
|
||||
num_pages, credit);
|
||||
return -EAGAIN;
|
||||
}
|
||||
debt = -credit;
|
||||
|
||||
parray = (unsigned long *)vmalloc(num_pages * sizeof(unsigned long));
|
||||
if ( parray == NULL )
|
||||
{
|
||||
printk(KERN_ERR "deflate_balloon: Unable to vmalloc parray\n");
|
||||
return 0;
|
||||
}
|
||||
mfn_list = (unsigned long *)vmalloc(debt * sizeof(*mfn_list));
|
||||
if ( mfn_list == NULL )
|
||||
goto out;
|
||||
|
||||
ret = HYPERVISOR_dom_mem_op(MEMOP_increase_reservation,
|
||||
parray, num_pages, 0);
|
||||
if ( unlikely(ret != num_pages) )
|
||||
{
|
||||
printk(KERN_ERR "deflate_balloon: xen increase_reservation err %lx\n",
|
||||
ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ( (ret = process_returned_pages(parray, num_pages)) < num_pages )
|
||||
{
|
||||
printk(KERN_WARNING
|
||||
"deflate_balloon: restored only %lx of %lx pages.\n",
|
||||
ret, num_pages);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = num_pages;
|
||||
credit -= num_pages;
|
||||
|
||||
cleanup:
|
||||
vfree(parray);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define PAGE_TO_MB_SHIFT 8
|
||||
|
||||
/*
|
||||
* pagetable_extend() mimics pagetable_init() from arch/xen/mm/init.c
|
||||
* The loops do go through all of low memory (ZONE_NORMAL). The
|
||||
* old pages have _PAGE_PRESENT set and so get skipped.
|
||||
* If low memory is not full, the new pages are used to fill it, going
|
||||
* from cur_low_pfn to low_pfn. high memory is not direct mapped so
|
||||
* no extension is needed for new high memory.
|
||||
*/
|
||||
|
||||
static void pagetable_extend (int cur_low_pfn, int newpages)
|
||||
{
|
||||
unsigned long vaddr, end;
|
||||
pgd_t *kpgd, *pgd, *pgd_base;
|
||||
int i, j, k;
|
||||
pmd_t *kpmd, *pmd;
|
||||
pte_t *kpte, *pte, *pte_base;
|
||||
int low_pfn = min(cur_low_pfn+newpages,(int)max_low_pfn);
|
||||
|
||||
/*
|
||||
* This can be zero as well - no problem, in that case we exit
|
||||
* the loops anyway due to the PTRS_PER_* conditions.
|
||||
*/
|
||||
end = (unsigned long)__va(low_pfn*PAGE_SIZE);
|
||||
|
||||
pgd_base = init_mm.pgd;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
i = pgd_index(PAGE_OFFSET);
|
||||
#else
|
||||
i = __pgd_offset(PAGE_OFFSET);
|
||||
#endif
|
||||
pgd = pgd_base + i;
|
||||
|
||||
for (; i < PTRS_PER_PGD; pgd++, i++) {
|
||||
vaddr = i*PGDIR_SIZE;
|
||||
if (end && (vaddr >= end))
|
||||
break;
|
||||
pmd = (pmd_t *)pgd;
|
||||
for (j = 0; j < PTRS_PER_PMD; pmd++, j++) {
|
||||
vaddr = i*PGDIR_SIZE + j*PMD_SIZE;
|
||||
if (end && (vaddr >= end))
|
||||
for ( i = 0; i < debt; i++ )
|
||||
{
|
||||
if ( (page = alloc_page(GFP_HIGHUSER)) == NULL )
|
||||
{
|
||||
debt = i;
|
||||
break;
|
||||
|
||||
/* Filled in for us already? */
|
||||
if ( pmd_val(*pmd) & _PAGE_PRESENT )
|
||||
continue;
|
||||
|
||||
pte_base = pte = (pte_t *) __get_free_page(GFP_KERNEL);
|
||||
|
||||
for (k = 0; k < PTRS_PER_PTE; pte++, k++) {
|
||||
vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE;
|
||||
if (end && (vaddr >= end))
|
||||
break;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
*pte = mk_pte(virt_to_page(vaddr), PAGE_KERNEL);
|
||||
#else
|
||||
*pte = mk_pte_phys(__pa(vaddr), PAGE_KERNEL);
|
||||
#endif
|
||||
}
|
||||
kpgd = pgd_offset_k((unsigned long)pte_base);
|
||||
kpmd = pmd_offset(kpgd, (unsigned long)pte_base);
|
||||
kpte = pte_offset_kernel(kpmd, (unsigned long)pte_base);
|
||||
queue_l1_entry_update(kpte,
|
||||
(*(unsigned long *)kpte)&~_PAGE_RW);
|
||||
set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte_base)));
|
||||
XEN_flush_page_update_queue();
|
||||
|
||||
pfn = page - mem_map;
|
||||
mfn_list[i] = phys_to_machine_mapping[pfn];
|
||||
phys_to_machine_mapping[pfn] = INVALID_P2M_ENTRY;
|
||||
|
||||
if ( !PageHighMem(page) )
|
||||
{
|
||||
v = phys_to_virt((page - mem_map) << PAGE_SHIFT);
|
||||
scrub_pages(v, 1);
|
||||
queue_l1_entry_update(get_ptep((unsigned long)v), 0);
|
||||
}
|
||||
#ifdef CONFIG_XEN_SCRUB_PAGES
|
||||
else
|
||||
{
|
||||
v = kmap(page);
|
||||
scrub_pages(v, 1);
|
||||
kunmap(page);
|
||||
}
|
||||
#endif
|
||||
|
||||
balloon_append(page);
|
||||
}
|
||||
|
||||
/* Flush updates through and flush the TLB. */
|
||||
xen_tlb_flush();
|
||||
|
||||
if ( HYPERVISOR_dom_mem_op(
|
||||
MEMOP_decrease_reservation, mfn_list, debt, 0) != debt )
|
||||
BUG();
|
||||
|
||||
current_pages -= debt;
|
||||
}
|
||||
|
||||
out:
|
||||
if ( mfn_list != NULL )
|
||||
vfree(mfn_list);
|
||||
|
||||
/* Schedule more work if there is some still to be done. */
|
||||
if ( current_target() != current_pages )
|
||||
mod_timer(&balloon_timer, jiffies + HZ);
|
||||
|
||||
up(&balloon_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* claim_new_pages() asks xen to increase this domain's memory reservation
|
||||
* and return a list of the new pages of memory. This new pages are
|
||||
* added to the free list of the memory manager.
|
||||
*
|
||||
* Available RAM does not normally change while Linux runs. To make this work,
|
||||
* the linux mem= boottime command line param must say how big memory could
|
||||
* possibly grow. Then setup_arch() in arch/xen/kernel/setup.c
|
||||
* sets max_pfn, max_low_pfn and the zones according to
|
||||
* this max memory size. The page tables themselves can only be
|
||||
* extended after xen has assigned new pages to this domain.
|
||||
*/
|
||||
|
||||
static unsigned long
|
||||
claim_new_pages(unsigned long num_pages)
|
||||
/* Resets the Xen limit, sets new target, and kicks off processing. */
|
||||
static void set_new_target(unsigned long target)
|
||||
{
|
||||
unsigned long new_page_cnt, pfn;
|
||||
unsigned long * parray, *curr;
|
||||
|
||||
if (most_seen_pages+num_pages> max_pfn)
|
||||
num_pages = max_pfn-most_seen_pages;
|
||||
if (num_pages==0) return -EINVAL;
|
||||
|
||||
parray = (unsigned long *)vmalloc(num_pages * sizeof(unsigned long));
|
||||
if ( parray == NULL )
|
||||
{
|
||||
printk(KERN_ERR "claim_new_pages: Unable to vmalloc parray\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
new_page_cnt = HYPERVISOR_dom_mem_op(MEMOP_increase_reservation,
|
||||
parray, num_pages, 0);
|
||||
if ( new_page_cnt != num_pages )
|
||||
{
|
||||
printk(KERN_WARNING
|
||||
"claim_new_pages: xen granted only %lu of %lu requested pages\n",
|
||||
new_page_cnt, num_pages);
|
||||
|
||||
/*
|
||||
* Avoid xen lockup when user forgot to setdomainmaxmem. Xen
|
||||
* usually can dribble out a few pages and then hangs.
|
||||
*/
|
||||
if ( new_page_cnt < 1000 )
|
||||
{
|
||||
printk(KERN_WARNING "Remember to use setdomainmaxmem\n");
|
||||
HYPERVISOR_dom_mem_op(MEMOP_decrease_reservation,
|
||||
parray, new_page_cnt, 0);
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
memcpy(phys_to_machine_mapping+most_seen_pages, parray,
|
||||
new_page_cnt * sizeof(unsigned long));
|
||||
|
||||
pagetable_extend(most_seen_pages,new_page_cnt);
|
||||
|
||||
for ( pfn = most_seen_pages, curr = parray;
|
||||
pfn < most_seen_pages+new_page_cnt;
|
||||
pfn++, curr++ )
|
||||
{
|
||||
struct page *page = mem_map + pfn;
|
||||
|
||||
#ifndef CONFIG_HIGHMEM
|
||||
if ( pfn>=max_low_pfn )
|
||||
{
|
||||
printk(KERN_WARNING "Warning only %ldMB will be used.\n",
|
||||
pfn>>PAGE_TO_MB_SHIFT);
|
||||
printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
queue_machphys_update(*curr, pfn);
|
||||
if ( pfn < max_low_pfn )
|
||||
queue_l1_entry_update(
|
||||
get_ptep((unsigned long)__va(pfn << PAGE_SHIFT)),
|
||||
((*curr) << PAGE_SHIFT) | pgprot_val(PAGE_KERNEL));
|
||||
|
||||
XEN_flush_page_update_queue();
|
||||
|
||||
/* this next bit mimics arch/xen/mm/init.c:one_highpage_init() */
|
||||
ClearPageReserved(page);
|
||||
if ( pfn >= max_low_pfn )
|
||||
set_bit(PG_highmem, &page->flags);
|
||||
set_page_count(page, 1);
|
||||
__free_page(page);
|
||||
}
|
||||
|
||||
vfree(parray);
|
||||
|
||||
return new_page_cnt;
|
||||
/* No need for lock. Not read-modify-write updates. */
|
||||
hard_limit = ~0UL;
|
||||
target_pages = target;
|
||||
schedule_work(&balloon_worker);
|
||||
}
|
||||
|
||||
|
||||
static int balloon_try_target(int target)
|
||||
{
|
||||
int change, reclaim;
|
||||
|
||||
if ( target < current_pages )
|
||||
{
|
||||
int change = inflate_balloon(current_pages-target);
|
||||
if ( change <= 0 )
|
||||
return change;
|
||||
|
||||
current_pages -= change;
|
||||
printk(KERN_INFO "Relinquish %dMB to xen. Domain now has %luMB\n",
|
||||
change>>PAGE_TO_MB_SHIFT, current_pages>>PAGE_TO_MB_SHIFT);
|
||||
}
|
||||
else if ( target > current_pages )
|
||||
{
|
||||
reclaim = min((unsigned long)target,most_seen_pages) - current_pages;
|
||||
|
||||
if ( reclaim )
|
||||
{
|
||||
change = deflate_balloon( reclaim );
|
||||
if ( change <= 0 )
|
||||
return change;
|
||||
current_pages += change;
|
||||
printk(KERN_INFO "Reclaim %dMB from xen. Domain now has %luMB\n",
|
||||
change>>PAGE_TO_MB_SHIFT, current_pages>>PAGE_TO_MB_SHIFT);
|
||||
}
|
||||
|
||||
if ( most_seen_pages < target )
|
||||
{
|
||||
int growth = claim_new_pages(target-most_seen_pages);
|
||||
if ( growth <= 0 )
|
||||
return growth;
|
||||
most_seen_pages += growth;
|
||||
current_pages += growth;
|
||||
printk(KERN_INFO "Granted %dMB new mem. Dom now has %luMB\n",
|
||||
growth>>PAGE_TO_MB_SHIFT, current_pages>>PAGE_TO_MB_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void balloon_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
|
||||
{
|
||||
switch ( msg->subtype )
|
||||
{
|
||||
case CMSG_MEM_REQUEST_SET:
|
||||
{
|
||||
mem_request_t *req = (mem_request_t *)&msg->msg[0];
|
||||
if ( msg->length != sizeof(mem_request_t) )
|
||||
goto parse_error;
|
||||
{
|
||||
mem_request_t *req = (mem_request_t *)&msg->msg[0];
|
||||
req->status = balloon_try_target(req->target);
|
||||
}
|
||||
break;
|
||||
set_new_target(req->target);
|
||||
req->status = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto parse_error;
|
||||
}
|
||||
@@ -534,158 +320,122 @@ static void balloon_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
|
||||
ctrl_if_send_response(msg);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
typedef size_t count_t;
|
||||
#else
|
||||
typedef u_long count_t;
|
||||
#endif
|
||||
|
||||
static int do_balloon_write(const char *buffer, count_t count)
|
||||
static int balloon_write(struct file *file, const char __user *buffer,
|
||||
unsigned long count, void *data)
|
||||
{
|
||||
char memstring[64], *endchar;
|
||||
int len, i;
|
||||
unsigned long target;
|
||||
unsigned long long targetbytes;
|
||||
unsigned long long target_bytes;
|
||||
|
||||
/* Only admin can play with the balloon :) */
|
||||
if ( !capable(CAP_SYS_ADMIN) )
|
||||
return -EPERM;
|
||||
|
||||
if ( count <= 1 )
|
||||
return -EBADMSG; /* runt */
|
||||
if ( count > sizeof(memstring) )
|
||||
return -EFBIG;
|
||||
return -EFBIG; /* too long */
|
||||
|
||||
len = strnlen_user(buffer, count);
|
||||
if ( len == 0 ) return -EBADMSG;
|
||||
if ( len == 1 ) return 1; /* input starts with a NUL char */
|
||||
if ( strncpy_from_user(memstring, buffer, len) < 0 )
|
||||
if ( copy_from_user(memstring, buffer, count) )
|
||||
return -EFAULT;
|
||||
memstring[sizeof(memstring)-1] = '\0';
|
||||
|
||||
endchar = memstring;
|
||||
for ( i = 0; i < len; ++i, ++endchar )
|
||||
if ( (memstring[i] < '0') || (memstring[i] > '9') )
|
||||
break;
|
||||
if ( i == 0 )
|
||||
return -EBADMSG;
|
||||
target_bytes = memparse(memstring, &endchar);
|
||||
set_new_target(target_bytes >> PAGE_SHIFT);
|
||||
|
||||
targetbytes = memparse(memstring,&endchar);
|
||||
target = targetbytes >> PAGE_SHIFT;
|
||||
|
||||
i = balloon_try_target(target);
|
||||
|
||||
if ( i <= 0 ) return i;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
static int balloon_write(struct file *file, const char *buffer,
|
||||
size_t count, loff_t *offp)
|
||||
{
|
||||
int len = do_balloon_write(buffer, count);
|
||||
|
||||
if ( len <= 0 ) return len;
|
||||
|
||||
*offp += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int balloon_read(struct file *filp, char *buffer,
|
||||
size_t count, loff_t *offp)
|
||||
{
|
||||
static char priv_buf[32];
|
||||
char *priv_bufp = priv_buf;
|
||||
int len;
|
||||
len = sprintf(priv_buf,"%lu\n",current_pages<<PAGE_SHIFT);
|
||||
|
||||
len -= *offp;
|
||||
priv_bufp += *offp;
|
||||
if (len>count) len = count;
|
||||
if (len<0) len = 0;
|
||||
|
||||
if ( copy_to_user(buffer, priv_bufp, len) != 0 )
|
||||
return -EFAULT;
|
||||
|
||||
*offp += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
static struct file_operations balloon_fops = {
|
||||
.read = balloon_read,
|
||||
.write = balloon_write
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
static int balloon_write(struct file *file, const char *buffer,
|
||||
u_long count, void *data)
|
||||
{
|
||||
return do_balloon_write(buffer, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static int balloon_read(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data)
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
int len;
|
||||
len = sprintf(page,"%lu\n",current_pages<<PAGE_SHIFT);
|
||||
|
||||
if (len <= off+count) *eof = 1;
|
||||
*start = page + off;
|
||||
len -= off;
|
||||
if (len>count) len = count;
|
||||
if (len<0) len = 0;
|
||||
return len;
|
||||
}
|
||||
int len;
|
||||
|
||||
#endif
|
||||
#define K(_p) ((_p)<<(PAGE_SHIFT-10))
|
||||
len = sprintf(
|
||||
page,
|
||||
"Current allocation: %8lu kB\n"
|
||||
"Requested target: %8lu kB\n"
|
||||
"Low-mem balloon: %8lu kB\n"
|
||||
"High-mem balloon: %8lu kB\n"
|
||||
"Xen hard limit: ",
|
||||
K(current_pages), K(target_pages), K(balloon_low), K(balloon_high));
|
||||
|
||||
if ( hard_limit != ~0UL )
|
||||
len += sprintf(
|
||||
page + len,
|
||||
"%8lu kB (inc. %8lu kB driver headroom)\n",
|
||||
K(hard_limit), K(driver_pages));
|
||||
else
|
||||
len += sprintf(
|
||||
page + len,
|
||||
" ??? kB\n");
|
||||
|
||||
*eof = 1;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int __init balloon_init(void)
|
||||
{
|
||||
printk(KERN_ALERT "Starting Xen Balloon driver\n");
|
||||
unsigned long pfn;
|
||||
struct page *page;
|
||||
|
||||
most_seen_pages = current_pages = min(xen_start_info.nr_pages,max_pfn);
|
||||
if ( (balloon_pde = create_xen_proc_entry("memory_target", 0644)) == NULL )
|
||||
IPRINTK("Initialising balloon driver.\n");
|
||||
|
||||
current_pages = min(xen_start_info.nr_pages, max_pfn);
|
||||
target_pages = current_pages;
|
||||
balloon_low = 0;
|
||||
balloon_high = 0;
|
||||
driver_pages = 0UL;
|
||||
hard_limit = ~0UL;
|
||||
|
||||
init_timer(&balloon_timer);
|
||||
balloon_timer.data = 0;
|
||||
balloon_timer.function = balloon_alarm;
|
||||
|
||||
if ( (balloon_pde = create_xen_proc_entry("balloon", 0644)) == NULL )
|
||||
{
|
||||
printk(KERN_ALERT "Unable to create balloon driver proc entry!");
|
||||
WPRINTK("Unable to create /proc/xen/balloon.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
balloon_pde->owner = THIS_MODULE;
|
||||
balloon_pde->nlink = 1;
|
||||
balloon_pde->proc_fops = &balloon_fops;
|
||||
#else
|
||||
balloon_pde->write_proc = balloon_write;
|
||||
balloon_pde->read_proc = balloon_read;
|
||||
#endif
|
||||
balloon_pde->write_proc = balloon_write;
|
||||
|
||||
(void)ctrl_if_register_receiver(CMSG_MEM_REQUEST, balloon_ctrlif_rx,
|
||||
CALLBACK_IN_BLOCKING_CONTEXT);
|
||||
(void)ctrl_if_register_receiver(CMSG_MEM_REQUEST, balloon_ctrlif_rx, 0);
|
||||
|
||||
/*
|
||||
* make_module a new phys map if mem= says xen can give us memory to grow
|
||||
*/
|
||||
if ( max_pfn > xen_start_info.nr_pages )
|
||||
/* Initialise the balloon with excess memory space. */
|
||||
for ( pfn = xen_start_info.nr_pages; pfn < max_pfn; pfn++ )
|
||||
{
|
||||
extern unsigned long *phys_to_machine_mapping;
|
||||
unsigned long *newmap;
|
||||
newmap = (unsigned long *)vmalloc(max_pfn * sizeof(unsigned long));
|
||||
memset(newmap, ~0, max_pfn * sizeof(unsigned long));
|
||||
memcpy(newmap, phys_to_machine_mapping,
|
||||
xen_start_info.nr_pages * sizeof(unsigned long));
|
||||
phys_to_machine_mapping = newmap;
|
||||
page = &mem_map[pfn];
|
||||
if ( !PageReserved(page) )
|
||||
balloon_append(page);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit balloon_cleanup(void)
|
||||
subsys_initcall(balloon_init);
|
||||
|
||||
void balloon_update_driver_allowance(long delta)
|
||||
{
|
||||
if ( balloon_pde != NULL )
|
||||
{
|
||||
remove_xen_proc_entry("memory_target");
|
||||
balloon_pde = NULL;
|
||||
}
|
||||
unsigned long flags;
|
||||
balloon_lock(flags);
|
||||
driver_pages += delta; /* non-atomic update */
|
||||
balloon_unlock(flags);
|
||||
}
|
||||
|
||||
module_init(balloon_init);
|
||||
module_exit(balloon_cleanup);
|
||||
void balloon_put_pages(unsigned long *mfn_list, unsigned long nr_mfns)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
balloon_lock(flags);
|
||||
if ( HYPERVISOR_dom_mem_op(MEMOP_decrease_reservation,
|
||||
mfn_list, nr_mfns, 0) != nr_mfns )
|
||||
BUG();
|
||||
current_pages -= nr_mfns; /* non-atomic update */
|
||||
balloon_unlock(flags);
|
||||
|
||||
schedule_work(&balloon_worker);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(balloon_update_driver_allowance);
|
||||
EXPORT_SYMBOL(balloon_put_pages);
|
||||
@@ -35,8 +35,8 @@ static void __netif_disconnect_complete(void *arg)
|
||||
|
||||
/*
|
||||
* These can't be done in netif_disconnect() because at that point there
|
||||
* may be outstanding requests at the disc whose asynchronous responses
|
||||
* must still be notified to the remote driver.
|
||||
* may be outstanding requests in the network stack whose asynchronous
|
||||
* responses must still be notified to the remote driver.
|
||||
*/
|
||||
unbind_evtchn_from_irq(netif->evtchn);
|
||||
vfree(netif->tx); /* Frees netif->rx as well. */
|
||||
@@ -84,7 +84,7 @@ void netif_create(netif_be_create_t *create)
|
||||
unsigned int handle = create->netif_handle;
|
||||
struct net_device *dev;
|
||||
netif_t **pnetif, *netif;
|
||||
char name[IFNAMSIZ] = {};
|
||||
char name[IFNAMSIZ];
|
||||
|
||||
snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
|
||||
dev = alloc_netdev(sizeof(netif_t), name, ether_setup);
|
||||
@@ -116,7 +116,7 @@ void netif_create(netif_be_create_t *create)
|
||||
{
|
||||
DPRINTK("Could not create netif: already exists\n");
|
||||
create->status = NETIF_BE_STATUS_INTERFACE_EXISTS;
|
||||
kfree(dev);
|
||||
free_netdev(dev);
|
||||
return;
|
||||
}
|
||||
pnetif = &(*pnetif)->hash_next;
|
||||
@@ -137,7 +137,7 @@ void netif_create(netif_be_create_t *create)
|
||||
DPRINTK("Could not register new net device %s: err=%d\n",
|
||||
dev->name, err);
|
||||
create->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
|
||||
kfree(dev);
|
||||
free_netdev(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ void netif_destroy(netif_be_destroy_t *destroy)
|
||||
destroy:
|
||||
*pnetif = netif->hash_next;
|
||||
unregister_netdev(netif->dev);
|
||||
kfree(netif->dev);
|
||||
free_netdev(netif->dev);
|
||||
destroy->status = NETIF_BE_STATUS_OKAY;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include <asm-xen/balloon.h>
|
||||
|
||||
static void netif_page_release(struct page *page);
|
||||
static void netif_skb_release(struct sk_buff *skb);
|
||||
@@ -29,6 +30,8 @@ static DECLARE_TASKLET(net_tx_tasklet, net_tx_action, 0);
|
||||
static void net_rx_action(unsigned long unused);
|
||||
static DECLARE_TASKLET(net_rx_tasklet, net_rx_action, 0);
|
||||
|
||||
static struct timer_list net_timer;
|
||||
|
||||
static struct sk_buff_head rx_queue;
|
||||
static multicall_entry_t rx_mcl[NETIF_RX_RING_SIZE*2];
|
||||
static mmu_update_t rx_mmu[NETIF_RX_RING_SIZE*3];
|
||||
@@ -69,27 +72,20 @@ static unsigned long mfn_list[MAX_MFN_ALLOC];
|
||||
static unsigned int alloc_index = 0;
|
||||
static spinlock_t mfn_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
static void __refresh_mfn_list(void)
|
||||
static unsigned long alloc_mfn(void)
|
||||
{
|
||||
int ret = HYPERVISOR_dom_mem_op(MEMOP_increase_reservation,
|
||||
mfn_list, MAX_MFN_ALLOC, 0);
|
||||
if ( unlikely(ret != MAX_MFN_ALLOC) )
|
||||
BUG();
|
||||
alloc_index = MAX_MFN_ALLOC;
|
||||
}
|
||||
|
||||
static unsigned long get_new_mfn(void)
|
||||
{
|
||||
unsigned long mfn, flags;
|
||||
unsigned long mfn = 0, flags;
|
||||
spin_lock_irqsave(&mfn_lock, flags);
|
||||
if ( alloc_index == 0 )
|
||||
__refresh_mfn_list();
|
||||
mfn = mfn_list[--alloc_index];
|
||||
if ( unlikely(alloc_index == 0) )
|
||||
alloc_index = HYPERVISOR_dom_mem_op(
|
||||
MEMOP_increase_reservation, mfn_list, MAX_MFN_ALLOC, 0);
|
||||
if ( alloc_index != 0 )
|
||||
mfn = mfn_list[--alloc_index];
|
||||
spin_unlock_irqrestore(&mfn_lock, flags);
|
||||
return mfn;
|
||||
}
|
||||
|
||||
static void dealloc_mfn(unsigned long mfn)
|
||||
static void free_mfn(unsigned long mfn)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&mfn_lock, flags);
|
||||
@@ -210,8 +206,16 @@ static void net_rx_action(unsigned long unused)
|
||||
netif = (netif_t *)skb->dev->priv;
|
||||
vdata = (unsigned long)skb->data;
|
||||
mdata = virt_to_machine(vdata);
|
||||
new_mfn = get_new_mfn();
|
||||
|
||||
|
||||
/* Memory squeeze? Back off for an arbitrary while. */
|
||||
if ( (new_mfn = alloc_mfn()) == 0 )
|
||||
{
|
||||
if ( net_ratelimit() )
|
||||
printk(KERN_WARNING "Memory squeeze in netback driver.\n");
|
||||
mod_timer(&net_timer, jiffies + HZ);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the new P2M table entry before reassigning the old data page.
|
||||
* Heed the comment in pgtable-2level.h:pte_page(). :-)
|
||||
@@ -280,7 +284,7 @@ static void net_rx_action(unsigned long unused)
|
||||
if ( unlikely(mcl[1].args[5] != 0) )
|
||||
{
|
||||
DPRINTK("Failed MMU update transferring to DOM%u\n", netif->domid);
|
||||
dealloc_mfn(mdata >> PAGE_SHIFT);
|
||||
free_mfn(mdata >> PAGE_SHIFT);
|
||||
status = NETIF_RSP_ERROR;
|
||||
}
|
||||
|
||||
@@ -307,7 +311,7 @@ static void net_rx_action(unsigned long unused)
|
||||
}
|
||||
|
||||
/* More work to do? */
|
||||
if ( !skb_queue_empty(&rx_queue) )
|
||||
if ( !skb_queue_empty(&rx_queue) && !timer_pending(&net_timer) )
|
||||
tasklet_schedule(&net_rx_tasklet);
|
||||
#if 0
|
||||
else
|
||||
@@ -315,6 +319,11 @@ static void net_rx_action(unsigned long unused)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void net_alarm(unsigned long unused)
|
||||
{
|
||||
tasklet_schedule(&net_rx_tasklet);
|
||||
}
|
||||
|
||||
struct net_device_stats *netif_be_get_stats(struct net_device *dev)
|
||||
{
|
||||
netif_t *netif = dev->priv;
|
||||
@@ -781,9 +790,16 @@ static int __init netback_init(void)
|
||||
|
||||
printk("Initialising Xen netif backend\n");
|
||||
|
||||
/* We can increase reservation by this much in net_rx_action(). */
|
||||
balloon_update_driver_allowance(NETIF_RX_RING_SIZE);
|
||||
|
||||
skb_queue_head_init(&rx_queue);
|
||||
skb_queue_head_init(&tx_queue);
|
||||
|
||||
init_timer(&net_timer);
|
||||
net_timer.data = 0;
|
||||
net_timer.function = net_alarm;
|
||||
|
||||
netif_interface_init();
|
||||
|
||||
if ( (mmap_vstart = allocate_empty_lowmem_region(MAX_PENDING_REQS)) == 0 )
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <asm-xen/evtchn.h>
|
||||
#include <asm-xen/ctrl_if.h>
|
||||
#include <asm-xen/xen-public/io/netif.h>
|
||||
#include <asm-xen/balloon.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#include <net/arp.h>
|
||||
@@ -409,6 +410,9 @@ static void network_alloc_rx_buffers(struct net_device *dev)
|
||||
rx_mcl[i].args[3] = 0;
|
||||
rx_mcl[i].args[4] = DOMID_SELF;
|
||||
|
||||
/* Tell the ballon driver what is going on. */
|
||||
balloon_update_driver_allowance(i);
|
||||
|
||||
/* Zap PTEs and give away pages in one big multicall. */
|
||||
(void)HYPERVISOR_multicall(rx_mcl, i+1);
|
||||
|
||||
@@ -557,14 +561,15 @@ static int netif_poll(struct net_device *dev, int *pbudget)
|
||||
/*
|
||||
* An error here is very odd. Usually indicates a backend bug,
|
||||
* low-memory condition, or that we didn't have reservation headroom.
|
||||
* Whatever - print an error and queue the id again straight away.
|
||||
*/
|
||||
if ( unlikely(rx->status <= 0) )
|
||||
{
|
||||
printk(KERN_ALERT "bad buffer on RX ring!(%d)\n", rx->status);
|
||||
if ( net_ratelimit() )
|
||||
printk(KERN_WARNING "Bad rx buffer (memory squeeze?).\n");
|
||||
np->rx->ring[MASK_NETIF_RX_IDX(np->rx->req_prod)].req.id = rx->id;
|
||||
wmb();
|
||||
np->rx->req_prod++;
|
||||
work_done--;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -595,6 +600,9 @@ static int netif_poll(struct net_device *dev, int *pbudget)
|
||||
__skb_queue_tail(&rxq, skb);
|
||||
}
|
||||
|
||||
/* Some pages are no longer absent... */
|
||||
balloon_update_driver_allowance(-work_done);
|
||||
|
||||
/* Do all the remapping work, and M->P updates, in one big hypercall. */
|
||||
if ( likely((mcl - rx_mcl) != 0) )
|
||||
{
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -213,23 +212,9 @@ static int __init privcmd_init(void)
|
||||
|
||||
privcmd_intf = create_xen_proc_entry("privcmd", 0400);
|
||||
if ( privcmd_intf != NULL )
|
||||
{
|
||||
privcmd_intf->owner = THIS_MODULE;
|
||||
privcmd_intf->nlink = 1;
|
||||
privcmd_intf->proc_fops = &privcmd_file_ops;
|
||||
}
|
||||
privcmd_intf->proc_fops = &privcmd_file_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void __exit privcmd_cleanup(void)
|
||||
{
|
||||
if ( privcmd_intf == NULL ) return;
|
||||
remove_xen_proc_entry("privcmd");
|
||||
privcmd_intf = NULL;
|
||||
}
|
||||
|
||||
|
||||
module_init(privcmd_init);
|
||||
module_exit(privcmd_cleanup);
|
||||
__initcall(privcmd_init);
|
||||
@@ -449,4 +449,7 @@ BUILDIO(b,b,char)
|
||||
BUILDIO(w,w,short)
|
||||
BUILDIO(l,,int)
|
||||
|
||||
/* We will be supplying our own /dev/mem implementation */
|
||||
#define ARCH_HAS_DEV_MEM
|
||||
|
||||
#endif
|
||||
@@ -424,14 +424,13 @@ extern pte_t *lookup_address(unsigned long address);
|
||||
#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
|
||||
do { \
|
||||
if (__dirty) { \
|
||||
if (likely(vma->vm_mm == current->mm)) { \
|
||||
xen_flush_page_update_queue(); \
|
||||
HYPERVISOR_update_va_mapping(address>>PAGE_SHIFT, \
|
||||
entry, UVMF_INVLPG); \
|
||||
} else { \
|
||||
xen_l1_entry_update((__ptep), (__entry).pte_low); \
|
||||
flush_tlb_page(__vma, __address); \
|
||||
} \
|
||||
if ( likely((__vma)->vm_mm == current->mm) ) { \
|
||||
xen_flush_page_update_queue(); \
|
||||
HYPERVISOR_update_va_mapping((__address)>>PAGE_SHIFT, (__entry), UVMF_INVLPG); \
|
||||
} else { \
|
||||
xen_l1_entry_update((__ptep), (__entry).pte_low); \
|
||||
flush_tlb_page((__vma), (__address)); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
@@ -461,14 +460,14 @@ void make_page_writable(void *va);
|
||||
void make_pages_readonly(void *va, unsigned int nr);
|
||||
void make_pages_writable(void *va, unsigned int nr);
|
||||
|
||||
static inline unsigned long arbitrary_virt_to_machine(void *va)
|
||||
{
|
||||
pgd_t *pgd = pgd_offset_k((unsigned long)va);
|
||||
pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
|
||||
pte_t *pte = pte_offset_kernel(pmd, (unsigned long)va);
|
||||
unsigned long pa = (*(unsigned long *)pte) & PAGE_MASK;
|
||||
return pa | ((unsigned long)va & (PAGE_SIZE-1));
|
||||
}
|
||||
#define arbitrary_virt_to_machine(__va) \
|
||||
({ \
|
||||
pgd_t *__pgd = pgd_offset_k((unsigned long)(__va)); \
|
||||
pmd_t *__pmd = pmd_offset(__pgd, (unsigned long)(__va)); \
|
||||
pte_t *__pte = pte_offset_kernel(__pmd, (unsigned long)(__va)); \
|
||||
unsigned long __pa = (*(unsigned long *)__pte) & PAGE_MASK; \
|
||||
__pa | ((unsigned long)(__va) & (PAGE_SIZE-1)); \
|
||||
})
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
@@ -476,6 +475,17 @@ static inline unsigned long arbitrary_virt_to_machine(void *va)
|
||||
#define kern_addr_valid(addr) (1)
|
||||
#endif /* !CONFIG_DISCONTIGMEM */
|
||||
|
||||
int direct_remap_area_pages(struct mm_struct *mm,
|
||||
unsigned long address,
|
||||
unsigned long machine_addr,
|
||||
unsigned long size,
|
||||
pgprot_t prot,
|
||||
domid_t domid);
|
||||
int __direct_remap_area_pages(struct mm_struct *mm,
|
||||
unsigned long address,
|
||||
unsigned long size,
|
||||
mmu_update_t *v);
|
||||
|
||||
#define io_remap_page_range(vma,from,phys,size,prot) \
|
||||
direct_remap_area_pages(vma->vm_mm,from,phys,size,prot,DOMID_IO)
|
||||
|
||||
|
||||
@@ -54,13 +54,6 @@ void xen_cpu_idle (void);
|
||||
/* arch/xen/i386/kernel/hypervisor.c */
|
||||
void do_hypervisor_callback(struct pt_regs *regs);
|
||||
|
||||
/* arch/xen/i386/mm/init.c */
|
||||
/* NOTE: caller must call flush_page_update_queue() */
|
||||
#define PROT_ON 1
|
||||
#define PROT_OFF 0
|
||||
void /* __init */ protect_page(pgd_t *dpgd, void *page, int mode);
|
||||
void /* __init */ protect_pagetable(pgd_t *dpgd, pgd_t *spgd, int mode);
|
||||
|
||||
/* arch/xen/i386/kernel/head.S */
|
||||
void lgdt_finish(void);
|
||||
|
||||
@@ -109,8 +102,6 @@ void MULTICALL_flush_page_update_queue(void);
|
||||
#ifdef CONFIG_XEN_PHYSDEV_ACCESS
|
||||
/* Allocate a contiguous empty region of low memory. Return virtual start. */
|
||||
unsigned long allocate_empty_lowmem_region(unsigned long pages);
|
||||
/* Deallocate a contiguous region of low memory. Return it to the allocator. */
|
||||
void deallocate_lowmem_region(unsigned long vstart, unsigned long pages);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Originally from linux/drivers/char/mem.c
|
||||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*
|
||||
* Added devfs support.
|
||||
* Jan-11-1998, C. Scott Ananian <cananian@alumni.princeton.edu>
|
||||
* Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com>
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/raw.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/devfs_fs_kernel.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/device.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static inline int uncached_access(struct file *file, unsigned long addr)
|
||||
{
|
||||
if (file->f_flags & O_SYNC)
|
||||
return 1;
|
||||
/* Xen sets correct MTRR type on non-RAM for us. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This funcion reads the *physical* memory. The f_pos points directly to the
|
||||
* memory location.
|
||||
*/
|
||||
static ssize_t read_mem(struct file * file, char __user * buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
unsigned long i, p = *ppos;
|
||||
ssize_t read = 0;
|
||||
void *v;
|
||||
|
||||
if ((v = ioremap(p, count)) == NULL) {
|
||||
/*
|
||||
* Some programs (e.g., dmidecode) groove off into weird RAM
|
||||
* areas where no table scan possibly exist (because Xen will
|
||||
* have stomped on them!). These programs get rather upset if
|
||||
* we let them know that Xen failed their access, so we fake
|
||||
* out a read of all zeroes. :-)
|
||||
*/
|
||||
for (i = 0; i < count; i++)
|
||||
if (put_user(0, buf+i))
|
||||
return -EFAULT;
|
||||
return count;
|
||||
}
|
||||
if (copy_to_user(buf, v, count))
|
||||
return -EFAULT;
|
||||
iounmap(v);
|
||||
|
||||
read += count;
|
||||
*ppos += read;
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
static ssize_t write_mem(struct file * file, const char __user * buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
unsigned long p = *ppos;
|
||||
ssize_t written = 0;
|
||||
void *v;
|
||||
|
||||
if ((v = ioremap(p, count)) == NULL)
|
||||
return -EFAULT;
|
||||
if (copy_to_user(v, buf, count))
|
||||
return -EFAULT;
|
||||
iounmap(v);
|
||||
|
||||
written += count;
|
||||
*ppos += written;
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
static int mmap_mem(struct file * file, struct vm_area_struct * vma)
|
||||
{
|
||||
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
|
||||
int uncached;
|
||||
|
||||
uncached = uncached_access(file, offset);
|
||||
if (uncached)
|
||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||
|
||||
/* Don't try to swap out physical pages.. */
|
||||
vma->vm_flags |= VM_RESERVED;
|
||||
|
||||
/*
|
||||
* Don't dump addresses that are not real memory to a core file.
|
||||
*/
|
||||
if (uncached)
|
||||
vma->vm_flags |= VM_IO;
|
||||
|
||||
if (io_remap_page_range(vma, vma->vm_start, offset,
|
||||
vma->vm_end-vma->vm_start, vma->vm_page_prot))
|
||||
return -EAGAIN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The memory devices use the full 32/64 bits of the offset, and so we cannot
|
||||
* check against negative addresses: they are ok. The return value is weird,
|
||||
* though, in that case (0).
|
||||
*
|
||||
* also note that seeking relative to the "end of file" isn't supported:
|
||||
* it has no meaning, so it returns -EINVAL.
|
||||
*/
|
||||
static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
|
||||
{
|
||||
loff_t ret;
|
||||
|
||||
down(&file->f_dentry->d_inode->i_sem);
|
||||
switch (orig) {
|
||||
case 0:
|
||||
file->f_pos = offset;
|
||||
ret = file->f_pos;
|
||||
force_successful_syscall_return();
|
||||
break;
|
||||
case 1:
|
||||
file->f_pos += offset;
|
||||
ret = file->f_pos;
|
||||
force_successful_syscall_return();
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
up(&file->f_dentry->d_inode->i_sem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int open_mem(struct inode * inode, struct file * filp)
|
||||
{
|
||||
return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
|
||||
}
|
||||
|
||||
struct file_operations mem_fops = {
|
||||
.llseek = memory_lseek,
|
||||
.read = read_mem,
|
||||
.write = write_mem,
|
||||
.mmap = mmap_mem,
|
||||
.open = open_mem,
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
/******************************************************************************
|
||||
* balloon.h
|
||||
*
|
||||
* Xen balloon driver - enables returning/claiming memory to/from Xen.
|
||||
*
|
||||
* Copyright (c) 2003, B Dragovic
|
||||
* Copyright (c) 2003-2004, M Williamson, K Fraser
|
||||
*
|
||||
* This file may be distributed separately from the Linux kernel, or
|
||||
* incorporated into other software packages, subject to the following license:
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this source file (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy, modify,
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __ASM_BALLOON_H__
|
||||
#define __ASM_BALLOON_H__
|
||||
|
||||
/*
|
||||
* Inform the balloon driver that it should allow some slop for device-driver
|
||||
* memory activities.
|
||||
*/
|
||||
extern void balloon_update_driver_allowance(long delta);
|
||||
|
||||
/* Give up unmapped pages to the balloon driver. */
|
||||
extern void balloon_put_pages(unsigned long *mfn_list, unsigned long nr_mfns);
|
||||
|
||||
/*
|
||||
* Prevent the balloon driver from changing the memory reservation during
|
||||
* a driver critical region.
|
||||
*/
|
||||
extern spinlock_t balloon_lock;
|
||||
#define balloon_lock(__flags) spin_lock_irqsave(&balloon_lock, __flags)
|
||||
#define balloon_unlock(__flags) spin_unlock_irqrestore(&balloon_lock, __flags)
|
||||
|
||||
#endif /* __ASM_BALLOON_H__ */
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
MAJOR = 1.3
|
||||
MAJOR = 2.0
|
||||
MINOR = 0
|
||||
SONAME = libxc.so.$(MAJOR)
|
||||
|
||||
|
||||
+7
-2
@@ -178,14 +178,19 @@ int xc_domain_setinitialmem(int xc_handle,
|
||||
unsigned int initial_memkb);
|
||||
|
||||
int xc_domain_setmaxmem(int xc_handle,
|
||||
u32 domid,
|
||||
unsigned int max_memkb);
|
||||
u32 domid,
|
||||
unsigned int max_memkb);
|
||||
|
||||
int xc_domain_setvmassist(int xc_handle,
|
||||
u32 domid,
|
||||
unsigned int cmd,
|
||||
unsigned int type);
|
||||
|
||||
typedef dom0_perfc_desc_t xc_perfc_desc_t;
|
||||
/* IMPORTANT: The caller is responsible for mlock()'ing the @desc array. */
|
||||
int xc_perfc_control(int xc_handle,
|
||||
u32 op,
|
||||
xc_perfc_desc_t *desc);
|
||||
|
||||
void *xc_map_foreign_range(int xc_handle, u32 dom,
|
||||
int size, int prot,
|
||||
|
||||
+17
-1
@@ -74,10 +74,26 @@ int xc_sched_id(int xc_handle,
|
||||
op.cmd = DOM0_SCHED_ID;
|
||||
op.interface_version = DOM0_INTERFACE_VERSION;
|
||||
|
||||
if((ret = do_dom0_op(xc_handle, &op))) return ret;
|
||||
if ( (ret = do_dom0_op(xc_handle, &op)) != 0 )
|
||||
return ret;
|
||||
|
||||
*sched_id = op.u.sched_id.sched_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xc_perfc_control(int xc_handle,
|
||||
u32 op,
|
||||
xc_perfc_desc_t *desc)
|
||||
{
|
||||
int rc;
|
||||
dom0_op_t dop;
|
||||
|
||||
dop.cmd = DOM0_PERFCCONTROL;
|
||||
dop.u.perfccontrol.op = op;
|
||||
dop.u.perfccontrol.desc = desc;
|
||||
|
||||
rc = do_dom0_op(xc_handle, &dop);
|
||||
|
||||
return (rc == 0) ? dop.u.perfccontrol.nr_counters : rc;
|
||||
}
|
||||
@@ -30,7 +30,7 @@ CFLAGS += -fno-strict-aliasing
|
||||
CFLAGS += -Wp,-MD,.$(@F).d
|
||||
DEPS = .*.d
|
||||
|
||||
MAJOR := 1.3
|
||||
MAJOR := 2.0
|
||||
MINOR := 0
|
||||
LIB_NAME := libxutil
|
||||
LIB := $(LIB_NAME).so
|
||||
|
||||
+6
-10
@@ -3,22 +3,18 @@ XEN_ROOT=../..
|
||||
include $(XEN_ROOT)/tools/Make.defs
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -O3
|
||||
CFLAGS = -Wall -Werror -O3
|
||||
|
||||
INCLUDES += -I $(XEN_XC)
|
||||
INCLUDES += -I $(XEN_LIBXC)
|
||||
INCLUDES += -I $(XEN_LIBXUTIL)
|
||||
|
||||
CFLAGS += $(INCLUDES)
|
||||
CFLAGS += $(INCLUDES)
|
||||
|
||||
HDRS = $(wildcard *.h)
|
||||
SRCS = $(wildcard *.c)
|
||||
OBJS = $(patsubst %.c,%.o,$(SRCS))
|
||||
|
||||
TARGETS =
|
||||
TARGETS = xenperf
|
||||
|
||||
INSTALL_BIN = $(TARGETS) xencons
|
||||
INSTALL_SBIN = netfix xm xend xensv
|
||||
INSTALL_SBIN = netfix xm xend xensv xenperf
|
||||
|
||||
all: $(TARGETS)
|
||||
$(MAKE) -C miniterm
|
||||
@@ -32,7 +28,7 @@ install: all
|
||||
|
||||
clean:
|
||||
$(RM) *.o $(TARGETS) *~
|
||||
$(MAKE) -C miniterm clean
|
||||
$(MAKE) -C miniterm clean
|
||||
|
||||
%: %.c $(HDRS) Makefile
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
$(CC) $(CFLAGS) -o $@ $< -L$(XEN_LIBXC) -lxc -L$(XEN_LIBXUTIL) -lxutil
|
||||
@@ -0,0 +1,104 @@
|
||||
/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
|
||||
****************************************************************************
|
||||
* (C) 2004 - Rolf Neugebauer - Intel Research Cambridge
|
||||
****************************************************************************
|
||||
*
|
||||
* File: xenperf.c
|
||||
* Author: Rolf Neugebauer (rolf.neugebauer@intel.com)
|
||||
* Date: Nov 2004
|
||||
*
|
||||
* Description:
|
||||
*/
|
||||
|
||||
|
||||
#include <xc.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i, j, xc_handle;
|
||||
xc_perfc_desc_t *pcd;
|
||||
unsigned int num, sum, reset = 0;
|
||||
|
||||
if ( argc > 1 )
|
||||
{
|
||||
char *p = argv[1];
|
||||
if ( (*p++ == '-') && (*p == 'r') )
|
||||
reset = 1;
|
||||
else
|
||||
{
|
||||
printf("%s: [-r]\n", argv[0]);
|
||||
printf("no args: print xen performance counters\n");
|
||||
printf(" -r : reset xen performance counters\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (xc_handle = xc_interface_open()) == -1 )
|
||||
{
|
||||
fprintf(stderr, "Error opening xc interface: %d (%s)\n",
|
||||
errno, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( reset )
|
||||
{
|
||||
if ( xc_perfc_control(xc_handle, DOM0_PERFCCONTROL_OP_RESET,
|
||||
NULL) < 0 )
|
||||
{
|
||||
fprintf(stderr, "Error reseting performance counters: %d (%s)\n",
|
||||
errno, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if ( (num = xc_perfc_control(xc_handle, DOM0_PERFCCONTROL_OP_QUERY,
|
||||
NULL)) < 0 )
|
||||
{
|
||||
fprintf(stderr, "Error getting number of perf counters: %d (%s)\n",
|
||||
errno, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
pcd = malloc(sizeof(*pcd) * num);
|
||||
|
||||
if ( mlock(pcd, sizeof(*pcd) * num) != 0 )
|
||||
{
|
||||
fprintf(stderr, "Could not mlock descriptor buffer: %d (%s)\n",
|
||||
errno, strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if ( xc_perfc_control(xc_handle, DOM0_PERFCCONTROL_OP_QUERY, pcd) <= 0 )
|
||||
{
|
||||
fprintf(stderr, "Error getting perf counter description: %d (%s)\n",
|
||||
errno, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
munlock(pcd, sizeof(*pcd) * num);
|
||||
|
||||
for ( i = 0; i < num; i++ )
|
||||
{
|
||||
printf ("%-35s ", pcd[i].name);
|
||||
|
||||
sum = 0;
|
||||
for ( j = 0; j < pcd[i].nr_vals; j++ )
|
||||
sum += pcd[i].vals[j];
|
||||
printf ("T=%10u ", (unsigned int)sum);
|
||||
|
||||
for ( j = 0; j < pcd[i].nr_vals; j++ )
|
||||
printf(" %10u", (unsigned int)pcd[i].vals[j]);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1299,9 +1299,6 @@ int do_mmu_update(
|
||||
u32 type_info;
|
||||
domid_t domid;
|
||||
|
||||
perfc_incrc(calls_to_mmu_update);
|
||||
perfc_addc(num_page_updates, count);
|
||||
|
||||
cleanup_writable_pagetable(d, PTWR_CLEANUP_ACTIVE | PTWR_CLEANUP_INACTIVE);
|
||||
|
||||
/*
|
||||
@@ -1331,6 +1328,9 @@ int do_mmu_update(
|
||||
}
|
||||
}
|
||||
|
||||
perfc_incrc(calls_to_mmu_update);
|
||||
perfc_addc(num_page_updates, count);
|
||||
|
||||
if ( unlikely(!array_access_ok(VERIFY_READ, ureqs, count, sizeof(req))) )
|
||||
{
|
||||
rc = -EFAULT;
|
||||
|
||||
@@ -341,6 +341,7 @@ process_guest_exception_and_events:
|
||||
leal DOMAIN_trap_bounce(%ebx),%edx
|
||||
testb $TBF_EXCEPTION,TRAPBOUNCE_flags(%edx)
|
||||
jz test_all_events
|
||||
cli # create_bounce_frame needs CLI for pre-exceptions to work
|
||||
call create_bounce_frame
|
||||
jmp test_all_events
|
||||
|
||||
|
||||
@@ -651,6 +651,16 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef PERF_COUNTERS
|
||||
case DOM0_PERFCCONTROL:
|
||||
{
|
||||
extern int perfc_control(dom0_perfccontrol_t *);
|
||||
ret = perfc_control(&op->u.perfccontrol);
|
||||
copy_to_user(u_dom0_op, op, sizeof(*op));
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
ret = arch_do_dom0_op(op,u_dom0_op);
|
||||
|
||||
|
||||
+109
-2
@@ -4,6 +4,8 @@
|
||||
#include <xen/time.h>
|
||||
#include <xen/perfc.h>
|
||||
#include <xen/keyhandler.h>
|
||||
#include <public/dom0_ops.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#undef PERFCOUNTER
|
||||
#undef PERFCOUNTER_CPU
|
||||
@@ -79,8 +81,9 @@ void perfc_reset(unsigned char key)
|
||||
s_time_t now = NOW();
|
||||
atomic_t *counters = (atomic_t *)&perfcounters;
|
||||
|
||||
printk("Xen performance counters RESET (now = 0x%08X:%08X)\n",
|
||||
(u32)(now>>32), (u32)now);
|
||||
if ( key != '\0' )
|
||||
printk("Xen performance counters RESET (now = 0x%08X:%08X)\n",
|
||||
(u32)(now>>32), (u32)now);
|
||||
|
||||
/* leave STATUS counters alone -- don't reset */
|
||||
|
||||
@@ -109,3 +112,107 @@ void perfc_reset(unsigned char key)
|
||||
}
|
||||
}
|
||||
|
||||
static dom0_perfc_desc_t perfc_d[NR_PERFCTRS];
|
||||
static int perfc_init = 0;
|
||||
static int perfc_copy_info(dom0_perfc_desc_t *desc)
|
||||
{
|
||||
unsigned int i, j;
|
||||
atomic_t *counters = (atomic_t *)&perfcounters;
|
||||
|
||||
if ( desc == NULL )
|
||||
return 0;
|
||||
|
||||
/* We only copy the name and array-size information once. */
|
||||
if ( !perfc_init )
|
||||
{
|
||||
for ( i = 0; i < NR_PERFCTRS; i++ )
|
||||
{
|
||||
strncpy(perfc_d[i].name, perfc_info[i].name,
|
||||
sizeof(perfc_d[i].name));
|
||||
perfc_d[i].name[sizeof(perfc_d[i].name)-1] = '\0';
|
||||
|
||||
switch ( perfc_info[i].type )
|
||||
{
|
||||
case TYPE_SINGLE:
|
||||
case TYPE_S_SINGLE:
|
||||
perfc_d[i].nr_vals = 1;
|
||||
break;
|
||||
case TYPE_CPU:
|
||||
case TYPE_S_CPU:
|
||||
perfc_d[i].nr_vals = smp_num_cpus;
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
case TYPE_S_ARRAY:
|
||||
perfc_d[i].nr_vals = perfc_info[i].nr_elements;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( perfc_d[i].nr_vals > ARRAY_SIZE(perfc_d[i].vals) )
|
||||
perfc_d[i].nr_vals = ARRAY_SIZE(perfc_d[i].vals);
|
||||
}
|
||||
|
||||
perfc_init = 1;
|
||||
}
|
||||
|
||||
/* We gather the counts together every time. */
|
||||
for ( i = 0; i < NR_PERFCTRS; i++ )
|
||||
{
|
||||
switch ( perfc_info[i].type )
|
||||
{
|
||||
case TYPE_SINGLE:
|
||||
case TYPE_S_SINGLE:
|
||||
perfc_d[i].vals[0] = atomic_read(&counters[0]);
|
||||
counters += 1;
|
||||
break;
|
||||
case TYPE_CPU:
|
||||
case TYPE_S_CPU:
|
||||
for ( j = 0; j < perfc_d[i].nr_vals; j++ )
|
||||
perfc_d[i].vals[j] = atomic_read(&counters[j]);
|
||||
counters += NR_CPUS;
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
case TYPE_S_ARRAY:
|
||||
for ( j = 0; j < perfc_d[i].nr_vals; j++ )
|
||||
perfc_d[i].vals[j] = atomic_read(&counters[j]);
|
||||
counters += perfc_info[i].nr_elements;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (copy_to_user(desc, perfc_d, NR_PERFCTRS * sizeof(*desc)) ?
|
||||
-EFAULT : 0);
|
||||
}
|
||||
|
||||
/* Dom0 control of perf counters */
|
||||
int perfc_control(dom0_perfccontrol_t *pc)
|
||||
{
|
||||
static spinlock_t lock = SPIN_LOCK_UNLOCKED;
|
||||
u32 op = pc->op;
|
||||
int rc;
|
||||
|
||||
pc->nr_counters = NR_PERFCTRS;
|
||||
|
||||
spin_lock(&lock);
|
||||
|
||||
switch ( op )
|
||||
{
|
||||
case DOM0_PERFCCONTROL_OP_RESET:
|
||||
perfc_copy_info(pc->desc);
|
||||
perfc_reset(0);
|
||||
rc = 0;
|
||||
break;
|
||||
|
||||
case DOM0_PERFCCONTROL_OP_QUERY:
|
||||
perfc_copy_info(pc->desc);
|
||||
rc = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock(&lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -386,6 +386,25 @@ typedef struct {
|
||||
u32 __pad1;
|
||||
} PACKED dom0_read_memtype_t; /* 32 bytes */
|
||||
|
||||
/* Interface for controlling Xen software performance counters. */
|
||||
#define DOM0_PERFCCONTROL 34
|
||||
/* Sub-operations: */
|
||||
#define DOM0_PERFCCONTROL_OP_RESET 1 /* Reset all counters to zero. */
|
||||
#define DOM0_PERFCCONTROL_OP_QUERY 2 /* Get perfctr information. */
|
||||
typedef struct {
|
||||
u8 name[80]; /* 0: name of perf counter */
|
||||
u32 nr_vals; /* 80: number of values for this counter */
|
||||
u32 vals[64]; /* 84: array of values */
|
||||
} PACKED dom0_perfc_desc_t; /* 340 bytes */
|
||||
typedef struct {
|
||||
/* IN variables. */
|
||||
u32 op; /* 0: DOM0_PERFCCONTROL_OP_??? */
|
||||
/* OUT variables. */
|
||||
u32 nr_counters; /* 4: number of counters */
|
||||
dom0_perfc_desc_t *desc; /* 8: counter information (or NULL) */
|
||||
MEMORY_PADDING;
|
||||
} PACKED dom0_perfccontrol_t; /* 16 bytes */
|
||||
|
||||
typedef struct {
|
||||
u32 cmd; /* 0 */
|
||||
u32 interface_version; /* 4 */ /* DOM0_INTERFACE_VERSION */
|
||||
@@ -419,6 +438,7 @@ typedef struct {
|
||||
dom0_add_memtype_t add_memtype;
|
||||
dom0_del_memtype_t del_memtype;
|
||||
dom0_read_memtype_t read_memtype;
|
||||
dom0_perfccontrol_t perfccontrol;
|
||||
} PACKED u;
|
||||
} PACKED dom0_op_t; /* 80 bytes */
|
||||
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
#ifndef __XEN_PUBLIC_XEN_H__
|
||||
#define __XEN_PUBLIC_XEN_H__
|
||||
|
||||
#ifndef PACKED
|
||||
/* GCC-specific way to pack structure definitions (no implicit padding). */
|
||||
#define PACKED __attribute__ ((packed))
|
||||
#endif
|
||||
|
||||
#if defined(__i386__)
|
||||
#include "arch-x86_32.h"
|
||||
|
||||