diff options
Diffstat (limited to 'mm/filemap.c')
| -rw-r--r-- | mm/filemap.c | 38 | 
1 files changed, 21 insertions, 17 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 75572b5f237..6b9aee20f24 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -143,13 +143,18 @@ void __remove_from_page_cache(struct page *page)  void remove_from_page_cache(struct page *page)  {  	struct address_space *mapping = page->mapping; +	void (*freepage)(struct page *);  	BUG_ON(!PageLocked(page)); +	freepage = mapping->a_ops->freepage;  	spin_lock_irq(&mapping->tree_lock);  	__remove_from_page_cache(page);  	spin_unlock_irq(&mapping->tree_lock);  	mem_cgroup_uncharge_cache_page(page); + +	if (freepage) +		freepage(page);  }  EXPORT_SYMBOL(remove_from_page_cache); @@ -644,7 +649,9 @@ repeat:  	pagep = radix_tree_lookup_slot(&mapping->page_tree, offset);  	if (pagep) {  		page = radix_tree_deref_slot(pagep); -		if (unlikely(!page || page == RADIX_TREE_RETRY)) +		if (unlikely(!page)) +			goto out; +		if (radix_tree_deref_retry(page))  			goto repeat;  		if (!page_cache_get_speculative(page)) @@ -660,6 +667,7 @@ repeat:  			goto repeat;  		}  	} +out:  	rcu_read_unlock();  	return page; @@ -777,12 +785,11 @@ repeat:  		page = radix_tree_deref_slot((void **)pages[i]);  		if (unlikely(!page))  			continue; -		/* -		 * this can only trigger if nr_found == 1, making livelock -		 * a non issue. -		 */ -		if (unlikely(page == RADIX_TREE_RETRY)) +		if (radix_tree_deref_retry(page)) { +			if (ret) +				start = pages[ret-1]->index;  			goto restart; +		}  		if (!page_cache_get_speculative(page))  			goto repeat; @@ -830,11 +837,7 @@ repeat:  		page = radix_tree_deref_slot((void **)pages[i]);  		if (unlikely(!page))  			continue; -		/* -		 * this can only trigger if nr_found == 1, making livelock -		 * a non issue. -		 */ -		if (unlikely(page == RADIX_TREE_RETRY)) +		if (radix_tree_deref_retry(page))  			goto restart;  		if (page->mapping == NULL || page->index != index) @@ -887,11 +890,7 @@ repeat:  		page = radix_tree_deref_slot((void **)pages[i]);  		if (unlikely(!page))  			continue; -		/* -		 * this can only trigger if nr_found == 1, making livelock -		 * a non issue. -		 */ -		if (unlikely(page == RADIX_TREE_RETRY)) +		if (radix_tree_deref_retry(page))  			goto restart;  		if (!page_cache_get_speculative(page)) @@ -1029,6 +1028,9 @@ find_page:  				goto page_not_up_to_date;  			if (!trylock_page(page))  				goto page_not_up_to_date; +			/* Did it get truncated before we got the lock? */ +			if (!page->mapping) +				goto page_not_up_to_date_locked;  			if (!mapping->a_ops->is_partially_uptodate(page,  								desc, offset))  				goto page_not_up_to_date_locked; @@ -1563,8 +1565,10 @@ retry_find:  			goto no_cached_page;  	} -	if (!lock_page_or_retry(page, vma->vm_mm, vmf->flags)) +	if (!lock_page_or_retry(page, vma->vm_mm, vmf->flags)) { +		page_cache_release(page);  		return ret | VM_FAULT_RETRY; +	}  	/* Did it get truncated? */  	if (unlikely(page->mapping != mapping)) {  |