X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=mm%2Ftruncate.c;h=dc2e9a53f5da58a2ea2751b75ce7215fb18e114f;hb=f1227cd3e0e73c48b93368800aa89f4341103a00;hp=fe9071b60c02bb3098c922b5d246deafdacf8a78;hpb=340e2b1a4c74f653454348914c408420d5d3c28a;p=linux-2.6.git diff --git a/mm/truncate.c b/mm/truncate.c index fe9071b60..dc2e9a53f 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -64,8 +64,6 @@ truncate_complete_page(struct address_space *mapping, struct page *page) * be marked dirty at any time too. So we re-check the dirtiness inside * ->tree_lock. That provides exclusion against the __set_page_dirty * functions. - * - * Returns non-zero if the page was successfully invalidated. */ static int invalidate_complete_page(struct address_space *mapping, struct page *page) @@ -76,15 +74,19 @@ invalidate_complete_page(struct address_space *mapping, struct page *page) if (PagePrivate(page) && !try_to_release_page(page, 0)) return 0; - write_lock_irq(&mapping->tree_lock); + spin_lock_irq(&mapping->tree_lock); if (PageDirty(page)) { - write_unlock_irq(&mapping->tree_lock); + spin_unlock_irq(&mapping->tree_lock); return 0; } BUG_ON(PagePrivate(page)); + if (page_count(page) != 2) { + spin_unlock_irq(&mapping->tree_lock); + return 0; + } __remove_from_page_cache(page); - write_unlock_irq(&mapping->tree_lock); + spin_unlock_irq(&mapping->tree_lock); ClearPageUptodate(page); page_cache_release(page); /* pagecache ref */ return 1; @@ -243,96 +245,50 @@ unsigned long invalidate_inode_pages(struct address_space *mapping) EXPORT_SYMBOL(invalidate_inode_pages); /** - * invalidate_inode_pages2_range - remove range of pages from an address_space - * @mapping: the address_space - * @start: the page offset 'from' which to invalidate - * @end: the page offset 'to' which to invalidate (inclusive) + * invalidate_inode_pages2 - remove all unmapped pages from an address_space + * @mapping - the address_space * - * Any pages which are found to be mapped into pagetables are unmapped prior to - * invalidation. + * invalidate_inode_pages2() is like truncate_inode_pages(), except for the case + * where the page is seen to be mapped into process pagetables. In that case, + * the page is marked clean but is left attached to its address_space. * - * Returns -EIO if any pages could not be invalidated. + * The page is also marked not uptodate so that a subsequent pagefault will + * perform I/O to bringthe page's contents back into sync with its backing + * store. + * + * FIXME: invalidate_inode_pages2() is probably trivially livelockable. */ -int invalidate_inode_pages2_range(struct address_space *mapping, - pgoff_t start, pgoff_t end) +void invalidate_inode_pages2(struct address_space *mapping) { struct pagevec pvec; - pgoff_t next; + pgoff_t next = 0; int i; - int ret = 0; - int did_range_unmap = 0; - int wrapped = 0; pagevec_init(&pvec, 0); - next = start; - while (next <= end && !ret && !wrapped && - pagevec_lookup(&pvec, mapping, next, - min(end - next, (pgoff_t)PAGEVEC_SIZE - 1) + 1)) { - for (i = 0; !ret && i < pagevec_count(&pvec); i++) { + while (pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) { + for (i = 0; i < pagevec_count(&pvec); i++) { struct page *page = pvec.pages[i]; - pgoff_t page_index; - int was_dirty; lock_page(page); - if (page->mapping != mapping) { - unlock_page(page); - continue; - } - page_index = page->index; - next = page_index + 1; - if (next == 0) - wrapped = 1; - if (page_index > end) { - unlock_page(page); - break; - } - wait_on_page_writeback(page); - while (page_mapped(page)) { - if (!did_range_unmap) { - /* - * Zap the rest of the file in one hit. - */ - unmap_mapping_range(mapping, - page_index << PAGE_CACHE_SHIFT, - (end - page_index + 1) - << PAGE_CACHE_SHIFT, - 0); - did_range_unmap = 1; + if (page->mapping == mapping) { /* truncate race? */ + wait_on_page_writeback(page); + next = page->index + 1; + if (page_mapped(page)) { + clear_page_dirty(page); + ClearPageUptodate(page); } else { - /* - * Just zap this page - */ - unmap_mapping_range(mapping, - page_index << PAGE_CACHE_SHIFT, - PAGE_CACHE_SIZE, 0); + if (!invalidate_complete_page(mapping, + page)) { + clear_page_dirty(page); + ClearPageUptodate(page); + } } } - was_dirty = test_clear_page_dirty(page); - if (!invalidate_complete_page(mapping, page)) { - if (was_dirty) - set_page_dirty(page); - ret = -EIO; - } unlock_page(page); } pagevec_release(&pvec); cond_resched(); } - return ret; } -EXPORT_SYMBOL_GPL(invalidate_inode_pages2_range); -/** - * invalidate_inode_pages2 - remove all pages from an address_space - * @mapping: the address_space - * - * Any pages which are found to be mapped into pagetables are unmapped prior to - * invalidation. - * - * Returns -EIO if any pages could not be invalidated. - */ -int invalidate_inode_pages2(struct address_space *mapping) -{ - return invalidate_inode_pages2_range(mapping, 0, -1); -} EXPORT_SYMBOL_GPL(invalidate_inode_pages2);