summaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-06-30 00:21:34 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-06-30 00:21:34 +0000
commit3917ac5846dd0f9ad1238166f90caab9912052e6 (patch)
tree1c298935def4f29edb39192365a65d73de999155 /mm
parentaf2f803c8b2d469fe38e4a7ce952658dfcb6681a (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/Makefile2
-rw-r--r--mm/filemap.c13
-rw-r--r--mm/memory.c24
-rw-r--r--mm/mlock.c4
-rw-r--r--mm/page_alloc.c23
-rw-r--r--mm/swap.c10
-rw-r--r--mm/swap_state.c6
-rw-r--r--mm/swapfile.c6
-rw-r--r--mm/vmalloc.c6
-rw-r--r--mm/vmscan.c39
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)
diff --git a/mm/swap.c b/mm/swap.c
index 957ad0a95..c760208da 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -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);
}