diff options
author | bd240@boulderdash.cl.cam.ac.uk <bd240@boulderdash.cl.cam.ac.uk> | 2003-01-26 11:30:21 +0000 |
---|---|---|
committer | bd240@boulderdash.cl.cam.ac.uk <bd240@boulderdash.cl.cam.ac.uk> | 2003-01-26 11:30:21 +0000 |
commit | 1e776af7cca070828ee0c40eaa4ec036d0a14dc4 (patch) | |
tree | 0485c82d5ea3550caccac4e9cc7c883cb783cae8 | |
parent | 430d2e106d329b19167290281e92d14279051b2f (diff) | |
parent | 76858e72974578745ce60257367fd34e21a08c30 (diff) | |
download | xen-1e776af7cca070828ee0c40eaa4ec036d0a14dc4.tar.gz xen-1e776af7cca070828ee0c40eaa4ec036d0a14dc4.tar.bz2 xen-1e776af7cca070828ee0c40eaa4ec036d0a14dc4.zip |
bitkeeper revision 1.18 (3e33c6cdMqnqQnkIxpq_9HHmWHAHfA)
Merge boulderdash.cl.cam.ac.uk:/usr/groups/xeno/BK/xeno
into boulderdash.cl.cam.ac.uk:/local/scratch/bd240/xeno
-rw-r--r-- | .rootkeys | 1 | ||||
-rw-r--r-- | BitKeeper/etc/logging_ok | 1 | ||||
-rw-r--r-- | xen-2.4.16/arch/i386/mm.c | 3 | ||||
-rw-r--r-- | xen-2.4.16/common/domain.c | 55 | ||||
-rw-r--r-- | xen-2.4.16/common/domain_page.c | 67 | ||||
-rw-r--r-- | xen-2.4.16/common/memory.c | 141 | ||||
-rw-r--r-- | xen-2.4.16/common/page_alloc.c | 54 | ||||
-rw-r--r-- | xen-2.4.16/common/slab.c | 106 | ||||
-rw-r--r-- | xen-2.4.16/include/asm-i386/domain_page.h | 16 | ||||
-rw-r--r-- | xen-2.4.16/include/asm-i386/page.h | 4 | ||||
-rw-r--r-- | xen-2.4.16/include/xeno/slab.h | 3 | ||||
-rw-r--r-- | xen-2.4.16/net/dev.c | 22 |
12 files changed, 350 insertions, 123 deletions
@@ -39,6 +39,7 @@ 3ddb79bdrqnW93GR9gZk1OJe1qK-iQ xen-2.4.16/common/brlock.c 3ddb79bdLX_P6iB7ILiblRLWvebapg xen-2.4.16/common/dom0_ops.c 3ddb79bdYO5D8Av12NHqPeSviav7cg xen-2.4.16/common/domain.c +3e32af9aRnYGl4GMOaDKp7JdfhOGhg xen-2.4.16/common/domain_page.c 3ddb79bdeyutmaXEfpQvvxj7eQ0fCw xen-2.4.16/common/event.c 3ddb79bd9drcFPVxd4w2GPOIjLlXpA xen-2.4.16/common/kernel.c 3ddb79bduhSEZI8xa7IbGQCpap5y2A xen-2.4.16/common/lib.c diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index af88da45af..2fd8b201d7 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -1,6 +1,7 @@ akw27@boulderdash.cl.cam.ac.uk akw27@labyrinth.cl.cam.ac.uk bd240@boulderdash.cl.cam.ac.uk +iap10@labyrinth.cl.cam.ac.uk kaf24@labyrinth.cl.cam.ac.uk kaf24@plym.cl.cam.ac.uk kaf24@striker.cl.cam.ac.uk diff --git a/xen-2.4.16/arch/i386/mm.c b/xen-2.4.16/arch/i386/mm.c index 2260882efc..29553a9c9b 100644 --- a/xen-2.4.16/arch/i386/mm.c +++ b/xen-2.4.16/arch/i386/mm.c @@ -102,7 +102,8 @@ long do_stack_and_ldt_switch( if ( ldts != current->mm.ldt_sel ) { - unsigned long *ptabent = GET_GDT_ADDRESS(current); + unsigned long *ptabent; + ptabent = (unsigned long *)GET_GDT_ADDRESS(current); /* Out of range for GDT table? */ if ( (ldts * 8) > GET_GDT_ENTRIES(current) ) return -1; ptabent += ldts * 2; /* 8 bytes per desc == 2 * unsigned long */ diff --git a/xen-2.4.16/common/domain.c b/xen-2.4.16/common/domain.c index 7ccf9501d0..5fefac1747 100644 --- a/xen-2.4.16/common/domain.c +++ b/xen-2.4.16/common/domain.c @@ -554,7 +554,7 @@ int setup_guestos(struct task_struct *p, dom0_newdomain_t *params) unsigned int ft_size = 0; start_info_t *virt_startinfo_address; unsigned long long time; - l2_pgentry_t *l2tab; + l2_pgentry_t *l2tab, *l2start; l1_pgentry_t *l1tab = NULL; struct pfn_info *page = NULL; net_ring_t *net_ring; @@ -609,7 +609,7 @@ int setup_guestos(struct task_struct *p, dom0_newdomain_t *params) * filled in by now !! */ phys_l2tab = ALLOC_FRAME_FROM_DOMAIN(); - l2tab = map_domain_mem(phys_l2tab); + l2start = l2tab = map_domain_mem(phys_l2tab); memcpy(l2tab, idle_pg_table[p->processor], PAGE_SIZE); l2tab[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT] = mk_l2_pgentry(__pa(p->mm.perdomain_pt) | __PAGE_HYPERVISOR); @@ -630,17 +630,16 @@ int setup_guestos(struct task_struct *p, dom0_newdomain_t *params) if(dom == 0) ft_size = frame_table_size; - phys_l2tab += l2_table_offset(virt_load_address)*sizeof(l2_pgentry_t); + l2tab += l2_table_offset(virt_load_address); for ( cur_address = start_address; cur_address != (end_address + PAGE_SIZE + ft_size); cur_address += PAGE_SIZE ) { if ( !((unsigned long)l1tab & (PAGE_SIZE-1)) ) { + if ( l1tab != NULL ) unmap_domain_mem(l1tab-1); phys_l1tab = ALLOC_FRAME_FROM_DOMAIN(); - l2tab = map_domain_mem(phys_l2tab); - *l2tab = mk_l2_pgentry(phys_l1tab|L2_PROT); - phys_l2tab += sizeof(l2_pgentry_t); + *l2tab++ = mk_l2_pgentry(phys_l1tab|L2_PROT); l1tab = map_domain_mem(phys_l1tab); clear_page(l1tab); l1tab += l1_table_offset( @@ -656,43 +655,39 @@ int setup_guestos(struct task_struct *p, dom0_newdomain_t *params) page->type_count = page->tot_count = 1; } } + unmap_domain_mem(l1tab-1); /* Pages that are part of page tables must be read-only. */ vaddr = virt_load_address + alloc_address - start_address; - phys_l2tab = pagetable_val(p->mm.pagetable) + - (l2_table_offset(vaddr) * sizeof(l2_pgentry_t)); - l2tab = map_domain_mem(phys_l2tab); - phys_l1tab = l2_pgentry_to_phys(*l2tab) + - (l1_table_offset(vaddr) * sizeof(l1_pgentry_t)); - phys_l2tab += sizeof(l2_pgentry_t); - l1tab = map_domain_mem(phys_l1tab); + l2tab = l2start + l2_table_offset(vaddr); + l1tab = map_domain_mem(l2_pgentry_to_phys(*l2tab)); + l1tab += l1_table_offset(vaddr); + l2tab++; for ( cur_address = alloc_address; cur_address != end_address; cur_address += PAGE_SIZE ) { - *l1tab++ = mk_l1_pgentry(l1_pgentry_val(*l1tab) & ~_PAGE_RW); if ( !((unsigned long)l1tab & (PAGE_SIZE-1)) ) { - l2tab = map_domain_mem(phys_l2tab); - phys_l1tab = l2_pgentry_to_phys(*l2tab); - phys_l2tab += sizeof(l2_pgentry_t); - l1tab = map_domain_mem(phys_l1tab); + unmap_domain_mem(l1tab-1); + l1tab = map_domain_mem(l2_pgentry_to_phys(*l2tab)); + l2tab++; } + *l1tab++ = mk_l1_pgentry(l1_pgentry_val(*l1tab) & ~_PAGE_RW); page = frame_table + (cur_address >> PAGE_SHIFT); page->flags = dom | PGT_l1_page_table; page->tot_count++; } + unmap_domain_mem(l1tab-1); page->flags = dom | PGT_l2_page_table; /* Map in the the shared info structure. */ virt_shinfo_address = end_address - start_address + virt_load_address; - phys_l2tab = pagetable_val(p->mm.pagetable) + - (l2_table_offset(virt_shinfo_address) * sizeof(l2_pgentry_t)); - l2tab = map_domain_mem(phys_l2tab); - phys_l1tab = l2_pgentry_to_phys(*l2tab) + - (l1_table_offset(virt_shinfo_address) * sizeof(l1_pgentry_t)); - l1tab = map_domain_mem(phys_l1tab); + l2tab = l2start + l2_table_offset(virt_shinfo_address); + l1tab = map_domain_mem(l2_pgentry_to_phys(*l2tab)); + l1tab += l1_table_offset(virt_shinfo_address); *l1tab = mk_l1_pgentry(__pa(p->shared_info)|L1_PROT); + unmap_domain_mem(l1tab); /* Set up shared info area. */ rdtscll(time); @@ -709,13 +704,11 @@ int setup_guestos(struct task_struct *p, dom0_newdomain_t *params) cur_address < virt_ftable_end_addr; cur_address += PAGE_SIZE) { - phys_l2tab = pagetable_val(p->mm.pagetable) + - (l2_table_offset(cur_address) * sizeof(l2_pgentry_t)); - l2tab = map_domain_mem(phys_l2tab); - phys_l1tab = l2_pgentry_to_phys(*l2tab) + - (l1_table_offset(cur_address) * sizeof(l1_pgentry_t)); - l1tab = map_domain_mem(phys_l1tab); + l2tab = l2start + l2_table_offset(cur_address); + l1tab = map_domain_mem(l2_pgentry_to_phys(*l2tab)); + l1tab += l1_table_offset(cur_address); *l1tab = mk_l1_pgentry(__pa(ft_mapping)|L1_PROT); + unmap_domain_mem(l1tab); ft_mapping += PAGE_SIZE; } } @@ -724,6 +717,8 @@ int setup_guestos(struct task_struct *p, dom0_newdomain_t *params) (alloc_address - start_address - PAGE_SIZE + virt_load_address); virt_stack_address = (unsigned long)virt_startinfo_address; + unmap_domain_mem(l2start); + /* Install the new page tables. */ __cli(); __asm__ __volatile__ ( diff --git a/xen-2.4.16/common/domain_page.c b/xen-2.4.16/common/domain_page.c new file mode 100644 index 0000000000..2e37b72c5c --- /dev/null +++ b/xen-2.4.16/common/domain_page.c @@ -0,0 +1,67 @@ +/****************************************************************************** + * domain_page.h + * + * Allow temporary mapping of domain pages. Based on ideas from the + * Linux PKMAP code -- the copyrights and credits are retained below. + */ + +/* + * (C) 1999 Andrea Arcangeli, SuSE GmbH, andrea@suse.de + * Gerhard Wichert, Siemens AG, Gerhard.Wichert@pdb.siemens.de * + * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com> + */ + +#include <xeno/config.h> +#include <xeno/sched.h> +#include <xeno/mm.h> +#include <asm/domain_page.h> +#include <asm/pgalloc.h> + +static unsigned int map_idx[NR_CPUS]; + +/* Use a spare PTE bit to mark entries ready for recycling. */ +#define READY_FOR_TLB_FLUSH (1<<10) + +static void flush_all_ready_maps(void) +{ + unsigned long *cache = mapcache[smp_processor_id()]; + + /* A bit skanky -- depends on having an aligned PAGE_SIZE set of PTEs. */ + do { if ( (*cache & READY_FOR_TLB_FLUSH) ) *cache = 0; } + while ( ((unsigned long)(++cache) & ~PAGE_MASK) != 0 ); + + local_flush_tlb(); +} + + +void *map_domain_mem(unsigned long pa) +{ + unsigned long va; + int cpu = smp_processor_id(); + unsigned int idx; + unsigned long *cache = mapcache[cpu]; + unsigned long flags; + + local_irq_save(flags); + + for ( ; ; ) + { + idx = map_idx[cpu] = (map_idx[cpu] + 1) & (MAPCACHE_ENTRIES - 1); + if ( idx == 0 ) flush_all_ready_maps(); + if ( cache[idx] == 0 ) break; + } + + cache[idx] = (pa & PAGE_MASK) | PAGE_HYPERVISOR; + + local_irq_restore(flags); + + va = MAPCACHE_VIRT_START + (idx << PAGE_SHIFT) + (pa & ~PAGE_MASK); + return (void *)va; +} + +void unmap_domain_mem(void *va) +{ + unsigned int idx; + idx = ((unsigned long)va - MAPCACHE_VIRT_START) >> PAGE_SHIFT; + mapcache[smp_processor_id()][idx] |= READY_FOR_TLB_FLUSH; +} diff --git a/xen-2.4.16/common/memory.c b/xen-2.4.16/common/memory.c index 6c8deafff9..fad0768e8b 100644 --- a/xen-2.4.16/common/memory.c +++ b/xen-2.4.16/common/memory.c @@ -181,13 +181,17 @@ #define MEM_LOG(_f, _a...) ((void)0) #endif +/* Domain 0 is allowed to submit requests on behalf of others. */ +#define DOMAIN_OKAY(_f) \ + ((((_f) & PG_domain_mask) == current->domain) || (current->domain == 0)) + /* 'get' checks parameter for validity before inc'ing refcnt. */ static int get_l2_table(unsigned long page_nr); static int get_l1_table(unsigned long page_nr); static int get_page(unsigned long page_nr, int writeable); static int inc_page_refcnt(unsigned long page_nr, unsigned int type); /* 'put' does no checking because if refcnt not zero, entity must be valid. */ -static int put_l2_table(unsigned long page_nr); +static void put_l2_table(unsigned long page_nr); static void put_l1_table(unsigned long page_nr); static void put_page(unsigned long page_nr, int writeable); static int dec_page_refcnt(unsigned long page_nr, unsigned int type); @@ -247,14 +251,14 @@ static int inc_page_refcnt(unsigned long page_nr, unsigned int type) if ( page_nr >= max_page ) { MEM_LOG("Page out of range (%08lx>%08lx)", page_nr, max_page); - return(-1); + return -1; } page = frame_table + page_nr; flags = page->flags; - if ( (flags & PG_domain_mask) != current->domain ) + if ( !DOMAIN_OKAY(flags) ) { MEM_LOG("Bad page domain (%ld)", flags & PG_domain_mask); - return(-1); + return -1; } if ( (flags & PG_type_mask) != type ) { @@ -263,13 +267,13 @@ static int inc_page_refcnt(unsigned long page_nr, unsigned int type) MEM_LOG("Page %08lx bad type/count (%08lx!=%08x) cnt=%ld", page_nr << PAGE_SHIFT, flags & PG_type_mask, type, page_type_count(page)); - return(-1); + return -1; } page->flags |= type; } get_page_tot(page); - return(get_page_type(page)); + return get_page_type(page); } /* Return new refcnt, or -1 on error. */ @@ -281,21 +285,46 @@ static int dec_page_refcnt(unsigned long page_nr, unsigned int type) if ( page_nr >= max_page ) { MEM_LOG("Page out of range (%08lx>%08lx)", page_nr, max_page); - return(-1); + return -1; } page = frame_table + page_nr; - if ( (page->flags & (PG_type_mask | PG_domain_mask)) != - (type | current->domain) ) + if ( !DOMAIN_OKAY(page->flags) || + ((page->flags & PG_type_mask) != type) ) { MEM_LOG("Bad page type/domain (dom=%ld) (type %ld != expected %d)", page->flags & PG_domain_mask, page->flags & PG_type_mask, type); - return(-1); + return -1; } ASSERT(page_type_count(page) != 0); if ( (ret = put_page_type(page)) == 0 ) page->flags &= ~PG_type_mask; put_page_tot(page); - return(ret); + return ret; +} + + +/* We allow a L2 table to map itself, to achieve a linear pagetable. */ +/* NB. There's no need for a put_twisted_l2_table() function!! */ +static int get_twisted_l2_table(unsigned long entry_pfn, l2_pgentry_t l2e) +{ + unsigned long l2v = l2_pgentry_val(l2e); + + /* Clearly the mapping must be read-only :-) */ + if ( (l2v & _PAGE_RW) ) + { + MEM_LOG("Attempt to install twisted L2 entry with write permissions"); + return -1; + } + + /* This is a sufficient final check. */ + if ( (l2v >> PAGE_SHIFT) != entry_pfn ) + { + MEM_LOG("L2 tables may not map _other_ L2 tables!\n"); + return -1; + } + + /* We don't bump the reference counts. */ + return 0; } @@ -305,7 +334,7 @@ static int get_l2_table(unsigned long page_nr) int i, ret=0; ret = inc_page_refcnt(page_nr, PGT_l2_page_table); - if ( ret != 0 ) return((ret < 0) ? ret : 0); + if ( ret != 0 ) return (ret < 0) ? ret : 0; /* NEW level-2 page table! Deal with every PDE in the table. */ p_l2_entry = map_domain_mem(page_nr << PAGE_SHIFT); @@ -317,12 +346,13 @@ static int get_l2_table(unsigned long page_nr) { MEM_LOG("Bad L2 page type settings %04lx", l2_pgentry_val(l2_entry) & (_PAGE_GLOBAL|_PAGE_PSE)); - return(-1); + ret = -1; + goto out; } + /* Assume we're mapping an L1 table, falling back to twisted L2. */ ret = get_l1_table(l2_pgentry_to_pagenr(l2_entry)); - if ( ret ) return(ret); - p_l2_entry = map_domain_mem((page_nr << PAGE_SHIFT) + - ((i+1) * sizeof(l2_pgentry_t))); + if ( ret ) ret = get_twisted_l2_table(page_nr, l2_entry); + if ( ret ) goto out; } /* Now we simply slap in our high mapping. */ @@ -333,7 +363,9 @@ static int get_l2_table(unsigned long page_nr) DOMAIN_ENTRIES_PER_L2_PAGETABLE] = mk_l2_pgentry(__pa(current->mm.perdomain_pt) | __PAGE_HYPERVISOR); - return(ret); + out: + unmap_domain_mem(p_l2_entry); + return ret; } static int get_l1_table(unsigned long page_nr) @@ -343,7 +375,7 @@ static int get_l1_table(unsigned long page_nr) /* Update ref count for page pointed at by PDE. */ ret = inc_page_refcnt(page_nr, PGT_l1_page_table); - if ( ret != 0 ) return((ret < 0) ? ret : 0); + if ( ret != 0 ) return (ret < 0) ? ret : 0; /* NEW level-1 page table! Deal with every PTE in the table. */ p_l1_entry = map_domain_mem(page_nr << PAGE_SHIFT); @@ -357,14 +389,18 @@ static int get_l1_table(unsigned long page_nr) MEM_LOG("Bad L1 page type settings %04lx", l1_pgentry_val(l1_entry) & (_PAGE_GLOBAL|_PAGE_PAT)); - return(-1); + ret = -1; + goto out; } ret = get_page(l1_pgentry_to_pagenr(l1_entry), l1_pgentry_val(l1_entry) & _PAGE_RW); - if ( ret ) return(ret); + if ( ret ) goto out; } - return(ret); + out: + /* Make sure we unmap the right page! */ + unmap_domain_mem(p_l1_entry-1); + return ret; } static int get_page(unsigned long page_nr, int writeable) @@ -380,7 +416,7 @@ static int get_page(unsigned long page_nr, int writeable) } page = frame_table + page_nr; flags = page->flags; - if ( (flags & PG_domain_mask) != current->domain ) + if ( !DOMAIN_OKAY(flags) ) { MEM_LOG("Bad page domain (%ld)", flags & PG_domain_mask); return(-1); @@ -407,28 +443,23 @@ static int get_page(unsigned long page_nr, int writeable) return(0); } -static int put_l2_table(unsigned long page_nr) +static void put_l2_table(unsigned long page_nr) { l2_pgentry_t *p_l2_entry, l2_entry; - int i, ret; + int i; - ret = dec_page_refcnt(page_nr, PGT_l2_page_table); - if ( ret != 0 ) return((ret < 0) ? ret : 0); + if ( dec_page_refcnt(page_nr, PGT_l2_page_table) ) return; /* We had last reference to level-2 page table. Free the PDEs. */ p_l2_entry = map_domain_mem(page_nr << PAGE_SHIFT); - for ( i = 0; i < HYPERVISOR_ENTRIES_PER_L2_PAGETABLE; i++ ) + for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ ) { l2_entry = *p_l2_entry++; if ( (l2_pgentry_val(l2_entry) & _PAGE_PRESENT) ) - { put_l1_table(l2_pgentry_to_pagenr(l2_entry)); - p_l2_entry = map_domain_mem((page_nr << PAGE_SHIFT) + - ((i+1) * sizeof(l2_pgentry_t))); - } } - return(0); + unmap_domain_mem(p_l2_entry); } static void put_l1_table(unsigned long page_nr) @@ -436,7 +467,7 @@ static void put_l1_table(unsigned long page_nr) l1_pgentry_t *p_l1_entry, l1_entry; int i; - if ( dec_page_refcnt(page_nr, PGT_l1_page_table) != 0 ) return; + if ( dec_page_refcnt(page_nr, PGT_l1_page_table) ) return; /* We had last reference to level-1 page table. Free the PTEs. */ p_l1_entry = map_domain_mem(page_nr << PAGE_SHIFT); @@ -449,6 +480,9 @@ static void put_l1_table(unsigned long page_nr) l1_pgentry_val(l1_entry) & _PAGE_RW); } } + + /* Make sure we unmap the right page! */ + unmap_domain_mem(p_l1_entry-1); } static void put_page(unsigned long page_nr, int writeable) @@ -456,7 +490,7 @@ static void put_page(unsigned long page_nr, int writeable) struct pfn_info *page; ASSERT(page_nr < max_page); page = frame_table + page_nr; - ASSERT((page->flags & PG_domain_mask) == current->domain); + ASSERT(DOMAIN_OKAY(page->flags)); ASSERT((!writeable) || ((page_type_count(page) != 0) && ((page->flags & PG_type_mask) == PGT_writeable_page))); @@ -484,12 +518,6 @@ static int mod_l2_entry(unsigned long pa, l2_pgentry_t new_l2_entry) goto fail; } - /* - * Write the new value while pointer is still valid. The mapping cache - * entry for p_l2_entry may get clobbered by {put,get}_l1_table. - */ - *p_l2_entry = new_l2_entry; - if ( (l2_pgentry_val(new_l2_entry) & _PAGE_PRESENT) ) { if ( (l2_pgentry_val(new_l2_entry) & (_PAGE_GLOBAL|_PAGE_PSE)) ) @@ -508,7 +536,9 @@ static int mod_l2_entry(unsigned long pa, l2_pgentry_t new_l2_entry) put_l1_table(l2_pgentry_to_pagenr(old_l2_entry)); } - if ( get_l1_table(l2_pgentry_to_pagenr(new_l2_entry)) ) + /* Assume we're mapping an L1 table, falling back to twisted L2. */ + if ( get_l1_table(l2_pgentry_to_pagenr(new_l2_entry)) && + get_twisted_l2_table(pa >> PAGE_SHIFT, new_l2_entry) ) goto fail; } } @@ -517,16 +547,13 @@ static int mod_l2_entry(unsigned long pa, l2_pgentry_t new_l2_entry) put_l1_table(l2_pgentry_to_pagenr(old_l2_entry)); } - return(0); + *p_l2_entry = new_l2_entry; + unmap_domain_mem(p_l2_entry); + return 0; fail: - /* - * On failure we put the old value back. We need to regrab the - * mapping of the physical page frame. - */ - p_l2_entry = map_domain_mem(pa); - *p_l2_entry = old_l2_entry; - return(-1); + unmap_domain_mem(p_l2_entry); + return -1; } @@ -571,12 +598,13 @@ static int mod_l1_entry(unsigned long pa, l1_pgentry_t new_l1_entry) l1_pgentry_val(old_l1_entry) & _PAGE_RW); } - /* p_l1_entry is still valid here */ *p_l1_entry = new_l1_entry; + unmap_domain_mem(p_l1_entry); + return 0; - return(0); fail: - return(-1); + unmap_domain_mem(p_l1_entry); + return -1; } @@ -614,7 +642,7 @@ static int do_extended_command(unsigned long ptr, unsigned long val) break; case PGEXT_UNPIN_TABLE: - if ( (page->flags & PG_domain_mask) != current->domain ) + if ( !DOMAIN_OKAY(page->flags) ) { err = 1; MEM_LOG("Page %08lx bad domain (dom=%ld)", @@ -700,7 +728,7 @@ int do_process_page_updates(page_update_request_t *updates, int count) case PGREQ_NORMAL: page = frame_table + pfn; flags = page->flags; - if ( (flags & PG_domain_mask) == current->domain ) + if ( DOMAIN_OKAY(flags) ) { switch ( (flags & PG_type_mask) ) { @@ -730,8 +758,9 @@ int do_process_page_updates(page_update_request_t *updates, int count) flags = page->flags; if ( (flags | current->domain) == PGT_l1_page_table ) { - - *(unsigned long *)map_domain_mem(cur.ptr) = cur.val; + unsigned long *va = map_domain_mem(cur.ptr); + *va = cur.val; + unmap_domain_mem(va); err = 0; } else diff --git a/xen-2.4.16/common/page_alloc.c b/xen-2.4.16/common/page_alloc.c index 48966e2acc..1bfeed440f 100644 --- a/xen-2.4.16/common/page_alloc.c +++ b/xen-2.4.16/common/page_alloc.c @@ -12,7 +12,7 @@ #include <xeno/lib.h> #include <asm/page.h> #include <xeno/spinlock.h> - +#include <xeno/slab.h> static spinlock_t alloc_lock = SPIN_LOCK_UNLOCKED; @@ -102,7 +102,7 @@ struct chunk_tail_st { /* Linked lists of free chunks of different powers-of-two in size. */ #define FREELIST_SIZE ((sizeof(void*)<<3)-PAGE_SHIFT) -static chunk_head_t *free_list[FREELIST_SIZE]; +static chunk_head_t *free_head[FREELIST_SIZE]; static chunk_head_t free_tail[FREELIST_SIZE]; #define FREELIST_EMPTY(_l) ((_l)->next == NULL) @@ -120,8 +120,8 @@ void __init init_page_allocator(unsigned long min, unsigned long max) for ( i = 0; i < FREELIST_SIZE; i++ ) { - free_list[i] = &free_tail[i]; - free_tail[i].pprev = &free_list[i]; + free_head[i] = &free_tail[i]; + free_tail[i].pprev = &free_head[i]; free_tail[i].next = NULL; } @@ -159,10 +159,10 @@ void __init init_page_allocator(unsigned long min, unsigned long max) ct = (chunk_tail_t *)min-1; i -= PAGE_SHIFT; ch->level = i; - ch->next = free_list[i]; - ch->pprev = &free_list[i]; + ch->next = free_head[i]; + ch->pprev = &free_head[i]; ch->next->pprev = &ch->next; - free_list[i] = ch; + free_head[i] = ch; ct->level = i; } } @@ -171,29 +171,26 @@ void __init init_page_allocator(unsigned long min, unsigned long max) /* Allocate 2^@order contiguous pages. */ unsigned long __get_free_pages(int mask, int order) { - int i; + int i, attempts = 0; chunk_head_t *alloc_ch, *spare_ch; chunk_tail_t *spare_ct; unsigned long flags; +retry: spin_lock_irqsave(&alloc_lock, flags); /* Find smallest order which can satisfy the request. */ for ( i = order; i < FREELIST_SIZE; i++ ) { - if ( !FREELIST_EMPTY(free_list[i]) ) + if ( !FREELIST_EMPTY(free_head[i]) ) break; } - if ( i == FREELIST_SIZE ) - { - printk("Cannot handle page request order %d!\n", order); - return 0; - } + if ( i == FREELIST_SIZE ) goto no_memory; /* Unlink a chunk. */ - alloc_ch = free_list[i]; - free_list[i] = alloc_ch->next; + alloc_ch = free_head[i]; + free_head[i] = alloc_ch->next; alloc_ch->next->pprev = alloc_ch->pprev; /* We may have to break the chunk a number of times. */ @@ -206,13 +203,13 @@ unsigned long __get_free_pages(int mask, int order) /* Create new header for spare chunk. */ spare_ch->level = i; - spare_ch->next = free_list[i]; - spare_ch->pprev = &free_list[i]; + spare_ch->next = free_head[i]; + spare_ch->pprev = &free_head[i]; spare_ct->level = i; /* Link in the spare chunk. */ spare_ch->next->pprev = &spare_ch->next; - free_list[i] = spare_ch; + free_head[i] = spare_ch; } map_alloc(__pa(alloc_ch)>>PAGE_SHIFT, 1<<order); @@ -220,6 +217,19 @@ unsigned long __get_free_pages(int mask, int order) spin_unlock_irqrestore(&alloc_lock, flags); return((unsigned long)alloc_ch); + + no_memory: + if ( attempts++ < 8 ) + { + spin_unlock_irqrestore(&alloc_lock, flags); + kmem_cache_reap(0); + goto retry; + } + + printk("Cannot handle page request order %d!\n", order); + dump_slabinfo(); + + return 0; } @@ -269,10 +279,10 @@ void __free_pages(unsigned long p, int order) ct = (chunk_tail_t *)(p+size)-1; ct->level = order; ch->level = order; - ch->pprev = &free_list[order]; - ch->next = free_list[order]; + ch->pprev = &free_head[order]; + ch->next = free_head[order]; ch->next->pprev = &ch->next; - free_list[order] = ch; + free_head[order] = ch; spin_unlock_irqrestore(&alloc_lock, flags); } diff --git a/xen-2.4.16/common/slab.c b/xen-2.4.16/common/slab.c index 98a79bb052..3452e89aa7 100644 --- a/xen-2.4.16/common/slab.c +++ b/xen-2.4.16/common/slab.c @@ -1837,3 +1837,109 @@ out: return ret; } +void dump_slabinfo() +{ + struct list_head *p; + unsigned long spin_flags; + + /* Output format version, so at least we can change it without _too_ + * many complaints. + */ + printk( "slabinfo - version: 1.1" +#if STATS + " (statistics)" +#endif +#ifdef CONFIG_SMP + " (SMP)" +#endif + "\n"); + down(&cache_chain_sem); + p = &cache_cache.next; + do { + kmem_cache_t *cachep; + struct list_head *q; + slab_t *slabp; + unsigned long active_objs; + unsigned long num_objs; + unsigned long active_slabs = 0; + unsigned long num_slabs; + cachep = list_entry(p, kmem_cache_t, next); + + spin_lock_irq(&cachep->spinlock); + active_objs = 0; + num_slabs = 0; + list_for_each(q,&cachep->slabs_full) { + slabp = list_entry(q, slab_t, list); + if (slabp->inuse != cachep->num) + BUG(); + active_objs += cachep->num; + active_slabs++; + } + list_for_each(q,&cachep->slabs_partial) { + slabp = list_entry(q, slab_t, list); + if (slabp->inuse == cachep->num || !slabp->inuse) + BUG(); + active_objs += slabp->inuse; + active_slabs++; + } + list_for_each(q,&cachep->slabs_free) { + slabp = list_entry(q, slab_t, list); + if (slabp->inuse) + BUG(); + num_slabs++; + } + num_slabs+=active_slabs; + num_objs = num_slabs*cachep->num; + + printk("%-17s %6lu %6lu %6u %4lu %4lu %4u", + cachep->name, active_objs, num_objs, cachep->objsize, + active_slabs, num_slabs, (1<<cachep->gfporder)); + +#if STATS + { + unsigned long errors = cachep->errors; + unsigned long high = cachep->high_mark; + unsigned long grown = cachep->grown; + unsigned long reaped = cachep->reaped; + unsigned long allocs = cachep->num_allocations; + + printk(" : %6lu %7lu %5lu %4lu %4lu", + high, allocs, grown, reaped, errors); + } +#endif +#ifdef CONFIG_SMP + { + unsigned int batchcount = cachep->batchcount; + unsigned int limit; + + if (cc_data(cachep)) + limit = cc_data(cachep)->limit; + else + limit = 0; + printk(" : %4u %4u", + limit, batchcount); + } +#endif +#if STATS && defined(CONFIG_SMP) + { + unsigned long allochit = atomic_read(&cachep->allochit); + unsigned long allocmiss = atomic_read(&cachep->allocmiss); + unsigned long freehit = atomic_read(&cachep->freehit); + unsigned long freemiss = atomic_read(&cachep->freemiss); + printk(" : %6lu %6lu %6lu %6lu", + allochit, allocmiss, freehit, freemiss); + } +#endif + printk("\n"); + spin_unlock_irq(&cachep->spinlock); + + p = cachep->next.next; + } while (p != &cache_cache.next); + + up(&cache_chain_sem); + + return; +} + + + diff --git a/xen-2.4.16/include/asm-i386/domain_page.h b/xen-2.4.16/include/asm-i386/domain_page.h index a8e4c71013..bae558c377 100644 --- a/xen-2.4.16/include/asm-i386/domain_page.h +++ b/xen-2.4.16/include/asm-i386/domain_page.h @@ -9,6 +9,21 @@ extern unsigned long *mapcache[NR_CPUS]; #define MAPCACHE_ENTRIES 1024 + +/* + * Maps a given physical address, returning corresponding virtual address. + * The entire page containing that VA is now accessible until a + * corresponding call to unmap_domain_mem(). + */ +extern void *map_domain_mem(unsigned long pa); + +/* + * Pass a VA within a page previously mapped with map_domain_mem(). + * That page will then be removed from the mapping lists. + */ +extern void unmap_domain_mem(void *va); + +#if 0 #define MAPCACHE_HASH(_pfn) ((_pfn) & (MAPCACHE_ENTRIES-1)) static inline void *map_domain_mem(unsigned long pa) { @@ -25,3 +40,4 @@ static inline void *map_domain_mem(unsigned long pa) } return va; } +#endif diff --git a/xen-2.4.16/include/asm-i386/page.h b/xen-2.4.16/include/asm-i386/page.h index b6fe406f0c..b0d68a324a 100644 --- a/xen-2.4.16/include/asm-i386/page.h +++ b/xen-2.4.16/include/asm-i386/page.h @@ -123,8 +123,8 @@ extern void paging_init(void); : "memory"); \ } while (0) -#define __flush_tlb_one(addr) \ -__asm__ __volatile__("invlpg %0": :"m" (*(char *) addr)) +#define __flush_tlb_one(__addr) \ +__asm__ __volatile__("invlpg %0": :"m" (*(char *) (__addr))) #endif /* !__ASSEMBLY__ */ diff --git a/xen-2.4.16/include/xeno/slab.h b/xen-2.4.16/include/xeno/slab.h index c7aadff3ea..21a53051f1 100644 --- a/xen-2.4.16/include/xeno/slab.h +++ b/xen-2.4.16/include/xeno/slab.h @@ -59,6 +59,9 @@ extern void *kmalloc(size_t, int); extern void kfree(const void *); extern int FASTCALL(kmem_cache_reap(int)); + +extern void dump_slabinfo(); + #if 0 extern int slabinfo_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data); diff --git a/xen-2.4.16/net/dev.c b/xen-2.4.16/net/dev.c index 5c4d999bf3..b99a2e91b4 100644 --- a/xen-2.4.16/net/dev.c +++ b/xen-2.4.16/net/dev.c @@ -690,6 +690,7 @@ int netif_rx(struct sk_buff *skb) int this_cpu = smp_processor_id(); struct softnet_data *queue; unsigned long flags; + net_vif_t *vif; if (skb->stamp.tv_sec == 0) get_fast_time(&skb->stamp); @@ -703,13 +704,13 @@ int netif_rx(struct sk_buff *skb) netdev_rx_stat[this_cpu].total++; - if (skb->src_vif == VIF_UNKNOWN_INTERFACE) + if ( skb->src_vif == VIF_UNKNOWN_INTERFACE ) skb->src_vif = VIF_PHYSICAL_INTERFACE; - if (skb->dst_vif == VIF_UNKNOWN_INTERFACE) + if ( skb->dst_vif == VIF_UNKNOWN_INTERFACE ) net_get_target_vif(skb); - if (sys_vif_list[skb->dst_vif] == NULL) + if ( (vif = sys_vif_list[skb->dst_vif]) == NULL ) { // the target vif does not exist. goto drop; @@ -730,8 +731,9 @@ int netif_rx(struct sk_buff *skb) read_lock(&tasklist_lock); p = &idle0_task; do { - if ( p->domain != sys_vif_list[skb->dst_vif]->domain ) continue; - skb_queue_tail(&sys_vif_list[skb->dst_vif]->skb_list, skb); + if ( p->domain != vif->domain ) continue; + if ( vif->skb_list.qlen > 100 ) break; + skb_queue_tail(&vif->skb_list, skb); cpu_mask = mark_hyp_event(p, _HYP_EVENT_NET_RX); read_unlock(&tasklist_lock); goto found; @@ -1975,21 +1977,17 @@ long do_net_update(void) if ( skb != NULL ) { - skb_get(skb); /* get a reference for non-local delivery */ skb->protocol = eth_type_trans(skb, skb->dev); skb->src_vif = current_vif->id; net_get_target_vif(skb); if ( skb->dst_vif > VIF_PHYSICAL_INTERFACE ) { - if (netif_rx(skb) == 0) - /* Give up non-local reference. Packet delivered locally. */ - kfree_skb(skb); + (void)netif_rx(skb); } else if ( skb->dst_vif == VIF_PHYSICAL_INTERFACE ) { - - skb_push(skb, skb->dev->hard_header_len); - dev_queue_xmit(skb); + skb_push(skb, skb->dev->hard_header_len); + dev_queue_xmit(skb); } else { |