diff options
author | Dmitry Monakhov <dmonakhov@openvz.org> | 2012-09-28 23:36:25 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2012-09-28 23:36:25 -0400 |
commit | 82e54229118785badffb4ef5ba4803df25fe007f (patch) | |
tree | 270d0afb27dce342b7508cd05bb0db45cdad089d /fs/ext4/page-io.c | |
parent | e27f41e1b789e60e7d8cc9c81fd93ca49ef31f13 (diff) |
ext4: fix unwritten counter leakage
ext4_set_io_unwritten_flag() will increment i_unwritten counter, so
once we mark end_io with EXT4_END_IO_UNWRITTEN we have to revert it back
on error path.
- add missed error checks to prevent counter leakage
- ext4_end_io_nolock() will clear EXT4_END_IO_UNWRITTEN flag to signal
that conversion finished.
- add BUG_ON to ext4_free_end_io() to prevent similar leakage in future.
Visible effect of this bug is that unaligned aio_stress may deadlock
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/page-io.c')
-rw-r--r-- | fs/ext4/page-io.c | 6 |
1 files changed, 5 insertions, 1 deletions
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index de77e31cc11..99700221822 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c | |||
@@ -71,6 +71,8 @@ void ext4_free_io_end(ext4_io_end_t *io) | |||
71 | int i; | 71 | int i; |
72 | 72 | ||
73 | BUG_ON(!io); | 73 | BUG_ON(!io); |
74 | BUG_ON(io->flag & EXT4_IO_END_UNWRITTEN); | ||
75 | |||
74 | if (io->page) | 76 | if (io->page) |
75 | put_page(io->page); | 77 | put_page(io->page); |
76 | for (i = 0; i < io->num_io_pages; i++) | 78 | for (i = 0; i < io->num_io_pages; i++) |
@@ -94,6 +96,8 @@ int ext4_end_io_nolock(ext4_io_end_t *io) | |||
94 | ssize_t size = io->size; | 96 | ssize_t size = io->size; |
95 | int ret = 0; | 97 | int ret = 0; |
96 | 98 | ||
99 | BUG_ON(!(io->flag & EXT4_IO_END_UNWRITTEN)); | ||
100 | |||
97 | ext4_debug("ext4_end_io_nolock: io 0x%p from inode %lu,list->next 0x%p," | 101 | ext4_debug("ext4_end_io_nolock: io 0x%p from inode %lu,list->next 0x%p," |
98 | "list->prev 0x%p\n", | 102 | "list->prev 0x%p\n", |
99 | io, inode->i_ino, io->list.next, io->list.prev); | 103 | io, inode->i_ino, io->list.next, io->list.prev); |
@@ -106,7 +110,7 @@ int ext4_end_io_nolock(ext4_io_end_t *io) | |||
106 | "(inode %lu, offset %llu, size %zd, error %d)", | 110 | "(inode %lu, offset %llu, size %zd, error %d)", |
107 | inode->i_ino, offset, size, ret); | 111 | inode->i_ino, offset, size, ret); |
108 | } | 112 | } |
109 | 113 | io->flag &= ~EXT4_IO_END_UNWRITTEN; | |
110 | if (io->iocb) | 114 | if (io->iocb) |
111 | aio_complete(io->iocb, io->result, 0); | 115 | aio_complete(io->iocb, io->result, 0); |
112 | 116 | ||