diff options
Diffstat (limited to 'mm/filemap.c')
-rw-r--r-- | mm/filemap.c | 46 |
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, | |||
169 | static void page_cache_tree_delete(struct address_space *mapping, | 169 | static 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 | /* |