diff options
author | Jan Kara <jack@suse.cz> | 2012-12-25 13:29:52 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2012-12-25 13:29:52 -0500 |
commit | 53e872681fed6a43047e71bf927f77d06f467988 (patch) | |
tree | 8b5061acbaf222b3f25df54ddbcaa0b1123c471a /include | |
parent | 4520fb3c3690f2643006d85f09ecb74554c10e95 (diff) |
ext4: fix deadlock in journal_unmap_buffer()
We cannot wait for transaction commit in journal_unmap_buffer()
because we hold page lock which ranks below transaction start. We
solve the issue by bailing out of journal_unmap_buffer() and
jbd2_journal_invalidatepage() with -EBUSY. Caller is then responsible
for waiting for transaction commit to finish and try invalidation
again. Since the issue can happen only for page stradding i_size, it
is simple enough to manually call jbd2_journal_invalidatepage() for
such page from ext4_setattr(), check the return value and wait if
necessary.
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/jbd2.h | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index 1be23d9fdacb..e30b66346942 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h | |||
@@ -1098,7 +1098,7 @@ void jbd2_journal_set_triggers(struct buffer_head *, | |||
1098 | extern int jbd2_journal_dirty_metadata (handle_t *, struct buffer_head *); | 1098 | extern int jbd2_journal_dirty_metadata (handle_t *, struct buffer_head *); |
1099 | extern int jbd2_journal_forget (handle_t *, struct buffer_head *); | 1099 | extern int jbd2_journal_forget (handle_t *, struct buffer_head *); |
1100 | extern void journal_sync_buffer (struct buffer_head *); | 1100 | extern void journal_sync_buffer (struct buffer_head *); |
1101 | extern void jbd2_journal_invalidatepage(journal_t *, | 1101 | extern int jbd2_journal_invalidatepage(journal_t *, |
1102 | struct page *, unsigned long); | 1102 | struct page *, unsigned long); |
1103 | extern int jbd2_journal_try_to_free_buffers(journal_t *, struct page *, gfp_t); | 1103 | extern int jbd2_journal_try_to_free_buffers(journal_t *, struct page *, gfp_t); |
1104 | extern int jbd2_journal_stop(handle_t *); | 1104 | extern int jbd2_journal_stop(handle_t *); |