diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-06-22 23:49:01 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-06-22 23:49:01 +0000 |
commit | d221c44b7afefd8f77f8595af468dfacb3b21cc2 (patch) | |
tree | ef1c7aa4fe157c9f63be777cc6809f292da1f5d5 /mm | |
parent | 51d3b7814cdccef9188240fe0cbd8d97ff2c7470 (diff) |
Merge with Linux 2.3.8.
Diffstat (limited to 'mm')
-rw-r--r-- | mm/filemap.c | 209 | ||||
-rw-r--r-- | mm/page_alloc.c | 7 | ||||
-rw-r--r-- | mm/page_io.c | 139 | ||||
-rw-r--r-- | mm/swap_state.c | 39 | ||||
-rw-r--r-- | mm/swapfile.c | 21 | ||||
-rw-r--r-- | mm/vmscan.c | 67 |
6 files changed, 121 insertions, 361 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 4e885758f..8936d35d1 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -37,29 +37,11 @@ atomic_t page_cache_size = ATOMIC_INIT(0); struct page * page_hash_table[PAGE_HASH_SIZE]; -/* - * Define a request structure for outstanding page write requests - * to the background page io daemon - */ - -struct pio_request -{ - struct pio_request * next; - struct file * file; - unsigned long offset; - unsigned long page; -}; -static struct pio_request *pio_first = NULL, **pio_last = &pio_first; -static kmem_cache_t *pio_request_cache; -static DECLARE_WAIT_QUEUE_HEAD(pio_wait); - spinlock_t pagecache_lock = SPIN_LOCK_UNLOCKED; -static inline void -make_pio_request(struct file *, unsigned long, unsigned long); - -void __add_page_to_hash_queue(struct page * page, struct page **p){ +void __add_page_to_hash_queue(struct page * page, struct page **p) +{ atomic_inc(&page_cache_size); if((page->next_hash = *p) != NULL) (*p)->pprev_hash = &page->next_hash; @@ -233,7 +215,7 @@ extern atomic_t too_many_dirty_buffers; int shrink_mmap(int priority, int gfp_mask) { static unsigned long clock = 0; - unsigned long limit = num_physpages; + unsigned long limit = num_physpages << 1; struct page * page; int count, users; @@ -264,6 +246,8 @@ int shrink_mmap(int priority, int gfp_mask) if ((gfp_mask & __GFP_DMA) && !PageDMA(page)) continue; + count--; + /* * Some common cases that we just short-circuit without * getting the locks - we need to re-check this once we @@ -308,23 +292,16 @@ int shrink_mmap(int priority, int gfp_mask) /* Is it a buffer page? */ if (page->buffers) { - kdev_t dev = page->buffers->b_dev; spin_unlock(&pagecache_lock); if (try_to_free_buffers(page)) goto made_progress; - if (!atomic_read(&too_many_dirty_buffers)) { - atomic_set(&too_many_dirty_buffers, 1); - balance_dirty(dev); - } - goto unlock_continue; + spin_lock(&pagecache_lock); } /* We can't free pages unless there's just one user */ if (page_count(page) != 2) goto spin_unlock_continue; - count--; - /* * Is it a page swap page? If so, we want to * drop it if it is no longer used, even if it @@ -485,6 +462,13 @@ static inline void __add_to_page_cache(struct page * page, __add_page_to_hash_queue(page, hash); } +void add_to_page_cache(struct page * page, struct inode * inode, unsigned long offset) +{ + spin_lock(&pagecache_lock); + __add_to_page_cache(page, inode, offset, page_hash(inode, offset)); + spin_unlock(&pagecache_lock); +} + int add_to_page_cache_unique(struct page * page, struct inode * inode, unsigned long offset, struct page **hash) @@ -646,7 +630,6 @@ repeat: struct page * __find_lock_page (struct inode * inode, unsigned long offset, struct page **hash) { - int locked; struct page *page; /* @@ -656,16 +639,12 @@ struct page * __find_lock_page (struct inode * inode, repeat: spin_lock(&pagecache_lock); page = __find_page_nolock(inode, offset, *hash); - locked = 0; - if (page) { + if (page) get_page(page); - if (TryLockPage(page)) - locked = 1; - } spin_unlock(&pagecache_lock); /* Found the page, sleep if locked. */ - if (page && locked) { + if (page && TryLockPage(page)) { struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); @@ -1460,7 +1439,6 @@ static inline int do_write_page(struct inode * inode, struct file * file, { int retval; unsigned long size; - loff_t loff = offset; int (*writepage) (struct file *, struct page *); struct page * page; @@ -1479,15 +1457,8 @@ static inline int do_write_page(struct inode * inode, struct file * file, page = mem_map + MAP_NR(page_addr); lock_page(page); - if (writepage) { - retval = writepage(file, page); - } else { - mm_segment_t old_fs = get_fs(); - set_fs(KERNEL_DS); - if (size == file->f_op->write(file, page_addr, size, &loff)) - retval = 0; - set_fs(old_fs); - } + retval = writepage(file, page); + UnlockPage(page); return retval; } @@ -1505,25 +1476,12 @@ static int filemap_write_page(struct vm_area_struct * vma, file = vma->vm_file; dentry = file->f_dentry; inode = dentry->d_inode; - if (!file->f_op->write) - return -EIO; /* * If a task terminates while we're swapping the page, the vma and * and file could be released ... increment the count to be safe. */ file->f_count++; - - /* - * If this is a swapping operation rather than msync(), then - * leave the actual IO, and the restoration of the file count, - * to the kpiod thread. Just queue the request for now. - */ - if (!wait) { - make_pio_request(file, offset, page); - return 0; - } - result = do_write_page(inode, file, (const char *) page, offset); fput(file); return result; @@ -1535,9 +1493,12 @@ static int filemap_write_page(struct vm_area_struct * vma, * trying to swap something out and swap something in * at the same time.. */ +extern void wakeup_bdflush(int); int filemap_swapout(struct vm_area_struct * vma, struct page * page) { - return filemap_write_page(vma, page->offset, page_address(page), 0); + int retval = filemap_write_page(vma, page->offset, page_address(page), 0); + wakeup_bdflush(0); + return retval; } static inline int filemap_sync_pte(pte_t * ptep, struct vm_area_struct *vma, @@ -1712,8 +1673,11 @@ int generic_file_mmap(struct file * file, struct vm_area_struct * vma) struct inode *inode = file->f_dentry->d_inode; ops = &file_private_mmap; - if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) + if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) { + if (!inode->i_op || !inode->i_op->writepage) + return -EINVAL; ops = &file_shared_mmap; + } if (!inode->i_sb || !S_ISREG(inode->i_mode)) return -EACCES; if (!inode->i_op || !inode->i_op->readpage) @@ -1950,126 +1914,3 @@ void put_cached_page(unsigned long addr) page_count(page)); page_cache_release(page); } - - -/* Add request for page IO to the queue */ - -static inline void put_pio_request(struct pio_request *p) -{ - *pio_last = p; - p->next = NULL; - pio_last = &p->next; -} - -/* Take the first page IO request off the queue */ - -static inline struct pio_request * get_pio_request(void) -{ - struct pio_request * p = pio_first; - pio_first = p->next; - if (!pio_first) - pio_last = &pio_first; - return p; -} - -/* Make a new page IO request and queue it to the kpiod thread */ - -static inline void make_pio_request(struct file *file, - unsigned long offset, - unsigned long pageaddr) -{ - struct pio_request *p; - struct page *page; - - page = page_cache_entry(pageaddr); - get_page(page); - - /* - * We need to allocate without causing any recursive IO in the - * current thread's context. We might currently be swapping out - * as a result of an allocation made while holding a critical - * filesystem lock. To avoid deadlock, we *MUST* not reenter - * the filesystem in this thread. - * - * We can wait for kswapd to free memory, or we can try to free - * pages without actually performing further IO, without fear of - * deadlock. --sct - */ - - while ((p = kmem_cache_alloc(pio_request_cache, GFP_BUFFER)) == NULL) { - if (try_to_free_pages(__GFP_WAIT)) - continue; - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); - } - - p->file = file; - p->offset = offset; - p->page = pageaddr; - - put_pio_request(p); - wake_up(&pio_wait); -} - - -/* - * This is the only thread which is allowed to write out filemap pages - * while swapping. - * - * To avoid deadlock, it is important that we never reenter this thread. - * Although recursive memory allocations within this thread may result - * in more page swapping, that swapping will always be done by queuing - * another IO request to the same thread: we will never actually start - * that IO request until we have finished with the current one, and so - * we will not deadlock. - */ - -int kpiod(void * unused) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - struct inode * inode; - struct dentry * dentry; - struct pio_request * p; - - tsk->session = 1; - tsk->pgrp = 1; - strcpy(tsk->comm, "kpiod"); - sigfillset(&tsk->blocked); - /* - * Mark this task as a memory allocator - we don't want to get caught - * up in the regular mm freeing frenzy if we have to allocate memory - * in order to write stuff out. - */ - tsk->flags |= PF_MEMALLOC; - - lock_kernel(); - - pio_request_cache = kmem_cache_create("pio_request", - sizeof(struct pio_request), - 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); - if (!pio_request_cache) - panic ("Could not create pio_request slab cache"); - - while (1) { - tsk->state = TASK_INTERRUPTIBLE; - add_wait_queue(&pio_wait, &wait); - if (!pio_first) - schedule(); - remove_wait_queue(&pio_wait, &wait); - tsk->state = TASK_RUNNING; - - while (pio_first) { - p = get_pio_request(); - dentry = p->file->f_dentry; - inode = dentry->d_inode; - - do_write_page(inode, p->file, - (const char *) p->page, p->offset); - fput(p->file); - page_cache_free(p->page); - kmem_cache_free(pio_request_cache, p); - } - } -} diff --git a/mm/page_alloc.c b/mm/page_alloc.c index fad87ba27..3f30a049e 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -124,6 +124,9 @@ int __free_page(struct page *page) if (!PageReserved(page) && put_page_testzero(page)) { if (PageSwapCache(page)) PAGE_BUG(page); + if (PageLocked(page)) + PAGE_BUG(page); + page->flags &= ~(1 << PG_referenced); free_pages_ok(page - mem_map, 0); return 1; @@ -140,6 +143,8 @@ int free_pages(unsigned long addr, unsigned long order) if (!PageReserved(map) && put_page_testzero(map)) { if (PageSwapCache(map)) PAGE_BUG(map); + if (PageLocked(map)) + PAGE_BUG(map); map->flags &= ~(1 << PG_referenced); free_pages_ok(map_nr, order); return 1; @@ -369,8 +374,6 @@ void swapin_readahead(unsigned long entry) break; if (swapdev->swap_map[offset] == SWAP_MAP_BAD) break; - if (test_bit(offset, swapdev->swap_lockmap)) - break; /* Ok, do the async read-ahead now */ new_page = read_swap_cache_async(SWP_ENTRY(SWP_TYPE(entry), offset), 0); diff --git a/mm/page_io.c b/mm/page_io.c index 2226c2c9d..75b7195fb 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -35,7 +35,7 @@ static DECLARE_WAIT_QUEUE_HEAD(lock_queue); * that shared pages stay shared while being swapped. */ -static void rw_swap_page_base(int rw, unsigned long entry, struct page *page, int wait) +static void rw_swap_page_base(int rw, unsigned long entry, struct page *page, int wait, int dolock) { unsigned long type, offset; struct swap_info_struct * p; @@ -84,26 +84,6 @@ static void rw_swap_page_base(int rw, unsigned long entry, struct page *page, in return; } - if (PageSwapCache(page)) { - /* Make sure we are the only process doing I/O with this swap page. */ - while (test_and_set_bit(offset,p->swap_lockmap)) { - run_task_queue(&tq_disk); - sleep_on(&lock_queue); - } - - /* - * Make sure that we have a swap cache association for this - * page. We need this to find which swap page to unlock once - * the swap IO has completed to the physical page. If the page - * is not already in the cache, just overload the offset entry - * as if it were: we are not allowed to manipulate the inode - * hashing for locked pages. - */ - if (page->offset != entry) { - printk ("swap entry mismatch"); - return; - } - } if (rw == READ) { ClearPageUptodate(page); kstat.pswpin++; @@ -159,14 +139,6 @@ static void rw_swap_page_base(int rw, unsigned long entry, struct page *page, in } } else { printk(KERN_ERR "rw_swap_page: no swap file or device\n"); - /* Do some cleaning up so if this ever happens we can hopefully - * trigger controlled shutdown. - */ - if (PageSwapCache(page)) { - if (!test_and_clear_bit(offset,p->swap_lockmap)) - printk("swap_after_unlock_page: lock already cleared\n"); - wake_up(&lock_queue); - } put_page(page); return; } @@ -174,9 +146,10 @@ static void rw_swap_page_base(int rw, unsigned long entry, struct page *page, in set_bit(PG_decr_after, &page->flags); atomic_inc(&nr_async_pages); } - if (PageSwapCache(page)) { + if (dolock) { /* only lock/unlock swap cache pages! */ set_bit(PG_swap_unlock_after, &page->flags); + p->swap_map[offset]++; } set_bit(PG_free_after, &page->flags); @@ -203,93 +176,51 @@ static void rw_swap_page_base(int rw, unsigned long entry, struct page *page, in #endif } -/* Note: We could remove this totally asynchronous function, - * and improve swap performance, and remove the need for the swap lock map, - * by not removing pages from the swap cache until after I/O has been - * processed and letting remove_from_page_cache decrement the swap count - * just before it removes the page from the page cache. +/* + * This is run when asynchronous page I/O has completed. + * It decrements the swap bitmap counter */ -/* This is run when asynchronous page I/O has completed. */ -void swap_after_unlock_page (unsigned long entry) +void swap_after_unlock_page(unsigned long entry) { - unsigned long type, offset; - struct swap_info_struct * p; - - type = SWP_TYPE(entry); - if (type >= nr_swapfiles) { - printk("swap_after_unlock_page: bad swap-device\n"); - return; - } - p = &swap_info[type]; - offset = SWP_OFFSET(entry); - if (offset >= p->max) { - printk("swap_after_unlock_page: weirdness\n"); - return; - } - if (!test_and_clear_bit(offset,p->swap_lockmap)) - printk("swap_after_unlock_page: lock already cleared\n"); - wake_up(&lock_queue); + swap_free(entry); } -/* A simple wrapper so the base function doesn't need to enforce - * that all swap pages go through the swap cache! +/* + * A simple wrapper so the base function doesn't need to enforce + * that all swap pages go through the swap cache! We verify that: + * - the page is locked + * - it's marked as being swap-cache + * - it's associated with the swap inode */ -void rw_swap_page(int rw, unsigned long entry, char *buf, int wait) +void rw_swap_page(int rw, struct page *page, int wait) { - struct page *page = mem_map + MAP_NR(buf); + unsigned long entry = page->offset; - if (page->inode && page->inode != &swapper_inode) + if (!PageLocked(page)) PAGE_BUG(page); - - /* - * Make sure that we have a swap cache association for this - * page. We need this to find which swap page to unlock once - * the swap IO has completed to the physical page. If the page - * is not already in the cache, just overload the offset entry - * as if it were: we are not allowed to manipulate the inode - * hashing for locked pages. - */ - if (!PageSwapCache(page)) { - printk("VM: swap page is not in swap cache\n"); - return; - } - if (page->offset != entry) { - printk ("swap entry mismatch"); - return; - } - rw_swap_page_base(rw, entry, page, wait); + if (!PageSwapCache(page)) + PAGE_BUG(page); + if (page->inode != &swapper_inode) + PAGE_BUG(page); + rw_swap_page_base(rw, entry, page, wait, 1); } /* * Setting up a new swap file needs a simple wrapper just to read the * swap signature. SysV shared memory also needs a simple wrapper. */ -void rw_swap_page_nocache(int rw, unsigned long entry, char *buffer) +void rw_swap_page_nocache(int rw, unsigned long entry, char *buf) { - struct page *page; + struct page *page = mem_map + MAP_NR(buf); - page = mem_map + MAP_NR((unsigned long) buffer); - if (TryLockPage(page)) PAGE_BUG(page); - if (test_and_set_bit(PG_swap_cache, &page->flags)) + if (PageSwapCache(page)) PAGE_BUG(page); if (page->inode) PAGE_BUG(page); - get_page(page); /* Protect from shrink_mmap() */ - page->inode = &swapper_inode; page->offset = entry; - rw_swap_page(rw, entry, buffer, 1); - - /* - * and now remove it from the pagecache ... - */ - if (TryLockPage(page)) - PAGE_BUG(page); - PageClearSwapCache(page); - remove_inode_page(page); - page_cache_release(page); - UnlockPage(page); + rw_swap_page_base(rw, entry, page, 1, 1); } /* @@ -298,17 +229,13 @@ void rw_swap_page_nocache(int rw, unsigned long entry, char *buffer) * Therefore we can't use it. Later when we can remove the need for the * lock map and we can reduce the number of functions exported. */ -void rw_swap_page_nolock(int rw, unsigned long entry, char *buffer, int wait) +void rw_swap_page_nolock(int rw, unsigned long entry, char *buf, int wait) { - struct page *page = mem_map + MAP_NR((unsigned long) buffer); + struct page *page = mem_map + MAP_NR(buf); - if (!PageLocked(page)) { - printk("VM: rw_swap_page_nolock: page not locked!\n"); - return; - } - if (PageSwapCache(page)) { - printk ("VM: rw_swap_page_nolock: page in swap cache!\n"); - return; - } - rw_swap_page_base(rw, entry, page, wait); + if (!PageLocked(page)) + PAGE_BUG(page); + if (PageSwapCache(page)) + PAGE_BUG(page); + rw_swap_page_base(rw, entry, page, wait, 0); } diff --git a/mm/swap_state.c b/mm/swap_state.c index 21723c1db..8ee2699f0 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -66,7 +66,7 @@ void show_swap_cache_info(void) } #endif -int add_to_swap_cache(struct page *page, unsigned long entry) +void add_to_swap_cache(struct page *page, unsigned long entry) { #ifdef SWAP_CACHE_INFO swap_cache_add_total++; @@ -79,19 +79,12 @@ int add_to_swap_cache(struct page *page, unsigned long entry) 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(KERN_ERR "swap_cache: replacing page-cached entry " "on page %08lx\n", page_address(page)); - return 0; } - get_page(page); - page->inode = &swapper_inode; - page->offset = entry; - add_page_to_hash_queue(page, &swapper_inode, entry); - add_page_to_inode_queue(&swapper_inode, page); - return 1; + add_to_page_cache(page, &swapper_inode, entry); } /* @@ -202,21 +195,27 @@ bad_unused: static inline void remove_from_swap_cache(struct page *page) { - if (!page->inode) { + struct inode *inode = page->inode; + + if (!inode) { printk ("VM: Removing swap cache page with zero inode hash " "on page %08lx\n", page_address(page)); return; } - if (page->inode != &swapper_inode) { + if (inode != &swapper_inode) { printk ("VM: Removing swap cache page with wrong inode hash " "on page %08lx\n", page_address(page)); } + if (!PageSwapCache(page)) + PAGE_BUG(page); #ifdef DEBUG_SWAP printk("DebugVM: remove_from_swap_cache(%08lx count %d)\n", page_address(page), page_count(page)); #endif PageClearSwapCache(page); + if (inode->i_op->flushpage) + inode->i_op->flushpage(inode, page, 0); remove_inode_page(page); } @@ -266,8 +265,14 @@ void free_page_and_swap_cache(unsigned long addr) /* * If we are the only user, then free up the swap cache. */ - if (PageSwapCache(page) && !is_page_shared(page)) - delete_from_swap_cache(page); + lock_page(page); + if (PageSwapCache(page) && !is_page_shared(page)) { + long entry = page->offset; + remove_from_swap_cache(page); + swap_free(entry); + page_cache_release(page); + } + UnlockPage(page); __free_page(page); } @@ -351,11 +356,8 @@ struct page * read_swap_cache_async(unsigned long entry, int wait) /* * Add it to the swap cache and read its contents. */ - if (!add_to_swap_cache(new_page, entry)) - goto out_free_page; - - LockPage(new_page); - rw_swap_page(READ, entry, (char *) new_page_addr, wait); + add_to_swap_cache(new_page, entry); + rw_swap_page(READ, new_page, wait); #ifdef DEBUG_SWAP printk("DebugVM: read_swap_cache_async created " "entry %08lx at %p\n", @@ -370,4 +372,3 @@ out_free_swap: out: return found_page; } - diff --git a/mm/swapfile.c b/mm/swapfile.c index 794e39aff..a4a523ef2 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -42,8 +42,6 @@ static inline int scan_swap_map(struct swap_info_struct *si) offset = si->cluster_next++; if (si->swap_map[offset]) continue; - if (test_bit(offset, si->swap_lockmap)) - continue; si->cluster_nr--; goto got_page; } @@ -52,8 +50,6 @@ static inline int scan_swap_map(struct swap_info_struct *si) for (offset = si->lowest_bit; offset <= si->highest_bit ; offset++) { if (si->swap_map[offset]) continue; - if (test_bit(offset, si->swap_lockmap)) - continue; si->lowest_bit = offset; got_page: si->swap_map[offset] = 1; @@ -424,8 +420,6 @@ asmlinkage int sys_swapoff(const char * specialfile) p->swap_device = 0; vfree(p->swap_map); p->swap_map = NULL; - vfree(p->swap_lockmap); - p->swap_lockmap = NULL; p->flags = 0; err = 0; @@ -505,7 +499,6 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags) int lock_map_size = PAGE_SIZE; int nr_good_pages = 0; unsigned long maxpages; - unsigned long tmp_lock_map = 0; int swapfilesize; lock_kernel(); @@ -524,7 +517,6 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags) p->swap_file = NULL; p->swap_device = 0; p->swap_map = NULL; - p->swap_lockmap = NULL; p->lowest_bit = 0; p->highest_bit = 0; p->cluster_nr = 0; @@ -590,9 +582,8 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags) goto bad_swap; } - p->swap_lockmap = (char *) &tmp_lock_map; - rw_swap_page_nocache(READ, SWP_ENTRY(type,0), (char *) swap_header); - p->swap_lockmap = NULL; + lock_page(mem_map + MAP_NR(swap_header)); + rw_swap_page_nolock(READ, SWP_ENTRY(type,0), (char *) swap_header, 1); if (!memcmp("SWAP-SPACE",swap_header->magic.magic,10)) swap_header_version = 1; @@ -689,11 +680,6 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags) goto bad_swap; } p->swap_map[0] = SWAP_MAP_BAD; - if (!(p->swap_lockmap = vmalloc (lock_map_size))) { - error = -ENOMEM; - goto bad_swap; - } - memset(p->swap_lockmap,0,lock_map_size); p->flags = SWP_WRITEOK; p->pages = nr_good_pages; nr_swap_pages += nr_good_pages; @@ -720,15 +706,12 @@ bad_swap: if(filp.f_op && filp.f_op->release) filp.f_op->release(filp.f_dentry->d_inode,&filp); bad_swap_2: - 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; p->swap_map = NULL; - p->swap_lockmap = NULL; p->flags = 0; if (!(swap_flags & SWAP_FLAG_PREFER)) ++least_priority; diff --git a/mm/vmscan.c b/mm/vmscan.c index 9ca4988e4..4cccaf171 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -36,31 +36,35 @@ static int try_to_swap_out(struct task_struct * tsk, struct vm_area_struct* vma, { pte_t pte; unsigned long entry; - unsigned long page; - struct page * page_map; + unsigned long page_addr; + struct page * page; pte = *page_table; if (!pte_present(pte)) - return 0; - page = pte_page(pte); - if (MAP_NR(page) >= max_mapnr) - return 0; - page_map = mem_map + MAP_NR(page); + goto out_failed; + page_addr = pte_page(pte); + if (MAP_NR(page_addr) >= max_mapnr) + goto out_failed; + page = mem_map + MAP_NR(page_addr); - if (pte_young(pte)) { + /* + * Dont be too eager to get aging right if + * memory is dangerously low. + */ + if (!low_on_memory && pte_young(pte)) { /* * Transfer the "accessed" bit from the page * tables to the global page map. */ set_pte(page_table, pte_mkold(pte)); - set_bit(PG_referenced, &page_map->flags); - return 0; + set_bit(PG_referenced, &page->flags); + goto out_failed; } - if (PageReserved(page_map) - || PageLocked(page_map) - || ((gfp_mask & __GFP_DMA) && !PageDMA(page_map))) - return 0; + if (PageReserved(page) + || PageLocked(page) + || ((gfp_mask & __GFP_DMA) && !PageDMA(page))) + goto out_failed; /* * Is the page already in the swap cache? If so, then @@ -70,15 +74,15 @@ static int try_to_swap_out(struct task_struct * tsk, struct vm_area_struct* vma, * Return 0, as we didn't actually free any real * memory, and we should just continue our scan. */ - if (PageSwapCache(page_map)) { - entry = page_map->offset; + if (PageSwapCache(page)) { + entry = page->offset; swap_duplicate(entry); set_pte(page_table, __pte(entry)); drop_pte: vma->vm_mm->rss--; flush_tlb_page(vma, address); - __free_page(page_map); - return 0; + __free_page(page); + goto out_failed; } /* @@ -105,7 +109,7 @@ drop_pte: * locks etc. */ if (!(gfp_mask & __GFP_IO)) - return 0; + goto out_failed; /* * Ok, it's really dirty. That means that @@ -120,7 +124,7 @@ drop_pte: * assume we free'd something. * * NOTE NOTE NOTE! This should just set a - * dirty bit in page_map, and just drop the + * dirty bit in 'page', and just drop the * pte. All the hard work would be done by * shrink_mmap(). * @@ -133,10 +137,9 @@ drop_pte: flush_tlb_page(vma, address); vma->vm_mm->rss--; - if (vma->vm_ops->swapout(vma, page_map)) + if (vma->vm_ops->swapout(vma, page)) kill_proc(pid, SIGBUS, 1); - __free_page(page_map); - return 1; + goto out_free_success; } /* @@ -147,23 +150,25 @@ drop_pte: */ entry = get_swap_page(); if (!entry) - return 0; /* No swap space left */ + goto out_failed; /* No swap space left */ vma->vm_mm->rss--; tsk->nswap++; set_pte(page_table, __pte(entry)); flush_tlb_page(vma, address); swap_duplicate(entry); /* One for the process, one for the swap cache */ - add_to_swap_cache(page_map, entry); - /* We checked we were unlocked way up above, and we - have been careful not to stall until here */ - LockPage(page_map); + + /* This will also lock the page */ + add_to_swap_cache(page, entry); /* OK, do a physical asynchronous write to swap. */ - rw_swap_page(WRITE, entry, (char *) page, 0); + rw_swap_page(WRITE, page, 0); - __free_page(page_map); +out_free_success: + __free_page(page); return 1; +out_failed: + return 0; } /* @@ -490,8 +495,8 @@ int kswapd(void *unused) if (!do_try_to_free_pages(GFP_KSWAPD)) break; + run_task_queue(&tq_disk); } while (!tsk->need_resched); - run_task_queue(&tq_disk); tsk->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ); } |