diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-06-30 00:21:34 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-06-30 00:21:34 +0000 |
commit | 3917ac5846dd0f9ad1238166f90caab9912052e6 (patch) | |
tree | 1c298935def4f29edb39192365a65d73de999155 /mm | |
parent | af2f803c8b2d469fe38e4a7ce952658dfcb6681a (diff) |
o Merge with Linux 2.1.100.
o Cleanup the machine dependencies of floppy and rtc. The driver for
the Dallas thingy in the Indy is still missing.
o Handle allocation of zero'd pages correct for R4000SC / R4400SC.
o Page colouring shit to match the virtual and physical colour of all
mapped pages. This tends to produce extreme fragmentation problems,
so it's deactivated for now. Users of R4000SC / R4400SC may re-enable
the code in arch/mips/mm/init.c by removing the definition of
CONF_GIVE_A_SHIT_ABOUT_COLOURS. Should get them somewhat further -
but don't shake to hard ...
o Fixed ptrace(2)-ing of syscalls, strace is now working again.
o Fix the interrupt forwarding from the keyboard driver to the psaux
driver, PS/2 mice are now working on the Indy. The fix is somewhat
broken as it prevents generic kernels for Indy and machines which handle
things different.
o Things I can't remember.
Diffstat (limited to 'mm')
-rw-r--r-- | mm/Makefile | 2 | ||||
-rw-r--r-- | mm/filemap.c | 13 | ||||
-rw-r--r-- | mm/memory.c | 24 | ||||
-rw-r--r-- | mm/mlock.c | 4 | ||||
-rw-r--r-- | mm/page_alloc.c | 23 | ||||
-rw-r--r-- | mm/swap.c | 10 | ||||
-rw-r--r-- | mm/swap_state.c | 6 | ||||
-rw-r--r-- | mm/swapfile.c | 6 | ||||
-rw-r--r-- | mm/vmalloc.c | 6 | ||||
-rw-r--r-- | mm/vmscan.c | 39 |
10 files changed, 73 insertions, 60 deletions
diff --git a/mm/Makefile b/mm/Makefile index ef3820d1c..c64eefbd2 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -9,7 +9,7 @@ O_TARGET := mm.o O_OBJS := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \ - vmalloc.o slab.o simp.o\ + vmalloc.o slab.o \ swap.o vmscan.o page_io.o page_alloc.o swap_state.o swapfile.o include $(TOPDIR)/Rules.make diff --git a/mm/filemap.c b/mm/filemap.c index 0971c63b7..3f2632a15 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -289,7 +289,7 @@ static unsigned long try_to_read_ahead(struct file * file, offset &= PAGE_MASK; switch (page_cache) { case 0: - page_cache = __get_free_page(GFP_KERNEL); + page_cache = get_user_page(offset); if (!page_cache) break; default: @@ -703,7 +703,7 @@ no_cached_page: * page.. */ if (!page_cache) { - page_cache = __get_free_page(GFP_KERNEL); + page_cache = get_user_page(pos & PAGE_MASK); /* * That could have slept, so go around to the * very beginning.. @@ -813,7 +813,7 @@ found_page: * extra page -- better to overlap the allocation with the I/O. */ if (no_share && !new_page) { - new_page = __get_free_page(GFP_KERNEL); + new_page = get_user_page(address); if (!new_page) goto failure; } @@ -850,7 +850,7 @@ success: return new_page; no_cached_page: - new_page = __get_free_page(GFP_KERNEL); + new_page = get_user_page(address); if (!new_page) goto no_page; @@ -878,7 +878,8 @@ no_cached_page: * Do a very limited read-ahead if appropriate */ if (PageLocked(page)) - new_page = try_to_read_ahead(file, offset + PAGE_SIZE, 0); + new_page = try_to_read_ahead(file, offset + PAGE_SIZE, + get_user_page(address + PAGE_SIZE)); goto found_page; page_locked_wait: @@ -1360,7 +1361,7 @@ generic_file_write(struct file *file, const char *buf, hash = page_hash(inode, pgpos); if (!(page = __find_page(inode, pgpos, *hash))) { if (!page_cache) { - page_cache = __get_free_page(GFP_KERNEL); + page_cache = get_user_page(pgpos); if (page_cache) continue; status = -ENOMEM; diff --git a/mm/memory.c b/mm/memory.c index 66cdf0bc1..af4297702 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -61,7 +61,7 @@ void * high_memory = NULL; */ static inline void copy_cow_page(unsigned long from, unsigned long to) { - if (from == ZERO_PAGE) { + if (from == ZERO_PAGE(to)) { clear_page(to); return; } @@ -406,7 +406,8 @@ void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long s } } -static inline void zeromap_pte_range(pte_t * pte, unsigned long address, unsigned long size, pte_t zero_pte) +static inline void zeromap_pte_range(pte_t * pte, unsigned long address, + unsigned long size, pgprot_t prot) { unsigned long end; @@ -415,6 +416,8 @@ static inline void zeromap_pte_range(pte_t * pte, unsigned long address, unsigne if (end > PMD_SIZE) end = PMD_SIZE; do { + pte_t zero_pte = pte_wrprotect(mk_pte(ZERO_PAGE(address), + prot)); pte_t oldpage = *pte; set_pte(pte, zero_pte); forget_pte(oldpage); @@ -423,7 +426,8 @@ static inline void zeromap_pte_range(pte_t * pte, unsigned long address, unsigne } while (address < end); } -static inline int zeromap_pmd_range(pmd_t * pmd, unsigned long address, unsigned long size, pte_t zero_pte) +static inline int zeromap_pmd_range(pmd_t * pmd, unsigned long address, + unsigned long size, pgprot_t prot) { unsigned long end; @@ -435,7 +439,7 @@ static inline int zeromap_pmd_range(pmd_t * pmd, unsigned long address, unsigned pte_t * pte = pte_alloc(pmd, address); if (!pte) return -ENOMEM; - zeromap_pte_range(pte, address, end - address, zero_pte); + zeromap_pte_range(pte, address, end - address, prot); address = (address + PMD_SIZE) & PMD_MASK; pmd++; } while (address < end); @@ -448,9 +452,7 @@ int zeromap_page_range(unsigned long address, unsigned long size, pgprot_t prot) pgd_t * dir; unsigned long beg = address; unsigned long end = address + size; - pte_t zero_pte; - zero_pte = pte_wrprotect(mk_pte(ZERO_PAGE, prot)); dir = pgd_offset(current->mm, address); flush_cache_range(current->mm, beg, end); while (address < end) { @@ -458,7 +460,7 @@ int zeromap_page_range(unsigned long address, unsigned long size, pgprot_t prot) error = -ENOMEM; if (!pmd) break; - error = zeromap_pmd_range(pmd, address, end - address, zero_pte); + error = zeromap_pmd_range(pmd, address, end - address, prot); if (error) break; address = (address + PGDIR_SIZE) & PGDIR_MASK; @@ -619,7 +621,7 @@ static void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma, struct page * page_map; pte = *page_table; - new_page = __get_free_page(GFP_KERNEL); + new_page = get_user_page(address); /* Did someone else copy this page for us while we slept? */ if (pte_val(*page_table) != pte_val(pte)) goto end_wp_page; @@ -766,7 +768,7 @@ static inline void do_swap_page(struct task_struct * tsk, pte_t page; if (!vma->vm_ops || !vma->vm_ops->swapin) { - swap_in(tsk, vma, page_table, pte_val(entry), write_access); + swap_in(tsk, vma, address, page_table, pte_val(entry), write_access); flush_page_to_ram(pte_page(*page_table)); return; } @@ -838,9 +840,9 @@ static void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma, return; anonymous_page: - entry = pte_wrprotect(mk_pte(ZERO_PAGE, vma->vm_page_prot)); + entry = pte_wrprotect(mk_pte(ZERO_PAGE(address), vma->vm_page_prot)); if (write_access) { - unsigned long page = __get_free_page(GFP_KERNEL); + unsigned long page = get_user_page(address); if (!page) goto sigbus; clear_page(page); diff --git a/mm/mlock.c b/mm/mlock.c index 5bffab93f..3a322f8a5 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -144,7 +144,7 @@ static int do_mlock(unsigned long start, size_t len, int on) struct vm_area_struct * vma, * next; int error; - if (!suser()) + if (!capable(CAP_IPC_LOCK)) return -EPERM; len = (len + ~PAGE_MASK) & PAGE_MASK; end = start + len; @@ -235,7 +235,7 @@ static int do_mlockall(int flags) unsigned int def_flags; struct vm_area_struct * vma; - if (!suser()) + if (!capable(CAP_IPC_LOCK)) return -EPERM; def_flags = 0; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 85eaca9e5..d61d74f44 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -98,9 +98,7 @@ static inline void remove_mem_queue(struct page * entry) * * Hint: -mask = 1+~mask */ -#ifdef __SMP__ -static spinlock_t page_alloc_lock; -#endif +static spinlock_t page_alloc_lock = SPIN_LOCK_UNLOCKED; /* * This routine is used by the kernel swap deamon to determine @@ -125,7 +123,7 @@ int free_memory_available(int nr) * free unfragmented memory. * Added low/high water marks to avoid thrashing -- Rik. */ - if (nr_free_pages > (num_physpages >> 5) + (nr ? 0 : num_physpages >> 6)) + if (nr_free_pages > (nr ? freepages.low : freepages.high)) return nr+1; list = free_area + NR_MEM_LISTS; @@ -282,7 +280,6 @@ unsigned long __get_free_pages(int gfp_mask, unsigned long order) spin_unlock_irqrestore(&page_alloc_lock, flags); if (!(gfp_mask & __GFP_WAIT)) break; - shrink_dcache(); if (!try_to_free_pages(gfp_mask, SWAP_CLUSTER_MAX)) break; gfp_mask &= ~__GFP_WAIT; /* go through this only once */ @@ -335,15 +332,19 @@ __initfunc(unsigned long free_area_init(unsigned long start_mem, unsigned long e int i; /* - * select nr of pages we try to keep free for important stuff - * with a minimum of 48 pages. This is totally arbitrary + * Select nr of pages we try to keep free for important stuff + * with a minimum of 48 pages and a maximum of 256 pages, so + * that we don't waste too much memory on large systems. + * This is totally arbitrary. */ i = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT+7); if (i < 48) i = 48; + if (i > 256) + i = 256; freepages.min = i; - freepages.low = i + (i>>1); - freepages.high = i + i; + freepages.low = i << 1; + freepages.high = freepages.low + i; mem_map = (mem_map_t *) LONG_ALIGN(start_mem); p = mem_map + MAP_NR(end_mem); start_mem = LONG_ALIGN((unsigned long) p); @@ -378,12 +379,12 @@ __initfunc(unsigned long free_area_init(unsigned long start_mem, unsigned long e * was due to a write access. */ void swap_in(struct task_struct * tsk, struct vm_area_struct * vma, - pte_t * page_table, unsigned long entry, int write_access) + unsigned long address, pte_t * page_table, unsigned long entry, int write_access) { unsigned long page; struct page *page_map; - page_map = read_swap_cache(entry); + page_map = read_swap_cache(entry, address); if (pte_val(*page_table) != entry) { if (page_map) @@ -44,8 +44,8 @@ */ freepages_t freepages = { 48, /* freepages.min */ - 72, /* freepages.low */ - 96 /* freepages.high */ + 96, /* freepages.low */ + 144 /* freepages.high */ }; /* We track the number of pages currently being asynchronously swapped @@ -77,3 +77,9 @@ buffer_mem_t page_cache = { 30, /* borrow percent page cache */ 75 /* maximum */ }; + +pager_daemon_t pager_daemon = { + 512, /* base number for calculating the number of tries */ + SWAP_CLUSTER_MAX, /* minimum number of tries */ + SWAP_CLUSTER_MAX, /* do swap I/O in clusters of this size */ +}; diff --git a/mm/swap_state.c b/mm/swap_state.c index b575877ff..b91583340 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -219,7 +219,7 @@ void free_page_and_swap_cache(unsigned long addr) delete_from_swap_cache(page); } - free_page(addr); + free_user_page(page, addr); } @@ -256,7 +256,7 @@ static struct page * lookup_swap_cache(unsigned long entry) * only doing readahead, so don't worry if the page is already locked. */ -struct page * read_swap_cache_async(unsigned long entry, int wait) +struct page * read_swap_cache_async(unsigned long entry, unsigned long addr, int wait) { struct page *found_page, *new_page = 0; unsigned long new_page_addr = 0; @@ -276,7 +276,7 @@ repeat: /* The entry is not present. Lock down a new page, add it to * the swap cache and read its contents. */ if (!new_page) { - new_page_addr = __get_free_page(GFP_KERNEL); + new_page_addr = get_user_page(addr); if (!new_page_addr) return 0; /* Out of memory */ new_page = mem_map + MAP_NR(new_page_addr); diff --git a/mm/swapfile.c b/mm/swapfile.c index f9cd0d47e..d935433bb 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -323,7 +323,7 @@ static int try_to_unuse(unsigned int type) /* Get a page for the entry, using the existing swap cache page if there is one. Otherwise, get a clean page and read the swap into it. */ - page_map = read_swap_cache(entry); + page_map = read_swap_cache(entry, 0); if (!page_map) return -ENOMEM; page = page_address(page_map); @@ -356,7 +356,7 @@ asmlinkage int sys_swapoff(const char * specialfile) int err = -EPERM; lock_kernel(); - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) goto out; dentry = namei(specialfile); @@ -491,7 +491,7 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags) static int least_priority = 0; lock_kernel(); - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) goto out; memset(&filp, 0, sizeof(filp)); p = swap_info; diff --git a/mm/vmalloc.c b/mm/vmalloc.c index bf29463dd..6b87beaa2 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -5,6 +5,7 @@ */ #include <linux/malloc.h> +#include <linux/swapctl.h> #include <linux/vmalloc.h> #include <asm/uaccess.h> @@ -37,7 +38,8 @@ static inline void free_area_pte(pmd_t * pmd, unsigned long address, unsigned lo if (pte_none(page)) continue; if (pte_present(page)) { - free_page(pte_page(page)); + free_user_page(mem_map + MAP_NR(pte_page(page)), + pte_page(page)); continue; } printk("Whee.. Swapped out page in kernel page table\n"); @@ -95,7 +97,7 @@ static inline int alloc_area_pte(pte_t * pte, unsigned long address, unsigned lo unsigned long page; if (!pte_none(*pte)) printk("alloc_area_pte: page already exists\n"); - page = __get_free_page(GFP_KERNEL); + page = get_user_page(address); if (!page) return -ENOMEM; set_pte(pte, mk_pte(page, prot)); diff --git a/mm/vmscan.c b/mm/vmscan.c index 8eaeb23d5..919b97244 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -455,17 +455,20 @@ static inline int do_try_to_free_page(int gfp_mask) switch (state) { do { case 0: - state = 1; if (shrink_mmap(i, gfp_mask)) return 1; + state = 1; case 1: - state = 2; if ((gfp_mask & __GFP_IO) && shm_swap(i, gfp_mask)) return 1; - default: - state = 0; + state = 2; + case 2: if (swap_out(i, gfp_mask)) return 1; + state = 3; + case 3: + shrink_dcache_memory(i, gfp_mask); + state = 0; i--; } while ((i - stop) >= 0); } @@ -545,30 +548,28 @@ int kswapd(void *unused) schedule(); swapstats.wakeups++; - /* This will gently shrink the dcache.. */ - shrink_dcache_memory(); - /* * Do the background pageout: be * more aggressive if we're really * low on free memory. * - * The number of tries is 512 divided by an - * 'urgency factor'. In practice this will mean - * a value of 512 / 8 = 64 pages at a time, - * giving 64 * 4 (times/sec) * 4k (pagesize) = - * 1 MB/s in lowest-priority background - * paging. This number rises to 8 MB/s when the - * priority is highest (but then we'll be woken - * up more often and the rate will be even higher). - * -- Should make this sysctl tunable... + * We try page_daemon.tries_base times, divided by + * an 'urgency factor'. In practice this will mean + * a value of pager_daemon.tries_base / 8 or 4 = 64 + * or 128 pages at a time. + * This gives us 64 (or 128) * 4k * 4 (times/sec) = + * 1 (or 2) MB/s swapping bandwidth in low-priority + * background paging. This number rises to 8 MB/s + * when the priority is highest (but then we'll be + * woken up more often and the rate will be even + * higher). */ - tries = (512) >> free_memory_available(3); + tries = pager_daemon.tries_base >> free_memory_available(3); while (tries--) { int gfp_mask; - if (++tried > SWAP_CLUSTER_MAX && free_memory_available(0)) + if (++tried > pager_daemon.tries_min && free_memory_available(0)) break; gfp_mask = __GFP_IO; try_to_free_page(gfp_mask); @@ -576,7 +577,7 @@ int kswapd(void *unused) * Syncing large chunks is faster than swapping * synchronously (less head movement). -- Rik. */ - if (atomic_read(&nr_async_pages) >= SWAP_CLUSTER_MAX) + if (atomic_read(&nr_async_pages) >= pager_daemon.swap_cluster) run_task_queue(&tq_disk); } |