diff options
-rw-r--r-- | fs/ext3/inode.c | 6 | ||||
-rw-r--r-- | fs/jbd/transaction.c | 19 | ||||
-rw-r--r-- | include/linux/jbd.h | 2 | ||||
-rw-r--r-- | include/trace/events/ext3.h | 12 |
4 files changed, 25 insertions, 14 deletions
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index b6e5934f5dd6..f67668f724ba 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -1830,15 +1830,15 @@ static void ext3_invalidatepage(struct page *page, unsigned int offset, | |||
1830 | { | 1830 | { |
1831 | journal_t *journal = EXT3_JOURNAL(page->mapping->host); | 1831 | journal_t *journal = EXT3_JOURNAL(page->mapping->host); |
1832 | 1832 | ||
1833 | trace_ext3_invalidatepage(page, offset); | 1833 | trace_ext3_invalidatepage(page, offset, length); |
1834 | 1834 | ||
1835 | /* | 1835 | /* |
1836 | * If it's a full truncate we just forget about the pending dirtying | 1836 | * If it's a full truncate we just forget about the pending dirtying |
1837 | */ | 1837 | */ |
1838 | if (offset == 0) | 1838 | if (offset == 0 && length == PAGE_CACHE_SIZE) |
1839 | ClearPageChecked(page); | 1839 | ClearPageChecked(page); |
1840 | 1840 | ||
1841 | journal_invalidatepage(journal, page, offset); | 1841 | journal_invalidatepage(journal, page, offset, length); |
1842 | } | 1842 | } |
1843 | 1843 | ||
1844 | static int ext3_releasepage(struct page *page, gfp_t wait) | 1844 | static int ext3_releasepage(struct page *page, gfp_t wait) |
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index e3e255c0a509..be0c39b66fe0 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c | |||
@@ -2019,16 +2019,20 @@ zap_buffer_unlocked: | |||
2019 | * void journal_invalidatepage() - invalidate a journal page | 2019 | * void journal_invalidatepage() - invalidate a journal page |
2020 | * @journal: journal to use for flush | 2020 | * @journal: journal to use for flush |
2021 | * @page: page to flush | 2021 | * @page: page to flush |
2022 | * @offset: length of page to invalidate. | 2022 | * @offset: offset of the range to invalidate |
2023 | * @length: length of the range to invalidate | ||
2023 | * | 2024 | * |
2024 | * Reap page buffers containing data after offset in page. | 2025 | * Reap page buffers containing data in specified range in page. |
2025 | */ | 2026 | */ |
2026 | void journal_invalidatepage(journal_t *journal, | 2027 | void journal_invalidatepage(journal_t *journal, |
2027 | struct page *page, | 2028 | struct page *page, |
2028 | unsigned long offset) | 2029 | unsigned int offset, |
2030 | unsigned int length) | ||
2029 | { | 2031 | { |
2030 | struct buffer_head *head, *bh, *next; | 2032 | struct buffer_head *head, *bh, *next; |
2033 | unsigned int stop = offset + length; | ||
2031 | unsigned int curr_off = 0; | 2034 | unsigned int curr_off = 0; |
2035 | int partial_page = (offset || length < PAGE_CACHE_SIZE); | ||
2032 | int may_free = 1; | 2036 | int may_free = 1; |
2033 | 2037 | ||
2034 | if (!PageLocked(page)) | 2038 | if (!PageLocked(page)) |
@@ -2036,6 +2040,8 @@ void journal_invalidatepage(journal_t *journal, | |||
2036 | if (!page_has_buffers(page)) | 2040 | if (!page_has_buffers(page)) |
2037 | return; | 2041 | return; |
2038 | 2042 | ||
2043 | BUG_ON(stop > PAGE_CACHE_SIZE || stop < length); | ||
2044 | |||
2039 | /* We will potentially be playing with lists other than just the | 2045 | /* We will potentially be playing with lists other than just the |
2040 | * data lists (especially for journaled data mode), so be | 2046 | * data lists (especially for journaled data mode), so be |
2041 | * cautious in our locking. */ | 2047 | * cautious in our locking. */ |
@@ -2045,11 +2051,14 @@ void journal_invalidatepage(journal_t *journal, | |||
2045 | unsigned int next_off = curr_off + bh->b_size; | 2051 | unsigned int next_off = curr_off + bh->b_size; |
2046 | next = bh->b_this_page; | 2052 | next = bh->b_this_page; |
2047 | 2053 | ||
2054 | if (next_off > stop) | ||
2055 | return; | ||
2056 | |||
2048 | if (offset <= curr_off) { | 2057 | if (offset <= curr_off) { |
2049 | /* This block is wholly outside the truncation point */ | 2058 | /* This block is wholly outside the truncation point */ |
2050 | lock_buffer(bh); | 2059 | lock_buffer(bh); |
2051 | may_free &= journal_unmap_buffer(journal, bh, | 2060 | may_free &= journal_unmap_buffer(journal, bh, |
2052 | offset > 0); | 2061 | partial_page); |
2053 | unlock_buffer(bh); | 2062 | unlock_buffer(bh); |
2054 | } | 2063 | } |
2055 | curr_off = next_off; | 2064 | curr_off = next_off; |
@@ -2057,7 +2066,7 @@ void journal_invalidatepage(journal_t *journal, | |||
2057 | 2066 | ||
2058 | } while (bh != head); | 2067 | } while (bh != head); |
2059 | 2068 | ||
2060 | if (!offset) { | 2069 | if (!partial_page) { |
2061 | if (may_free && try_to_free_buffers(page)) | 2070 | if (may_free && try_to_free_buffers(page)) |
2062 | J_ASSERT(!page_has_buffers(page)); | 2071 | J_ASSERT(!page_has_buffers(page)); |
2063 | } | 2072 | } |
diff --git a/include/linux/jbd.h b/include/linux/jbd.h index 7e0b622503c4..9c505f1aa1fd 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h | |||
@@ -840,7 +840,7 @@ extern void journal_release_buffer (handle_t *, struct buffer_head *); | |||
840 | extern int journal_forget (handle_t *, struct buffer_head *); | 840 | extern int journal_forget (handle_t *, struct buffer_head *); |
841 | extern void journal_sync_buffer (struct buffer_head *); | 841 | extern void journal_sync_buffer (struct buffer_head *); |
842 | extern void journal_invalidatepage(journal_t *, | 842 | extern void journal_invalidatepage(journal_t *, |
843 | struct page *, unsigned long); | 843 | struct page *, unsigned int, unsigned int); |
844 | extern int journal_try_to_free_buffers(journal_t *, struct page *, gfp_t); | 844 | extern int journal_try_to_free_buffers(journal_t *, struct page *, gfp_t); |
845 | extern int journal_stop(handle_t *); | 845 | extern int journal_stop(handle_t *); |
846 | extern int journal_flush (journal_t *); | 846 | extern int journal_flush (journal_t *); |
diff --git a/include/trace/events/ext3.h b/include/trace/events/ext3.h index 15d11a39be47..6797b9de90ed 100644 --- a/include/trace/events/ext3.h +++ b/include/trace/events/ext3.h | |||
@@ -290,13 +290,14 @@ DEFINE_EVENT(ext3__page_op, ext3_releasepage, | |||
290 | ); | 290 | ); |
291 | 291 | ||
292 | TRACE_EVENT(ext3_invalidatepage, | 292 | TRACE_EVENT(ext3_invalidatepage, |
293 | TP_PROTO(struct page *page, unsigned long offset), | 293 | TP_PROTO(struct page *page, unsigned int offset, unsigned int length), |
294 | 294 | ||
295 | TP_ARGS(page, offset), | 295 | TP_ARGS(page, offset, length), |
296 | 296 | ||
297 | TP_STRUCT__entry( | 297 | TP_STRUCT__entry( |
298 | __field( pgoff_t, index ) | 298 | __field( pgoff_t, index ) |
299 | __field( unsigned long, offset ) | 299 | __field( unsigned int, offset ) |
300 | __field( unsigned int, length ) | ||
300 | __field( ino_t, ino ) | 301 | __field( ino_t, ino ) |
301 | __field( dev_t, dev ) | 302 | __field( dev_t, dev ) |
302 | 303 | ||
@@ -305,14 +306,15 @@ TRACE_EVENT(ext3_invalidatepage, | |||
305 | TP_fast_assign( | 306 | TP_fast_assign( |
306 | __entry->index = page->index; | 307 | __entry->index = page->index; |
307 | __entry->offset = offset; | 308 | __entry->offset = offset; |
309 | __entry->length = length; | ||
308 | __entry->ino = page->mapping->host->i_ino; | 310 | __entry->ino = page->mapping->host->i_ino; |
309 | __entry->dev = page->mapping->host->i_sb->s_dev; | 311 | __entry->dev = page->mapping->host->i_sb->s_dev; |
310 | ), | 312 | ), |
311 | 313 | ||
312 | TP_printk("dev %d,%d ino %lu page_index %lu offset %lu", | 314 | TP_printk("dev %d,%d ino %lu page_index %lu offset %u length %u", |
313 | MAJOR(__entry->dev), MINOR(__entry->dev), | 315 | MAJOR(__entry->dev), MINOR(__entry->dev), |
314 | (unsigned long) __entry->ino, | 316 | (unsigned long) __entry->ino, |
315 | __entry->index, __entry->offset) | 317 | __entry->index, __entry->offset, __entry->length) |
316 | ); | 318 | ); |
317 | 319 | ||
318 | TRACE_EVENT(ext3_discard_blocks, | 320 | TRACE_EVENT(ext3_discard_blocks, |