bitkeeper revision 1.1159.170.59 (41b4c2fdJ2gj_BWy27Vj3ptayZp_yg)

sync w/ head.
This commit is contained in:
cl349@arcadians.cl.cam.ac.uk committed 2004-12-06 20:37:17 +00:00
commit 3776bbe6f6
42 files changed
+1043 -899

No files matched your search

+3
View File
@@ -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
+1 -1
View File
@@ -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/*
+21 -12
View File
@@ -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++ )
{
+15 -34
View File
@@ -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;
+1
View File
@@ -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);
+20 -24
View File
@@ -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 -1
View File
@@ -1,5 +1,5 @@
MAJOR = 1.3
MAJOR = 2.0
MINOR = 0
SONAME = libxc.so.$(MAJOR)
+7 -2
View File
@@ -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
View File
@@ -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;
}
+1 -1
View File
@@ -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
View File
@@ -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
+104
View File
@@ -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;
}
+3 -3
View File
@@ -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;
+1
View File
@@ -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
+10
View File
@@ -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
View File
@@ -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;
}
+20
View File
@@ -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 */
+2
View File
@@ -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"
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.