From: Kenn H. <ke...@us...> - 2002-12-02 01:08:18
|
Update of /cvsroot/linux-vax/kernel-2.5/include/asm-vax/mm In directory sc8-pr-cvs1:/tmp/cvs-serv19236/include/asm-vax/mm Modified Files: pagelet.h pagelet_pgd.h pagelet_pmd.h pgalloc.h pgtable.h Log Message: 2.5.5 uses struct page * pointers to refer to pages in process page tables (to allow PTEs in HIGHMEM on x86). It also does away with the pgtable_cache quicklists. Dealing with these changes triggered quite a few changes in the VAX MM code. While working on this, I found that our existing page table allocation and management code wasn't very clear. So I've taken the opportunity to clean things up. o pgd_val(), __pgd(), pmd_val() and __pmd() are now gone. The MM core doesn't use them, and there is no reason why VAX-specific code should use them. After all, we have to be intimately familiar with the actual contents of pgd_t and pmd_t. pmd_val() and friends just obscure rather than clarify and are very type-unsafe. The pmd_t structure now contains a pte_t * instead of an unsigned long. This allows us to remove a lot of ugly casts. (Look at pte_offset() for example.) o PMDs are no longer allocated via a quicklist. They are allocated and freed directly via alloc_pages() and __free_pages(). o The job of invalidating the SPTE for a page in a process page table is now done by pmd_clear(). We used to do this in pte_free(), but we can't any more (and we shouldn't anyway), since pte_free() only gets a struct page * now, so we can't tell where in the process page table this page lies. pmd_clear() gets the address of the PMD entry, which then points to the PTE page that we need. o PTE pagesare no longer allocated via a quicklist, but via alloc_page() and __free_page(). o The old quicklist structure is now pgd_free_list, since this better describes its current function (holding previously allocated PGDs, which makes balance slot allocation simpler). pgd_t gets a .next member to simply free list insertion and removal. o pmd_populate() is now much simpler. We don't try to fill holes in page tables anymore. So each call to pmd_populate() only has to deal with one page (which the core already allocates for us). o Checks against WSMAX and STKMAX are now done in pte_alloc_one(), since the user address that we need is handed directly to pte_alloc_one(), whereas pmd_populate() would have to calculate it. The MM core can deal with pte_alloc_one() returning NULL, so calls to brk() or mmap() that would go beyond WSMAX will get ENOMEM rather than a SEGV. o pmd_populate_S0() is gone, since it's a bug if anything tries to expand our system page table. Index: pagelet.h =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/include/asm-vax/mm/pagelet.h,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- pagelet.h 20 May 2002 00:33:39 -0000 1.3 +++ pagelet.h 2 Dec 2002 01:08:08 -0000 1.4 @@ -64,6 +64,15 @@ * expects them here */ #ifndef __ASSEMBLY__ +/* definition of pte_t */ +typedef struct pagelet_pagecluster pte_t; + +/* definition of pmd_t, an entry in a Page Middle Directory. Each entry + is a pointer to a page of process PTEs */ +typedef struct { + pte_t *pte_page; +} pmd_t; + /* * this struct contains the base and length registers * needed for each part of the pgd @@ -79,32 +88,17 @@ * arch/vax/boot/head.S (ASM_SBR_OFFSET and ASM_SLR_OFFSET) */ -/* definition of pmd_t - needed for pgd_t */ -typedef struct { - unsigned long pmd; -} pmd_t; - - struct pgd_descriptor { unsigned long br; unsigned long lr; - pmd_t *pmd; /* first four pages of the task PTE slot are the pmds - * Our pmds hold 2048 entries and are 2 pages long */ - unsigned long slot; /* the base address of this slot */ - unsigned long segment; /* The segment index - used in pgd_clear */ + pmd_t *pmd; /* first four pages of the task PTE slot are the pmds + * Our pmds hold 2048 entries and are 2 pages long */ + unsigned long slot; /* the base address of this slot */ + unsigned long segment; /* The segment index - used in pgd_clear */ + struct pgd_descriptor *next; /* Links for PGD entry free list */ }; -/* pgd_t definitions */ typedef struct pgd_descriptor pgd_t; -/* the .pmd is not a typo */ -#define pgd_val(x) ((x).pmd) -#define __pgd(x) ((pgd_t) { (x) } ) - -#define pmd_val(x) ((x).pmd) -#define __pmd(x) ((pmd_t) { (x) } ) - -/* definition of pte_t */ -typedef struct pagelet_pagecluster pte_t; #define pte_val(x) ((x).pte) #define __pte(x) ((pte_t) { (x) } ) Index: pagelet_pgd.h =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/include/asm-vax/mm/pagelet_pgd.h,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- pagelet_pgd.h 20 May 2002 00:33:39 -0000 1.3 +++ pagelet_pgd.h 2 Dec 2002 01:08:08 -0000 1.4 @@ -33,7 +33,7 @@ #define pgd_ERROR(e) \ - printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) + printk("%s:%d: bad pgd - pmd is %p.\n", __FILE__, __LINE__, (e).pmd) /* This is the kernel pgd */ @@ -45,9 +45,9 @@ * into the pgd entry) * All the actual stuff is done by the pmd_xxx functions */ -static inline int pgd_none(pgd_t pgd) { return !(pgd).pmd; } -static inline int pgd_bad(pgd_t pgd) { return !(pgd).br; } -static inline int pgd_present(pgd_t pgd) { return ((pgd).pmd != 0); } +static inline int pgd_none(pgd_t pgd) { return !pgd.pmd; } +static inline int pgd_bad(pgd_t pgd) { return !pgd.br; } +static inline int pgd_present(pgd_t pgd) { return (pgd.pmd != 0); } extern void pgd_clear(pgd_t * pgdp); Index: pagelet_pmd.h =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/include/asm-vax/mm/pagelet_pmd.h,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- pagelet_pmd.h 20 May 2002 00:33:39 -0000 1.3 +++ pagelet_pmd.h 2 Dec 2002 01:08:08 -0000 1.4 @@ -26,7 +26,7 @@ #define PTRS_PER_PMD 2048 #define pmd_ERROR(e) \ - printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e)) + printk("%s:%d: bad pmd entry %p.\n", __FILE__, __LINE__, (e).pte_page) /* pmd_xxx functions */ @@ -41,28 +41,27 @@ * -- Change to a pmd that is a two page block of memeory. * -- remove special flag. */ -#define set_pmd(pmdptr, pmdval) -static inline int pmd_none(pmd_t pmd) -{ - return (pmd_val(pmd) == 0); -} -static inline int pmd_bad(pmd_t pmd) { return (pmd_val(pmd) == 0); } -static inline int pmd_present(pmd_t pmd) { return (pmd_val(pmd) != 0); } +static inline int pmd_none(pmd_t pmd) { return (pmd.pte_page == NULL); } +static inline int pmd_bad(pmd_t pmd) { return (pmd.pte_page == NULL); } +static inline int pmd_present(pmd_t pmd) { return (pmd.pte_page != NULL); } -/* clear the pmd entry */ -static inline void pmd_clear(pmd_t * pmdp) { pmd_val(*pmdp) = 0; } +/* Implemented in arch/vax/mm/pgalloc.c */ +void pmd_clear(pmd_t *pmd); /* Find an entry in the second-level page table.. */ #define pmd_index(address) ((address >> PMD_SHIFT) & (PTRS_PER_PMD-1)) +/* Given an PMD entry (which points to a page of PTEs), return the + struct page * for that page */ +#define pmd_page(p) virt_to_page((p).pte_page) static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) { /* locate the pmd entry according to address */ pmd_t *ptr; - ptr = (pmd_t *)pmd_val(*dir) + pmd_index(address); -// printk("pmd_offset: pgd %8p, pmd_val %8lx, address %8lx, index %8lx, offset %8p\n",dir,pmd_val(*dir),address,pmd_index(address),ptr); + ptr = dir->pmd + pmd_index(address); +// printk("pmd_offset: pgd %8p, pmd %p, address %8lx, index %8lx, offset %8p\n",dir,dir->pmd,address,pmd_index(address),ptr); return ptr; } Index: pgalloc.h =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/include/asm-vax/mm/pgalloc.h,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- pgalloc.h 20 May 2002 00:33:39 -0000 1.3 +++ pgalloc.h 2 Dec 2002 01:08:08 -0000 1.4 @@ -31,60 +31,35 @@ #include <linux/threads.h> #include <asm/mm/virtmap.h> #include <linux/vmalloc.h> +#include <asm/mm/task.h> #ifndef CONFIG_SMP -extern struct pgtable_cache_struct { - unsigned long *pgd_cache; /* These are special recyclable slots */ - unsigned long pgd_slots_used; - unsigned long pgd_cache_sz; - unsigned long *pmd_cache; /* These are two page blocks */ - unsigned long pmd_cache_sz; - unsigned long *pte_cache; /* These are one page blocks */ - unsigned long pgtable_cache_sz; -} quicklists; +extern struct pgd_cache { + pgd_t *head; /* These are special recyclable slots */ + unsigned long slots_used; + unsigned long size; +} pgd_free_list; #else - #include <asm/smp.h> //#define quicklists cpu_data[smp_processor_id()] #error SMP not supported #endif -#define pgd_quicklist (quicklists.pgd_cache) -#define pmd_quicklist (quicklists.pmd_cache) -#define pte_quicklist (quicklists.pte_cache) -#define pmd_cache_size (quicklists.pmd_cache_sz) -#define pgtable_cache_size (quicklists.pgtable_cache_sz) -#define pgd_cache_size (quicklists.pgd_cache_sz) -#define pgd_slots_used (quicklists.pgd_slots_used) /* * Allocate and free page tables. The xxx_kernel() versions are * used to allocate a kernel page table - this turns on ASN bits - * if any. + * if any in other archs. On VAX, we cannot manipulate the S0 page + * table after init, so they are BUG()-ed out. */ - -static inline void free_pgd_fast(pgd_t *pgd) -{ - *(unsigned long *)pgd = (unsigned long) pgd_quicklist; - pgd_quicklist = (unsigned long *) pgd; - pgd_cache_size++; -} - -static inline void free_pgd_slow(pgd_t *pgd) +static inline void pgd_free(pgd_t *pgd) { - /* - * atp Mar 2002. - * We never free pgd 'pages'. The cache structure maintains - * a free list of free pgd/memory map slots, in the user page - * tables. This is contiguous in S0 page space - * If we need a pgd, we pick a 'slot' which holds all the pmds - * and ptes in a contiguous block of system address space. - */ - + pgd->next = pgd_free_list.head; + pgd_free_list.head = pgd; + pgd_free_list.size++; } /* renamed from get_pmd_slow to pmd_alloc_one, mar 2002 */ -/* FIXME: This can be statically inlined -> pgalloc.h */ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) { pmd_t *ret; @@ -96,90 +71,50 @@ return ret; } -/* Page Mid level directory handling routines. - * renamed from get_pmd_fast */ -static inline pmd_t *pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address) +static inline void pmd_free(pmd_t *pmd) { - unsigned long *ret; - - if ((ret = (unsigned long *)pmd_quicklist) != NULL) { - pmd_quicklist = (unsigned long *)(*ret); - ret[0] = 0; - pmd_cache_size--; - } - return (pmd_t *)ret; + free_pages((unsigned long)pmd, 1); } -static inline void free_pmd_fast(pmd_t *pmd) -{ - *(unsigned long *)pmd = (unsigned long) pmd_quicklist; - pmd_quicklist = (unsigned long *) pmd; - pmd_cache_size++; -} - -static inline void free_pmd_slow(pmd_t *pmd) -{ - /* - * a pmd is a *two* page block of memory, allocated with - * __get_free_pages(GFP_KERNEL, 1); - */ - free_pages(((unsigned long)pmd),1); -} -/* renamed from get_pte_fast, mar 2002 */ -static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) +static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) { - unsigned long *ret; + struct page *page; - if((ret = (unsigned long *)pte_quicklist) != NULL) { - pte_quicklist = (unsigned long *)(*ret); - ret[0] = 0; - pgtable_cache_size--; + /* Is this an attempt to allocate a page outside the maximum memory + limits? */ + if ((address >= TASK_WSMAX) && (address < (0x80000000-TASK_STKMAX))) { + /* The address is in the no-go zone. Returning NULL here + will get treated as ENOMEM by callers, which is a + reasonable way to fail this, I think */ + return NULL; } - return (pte_t *)ret; -} -/* renamed from get_pte_slow mar 2002 */ -static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) -{ - unsigned long pte; - - pte = (unsigned long) __get_free_page(GFP_KERNEL); - if (pte) { - return (pte_t *) pte; - } - return NULL; + page = alloc_page(GFP_KERNEL); + if (page) { + clear_page(page_address(page)); + } + return page; } -static inline void free_pte_fast(pte_t *pte) +static inline void pte_free(struct page *pte_page) { - *(unsigned long *)pte = (unsigned long) pte_quicklist; - pte_quicklist = (unsigned long *) pte; - pgtable_cache_size++; + __free_page(pte_page); } - /* in arch/vax/mm/pgalloc.c */ -extern pgd_t *pgd_alloc(struct mm_struct *mm); -extern pgd_t *get_pgd_fast(void); -extern void pmd_free(pmd_t *pmd); -extern void pte_free(pte_t *pte); -extern pte_t *get_pageaddr_from_pte(pte_t *ptep); -extern void free_pte_slow(pte_t *pte); -extern void remap_and_clear_pte_page(pmd_t *s0addr, pte_t *page); -extern void remap_pte_invalidate(pmd_t *s0addr); -extern void pte_free_kernel(pte_t *pte); -extern pte_t * vax_pte_alloc_one(pmd_t *pmd); -extern void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd); -extern void pmd_populate(struct mm_struct *mm, pmd_t * pmd, pte_t *pte); -extern void pmd_populate_S0(pgd_t *pgd, pmd_t *pmd); - - -/* in arch/vax/mm/init.c */ -extern int do_check_pgt_cache(int, int); - -#define pgd_free(pgd) free_pgd_fast(pgd) - +pgd_t *pgd_alloc(struct mm_struct *mm); +void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd); +void pmd_populate(struct mm_struct *mm, pmd_t * pmd, struct page *pte); +void pmd_clear(pmd_t *pmd); + +/* Due to limitation of VAX memory management, dynamic allocation and + freeing of system PTEs is impossible. Nothing should be trying to + allocate or free these. */ +#define pte_free_kernel(pte) BUG() +#define pmd_populate_kernel(mm, pmd, pte) BUG() +#define pte_alloc_one_kernel(mm, address) ({ BUG(); (pte_t *)0; }) +#define pmd_page_kernel(pmd) BUG() /* tlb routines */ Index: pgtable.h =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/include/asm-vax/mm/pgtable.h,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- pgtable.h 20 May 2002 00:33:39 -0000 1.3 +++ pgtable.h 2 Dec 2002 01:08:08 -0000 1.4 @@ -63,9 +63,9 @@ * if you alter pgd_t change these. */ /* swapper_pg_dir[2].br */ -#define ASM_SBR_OFFSET 40 +#define ASM_SBR_OFFSET 48 /* swapper_pg_dir[2].lr */ -#define ASM_SLR_OFFSET 44 +#define ASM_SLR_OFFSET 52 /* * Macros to get page table addresses + offsets. @@ -164,7 +164,6 @@ */ extern unsigned long empty_zero_page[1024] __attribute__ ((__aligned__(PAGE_SIZE))); #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) -#define page_address(page) ((page)->virtual) /* Encode and de-code a swap entry */ #define SWP_TYPE(x) (((x).val >> 1) & 0x3f) |