summaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-09-19 19:15:08 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-09-19 19:15:08 +0000
commit03ba4131783cc9e872f8bb26a03f15bc11f27564 (patch)
tree88db8dba75ae06ba3bad08e42c5e52efc162535c /mm
parent257730f99381dd26e10b832fce4c94cae7ac1176 (diff)
- Merge with Linux 2.1.121.
- Bugfixes.
Diffstat (limited to 'mm')
-rw-r--r--mm/filemap.c8
-rw-r--r--mm/memory.c1
-rw-r--r--mm/mmap.c2
-rw-r--r--mm/page_alloc.c3
-rw-r--r--mm/page_io.c1
-rw-r--r--mm/slab.c4
-rw-r--r--mm/swap.c12
-rw-r--r--mm/swap_state.c132
-rw-r--r--mm/swapfile.c205
-rw-r--r--mm/vmscan.c22
10 files changed, 250 insertions, 140 deletions
diff --git a/mm/filemap.c b/mm/filemap.c
index d0bf1270f..ffda2b7c1 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -7,7 +7,7 @@
/*
* This file handles the generic file mmap semantics used by
* most "normal" filesystems (but you don't /have/ to use this:
- * the NFS filesystem does this differently, for example)
+ * the NFS filesystem used to do this differently, for example)
*/
#include <linux/stat.h>
#include <linux/sched.h>
@@ -172,12 +172,10 @@ static inline int shrink_one_page(struct page *page, int gfp_mask)
break;
}
age_page(page);
-#if 0
if (page->age)
break;
if (page_cache_size * 100 < (page_cache.min_percent * num_physpages))
break;
-#endif
if (PageSwapCache(page)) {
delete_from_swap_cache(page);
return 1;
@@ -213,8 +211,8 @@ int shrink_mmap(int priority, int gfp_mask)
struct page * page;
int count_max, count_min;
- count_max = (limit<<1) >> (priority>>1);
- count_min = (limit<<1) >> (priority);
+ count_max = (limit<<2) >> (priority>>1);
+ count_min = (limit<<2) >> (priority);
page = mem_map + clock;
do {
diff --git a/mm/memory.c b/mm/memory.c
index 77a814f07..388d9ce03 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -35,7 +35,6 @@
#include <linux/signal.h>
#include <linux/sched.h>
-#include <linux/head.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
diff --git a/mm/mmap.c b/mm/mmap.c
index 172bcd8f1..77b0c5d62 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -688,7 +688,7 @@ void merge_segments (struct mm_struct * mm, unsigned long start_addr, unsigned l
mm->mmap_cache = NULL; /* Kill the cache. */
}
-__initfunc(void vma_init(void))
+void __init vma_init(void)
{
vm_area_cachep = kmem_cache_create("vm_area_struct",
sizeof(struct vm_area_struct),
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index c51db59d9..70cad74eb 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -8,7 +8,6 @@
#include <linux/config.h>
#include <linux/mm.h>
#include <linux/sched.h>
-#include <linux/head.h>
#include <linux/kernel.h>
#include <linux/kernel_stat.h>
#include <linux/errno.h>
@@ -318,7 +317,7 @@ void show_free_areas(void)
* - mark all memory queues empty
* - clear the memory bitmaps
*/
-__initfunc(unsigned long free_area_init(unsigned long start_mem, unsigned long end_mem))
+unsigned long __init free_area_init(unsigned long start_mem, unsigned long end_mem)
{
mem_map_t * p;
unsigned long mask = PAGE_MASK;
diff --git a/mm/page_io.c b/mm/page_io.c
index 7e5a35186..44f592df8 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -11,7 +11,6 @@
#include <linux/mm.h>
#include <linux/sched.h>
-#include <linux/head.h>
#include <linux/kernel.h>
#include <linux/kernel_stat.h>
#include <linux/errno.h>
diff --git a/mm/slab.c b/mm/slab.c
index dc9dc05d2..d4be178a2 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -410,7 +410,7 @@ static kmem_cache_t *cache_slabp = NULL;
static unsigned long bufctl_limit = 0;
/* Initialisation - setup the `cache' cache. */
-__initfunc(long kmem_cache_init(long start, long end))
+long __init kmem_cache_init(long start, long end)
{
size_t size, i;
@@ -464,7 +464,7 @@ __initfunc(long kmem_cache_init(long start, long end))
/* Initialisation - setup remaining internal and general caches.
* Called after the gfp() functions have been enabled, and before smp_init().
*/
-__initfunc(void kmem_cache_sizes_init(void))
+void __init kmem_cache_sizes_init(void)
{
unsigned int found = 0;
diff --git a/mm/swap.c b/mm/swap.c
index 3cedb215c..1788021b9 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -15,7 +15,6 @@
#include <linux/mm.h>
#include <linux/sched.h>
-#include <linux/head.h>
#include <linux/kernel.h>
#include <linux/kernel_stat.h>
#include <linux/errno.h>
@@ -56,12 +55,15 @@ atomic_t nr_async_pages = ATOMIC_INIT(0);
* Constants for the page aging mechanism: the maximum age (actually,
* the maximum "youthfulness"); the quanta by which pages rejuvenate
* and age; and the initial age for new pages.
+ *
+ * The "pageout_weight" is strictly a fixedpoint number with the
+ * ten low bits being the fraction (ie 8192 really means "8.0").
*/
-
swap_control_t swap_control = {
20, 3, 1, 3, /* Page aging */
32, 4, /* Aging cluster */
- 8192, 8192, /* Pageout and bufferout weights */
+ 8192, /* sc_pageout_weight aka PAGEOUT_WEIGHT */
+ 8192, /* sc_bufferout_weight aka BUFFEROUT_WEIGHT */
};
swapstat_t swapstats = {0};
@@ -69,11 +71,11 @@ swapstat_t swapstats = {0};
buffer_mem_t buffer_mem = {
5, /* minimum percent buffer */
25, /* borrow percent buffer */
- 50 /* maximum percent buffer */
+ 60 /* maximum percent buffer */
};
buffer_mem_t page_cache = {
- 10, /* minimum percent page cache */
+ 5, /* minimum percent page cache */
30, /* borrow percent page cache */
75 /* maximum */
};
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 401c7a1fc..2aaf0c46b 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -9,7 +9,6 @@
#include <linux/mm.h>
#include <linux/sched.h>
-#include <linux/head.h>
#include <linux/kernel.h>
#include <linux/kernel_stat.h>
#include <linux/errno.h>
@@ -24,14 +23,6 @@
#include <asm/bitops.h>
#include <asm/pgtable.h>
-#ifdef SWAP_CACHE_INFO
-unsigned long swap_cache_add_total = 0;
-unsigned long swap_cache_add_success = 0;
-unsigned long swap_cache_del_total = 0;
-unsigned long swap_cache_del_success = 0;
-unsigned long swap_cache_find_total = 0;
-unsigned long swap_cache_find_success = 0;
-
/*
* Keep a reserved false inode which we will use to mark pages in the
* page cache are acting as swap cache instead of file cache.
@@ -43,6 +34,13 @@ unsigned long swap_cache_find_success = 0;
*/
struct inode swapper_inode;
+#ifdef SWAP_CACHE_INFO
+unsigned long swap_cache_add_total = 0;
+unsigned long swap_cache_add_success = 0;
+unsigned long swap_cache_del_total = 0;
+unsigned long swap_cache_del_success = 0;
+unsigned long swap_cache_find_total = 0;
+unsigned long swap_cache_find_success = 0;
void show_swap_cache_info(void)
{
@@ -63,13 +61,13 @@ int add_to_swap_cache(struct page *page, unsigned long entry)
page_address(page), atomic_read(&page->count), entry);
#endif
if (PageTestandSetSwapCache(page)) {
- printk("swap_cache: replacing non-empty entry %08lx "
+ printk(KERN_ERR "swap_cache: replacing non-empty entry %08lx "
"on page %08lx\n",
page->offset, page_address(page));
return 0;
}
if (page->inode) {
- printk("swap_cache: replacing page-cached entry "
+ printk(KERN_ERR "swap_cache: replacing page-cached entry "
"on page %08lx\n", page_address(page));
return 0;
}
@@ -85,12 +83,16 @@ int add_to_swap_cache(struct page *page, unsigned long entry)
}
/*
- * If swap_map[] reaches 127, the entries are treated as "permanent".
+ * Verify that a swap entry is valid and increment its swap map count.
+ *
+ * Note: if swap_map[] reaches SWAP_MAP_MAX the entries are treated as
+ * "permanent", but will be reclaimed by the next swapoff.
*/
-void swap_duplicate(unsigned long entry)
+int swap_duplicate(unsigned long entry)
{
struct swap_info_struct * p;
unsigned long offset, type;
+ int result = 0;
if (!entry)
goto out;
@@ -105,36 +107,44 @@ void swap_duplicate(unsigned long entry)
goto bad_offset;
if (!p->swap_map[offset])
goto bad_unused;
- if (p->swap_map[offset] < 126)
+ /*
+ * Entry is valid, so increment the map count.
+ */
+ if (p->swap_map[offset] < SWAP_MAP_MAX)
p->swap_map[offset]++;
else {
static int overflow = 0;
if (overflow++ < 5)
- printk("swap_duplicate: entry %08lx map count=%d\n",
+ printk(KERN_WARNING
+ "swap_duplicate: entry %08lx map count=%d\n",
entry, p->swap_map[offset]);
- p->swap_map[offset] = 127;
+ p->swap_map[offset] = SWAP_MAP_MAX;
}
+ result = 1;
#ifdef DEBUG_SWAP
printk("DebugVM: swap_duplicate(entry %08lx, count now %d)\n",
entry, p->swap_map[offset]);
#endif
out:
- return;
+ return result;
bad_file:
- printk("swap_duplicate: Trying to duplicate nonexistent swap-page\n");
+ printk(KERN_ERR
+ "swap_duplicate: entry %08lx, nonexistent swap file\n", entry);
goto out;
bad_offset:
- printk("swap_duplicate: offset exceeds max\n");
+ printk(KERN_ERR
+ "swap_duplicate: entry %08lx, offset exceeds max\n", entry);
goto out;
bad_unused:
- printk("swap_duplicate at %8p: unused page\n",
- __builtin_return_address(0));
+ printk(KERN_ERR
+ "swap_duplicate at %8p: entry %08lx, unused page\n",
+ __builtin_return_address(0), entry);
goto out;
}
-void remove_from_swap_cache(struct page *page)
+static inline void remove_from_swap_cache(struct page *page)
{
if (!page->inode) {
printk ("VM: Removing swap cache page with zero inode hash "
@@ -163,7 +173,7 @@ void remove_from_swap_cache(struct page *page)
}
-int delete_from_swap_cache(struct page *page)
+void delete_from_swap_cache(struct page *page)
{
#ifdef SWAP_CACHE_INFO
swap_cache_del_total++;
@@ -180,9 +190,7 @@ int delete_from_swap_cache(struct page *page)
#endif
remove_from_swap_cache (page);
swap_free (entry);
- return 1;
}
- return 0;
}
/*
@@ -218,57 +226,67 @@ static struct page * lookup_swap_cache(unsigned long entry)
found = find_page(&swapper_inode, entry);
if (!found)
return 0;
- if (found->inode != &swapper_inode
- || !PageSwapCache(found)) {
- __free_page(found);
- printk ("VM: Found a non-swapper swap page!\n");
- return 0;
- }
+ if (found->inode != &swapper_inode || !PageSwapCache(found))
+ goto out_bad;
if (!PageLocked(found))
return found;
__free_page(found);
__wait_on_page(found);
}
+
+out_bad:
+ printk (KERN_ERR "VM: Found a non-swapper swap page!\n");
+ __free_page(found);
+ return 0;
}
/*
* Locate a page of swap in physical memory, reserving swap cache space
* and reading the disk if it is not already cached. If wait==0, we are
* only doing readahead, so don't worry if the page is already locked.
+ *
+ * A failure return means that either the page allocation failed or that
+ * the swap entry is no longer in use.
*/
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;
+ struct page *found_page, *new_page;
+ unsigned long new_page_addr;
#ifdef DEBUG_SWAP
printk("DebugVM: read_swap_cache_async entry %08lx%s\n",
entry, wait ? ", wait" : "");
#endif
-repeat:
+ /*
+ * Look for the page in the swap cache.
+ */
found_page = lookup_swap_cache(entry);
- if (found_page) {
- if (new_page)
- __free_page(new_page);
- return found_page;
- }
+ if (found_page)
+ goto out;
+
+ new_page_addr = __get_free_page(GFP_KERNEL);
+ if (!new_page_addr)
+ goto out; /* Out of memory */
+ new_page = mem_map + MAP_NR(new_page_addr);
+
+ /*
+ * Check the swap cache again, in case we stalled above.
+ */
+ found_page = lookup_swap_cache(entry);
+ if (found_page)
+ goto out_free_page;
+ /*
+ * Make sure the swap entry is still in use.
+ */
+ if (!swap_duplicate(entry)) /* Account for the swap cache */
+ goto out_free_page;
+ /*
+ * Add it to the swap cache and read its contents.
+ */
+ if (!add_to_swap_cache(new_page, entry))
+ goto out_free_page;
- /* 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_user_page(addr);
- if (!new_page_addr)
- return 0; /* Out of memory */
- new_page = mem_map + MAP_NR(new_page_addr);
- goto repeat; /* We might have stalled */
- }
-
- if (!add_to_swap_cache(new_page, entry)) {
- free_page(new_page_addr);
- return 0;
- }
- swap_duplicate(entry); /* Account for the swap cache */
set_bit(PG_locked, &new_page->flags);
rw_swap_page(READ, entry, (char *) new_page_addr, wait);
#ifdef DEBUG_SWAP
@@ -277,5 +295,9 @@ repeat:
entry, (char *) page_address(new_page));
#endif
return new_page;
-}
+out_free_page:
+ __free_page(new_page);
+out:
+ return found_page;
+}
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 45f73de02..b7446b3b5 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -9,7 +9,6 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/sched.h>
-#include <linux/head.h>
#include <linux/kernel.h>
#include <linux/kernel_stat.h>
#include <linux/errno.h>
@@ -22,6 +21,7 @@
#include <linux/blkdev.h> /* for blk_size */
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
+#include <linux/shm.h>
#include <asm/bitops.h>
#include <asm/pgtable.h>
@@ -116,10 +116,7 @@ unsigned long get_swap_page(void)
}
}
-/*
- * If the swap count overflows (swap_map[] == 127), the entry is considered
- * "permanent" and can't be reclaimed until the swap device is closed.
- */
+
void swap_free(unsigned long entry)
{
struct swap_info_struct * p;
@@ -147,7 +144,7 @@ void swap_free(unsigned long entry)
p->highest_bit = offset;
if (!p->swap_map[offset])
goto bad_free;
- if (p->swap_map[offset] < 127) {
+ if (p->swap_map[offset] < SWAP_MAP_MAX) {
if (!--p->swap_map[offset])
nr_swap_pages++;
}
@@ -299,44 +296,55 @@ static int try_to_unuse(unsigned int type)
{
struct swap_info_struct * si = &swap_info[type];
struct task_struct *p;
- unsigned long page = 0;
struct page *page_map;
- unsigned long entry;
+ unsigned long entry, page;
int i;
while (1) {
/*
* Find a swap page in use and read it in.
*/
- for (i = 1 , entry = 0; i < si->max ; i++) {
- if (si->swap_map[i] > 0 && si->swap_map[i] != 0x80) {
- entry = SWP_ENTRY(type, i);
- break;
+ for (i = 1; i < si->max ; i++) {
+ if (si->swap_map[i] > 0 && si->swap_map[i] != SWAP_MAP_BAD) {
+ goto found_entry;
}
}
- if (!entry)
- break;
+ break;
+
+ found_entry:
+ entry = SWP_ENTRY(type, i);
/* 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, 0);
- if (!page_map)
+ if (!page_map) {
+ /*
+ * Continue searching if the entry became unused.
+ */
+ if (si->swap_map[i] == 0)
+ continue;
return -ENOMEM;
+ }
page = page_address(page_map);
read_lock(&tasklist_lock);
for_each_task(p)
unuse_process(p->mm, entry, page);
read_unlock(&tasklist_lock);
+ shm_unuse(entry, page);
/* Now get rid of the extra reference to the temporary
page we've been using. */
if (PageSwapCache(page_map))
delete_from_swap_cache(page_map);
- free_page(page);
+ __free_page(page_map);
+ /*
+ * Check for and clear any overflowed swap map counts.
+ */
if (si->swap_map[i] != 0) {
- if (si->swap_map[i] != 127)
- printk("try_to_unuse: entry %08lx "
- "not in use\n", entry);
+ if (si->swap_map[i] != SWAP_MAP_MAX)
+ printk(KERN_ERR
+ "try_to_unuse: entry %08lx count=%d\n",
+ entry, si->swap_map[i]);
si->swap_map[i] = 0;
nr_swap_pages++;
}
@@ -377,10 +385,9 @@ asmlinkage int sys_swapoff(const char * specialfile)
prev = type;
}
err = -EINVAL;
- if (type < 0){
- dput(dentry);
- goto out;
- }
+ if (type < 0)
+ goto out_dput;
+
if (prev < 0) {
swap_list.head = p->next;
} else {
@@ -393,7 +400,6 @@ asmlinkage int sys_swapoff(const char * specialfile)
p->flags = SWP_USED;
err = try_to_unuse(type);
if (err) {
- dput(dentry);
/* re-insert swap space back into swap_list */
for (prev = -1, i = swap_list.head; i >= 0; prev = i, i = swap_info[i].next)
if (p->prio >= swap_info[i].prio)
@@ -404,7 +410,7 @@ asmlinkage int sys_swapoff(const char * specialfile)
else
swap_info[prev].next = p - swap_info;
p->flags = SWP_WRITEOK;
- goto out;
+ goto out_dput;
}
if(p->swap_device){
memset(&filp, 0, sizeof(filp));
@@ -419,16 +425,19 @@ asmlinkage int sys_swapoff(const char * specialfile)
}
dput(dentry);
- nr_swap_pages -= p->pages;
- dput(p->swap_file);
+ dentry = p->swap_file;
p->swap_file = NULL;
+ nr_swap_pages -= p->pages;
p->swap_device = 0;
vfree(p->swap_map);
p->swap_map = NULL;
- free_page((long) p->swap_lockmap);
+ vfree(p->swap_lockmap);
p->swap_lockmap = NULL;
p->flags = 0;
err = 0;
+
+out_dput:
+ dput(dentry);
out:
unlock_kernel();
return err;
@@ -458,7 +467,7 @@ int get_swaparea_info(char *buf)
usedswap = 0;
for (j = 0; j < ptr->max; ++j)
switch (ptr->swap_map[j]) {
- case 128:
+ case SWAP_MAP_BAD:
case 0:
continue;
default:
@@ -486,7 +495,12 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags)
int error = -EPERM;
struct file filp;
static int least_priority = 0;
-
+ union swap_header *swap_header = 0;
+ int swap_header_version;
+ int lock_map_size = PAGE_SIZE;
+ int nr_good_pages = 0;
+ unsigned long tmp_lock_map = 0;
+
lock_kernel();
if (!capable(CAP_SYS_ADMIN))
goto out;
@@ -547,54 +561,114 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags)
}
} else if (!S_ISREG(swap_dentry->d_inode->i_mode))
goto bad_swap;
- p->swap_lockmap = (unsigned char *) get_free_page(GFP_USER);
- if (!p->swap_lockmap) {
+ swap_header = (void *) __get_free_page(GFP_USER);
+ if (!swap_header) {
printk("Unable to start swapping: out of memory :-)\n");
error = -ENOMEM;
goto bad_swap;
}
- rw_swap_page_nocache(READ, SWP_ENTRY(type,0), (char *) p->swap_lockmap);
- if (memcmp("SWAP-SPACE",p->swap_lockmap+PAGE_SIZE-10,10)) {
+
+ p->swap_lockmap = (char *) &tmp_lock_map;
+ rw_swap_page_nocache(READ, SWP_ENTRY(type,0), (char *) swap_header);
+ p->swap_lockmap = NULL;
+
+ if (!memcmp("SWAP-SPACE",swap_header->magic.magic,10))
+ swap_header_version = 1;
+ else if (!memcmp("SWAPSPACE2",swap_header->magic.magic,10))
+ swap_header_version = 2;
+ else {
printk("Unable to find swap-space signature\n");
error = -EINVAL;
goto bad_swap;
}
- memset(p->swap_lockmap+PAGE_SIZE-10,0,10);
- j = 0;
- p->lowest_bit = 0;
- p->highest_bit = 0;
- for (i = 1 ; i < 8*PAGE_SIZE ; i++) {
- if (test_bit(i,p->swap_lockmap)) {
- if (!p->lowest_bit)
- p->lowest_bit = i;
- p->highest_bit = i;
- p->max = i+1;
- j++;
+
+ switch (swap_header_version) {
+ case 1:
+ memset(((char *) swap_header)+PAGE_SIZE-10,0,10);
+ j = 0;
+ p->lowest_bit = 0;
+ p->highest_bit = 0;
+ for (i = 1 ; i < 8*PAGE_SIZE ; i++) {
+ if (test_bit(i,(char *) swap_header)) {
+ if (!p->lowest_bit)
+ p->lowest_bit = i;
+ p->highest_bit = i;
+ p->max = i+1;
+ j++;
+ }
+ }
+ nr_good_pages = j;
+ p->swap_map = vmalloc(p->max * sizeof(short));
+ if (!p->swap_map) {
+ error = -ENOMEM;
+ goto bad_swap;
+ }
+ for (i = 1 ; i < p->max ; i++) {
+ if (test_bit(i,(char *) swap_header))
+ p->swap_map[i] = 0;
+ else
+ p->swap_map[i] = SWAP_MAP_BAD;
+ }
+ break;
+
+ case 2:
+ /* Check the swap header's sub-version and the size of
+ the swap file and bad block lists */
+ if (swap_header->info.version != 1) {
+ printk(KERN_WARNING
+ "Unable to handle swap header version %d\n",
+ swap_header->info.version);
+ error = -EINVAL;
+ goto bad_swap;
+ }
+
+ p->lowest_bit = 1;
+ p->highest_bit = swap_header->info.last_page - 1;
+ p->max = swap_header->info.last_page;
+
+ if (p->max >= 0x7fffffffL/PAGE_SIZE ||
+ (void *) &swap_header->info.badpages[swap_header->info.nr_badpages-1] >= (void *) swap_header->magic.magic) {
+ error = -EINVAL;
+ goto bad_swap;
}
+
+ /* OK, set up the swap map and apply the bad block list */
+ if (!(p->swap_map = vmalloc (p->max * sizeof(short)))) {
+ error = -ENOMEM;
+ goto bad_swap;
+ }
+
+ error = 0;
+ memset(p->swap_map, 0, p->max * sizeof(short));
+ for (i=0; i<swap_header->info.nr_badpages; i++) {
+ int page = swap_header->info.badpages[i];
+ if (page <= 0 || page >= swap_header->info.last_page)
+ error = -EINVAL;
+ else
+ p->swap_map[page] = SWAP_MAP_BAD;
+ }
+ nr_good_pages = swap_header->info.last_page - i;
+ lock_map_size = (p->max + 7) / 8;
+ if (error)
+ goto bad_swap;
}
- if (!j) {
- printk("Empty swap-file\n");
+
+ if (!nr_good_pages) {
+ printk(KERN_WARNING "Empty swap-file\n");
error = -EINVAL;
goto bad_swap;
}
- p->swap_map = (unsigned char *) vmalloc(p->max);
- if (!p->swap_map) {
+ p->swap_map[0] = SWAP_MAP_BAD;
+ if (!(p->swap_lockmap = vmalloc (lock_map_size))) {
error = -ENOMEM;
goto bad_swap;
}
- for (i = 1 ; i < p->max ; i++) {
- if (test_bit(i,p->swap_lockmap))
- p->swap_map[i] = 0;
- else
- p->swap_map[i] = 0x80;
- }
- p->swap_map[0] = 0x80;
- memset(p->swap_lockmap,0,PAGE_SIZE);
+ memset(p->swap_lockmap,0,lock_map_size);
p->flags = SWP_WRITEOK;
- p->pages = j;
- nr_swap_pages += j;
+ p->pages = nr_good_pages;
+ nr_swap_pages += nr_good_pages;
printk(KERN_INFO "Adding Swap: %dk swap-space (priority %d)\n",
- j<<(PAGE_SHIFT-10), p->prio);
+ nr_good_pages<<(PAGE_SHIFT-10), p->prio);
/* insert swap space into swap_list: */
prev = -1;
@@ -616,8 +690,10 @@ bad_swap:
if(filp.f_op && filp.f_op->release)
filp.f_op->release(filp.f_dentry->d_inode,&filp);
bad_swap_2:
- free_page((long) p->swap_lockmap);
- vfree(p->swap_map);
+ if (p->swap_lockmap)
+ vfree(p->swap_lockmap);
+ if (p->swap_map)
+ vfree(p->swap_map);
dput(p->swap_file);
p->swap_device = 0;
p->swap_file = NULL;
@@ -625,6 +701,8 @@ bad_swap_2:
p->swap_lockmap = NULL;
p->flags = 0;
out:
+ if (swap_header)
+ free_page((long) swap_header);
unlock_kernel();
return error;
}
@@ -639,7 +717,7 @@ void si_swapinfo(struct sysinfo *val)
continue;
for (j = 0; j < swap_info[i].max; ++j)
switch (swap_info[i].swap_map[j]) {
- case 128:
+ case SWAP_MAP_BAD:
continue;
case 0:
++val->freeswap;
@@ -651,4 +729,3 @@ void si_swapinfo(struct sysinfo *val)
val->totalswap <<= PAGE_SHIFT;
return;
}
-
diff --git a/mm/vmscan.c b/mm/vmscan.c
index b586bce72..884e67150 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -12,7 +12,6 @@
#include <linux/mm.h>
#include <linux/sched.h>
-#include <linux/head.h>
#include <linux/kernel.h>
#include <linux/kernel_stat.h>
#include <linux/errno.h>
@@ -24,6 +23,7 @@
#include <linux/dcache.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
+#include <linux/init.h>
#include <asm/bitops.h>
#include <asm/pgtable.h>
@@ -491,7 +491,7 @@ static int do_try_to_free_page(int gfp_mask)
* may be printed in the middle of another driver's init
* message). It looks very bad when that happens.
*/
-void kswapd_setup(void)
+void __init kswapd_setup(void)
{
int i;
char *revision="$Revision: 1.5 $", *s, *e;
@@ -529,6 +529,20 @@ int kswapd(void *unused)
namings for POSIX.4 realtime scheduling
priorities. */
+ /*
+ * Tell the memory management that we're a "memory allocator",
+ * and that if we need more memory we should get access to it
+ * regardless (see "try_to_free_pages()"). "kswapd" should
+ * never get caught in the normal page freeing logic.
+ *
+ * (Kswapd normally doesn't need memory anyway, but sometimes
+ * you need a small amount of memory in order to be able to
+ * page out something else, and this flag essentially protects
+ * us from recursively trying to free more memory as we're
+ * trying to free the first piece of memory in the first place).
+ */
+ current->flags |= PF_MEMALLOC;
+
init_swap_timer();
add_wait_queue(&kswapd_wait, &wait);
while (1) {
@@ -592,7 +606,7 @@ int try_to_free_pages(unsigned int gfp_mask, int count)
int retval = 1;
lock_kernel();
- if (current->flags & PF_MEMALLOC) {
+ if (!(current->flags & PF_MEMALLOC)) {
current->flags |= PF_MEMALLOC;
do {
retval = do_try_to_free_page(gfp_mask);
@@ -600,7 +614,7 @@ int try_to_free_pages(unsigned int gfp_mask, int count)
break;
count--;
} while (count > 0);
- current->flags &= PF_MEMALLOC;
+ current->flags &= ~PF_MEMALLOC;
}
unlock_kernel();
return retval;