diff options
Diffstat (limited to 'mm/filemap.c')
-rw-r--r-- | mm/filemap.c | 37 |
1 files changed, 18 insertions, 19 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 61ba5e405791..ca389394fa2a 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -102,9 +102,6 @@ | |||
102 | * ->inode_lock (zap_pte_range->set_page_dirty) | 102 | * ->inode_lock (zap_pte_range->set_page_dirty) |
103 | * ->private_lock (zap_pte_range->__set_page_dirty_buffers) | 103 | * ->private_lock (zap_pte_range->__set_page_dirty_buffers) |
104 | * | 104 | * |
105 | * ->task->proc_lock | ||
106 | * ->dcache_lock (proc_pid_lookup) | ||
107 | * | ||
108 | * (code doesn't rely on that order, so you could switch it around) | 105 | * (code doesn't rely on that order, so you could switch it around) |
109 | * ->tasklist_lock (memory_failure, collect_procs_ao) | 106 | * ->tasklist_lock (memory_failure, collect_procs_ao) |
110 | * ->i_mmap_lock | 107 | * ->i_mmap_lock |
@@ -143,13 +140,18 @@ void __remove_from_page_cache(struct page *page) | |||
143 | void remove_from_page_cache(struct page *page) | 140 | void remove_from_page_cache(struct page *page) |
144 | { | 141 | { |
145 | struct address_space *mapping = page->mapping; | 142 | struct address_space *mapping = page->mapping; |
143 | void (*freepage)(struct page *); | ||
146 | 144 | ||
147 | BUG_ON(!PageLocked(page)); | 145 | BUG_ON(!PageLocked(page)); |
148 | 146 | ||
147 | freepage = mapping->a_ops->freepage; | ||
149 | spin_lock_irq(&mapping->tree_lock); | 148 | spin_lock_irq(&mapping->tree_lock); |
150 | __remove_from_page_cache(page); | 149 | __remove_from_page_cache(page); |
151 | spin_unlock_irq(&mapping->tree_lock); | 150 | spin_unlock_irq(&mapping->tree_lock); |
152 | mem_cgroup_uncharge_cache_page(page); | 151 | mem_cgroup_uncharge_cache_page(page); |
152 | |||
153 | if (freepage) | ||
154 | freepage(page); | ||
153 | } | 155 | } |
154 | EXPORT_SYMBOL(remove_from_page_cache); | 156 | EXPORT_SYMBOL(remove_from_page_cache); |
155 | 157 | ||
@@ -644,7 +646,9 @@ repeat: | |||
644 | pagep = radix_tree_lookup_slot(&mapping->page_tree, offset); | 646 | pagep = radix_tree_lookup_slot(&mapping->page_tree, offset); |
645 | if (pagep) { | 647 | if (pagep) { |
646 | page = radix_tree_deref_slot(pagep); | 648 | page = radix_tree_deref_slot(pagep); |
647 | if (unlikely(!page || page == RADIX_TREE_RETRY)) | 649 | if (unlikely(!page)) |
650 | goto out; | ||
651 | if (radix_tree_deref_retry(page)) | ||
648 | goto repeat; | 652 | goto repeat; |
649 | 653 | ||
650 | if (!page_cache_get_speculative(page)) | 654 | if (!page_cache_get_speculative(page)) |
@@ -660,6 +664,7 @@ repeat: | |||
660 | goto repeat; | 664 | goto repeat; |
661 | } | 665 | } |
662 | } | 666 | } |
667 | out: | ||
663 | rcu_read_unlock(); | 668 | rcu_read_unlock(); |
664 | 669 | ||
665 | return page; | 670 | return page; |
@@ -777,12 +782,11 @@ repeat: | |||
777 | page = radix_tree_deref_slot((void **)pages[i]); | 782 | page = radix_tree_deref_slot((void **)pages[i]); |
778 | if (unlikely(!page)) | 783 | if (unlikely(!page)) |
779 | continue; | 784 | continue; |
780 | /* | 785 | if (radix_tree_deref_retry(page)) { |
781 | * this can only trigger if nr_found == 1, making livelock | 786 | if (ret) |
782 | * a non issue. | 787 | start = pages[ret-1]->index; |
783 | */ | ||
784 | if (unlikely(page == RADIX_TREE_RETRY)) | ||
785 | goto restart; | 788 | goto restart; |
789 | } | ||
786 | 790 | ||
787 | if (!page_cache_get_speculative(page)) | 791 | if (!page_cache_get_speculative(page)) |
788 | goto repeat; | 792 | goto repeat; |
@@ -830,11 +834,7 @@ repeat: | |||
830 | page = radix_tree_deref_slot((void **)pages[i]); | 834 | page = radix_tree_deref_slot((void **)pages[i]); |
831 | if (unlikely(!page)) | 835 | if (unlikely(!page)) |
832 | continue; | 836 | continue; |
833 | /* | 837 | if (radix_tree_deref_retry(page)) |
834 | * this can only trigger if nr_found == 1, making livelock | ||
835 | * a non issue. | ||
836 | */ | ||
837 | if (unlikely(page == RADIX_TREE_RETRY)) | ||
838 | goto restart; | 838 | goto restart; |
839 | 839 | ||
840 | if (page->mapping == NULL || page->index != index) | 840 | if (page->mapping == NULL || page->index != index) |
@@ -887,11 +887,7 @@ repeat: | |||
887 | page = radix_tree_deref_slot((void **)pages[i]); | 887 | page = radix_tree_deref_slot((void **)pages[i]); |
888 | if (unlikely(!page)) | 888 | if (unlikely(!page)) |
889 | continue; | 889 | continue; |
890 | /* | 890 | if (radix_tree_deref_retry(page)) |
891 | * this can only trigger if nr_found == 1, making livelock | ||
892 | * a non issue. | ||
893 | */ | ||
894 | if (unlikely(page == RADIX_TREE_RETRY)) | ||
895 | goto restart; | 891 | goto restart; |
896 | 892 | ||
897 | if (!page_cache_get_speculative(page)) | 893 | if (!page_cache_get_speculative(page)) |
@@ -1029,6 +1025,9 @@ find_page: | |||
1029 | goto page_not_up_to_date; | 1025 | goto page_not_up_to_date; |
1030 | if (!trylock_page(page)) | 1026 | if (!trylock_page(page)) |
1031 | goto page_not_up_to_date; | 1027 | goto page_not_up_to_date; |
1028 | /* Did it get truncated before we got the lock? */ | ||
1029 | if (!page->mapping) | ||
1030 | goto page_not_up_to_date_locked; | ||
1032 | if (!mapping->a_ops->is_partially_uptodate(page, | 1031 | if (!mapping->a_ops->is_partially_uptodate(page, |
1033 | desc, offset)) | 1032 | desc, offset)) |
1034 | goto page_not_up_to_date_locked; | 1033 | goto page_not_up_to_date_locked; |