Commit f97f22cb authored by Linus Torvalds's avatar Linus Torvalds

v2.4.13.3 -> v2.4.13.4

  - Mikael Pettersson: fix P4 boot with APIC enabled
  - me: fix device queuing thinko, clean up VM locking
parent ff35c838
VERSION = 2 VERSION = 2
PATCHLEVEL = 4 PATCHLEVEL = 4
SUBLEVEL = 14 SUBLEVEL = 14
EXTRAVERSION =-pre3 EXTRAVERSION =-pre4
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
......
...@@ -588,6 +588,7 @@ static int __init detect_init_APIC (void) ...@@ -588,6 +588,7 @@ static int __init detect_init_APIC (void)
goto no_apic; goto no_apic;
case X86_VENDOR_INTEL: case X86_VENDOR_INTEL:
if (boot_cpu_data.x86 == 6 || if (boot_cpu_data.x86 == 6 ||
(boot_cpu_data.x86 == 15 && cpu_has_apic) ||
(boot_cpu_data.x86 == 5 && cpu_has_apic)) (boot_cpu_data.x86 == 5 && cpu_has_apic))
break; break;
goto no_apic; goto no_apic;
......
...@@ -446,12 +446,15 @@ static struct request *__get_request_wait(request_queue_t *q, int rw) ...@@ -446,12 +446,15 @@ static struct request *__get_request_wait(request_queue_t *q, int rw)
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
generic_unplug_device(q); generic_unplug_device(q);
add_wait_queue_exclusive(&q->wait_for_request, &wait); add_wait_queue(&q->wait_for_request, &wait);
do { do {
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
if (q->rq[rw].count < batch_requests) if (q->rq[rw].count < batch_requests)
schedule(); schedule();
} while ((rq = get_request(q,rw)) == NULL); spin_lock_irq(&io_request_lock);
rq = get_request(q,rw);
spin_unlock_irq(&io_request_lock);
} while (rq == NULL);
remove_wait_queue(&q->wait_for_request, &wait); remove_wait_queue(&q->wait_for_request, &wait);
current->state = TASK_RUNNING; current->state = TASK_RUNNING;
return rq; return rq;
......
...@@ -271,7 +271,7 @@ static struct block_device_operations pcd_bdops = { ...@@ -271,7 +271,7 @@ static struct block_device_operations pcd_bdops = {
release: cdrom_release, release: cdrom_release,
ioctl: cdrom_ioctl, ioctl: cdrom_ioctl,
check_media_change: cdrom_media_changed, check_media_change: cdrom_media_changed,
} };
static struct cdrom_device_ops pcd_dops = { static struct cdrom_device_ops pcd_dops = {
pcd_open, pcd_open,
......
...@@ -780,31 +780,23 @@ extern unsigned int DRM(poll)(struct file *filp, ...@@ -780,31 +780,23 @@ extern unsigned int DRM(poll)(struct file *filp,
/* Mapping support (drm_vm.h) */ /* Mapping support (drm_vm.h) */
#if LINUX_VERSION_CODE < 0x020317 #if LINUX_VERSION_CODE < 0x020317
extern unsigned long DRM(vm_nopage)(struct vm_area_struct *vma, extern unsigned long DRM(vm_nopage)(struct vm_area_struct *vma,
unsigned long address, unsigned long address);
int write_access);
extern unsigned long DRM(vm_shm_nopage)(struct vm_area_struct *vma, extern unsigned long DRM(vm_shm_nopage)(struct vm_area_struct *vma,
unsigned long address, unsigned long address);
int write_access);
extern unsigned long DRM(vm_dma_nopage)(struct vm_area_struct *vma, extern unsigned long DRM(vm_dma_nopage)(struct vm_area_struct *vma,
unsigned long address, unsigned long address);
int write_access);
extern unsigned long DRM(vm_sg_nopage)(struct vm_area_struct *vma, extern unsigned long DRM(vm_sg_nopage)(struct vm_area_struct *vma,
unsigned long address, unsigned long address);
int write_access);
#else #else
/* Return type changed in 2.3.23 */ /* Return type changed in 2.3.23 */
extern struct page *DRM(vm_nopage)(struct vm_area_struct *vma, extern struct page *DRM(vm_nopage)(struct vm_area_struct *vma,
unsigned long address, unsigned long address);
int write_access);
extern struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma, extern struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma,
unsigned long address, unsigned long address);
int write_access);
extern struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma, extern struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma,
unsigned long address, unsigned long address);
int write_access);
extern struct page *DRM(vm_sg_nopage)(struct vm_area_struct *vma, extern struct page *DRM(vm_sg_nopage)(struct vm_area_struct *vma,
unsigned long address, unsigned long address);
int write_access);
#endif #endif
extern void DRM(vm_open)(struct vm_area_struct *vma); extern void DRM(vm_open)(struct vm_area_struct *vma);
extern void DRM(vm_close)(struct vm_area_struct *vma); extern void DRM(vm_close)(struct vm_area_struct *vma);
......
...@@ -58,13 +58,11 @@ struct vm_operations_struct DRM(vm_sg_ops) = { ...@@ -58,13 +58,11 @@ struct vm_operations_struct DRM(vm_sg_ops) = {
#if LINUX_VERSION_CODE < 0x020317 #if LINUX_VERSION_CODE < 0x020317
unsigned long DRM(vm_nopage)(struct vm_area_struct *vma, unsigned long DRM(vm_nopage)(struct vm_area_struct *vma,
unsigned long address, unsigned long address)
int write_access)
#else #else
/* Return type changed in 2.3.23 */ /* Return type changed in 2.3.23 */
struct page *DRM(vm_nopage)(struct vm_area_struct *vma, struct page *DRM(vm_nopage)(struct vm_area_struct *vma,
unsigned long address, unsigned long address)
int write_access)
#endif #endif
{ {
#if __REALLY_HAVE_AGP #if __REALLY_HAVE_AGP
...@@ -136,13 +134,11 @@ struct page *DRM(vm_nopage)(struct vm_area_struct *vma, ...@@ -136,13 +134,11 @@ struct page *DRM(vm_nopage)(struct vm_area_struct *vma,
#if LINUX_VERSION_CODE < 0x020317 #if LINUX_VERSION_CODE < 0x020317
unsigned long DRM(vm_shm_nopage)(struct vm_area_struct *vma, unsigned long DRM(vm_shm_nopage)(struct vm_area_struct *vma,
unsigned long address, unsigned long address)
int write_access)
#else #else
/* Return type changed in 2.3.23 */ /* Return type changed in 2.3.23 */
struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma, struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma,
unsigned long address, unsigned long address)
int write_access)
#endif #endif
{ {
#if LINUX_VERSION_CODE >= 0x020300 #if LINUX_VERSION_CODE >= 0x020300
...@@ -272,13 +268,11 @@ void DRM(vm_shm_close)(struct vm_area_struct *vma) ...@@ -272,13 +268,11 @@ void DRM(vm_shm_close)(struct vm_area_struct *vma)
#if LINUX_VERSION_CODE < 0x020317 #if LINUX_VERSION_CODE < 0x020317
unsigned long DRM(vm_dma_nopage)(struct vm_area_struct *vma, unsigned long DRM(vm_dma_nopage)(struct vm_area_struct *vma,
unsigned long address, unsigned long address)
int write_access)
#else #else
/* Return type changed in 2.3.23 */ /* Return type changed in 2.3.23 */
struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma, struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma,
unsigned long address, unsigned long address)
int write_access)
#endif #endif
{ {
drm_file_t *priv = vma->vm_file->private_data; drm_file_t *priv = vma->vm_file->private_data;
...@@ -309,13 +303,11 @@ struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma, ...@@ -309,13 +303,11 @@ struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma,
#if LINUX_VERSION_CODE < 0x020317 #if LINUX_VERSION_CODE < 0x020317
unsigned long DRM(vm_sg_nopage)(struct vm_area_struct *vma, unsigned long DRM(vm_sg_nopage)(struct vm_area_struct *vma,
unsigned long address, unsigned long address)
int write_access)
#else #else
/* Return type changed in 2.3.23 */ /* Return type changed in 2.3.23 */
struct page *DRM(vm_sg_nopage)(struct vm_area_struct *vma, struct page *DRM(vm_sg_nopage)(struct vm_area_struct *vma,
unsigned long address, unsigned long address)
int write_access)
#endif #endif
{ {
#if LINUX_VERSION_CODE >= 0x020300 #if LINUX_VERSION_CODE >= 0x020300
......
...@@ -569,7 +569,7 @@ static void add_entropy_words(struct entropy_store *r, const __u32 *in, ...@@ -569,7 +569,7 @@ static void add_entropy_words(struct entropy_store *r, const __u32 *in,
__u32 w; __u32 w;
while (nwords--) { while (nwords--) {
w = rotate_left(r->input_rotate, *in); w = rotate_left(r->input_rotate, *in++);
i = r->add_ptr = (r->add_ptr - 1) & wordmask; i = r->add_ptr = (r->add_ptr - 1) & wordmask;
/* /*
* Normally, we add 7 bits of rotation to the pool. * Normally, we add 7 bits of rotation to the pool.
......
...@@ -770,12 +770,6 @@ static void end_buffer_io_async(struct buffer_head * bh, int uptodate) ...@@ -770,12 +770,6 @@ static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
if (!PageError(page)) if (!PageError(page))
SetPageUptodate(page); SetPageUptodate(page);
/*
* Run the hooks that have to be done when a page I/O has completed.
*/
if (PageTestandClearDecrAfter(page))
atomic_dec(&nr_async_pages);
UnlockPage(page); UnlockPage(page);
return; return;
......
...@@ -125,7 +125,7 @@ extern pgprot_t protection_map[16]; ...@@ -125,7 +125,7 @@ extern pgprot_t protection_map[16];
struct vm_operations_struct { struct vm_operations_struct {
void (*open)(struct vm_area_struct * area); void (*open)(struct vm_area_struct * area);
void (*close)(struct vm_area_struct * area); void (*close)(struct vm_area_struct * area);
struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int write_access); struct page * (*nopage)(struct vm_area_struct * area, unsigned long address);
}; };
/* /*
...@@ -270,7 +270,7 @@ typedef struct page { ...@@ -270,7 +270,7 @@ typedef struct page {
#define PG_referenced 2 #define PG_referenced 2
#define PG_uptodate 3 #define PG_uptodate 3
#define PG_dirty 4 #define PG_dirty 4
#define PG_decr_after 5 #define PG_unused 5
#define PG_active 6 #define PG_active 6
#define PG_inactive 7 #define PG_inactive 7
#define PG_slab 8 #define PG_slab 8
...@@ -325,9 +325,6 @@ static inline void set_page_dirty(struct page * page) ...@@ -325,9 +325,6 @@ static inline void set_page_dirty(struct page * page)
#define SetPageReferenced(page) set_bit(PG_referenced, &(page)->flags) #define SetPageReferenced(page) set_bit(PG_referenced, &(page)->flags)
#define ClearPageReferenced(page) clear_bit(PG_referenced, &(page)->flags) #define ClearPageReferenced(page) clear_bit(PG_referenced, &(page)->flags)
#define PageTestandClearReferenced(page) test_and_clear_bit(PG_referenced, &(page)->flags) #define PageTestandClearReferenced(page) test_and_clear_bit(PG_referenced, &(page)->flags)
#define PageDecrAfter(page) test_bit(PG_decr_after, &(page)->flags)
#define SetPageDecrAfter(page) set_bit(PG_decr_after, &(page)->flags)
#define PageTestandClearDecrAfter(page) test_and_clear_bit(PG_decr_after, &(page)->flags)
#define PageSlab(page) test_bit(PG_slab, &(page)->flags) #define PageSlab(page) test_bit(PG_slab, &(page)->flags)
#define PageSetSlab(page) set_bit(PG_slab, &(page)->flags) #define PageSetSlab(page) set_bit(PG_slab, &(page)->flags)
#define PageClearSlab(page) clear_bit(PG_slab, &(page)->flags) #define PageClearSlab(page) clear_bit(PG_slab, &(page)->flags)
...@@ -415,7 +412,7 @@ extern void show_free_areas_node(pg_data_t *pgdat); ...@@ -415,7 +412,7 @@ extern void show_free_areas_node(pg_data_t *pgdat);
extern void clear_page_tables(struct mm_struct *, unsigned long, int); extern void clear_page_tables(struct mm_struct *, unsigned long, int);
extern int fail_writepage(struct page *); extern int fail_writepage(struct page *);
struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int no_share); struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address);
struct file *shmem_file_setup(char * name, loff_t size); struct file *shmem_file_setup(char * name, loff_t size);
extern void shmem_lock(struct file * file, int lock); extern void shmem_lock(struct file * file, int lock);
extern int shmem_zero_setup(struct vm_area_struct *); extern int shmem_zero_setup(struct vm_area_struct *);
...@@ -541,7 +538,7 @@ extern void truncate_inode_pages(struct address_space *, loff_t); ...@@ -541,7 +538,7 @@ extern void truncate_inode_pages(struct address_space *, loff_t);
/* generic vm_area_ops exported for stackable file systems */ /* generic vm_area_ops exported for stackable file systems */
extern int filemap_sync(struct vm_area_struct *, unsigned long, size_t, unsigned int); extern int filemap_sync(struct vm_area_struct *, unsigned long, size_t, unsigned int);
extern struct page *filemap_nopage(struct vm_area_struct *, unsigned long, int); extern struct page *filemap_nopage(struct vm_area_struct *, unsigned long);
/* /*
* GFP bitmasks.. * GFP bitmasks..
......
...@@ -491,7 +491,6 @@ EXPORT_SYMBOL(file_fsync); ...@@ -491,7 +491,6 @@ EXPORT_SYMBOL(file_fsync);
EXPORT_SYMBOL(fsync_inode_buffers); EXPORT_SYMBOL(fsync_inode_buffers);
EXPORT_SYMBOL(fsync_inode_data_buffers); EXPORT_SYMBOL(fsync_inode_data_buffers);
EXPORT_SYMBOL(clear_inode); EXPORT_SYMBOL(clear_inode);
EXPORT_SYMBOL(nr_async_pages);
EXPORT_SYMBOL(___strtok); EXPORT_SYMBOL(___strtok);
EXPORT_SYMBOL(init_special_inode); EXPORT_SYMBOL(init_special_inode);
EXPORT_SYMBOL(read_ahead); EXPORT_SYMBOL(read_ahead);
......
...@@ -49,8 +49,13 @@ struct page **page_hash_table; ...@@ -49,8 +49,13 @@ struct page **page_hash_table;
spinlock_t pagecache_lock ____cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; spinlock_t pagecache_lock ____cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
/* /*
* NOTE: to avoid deadlocking you must never acquire the pagecache_lock with * NOTE: to avoid deadlocking you must never acquire the pagemap_lru_lock
* the pagemap_lru_lock held. * with the pagecache_lock held.
*
* Ordering:
* swap_lock ->
* pagemap_lru_lock ->
* pagecache_lock
*/ */
spinlock_t pagemap_lru_lock ____cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; spinlock_t pagemap_lru_lock ____cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
...@@ -164,8 +169,8 @@ void invalidate_inode_pages(struct inode * inode) ...@@ -164,8 +169,8 @@ void invalidate_inode_pages(struct inode * inode)
head = &inode->i_mapping->clean_pages; head = &inode->i_mapping->clean_pages;
spin_lock(&pagecache_lock);
spin_lock(&pagemap_lru_lock); spin_lock(&pagemap_lru_lock);
spin_lock(&pagecache_lock);
curr = head->next; curr = head->next;
while (curr != head) { while (curr != head) {
...@@ -196,8 +201,8 @@ void invalidate_inode_pages(struct inode * inode) ...@@ -196,8 +201,8 @@ void invalidate_inode_pages(struct inode * inode)
continue; continue;
} }
spin_unlock(&pagemap_lru_lock);
spin_unlock(&pagecache_lock); spin_unlock(&pagecache_lock);
spin_unlock(&pagemap_lru_lock);
} }
static inline void truncate_partial_page(struct page *page, unsigned partial) static inline void truncate_partial_page(struct page *page, unsigned partial)
...@@ -633,8 +638,9 @@ void add_to_page_cache_locked(struct page * page, struct address_space *mapping, ...@@ -633,8 +638,9 @@ void add_to_page_cache_locked(struct page * page, struct address_space *mapping,
spin_lock(&pagecache_lock); spin_lock(&pagecache_lock);
add_page_to_inode_queue(mapping, page); add_page_to_inode_queue(mapping, page);
add_page_to_hash_queue(page, page_hash(mapping, index)); add_page_to_hash_queue(page, page_hash(mapping, index));
lru_cache_add(page);
spin_unlock(&pagecache_lock); spin_unlock(&pagecache_lock);
lru_cache_add(page);
} }
/* /*
...@@ -653,7 +659,6 @@ static inline void __add_to_page_cache(struct page * page, ...@@ -653,7 +659,6 @@ static inline void __add_to_page_cache(struct page * page,
page->index = offset; page->index = offset;
add_page_to_inode_queue(mapping, page); add_page_to_inode_queue(mapping, page);
add_page_to_hash_queue(page, hash); add_page_to_hash_queue(page, hash);
lru_cache_add(page);
} }
void add_to_page_cache(struct page * page, struct address_space * mapping, unsigned long offset) void add_to_page_cache(struct page * page, struct address_space * mapping, unsigned long offset)
...@@ -661,6 +666,7 @@ void add_to_page_cache(struct page * page, struct address_space * mapping, unsig ...@@ -661,6 +666,7 @@ void add_to_page_cache(struct page * page, struct address_space * mapping, unsig
spin_lock(&pagecache_lock); spin_lock(&pagecache_lock);
__add_to_page_cache(page, mapping, offset, page_hash(mapping, offset)); __add_to_page_cache(page, mapping, offset, page_hash(mapping, offset));
spin_unlock(&pagecache_lock); spin_unlock(&pagecache_lock);
lru_cache_add(page);
} }
int add_to_page_cache_unique(struct page * page, int add_to_page_cache_unique(struct page * page,
...@@ -680,6 +686,8 @@ int add_to_page_cache_unique(struct page * page, ...@@ -680,6 +686,8 @@ int add_to_page_cache_unique(struct page * page,
} }
spin_unlock(&pagecache_lock); spin_unlock(&pagecache_lock);
if (!err)
lru_cache_add(page);
return err; return err;
} }
...@@ -909,7 +917,9 @@ struct page * find_or_create_page(struct address_space *mapping, unsigned long i ...@@ -909,7 +917,9 @@ struct page * find_or_create_page(struct address_space *mapping, unsigned long i
newpage = NULL; newpage = NULL;
} }
spin_unlock(&pagecache_lock); spin_unlock(&pagecache_lock);
if (unlikely(newpage != NULL)) if (newpage == NULL)
lru_cache_add(page);
else
page_cache_release(newpage); page_cache_release(newpage);
} }
} }
...@@ -1385,6 +1395,7 @@ void do_generic_file_read(struct file * filp, loff_t *ppos, read_descriptor_t * ...@@ -1385,6 +1395,7 @@ void do_generic_file_read(struct file * filp, loff_t *ppos, read_descriptor_t *
page = cached_page; page = cached_page;
__add_to_page_cache(page, mapping, index, hash); __add_to_page_cache(page, mapping, index, hash);
spin_unlock(&pagecache_lock); spin_unlock(&pagecache_lock);
lru_cache_add(page);
cached_page = NULL; cached_page = NULL;
goto readpage; goto readpage;
...@@ -1671,14 +1682,13 @@ static void nopage_sequential_readahead(struct vm_area_struct * vma, ...@@ -1671,14 +1682,13 @@ static void nopage_sequential_readahead(struct vm_area_struct * vma,
* it in the page cache, and handles the special cases reasonably without * it in the page cache, and handles the special cases reasonably without
* having a lot of duplicated code. * having a lot of duplicated code.
*/ */
struct page * filemap_nopage(struct vm_area_struct * area, struct page * filemap_nopage(struct vm_area_struct * area, unsigned long address)
unsigned long address, int no_share)
{ {
int error; int error;
struct file *file = area->vm_file; struct file *file = area->vm_file;
struct address_space *mapping = file->f_dentry->d_inode->i_mapping; struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
struct page *page, **hash, *old_page; struct page *page, **hash;
unsigned long size, pgoff, endoff; unsigned long size, pgoff, endoff;
pgoff = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff; pgoff = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
...@@ -1724,22 +1734,9 @@ struct page * filemap_nopage(struct vm_area_struct * area, ...@@ -1724,22 +1734,9 @@ struct page * filemap_nopage(struct vm_area_struct * area,
* Found the page and have a reference on it, need to check sharing * Found the page and have a reference on it, need to check sharing
* and possibly copy it over to another page.. * and possibly copy it over to another page..
*/ */
old_page = page;
mark_page_accessed(page); mark_page_accessed(page);
if (no_share) { flush_page_to_ram(page);
struct page *new_page = alloc_page(GFP_HIGHUSER); return page;
if (new_page) {
copy_user_highpage(new_page, old_page, address);
flush_page_to_ram(new_page);
} else
new_page = NOPAGE_OOM;
page_cache_release(page);
return new_page;
}
flush_page_to_ram(old_page);
return old_page;
no_cached_page: no_cached_page:
/* /*
......
...@@ -906,7 +906,8 @@ static inline void break_cow(struct vm_area_struct * vma, struct page * new_page ...@@ -906,7 +906,8 @@ static inline void break_cow(struct vm_area_struct * vma, struct page * new_page
* change only once the write actually happens. This avoids a few races, * change only once the write actually happens. This avoids a few races,
* and potentially makes it more efficient. * and potentially makes it more efficient.
* *
* We hold the mm semaphore and the page_table_lock on entry and exit. * We hold the mm semaphore and the page_table_lock on entry and exit
* with the page_table_lock released.
*/ */
static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma,
unsigned long address, pte_t *page_table, pte_t pte) unsigned long address, pte_t *page_table, pte_t pte)
...@@ -950,6 +951,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, ...@@ -950,6 +951,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma,
break; break;
flush_cache_page(vma, address); flush_cache_page(vma, address);
establish_pte(vma, address, page_table, pte_mkyoung(pte_mkdirty(pte_mkwrite(pte)))); establish_pte(vma, address, page_table, pte_mkyoung(pte_mkdirty(pte_mkwrite(pte))));
spin_unlock(&mm->page_table_lock);
return 1; /* Minor fault */ return 1; /* Minor fault */
} }
...@@ -978,15 +980,16 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, ...@@ -978,15 +980,16 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma,
/* Free the old page.. */ /* Free the old page.. */
new_page = old_page; new_page = old_page;
} }
spin_unlock(&mm->page_table_lock);
free_lru_page(new_page); free_lru_page(new_page);
return 1; /* Minor fault */ return 1; /* Minor fault */
bad_wp_page: bad_wp_page:
spin_unlock(&mm->page_table_lock);
printk("do_wp_page: bogus page at address %08lx (page 0x%lx)\n",address,(unsigned long)old_page); printk("do_wp_page: bogus page at address %08lx (page 0x%lx)\n",address,(unsigned long)old_page);
return -1; return -1;
no_mem: no_mem:
free_lru_page(old_page); free_lru_page(old_page);
spin_lock(&mm->page_table_lock);
return -1; return -1;
} }
...@@ -1091,10 +1094,6 @@ void swapin_readahead(swp_entry_t entry) ...@@ -1091,10 +1094,6 @@ void swapin_readahead(swp_entry_t entry)
*/ */
num = valid_swaphandles(entry, &offset); num = valid_swaphandles(entry, &offset);
for (i = 0; i < num; offset++, i++) { for (i = 0; i < num; offset++, i++) {
/* Don't block on I/O for read-ahead */
if (atomic_read(&nr_async_pages) >=
pager_daemon.swap_cluster << page_cluster)
break;
/* Ok, do the async read-ahead now */ /* Ok, do the async read-ahead now */
new_page = read_swap_cache_async(SWP_ENTRY(SWP_TYPE(entry), offset)); new_page = read_swap_cache_async(SWP_ENTRY(SWP_TYPE(entry), offset));
if (!new_page) if (!new_page)
...@@ -1109,7 +1108,8 @@ void swapin_readahead(swp_entry_t entry) ...@@ -1109,7 +1108,8 @@ void swapin_readahead(swp_entry_t entry)
(swapper_space.nrpages*5 > total_swap_pages*4) (swapper_space.nrpages*5 > total_swap_pages*4)
/* /*
* We hold the mm semaphore and the page_table_lock on entry and exit. * We hold the mm semaphore and the page_table_lock on entry and
* should release the pagetable lock on exit..
*/ */
static int do_swap_page(struct mm_struct * mm, static int do_swap_page(struct mm_struct * mm,
struct vm_area_struct * vma, unsigned long address, struct vm_area_struct * vma, unsigned long address,
...@@ -1126,24 +1126,23 @@ static int do_swap_page(struct mm_struct * mm, ...@@ -1126,24 +1126,23 @@ static int do_swap_page(struct mm_struct * mm,
swapin_readahead(entry); swapin_readahead(entry);
page = read_swap_cache_async(entry); page = read_swap_cache_async(entry);
if (!page) { if (!page) {
spin_lock(&mm->page_table_lock);
/* /*
* Back out if somebody else faulted in this pte while * Back out if somebody else faulted in this pte while
* we released the page table lock. * we released the page table lock.
*/ */
return pte_same(*page_table, orig_pte) ? -1 : 1; int retval;
spin_lock(&mm->page_table_lock);
retval = pte_same(*page_table, orig_pte) ? -1 : 1;
spin_unlock(&mm->page_table_lock);
return retval;
} }
/* Had to read the page from swap area: Major fault */ /* Had to read the page from swap area: Major fault */
ret = 2; ret = 2;
} }
/* if (!Page_Uptodate(page))
* Freeze the "shared"ness of the page, ie page_count + swap_count. wait_on_page(page);
* Must lock page before transferring our swap count to already
* obtained page count.
*/
lock_page(page);
/* /*
* Back out if somebody else faulted in this pte while we * Back out if somebody else faulted in this pte while we
...@@ -1153,6 +1152,7 @@ static int do_swap_page(struct mm_struct * mm, ...@@ -1153,6 +1152,7 @@ static int do_swap_page(struct mm_struct * mm,
if (!pte_same(*page_table, orig_pte)) { if (!pte_same(*page_table, orig_pte)) {
UnlockPage(page); UnlockPage(page);
page_cache_release(page); page_cache_release(page);
spin_unlock(&mm->page_table_lock);
return 1; return 1;
} }
...@@ -1161,16 +1161,6 @@ static int do_swap_page(struct mm_struct * mm, ...@@ -1161,16 +1161,6 @@ static int do_swap_page(struct mm_struct * mm,
pte = mk_pte(page, vma->vm_page_prot); pte = mk_pte(page, vma->vm_page_prot);
swap_free(entry); swap_free(entry);
mark_page_accessed(page);
if (exclusive_swap_page(page)) {
if (write_access || vm_swap_full()) {
pte = pte_mkdirty(pte);
if (vma->vm_flags & VM_WRITE)
pte = pte_mkwrite(pte);
delete_from_swap_cache(page);
}
}
UnlockPage(page);
flush_page_to_ram(page); flush_page_to_ram(page);
flush_icache_page(vma, page); flush_icache_page(vma, page);
...@@ -1178,6 +1168,7 @@ static int do_swap_page(struct mm_struct * mm, ...@@ -1178,6 +1168,7 @@ static int do_swap_page(struct mm_struct * mm,
/* No need to invalidate - it was non-present before */ /* No need to invalidate - it was non-present before */
update_mmu_cache(vma, address, pte); update_mmu_cache(vma, address, pte);
spin_unlock(&mm->page_table_lock);
return ret; return ret;
} }
...@@ -1208,6 +1199,7 @@ static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma, ...@@ -1208,6 +1199,7 @@ static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma,
spin_lock(&mm->page_table_lock); spin_lock(&mm->page_table_lock);
if (!pte_none(*page_table)) { if (!pte_none(*page_table)) {
page_cache_release(page); page_cache_release(page);
spin_unlock(&mm->page_table_lock);
return 1; return 1;
} }
mm->rss++; mm->rss++;
...@@ -1220,10 +1212,10 @@ static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma, ...@@ -1220,10 +1212,10 @@ static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma,
/* No need to invalidate - it was non-present before */ /* No need to invalidate - it was non-present before */
update_mmu_cache(vma, addr, entry); update_mmu_cache(vma, addr, entry);
spin_unlock(&mm->page_table_lock);
return 1; /* Minor fault */ return 1; /* Minor fault */
no_mem: no_mem:
spin_lock(&mm->page_table_lock);
return -1; return -1;
} }
...@@ -1237,7 +1229,7 @@ static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma, ...@@ -1237,7 +1229,7 @@ static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma,
* do not need to flush old virtual caches or the TLB. * do not need to flush old virtual caches or the TLB.
* *
* This is called with the MM semaphore held and the page table * This is called with the MM semaphore held and the page table
* spinlock held. * spinlock held. Exit with the spinlock released.
*/ */
static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma, static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma,
unsigned long address, int write_access, pte_t *page_table) unsigned long address, int write_access, pte_t *page_table)
...@@ -1249,18 +1241,27 @@ static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma, ...@@ -1249,18 +1241,27 @@ static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma,
return do_anonymous_page(mm, vma, page_table, write_access, address); return do_anonymous_page(mm, vma, page_table, write_access, address);
spin_unlock(&mm->page_table_lock); spin_unlock(&mm->page_table_lock);
/* new_page = vma->vm_ops->nopage(vma, address & PAGE_MASK);
* The third argument is "no_share", which tells the low-level code
* to copy, not share the page even if sharing is possible. It's
* essentially an early COW detection.
*/
new_page = vma->vm_ops->nopage(vma, address & PAGE_MASK, (vma->vm_flags & VM_SHARED)?0:write_access);
spin_lock(&mm->page_table_lock);
if (new_page == NULL) /* no page was available -- SIGBUS */ if (new_page == NULL) /* no page was available -- SIGBUS */
return 0; return 0;
if (new_page == NOPAGE_OOM) if (new_page == NOPAGE_OOM)
return -1; return -1;
/*
* Should we do an early C-O-W break?
*/
if (write_access && !(vma->vm_flags & VM_SHARED)) {
struct page * page = alloc_page(GFP_HIGHUSER);
if (!page)
return -1;
copy_highpage(page, new_page);
page_cache_release(new_page);
lru_cache_add(page);
new_page = page;
}
spin_lock(&mm->page_table_lock);
/* /*
* This silly early PAGE_DIRTY setting removes a race * This silly early PAGE_DIRTY setting removes a race
* due to the bad i386 page protection. But it's valid * due to the bad i386 page protection. But it's valid
...@@ -1277,20 +1278,19 @@ static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma, ...@@ -1277,20 +1278,19 @@ static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma,
flush_page_to_ram(new_page); flush_page_to_ram(new_page);
flush_icache_page(vma, new_page); flush_icache_page(vma, new_page);
entry = mk_pte(new_page, vma->vm_page_prot); entry = mk_pte(new_page, vma->vm_page_prot);
if (write_access) { if (write_access)
entry = pte_mkwrite(pte_mkdirty(entry)); entry = pte_mkwrite(pte_mkdirty(entry));
} else if (page_count(new_page) > 1 &&
!(vma->vm_flags & VM_SHARED))
entry = pte_wrprotect(entry);
set_pte(page_table, entry); set_pte(page_table, entry);
} else { } else {
/* One of our sibling threads was faster, back out. */ /* One of our sibling threads was faster, back out. */
page_cache_release(new_page); free_lru_page(new_page);
spin_unlock(&mm->page_table_lock);
return 1; return 1;
} }
/* no need to invalidate: a not-present page shouldn't be cached */ /* no need to invalidate: a not-present page shouldn't be cached */
update_mmu_cache(vma, address, entry); update_mmu_cache(vma, address, entry);
spin_unlock(&mm->page_table_lock);
return 2; /* Major fault */ return 2; /* Major fault */
} }
...@@ -1311,6 +1311,9 @@ static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma, ...@@ -1311,6 +1311,9 @@ static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma,
* The adding of pages is protected by the MM semaphore (which we hold), * The adding of pages is protected by the MM semaphore (which we hold),
* so we don't need to worry about a page being suddenly been added into * so we don't need to worry about a page being suddenly been added into
* our VM. * our VM.
*
* We enter with the pagetable spinlock held, we are supposed to
* release it when done.
*/ */
static inline int handle_pte_fault(struct mm_struct *mm, static inline int handle_pte_fault(struct mm_struct *mm,
struct vm_area_struct * vma, unsigned long address, struct vm_area_struct * vma, unsigned long address,
...@@ -1338,6 +1341,7 @@ static inline int handle_pte_fault(struct mm_struct *mm, ...@@ -1338,6 +1341,7 @@ static inline int handle_pte_fault(struct mm_struct *mm,
} }
entry = pte_mkyoung(entry); entry = pte_mkyoung(entry);
establish_pte(vma, address, pte, entry); establish_pte(vma, address, pte, entry);
spin_unlock(&mm->page_table_lock);
return 1; return 1;
} }
...@@ -1347,7 +1351,6 @@ static inline int handle_pte_fault(struct mm_struct *mm, ...@@ -1347,7 +1351,6 @@ static inline int handle_pte_fault(struct mm_struct *mm,
int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct * vma, int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct * vma,
unsigned long address, int write_access) unsigned long address, int write_access)
{ {
int ret = -1;
pgd_t *pgd; pgd_t *pgd;
pmd_t *pmd; pmd_t *pmd;
...@@ -1364,10 +1367,10 @@ int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct * vma, ...@@ -1364,10 +1367,10 @@ int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct * vma,
if (pmd) { if (pmd) {
pte_t * pte = pte_alloc(mm, pmd, address); pte_t * pte = pte_alloc(mm, pmd, address);
if (pte) if (pte)
ret = handle_pte_fault(mm, vma, address, write_access, pte); return handle_pte_fault(mm, vma, address, write_access, pte);
} }
spin_unlock(&mm->page_table_lock); spin_unlock(&mm->page_table_lock);
return ret; return -1;
} }
/* /*
......
...@@ -80,8 +80,6 @@ static void __free_pages_ok (struct page *page, unsigned int order) ...@@ -80,8 +80,6 @@ static void __free_pages_ok (struct page *page, unsigned int order)
BUG(); BUG();
if (PageLocked(page)) if (PageLocked(page))
BUG(); BUG();
if (PageDecrAfter(page))
BUG();
if (PageActive(page)) if (PageActive(page))
BUG(); BUG();
if (PageInactive(page)) if (PageInactive(page))
...@@ -274,8 +272,6 @@ static struct page * balance_classzone(zone_t * classzone, unsigned int gfp_mask ...@@ -274,8 +272,6 @@ static struct page * balance_classzone(zone_t * classzone, unsigned int gfp_mask
BUG(); BUG();
if (PageLocked(page)) if (PageLocked(page))
BUG(); BUG();
if (PageDecrAfter(page))
BUG();
if (PageActive(page)) if (PageActive(page))
BUG(); BUG();
if (PageInactive(page)) if (PageInactive(page))
......
...@@ -43,11 +43,6 @@ static int rw_swap_page_base(int rw, swp_entry_t entry, struct page *page) ...@@ -43,11 +43,6 @@ static int rw_swap_page_base(int rw, swp_entry_t entry, struct page *page)
struct inode *swapf = 0; struct inode *swapf = 0;
int wait = 0; int wait = 0;
/* Don't allow too many pending pages in flight.. */
if ((rw == WRITE) && atomic_read(&nr_async_pages) >
pager_daemon.swap_cluster * (1 << page_cluster))
wait = 1;
if (rw == READ) { if (rw == READ) {
ClearPageUptodate(page); ClearPageUptodate(page);
kstat.pswpin++; kstat.pswpin++;
...@@ -75,10 +70,6 @@ static int rw_swap_page_base(int rw, swp_entry_t entry, struct page *page) ...@@ -75,10 +70,6 @@ static int rw_swap_page_base(int rw, swp_entry_t entry, struct page *page)
} else { } else {
return 0; return 0;
} }
if (!wait) {
SetPageDecrAfter(page);
atomic_inc(&nr_async_pages);
}
/* block_size == PAGE_SIZE/zones_used */ /* block_size == PAGE_SIZE/zones_used */
brw_page(rw, page, dev, zones, block_size); brw_page(rw, page, dev, zones, block_size);
......
...@@ -449,7 +449,6 @@ static int shmem_writepage(struct page * page) ...@@ -449,7 +449,6 @@ static int shmem_writepage(struct page * page)
BUG(); BUG();
/* Remove it from the page cache */ /* Remove it from the page cache */
lru_cache_del(page);
remove_inode_page(page); remove_inode_page(page);
page_cache_release(page); page_cache_release(page);
...@@ -468,6 +467,7 @@ static int shmem_writepage(struct page * page) ...@@ -468,6 +467,7 @@ static int shmem_writepage(struct page * page)
*entry = swap; *entry = swap;
info->swapped++; info->swapped++;
spin_unlock(&info->lock); spin_unlock(&info->lock);
SetPageUptodate(page);
set_page_dirty(page); set_page_dirty(page);
UnlockPage(page); UnlockPage(page);
return 0; return 0;
...@@ -621,7 +621,7 @@ static int shmem_getpage(struct inode * inode, unsigned long idx, struct page ** ...@@ -621,7 +621,7 @@ static int shmem_getpage(struct inode * inode, unsigned long idx, struct page **
return error; return error;
} }
struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int no_share) struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address)
{ {
struct page * page; struct page * page;
unsigned int idx; unsigned int idx;
...@@ -633,19 +633,7 @@ struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, i ...@@ -633,19 +633,7 @@ struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, i
if (shmem_getpage(inode, idx, &page)) if (shmem_getpage(inode, idx, &page))
return page; return page;
if (no_share) { flush_page_to_ram(page);
struct page *new_page = page_cache_alloc(inode->i_mapping);
if (new_page) {
copy_user_highpage(new_page, page, address);
flush_page_to_ram(new_page);
} else
new_page = NOPAGE_OOM;
page_cache_release(page);
return new_page;
}
flush_page_to_ram (page);
return(page); return(page);
} }
...@@ -1150,7 +1138,7 @@ static int shmem_symlink(struct inode * dir, struct dentry *dentry, const char * ...@@ -1150,7 +1138,7 @@ static int shmem_symlink(struct inode * dir, struct dentry *dentry, const char *
inode = dentry->d_inode; inode = dentry->d_inode;
info = SHMEM_I(inode); info = SHMEM_I(inode);
inode->i_size = len; inode->i_size = len-1;
if (len <= sizeof(struct shmem_inode_info)) { if (len <= sizeof(struct shmem_inode_info)) {
/* do it inline */ /* do it inline */
memcpy(info, symname, len); memcpy(info, symname, len);
......
...@@ -27,10 +27,6 @@ ...@@ -27,10 +27,6 @@
/* How many pages do we try to swap or page in/out together? */ /* How many pages do we try to swap or page in/out together? */
int page_cluster; int page_cluster;
/* We track the number of pages currently being asynchronously swapped
out, so that we don't try to swap TOO many pages out at once */
atomic_t nr_async_pages = ATOMIC_INIT(0);
pager_daemon_t pager_daemon = { pager_daemon_t pager_daemon = {
512, /* base number for calculating the number of tries */ 512, /* base number for calculating the number of tries */
SWAP_CLUSTER_MAX, /* minimum number of tries */ SWAP_CLUSTER_MAX, /* minimum number of tries */
......
...@@ -17,17 +17,8 @@ ...@@ -17,17 +17,8 @@
#include <asm/pgtable.h> #include <asm/pgtable.h>
/*
* We may have stale swap cache pages in memory: notice
* them here and get rid of the unnecessary final write.
*/
static int swap_writepage(struct page *page) static int swap_writepage(struct page *page)
{ {
if (exclusive_swap_page(page)) {
delete_from_swap_cache(page);
UnlockPage(page);
return 0;
}
rw_swap_page(WRITE, page); rw_swap_page(WRITE, page);
return 0; return 0;
} }
...@@ -82,7 +73,6 @@ int add_to_swap_cache(struct page *page, swp_entry_t entry) ...@@ -82,7 +73,6 @@ int add_to_swap_cache(struct page *page, swp_entry_t entry)
INC_CACHE_INFO(exist_race); INC_CACHE_INFO(exist_race);
return -EEXIST; return -EEXIST;
} }
SetPageUptodate(page);
if (!PageLocked(page)) if (!PageLocked(page))
BUG(); BUG();
if (!PageSwapCache(page)) if (!PageSwapCache(page))
...@@ -119,8 +109,7 @@ void delete_from_swap_cache(struct page *page) ...@@ -119,8 +109,7 @@ void delete_from_swap_cache(struct page *page)
if (!PageLocked(page)) if (!PageLocked(page))
BUG(); BUG();
if (block_flushpage(page, 0)) block_flushpage(page, 0);
lru_cache_del(page);
entry.val = page->index; entry.val = page->index;
......
...@@ -242,7 +242,7 @@ void free_swap_and_cache(swp_entry_t entry) ...@@ -242,7 +242,7 @@ void free_swap_and_cache(swp_entry_t entry)
page_cache_get(page); page_cache_get(page);
delete_from_swap_cache(page); delete_from_swap_cache(page);
UnlockPage(page); UnlockPage(page);
page_cache_release(page); free_lru_page(page);
} }
} }
...@@ -582,7 +582,7 @@ static int try_to_unuse(unsigned int type) ...@@ -582,7 +582,7 @@ static int try_to_unuse(unsigned int type)
*/ */
SetPageDirty(page); SetPageDirty(page);
UnlockPage(page); UnlockPage(page);
page_cache_release(page); free_lru_page(page);
/* /*
* Make sure that we aren't completely killing * Make sure that we aren't completely killing
......
...@@ -134,6 +134,7 @@ static inline int try_to_swap_out(struct mm_struct * mm, struct vm_area_struct* ...@@ -134,6 +134,7 @@ static inline int try_to_swap_out(struct mm_struct * mm, struct vm_area_struct*
break; break;
/* Add it to the swap cache and mark it dirty */ /* Add it to the swap cache and mark it dirty */
if (add_to_swap_cache(page, entry) == 0) { if (add_to_swap_cache(page, entry) == 0) {
SetPageUptodate(page);
set_page_dirty(page); set_page_dirty(page);
goto set_swap_pte; goto set_swap_pte;
} }
...@@ -459,13 +460,7 @@ static int shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask, ...@@ -459,13 +460,7 @@ static int shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask,
} }
} }
if (unlikely(!spin_trylock(&pagecache_lock))) {
/* we hold the page lock so the page cannot go away from under us */
spin_unlock(&pagemap_lru_lock);
spin_lock(&pagecache_lock); spin_lock(&pagecache_lock);
spin_lock(&pagemap_lru_lock);
}
/* /*
* this is the non-racy check for busy page. * this is the non-racy check for busy page.
...@@ -520,6 +515,20 @@ static int shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask, ...@@ -520,6 +515,20 @@ static int shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask,
} }
spin_unlock(&pagemap_lru_lock); spin_unlock(&pagemap_lru_lock);
if (nr_pages <= 0)
return 0;
/*
* If swapping out isn't appropriate, and
* we still fail, try the other (usually smaller)
* caches instead.
*/
shrink_dcache_memory(priority, gfp_mask);
shrink_icache_memory(priority, gfp_mask);
#ifdef CONFIG_QUOTA
shrink_dqcache_memory(DEF_PRIORITY, gfp_mask);
#endif
return nr_pages; return nr_pages;
} }
...@@ -568,17 +577,7 @@ static int shrink_caches(zone_t * classzone, int priority, unsigned int gfp_mask ...@@ -568,17 +577,7 @@ static int shrink_caches(zone_t * classzone, int priority, unsigned int gfp_mask
ratio = (unsigned long) nr_pages * nr_active_pages / ((nr_inactive_pages + 1) * 2); ratio = (unsigned long) nr_pages * nr_active_pages / ((nr_inactive_pages + 1) * 2);
refill_inactive(ratio); refill_inactive(ratio);
nr_pages = shrink_cache(nr_pages, classzone, gfp_mask, priority); return shrink_cache(nr_pages, classzone, gfp_mask, priority);
if (nr_pages <= 0)
return 0;
shrink_dcache_memory(priority, gfp_mask);
shrink_icache_memory(priority, gfp_mask);
#ifdef CONFIG_QUOTA
shrink_dqcache_memory(DEF_PRIORITY, gfp_mask);
#endif
return nr_pages;
} }
int try_to_free_pages(zone_t *classzone, unsigned int gfp_mask, unsigned int order) int try_to_free_pages(zone_t *classzone, unsigned int gfp_mask, unsigned int order)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment