diff options
Diffstat (limited to 'mm/shmem.c')
-rw-r--r-- | mm/shmem.c | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index 04d11f9981b..4bb5a80dd13 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -499,22 +499,19 @@ void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend) } index = start; - for ( ; ; ) { + while (index <= end) { cond_resched(); pvec.nr = shmem_find_get_pages_and_swap(mapping, index, min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1, pvec.pages, indices); if (!pvec.nr) { - if (index == start) + /* If all gone or hole-punch, we're done */ + if (index == start || end != -1) break; + /* But if truncating, restart to make sure all gone */ index = start; continue; } - if (index == start && indices[0] > end) { - shmem_deswap_pagevec(&pvec); - pagevec_release(&pvec); - break; - } mem_cgroup_uncharge_start(); for (i = 0; i < pagevec_count(&pvec); i++) { struct page *page = pvec.pages[i]; @@ -524,8 +521,12 @@ void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend) break; if (radix_tree_exceptional_entry(page)) { - nr_swaps_freed += !shmem_free_swap(mapping, - index, page); + if (shmem_free_swap(mapping, index, page)) { + /* Swap was replaced by page: retry */ + index--; + break; + } + nr_swaps_freed++; continue; } @@ -533,6 +534,11 @@ void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend) if (page->mapping == mapping) { VM_BUG_ON(PageWriteback(page)); truncate_inode_page(mapping, page); + } else { + /* Page was replaced by swap: retry */ + unlock_page(page); + index--; + break; } unlock_page(page); } |