diff options
| author | Jiri Kosina <jkosina@suse.cz> | 2011-06-10 14:46:48 +0200 | 
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.cz> | 2011-06-10 14:46:57 +0200 | 
| commit | 5be5758c114b18260c6fd4c8373bf89e39b0fe82 (patch) | |
| tree | 54390f904df6ff11e570f764c444356cf2709fda /mm/filemap.c | |
| parent | 71f66a6580c4e42df377bebbcca5c72661a40700 (diff) | |
| parent | 7f45e5cd1718ed769295033ca214032848a0097d (diff) | |
| download | olio-linux-3.10-5be5758c114b18260c6fd4c8373bf89e39b0fe82.tar.xz olio-linux-3.10-5be5758c114b18260c6fd4c8373bf89e39b0fe82.zip  | |
Merge branch 'master' into for-next
Sync with Linus' tree to be able to apply patches against new
code I have in queue.
Diffstat (limited to 'mm/filemap.c')
| -rw-r--r-- | mm/filemap.c | 101 | 
1 files changed, 76 insertions, 25 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index c641edf553a..a8251a8d345 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -34,6 +34,7 @@  #include <linux/hardirq.h> /* for BUG_ON(!in_atomic()) only */  #include <linux/memcontrol.h>  #include <linux/mm_inline.h> /* for page_is_file_cache() */ +#include <linux/cleancache.h>  #include "internal.h"  /* @@ -58,16 +59,16 @@  /*   * Lock ordering:   * - *  ->i_mmap_lock		(truncate_pagecache) + *  ->i_mmap_mutex		(truncate_pagecache)   *    ->private_lock		(__free_pte->__set_page_dirty_buffers)   *      ->swap_lock		(exclusive_swap_page, others)   *        ->mapping->tree_lock   *   *  ->i_mutex - *    ->i_mmap_lock		(truncate->unmap_mapping_range) + *    ->i_mmap_mutex		(truncate->unmap_mapping_range)   *   *  ->mmap_sem - *    ->i_mmap_lock + *    ->i_mmap_mutex   *      ->page_table_lock or pte_lock	(various, mainly in memory.c)   *        ->mapping->tree_lock	(arch-dependent flush_dcache_mmap_lock)   * @@ -84,7 +85,7 @@   *    sb_lock			(fs/fs-writeback.c)   *    ->mapping->tree_lock	(__sync_single_inode)   * - *  ->i_mmap_lock + *  ->i_mmap_mutex   *    ->anon_vma.lock		(vma_adjust)   *   *  ->anon_vma.lock @@ -106,7 +107,7 @@   *   *  (code doesn't rely on that order, so you could switch it around)   *  ->tasklist_lock             (memory_failure, collect_procs_ao) - *    ->i_mmap_lock + *    ->i_mmap_mutex   */  /* @@ -118,6 +119,16 @@ void __delete_from_page_cache(struct page *page)  {  	struct address_space *mapping = page->mapping; +	/* +	 * if we're uptodate, flush out into the cleancache, otherwise +	 * invalidate any existing cleancache entries.  We can't leave +	 * stale data around in the cleancache once our page is gone +	 */ +	if (PageUptodate(page) && PageMappedToDisk(page)) +		cleancache_put_page(page); +	else +		cleancache_flush_page(mapping, page); +  	radix_tree_delete(&mapping->page_tree, page->index);  	page->mapping = NULL;  	mapping->nrpages--; @@ -562,6 +573,17 @@ void wait_on_page_bit(struct page *page, int bit_nr)  }  EXPORT_SYMBOL(wait_on_page_bit); +int wait_on_page_bit_killable(struct page *page, int bit_nr) +{ +	DEFINE_WAIT_BIT(wait, &page->flags, bit_nr); + +	if (!test_bit(bit_nr, &page->flags)) +		return 0; + +	return __wait_on_bit(page_waitqueue(page), &wait, +			     sleep_on_page_killable, TASK_KILLABLE); +} +  /**   * add_page_wait_queue - Add an arbitrary waiter to a page's wait queue   * @page: Page defining the wait queue of interest @@ -643,15 +665,32 @@ EXPORT_SYMBOL_GPL(__lock_page_killable);  int __lock_page_or_retry(struct page *page, struct mm_struct *mm,  			 unsigned int flags)  { -	if (!(flags & FAULT_FLAG_ALLOW_RETRY)) { -		__lock_page(page); -		return 1; -	} else { -		if (!(flags & FAULT_FLAG_RETRY_NOWAIT)) { -			up_read(&mm->mmap_sem); +	if (flags & FAULT_FLAG_ALLOW_RETRY) { +		/* +		 * CAUTION! In this case, mmap_sem is not released +		 * even though return 0. +		 */ +		if (flags & FAULT_FLAG_RETRY_NOWAIT) +			return 0; + +		up_read(&mm->mmap_sem); +		if (flags & FAULT_FLAG_KILLABLE) +			wait_on_page_locked_killable(page); +		else  			wait_on_page_locked(page); -		}  		return 0; +	} else { +		if (flags & FAULT_FLAG_KILLABLE) { +			int ret; + +			ret = __lock_page_killable(page); +			if (ret) { +				up_read(&mm->mmap_sem); +				return 0; +			} +		} else +			__lock_page(page); +		return 1;  	}  } @@ -1528,15 +1567,17 @@ static void do_sync_mmap_readahead(struct vm_area_struct *vma,  	/* If we don't want any read-ahead, don't bother */  	if (VM_RandomReadHint(vma))  		return; +	if (!ra->ra_pages) +		return; -	if (VM_SequentialReadHint(vma) || -			offset - 1 == (ra->prev_pos >> PAGE_CACHE_SHIFT)) { +	if (VM_SequentialReadHint(vma)) {  		page_cache_sync_readahead(mapping, ra, file, offset,  					  ra->ra_pages);  		return;  	} -	if (ra->mmap_miss < INT_MAX) +	/* Avoid banging the cache line if not needed */ +	if (ra->mmap_miss < MMAP_LOTSAMISS * 10)  		ra->mmap_miss++;  	/* @@ -1550,12 +1591,10 @@ static void do_sync_mmap_readahead(struct vm_area_struct *vma,  	 * mmap read-around  	 */  	ra_pages = max_sane_readahead(ra->ra_pages); -	if (ra_pages) { -		ra->start = max_t(long, 0, offset - ra_pages/2); -		ra->size = ra_pages; -		ra->async_size = 0; -		ra_submit(ra, mapping, file); -	} +	ra->start = max_t(long, 0, offset - ra_pages / 2); +	ra->size = ra_pages; +	ra->async_size = ra_pages / 4; +	ra_submit(ra, mapping, file);  }  /* @@ -1622,6 +1661,7 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)  		/* No page in the page cache at all */  		do_sync_mmap_readahead(vma, ra, file, offset);  		count_vm_event(PGMAJFAULT); +		mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT);  		ret = VM_FAULT_MAJOR;  retry_find:  		page = find_get_page(mapping, offset); @@ -1660,7 +1700,6 @@ retry_find:  		return VM_FAULT_SIGBUS;  	} -	ra->prev_pos = (loff_t)offset << PAGE_CACHE_SHIFT;  	vmf->page = page;  	return ret | VM_FAULT_LOCKED; @@ -1943,16 +1982,26 @@ static int __remove_suid(struct dentry *dentry, int kill)  int file_remove_suid(struct file *file)  {  	struct dentry *dentry = file->f_path.dentry; -	int killsuid = should_remove_suid(dentry); -	int killpriv = security_inode_need_killpriv(dentry); +	struct inode *inode = dentry->d_inode; +	int killsuid; +	int killpriv;  	int error = 0; +	/* Fast path for nothing security related */ +	if (IS_NOSEC(inode)) +		return 0; + +	killsuid = should_remove_suid(dentry); +	killpriv = security_inode_need_killpriv(dentry); +  	if (killpriv < 0)  		return killpriv;  	if (killpriv)  		error = security_inode_killpriv(dentry);  	if (!error && killsuid)  		error = __remove_suid(dentry, killsuid); +	if (!error && (inode->i_sb->s_flags & MS_NOSEC)) +		inode->i_flags |= S_NOSEC;  	return error;  } @@ -2288,7 +2337,7 @@ struct page *grab_cache_page_write_begin(struct address_space *mapping,  repeat:  	page = find_lock_page(mapping, index);  	if (page) -		return page; +		goto found;  	page = __page_cache_alloc(mapping_gfp_mask(mapping) & ~gfp_notmask);  	if (!page) @@ -2301,6 +2350,8 @@ repeat:  			goto repeat;  		return NULL;  	} +found: +	wait_on_page_writeback(page);  	return page;  }  EXPORT_SYMBOL(grab_cache_page_write_begin);  |