aboutsummaryrefslogtreecommitdiffstats
path: root/mm/filemap.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/filemap.c')
-rw-r--r--mm/filemap.c46
1 files changed, 30 insertions, 16 deletions
diff --git a/mm/filemap.c b/mm/filemap.c
index 2d0986a64f1f..96b9e9c30630 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -169,33 +169,35 @@ static int page_cache_tree_insert(struct address_space *mapping,
169static void page_cache_tree_delete(struct address_space *mapping, 169static void page_cache_tree_delete(struct address_space *mapping,
170 struct page *page, void *shadow) 170 struct page *page, void *shadow)
171{ 171{
172 struct radix_tree_node *node;
173 int i, nr = PageHuge(page) ? 1 : hpage_nr_pages(page); 172 int i, nr = PageHuge(page) ? 1 : hpage_nr_pages(page);
174 173
175 VM_BUG_ON_PAGE(!PageLocked(page), page); 174 VM_BUG_ON_PAGE(!PageLocked(page), page);
176 VM_BUG_ON_PAGE(PageTail(page), page); 175 VM_BUG_ON_PAGE(PageTail(page), page);
177 VM_BUG_ON_PAGE(nr != 1 && shadow, page); 176 VM_BUG_ON_PAGE(nr != 1 && shadow, page);
178 177
179 if (shadow) {
180 mapping->nrexceptional += nr;
181 /*
182 * Make sure the nrexceptional update is committed before
183 * the nrpages update so that final truncate racing
184 * with reclaim does not see both counters 0 at the
185 * same time and miss a shadow entry.
186 */
187 smp_wmb();
188 }
189 mapping->nrpages -= nr;
190
191 for (i = 0; i < nr; i++) { 178 for (i = 0; i < nr; i++) {
192 node = radix_tree_replace_clear_tags(&mapping->page_tree, 179 struct radix_tree_node *node;
193 page->index + i, shadow); 180 void **slot;
181
182 __radix_tree_lookup(&mapping->page_tree, page->index + i,
183 &node, &slot);
184
185 radix_tree_clear_tags(&mapping->page_tree, node, slot);
186
194 if (!node) { 187 if (!node) {
195 VM_BUG_ON_PAGE(nr != 1, page); 188 VM_BUG_ON_PAGE(nr != 1, page);
196 return; 189 /*
190 * We need a node to properly account shadow
191 * entries. Don't plant any without. XXX
192 */
193 shadow = NULL;
197 } 194 }
198 195
196 radix_tree_replace_slot(slot, shadow);
197
198 if (!node)
199 break;
200
199 workingset_node_pages_dec(node); 201 workingset_node_pages_dec(node);
200 if (shadow) 202 if (shadow)
201 workingset_node_shadows_inc(node); 203 workingset_node_shadows_inc(node);
@@ -219,6 +221,18 @@ static void page_cache_tree_delete(struct address_space *mapping,
219 &node->private_list); 221 &node->private_list);
220 } 222 }
221 } 223 }
224
225 if (shadow) {
226 mapping->nrexceptional += nr;
227 /*
228 * Make sure the nrexceptional update is committed before
229 * the nrpages update so that final truncate racing
230 * with reclaim does not see both counters 0 at the
231 * same time and miss a shadow entry.
232 */
233 smp_wmb();
234 }
235 mapping->nrpages -= nr;
222} 236}
223 237
224/* 238/*