aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mm/shmem.c32
1 files changed, 21 insertions, 11 deletions
diff --git a/mm/shmem.c b/mm/shmem.c
index b8c429a2d271..1077b1d903d2 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -481,7 +481,8 @@ static void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end)
481 long nr_swaps_freed = 0; 481 long nr_swaps_freed = 0;
482 int offset; 482 int offset;
483 int freed; 483 int freed;
484 int punch_hole = 0; 484 int punch_hole;
485 unsigned long upper_limit;
485 486
486 inode->i_ctime = inode->i_mtime = CURRENT_TIME; 487 inode->i_ctime = inode->i_mtime = CURRENT_TIME;
487 idx = (start + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; 488 idx = (start + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
@@ -492,11 +493,18 @@ static void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end)
492 info->flags |= SHMEM_TRUNCATE; 493 info->flags |= SHMEM_TRUNCATE;
493 if (likely(end == (loff_t) -1)) { 494 if (likely(end == (loff_t) -1)) {
494 limit = info->next_index; 495 limit = info->next_index;
496 upper_limit = SHMEM_MAX_INDEX;
495 info->next_index = idx; 497 info->next_index = idx;
498 punch_hole = 0;
496 } else { 499 } else {
497 limit = (end + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; 500 if (end + 1 >= inode->i_size) { /* we may free a little more */
498 if (limit > info->next_index) 501 limit = (inode->i_size + PAGE_CACHE_SIZE - 1) >>
499 limit = info->next_index; 502 PAGE_CACHE_SHIFT;
503 upper_limit = SHMEM_MAX_INDEX;
504 } else {
505 limit = (end + 1) >> PAGE_CACHE_SHIFT;
506 upper_limit = limit;
507 }
500 punch_hole = 1; 508 punch_hole = 1;
501 } 509 }
502 510
@@ -520,10 +528,10 @@ static void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end)
520 * If there are no indirect blocks or we are punching a hole 528 * If there are no indirect blocks or we are punching a hole
521 * below indirect blocks, nothing to be done. 529 * below indirect blocks, nothing to be done.
522 */ 530 */
523 if (!topdir || (punch_hole && (limit <= SHMEM_NR_DIRECT))) 531 if (!topdir || limit <= SHMEM_NR_DIRECT)
524 goto done2; 532 goto done2;
525 533
526 BUG_ON(limit <= SHMEM_NR_DIRECT); 534 upper_limit -= SHMEM_NR_DIRECT;
527 limit -= SHMEM_NR_DIRECT; 535 limit -= SHMEM_NR_DIRECT;
528 idx = (idx > SHMEM_NR_DIRECT)? (idx - SHMEM_NR_DIRECT): 0; 536 idx = (idx > SHMEM_NR_DIRECT)? (idx - SHMEM_NR_DIRECT): 0;
529 offset = idx % ENTRIES_PER_PAGE; 537 offset = idx % ENTRIES_PER_PAGE;
@@ -543,7 +551,7 @@ static void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end)
543 if (*dir) { 551 if (*dir) {
544 diroff = ((idx - ENTRIES_PER_PAGEPAGE/2) % 552 diroff = ((idx - ENTRIES_PER_PAGEPAGE/2) %
545 ENTRIES_PER_PAGEPAGE) / ENTRIES_PER_PAGE; 553 ENTRIES_PER_PAGEPAGE) / ENTRIES_PER_PAGE;
546 if (!diroff && !offset) { 554 if (!diroff && !offset && upper_limit >= stage) {
547 *dir = NULL; 555 *dir = NULL;
548 nr_pages_to_free++; 556 nr_pages_to_free++;
549 list_add(&middir->lru, &pages_to_free); 557 list_add(&middir->lru, &pages_to_free);
@@ -570,9 +578,11 @@ static void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end)
570 } 578 }
571 stage = idx + ENTRIES_PER_PAGEPAGE; 579 stage = idx + ENTRIES_PER_PAGEPAGE;
572 middir = *dir; 580 middir = *dir;
573 *dir = NULL; 581 if (upper_limit >= stage) {
574 nr_pages_to_free++; 582 *dir = NULL;
575 list_add(&middir->lru, &pages_to_free); 583 nr_pages_to_free++;
584 list_add(&middir->lru, &pages_to_free);
585 }
576 shmem_dir_unmap(dir); 586 shmem_dir_unmap(dir);
577 cond_resched(); 587 cond_resched();
578 dir = shmem_dir_map(middir); 588 dir = shmem_dir_map(middir);
@@ -598,7 +608,7 @@ static void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end)
598 } 608 }
599 if (offset) 609 if (offset)
600 offset = 0; 610 offset = 0;
601 else if (subdir && !page_private(subdir)) { 611 else if (subdir && upper_limit - idx >= ENTRIES_PER_PAGE) {
602 dir[diroff] = NULL; 612 dir[diroff] = NULL;
603 nr_pages_to_free++; 613 nr_pages_to_free++;
604 list_add(&subdir->lru, &pages_to_free); 614 list_add(&subdir->lru, &pages_to_free);