diff options
author | jiayingz@google.com (Jiaying Zhang) <> | 2010-07-27 11:56:06 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2010-07-27 11:56:06 -0400 |
commit | 5b3ff237bef43b9e7fb7d1eb858e29b73fd664f9 (patch) | |
tree | e3810d974a0e51a8c4b9046abdd36a5a4022abb3 /fs | |
parent | 552ef8024f909d9b3a7442d0ab0d48a22de24e9e (diff) |
ext4: move aio completion after unwritten extent conversion
This patch is to be applied upon Christoph's "direct-io: move aio_complete
into ->end_io" patch. It adds iocb and result fields to struct ext4_io_end_t,
so that we can call aio_complete from ext4_end_io_nolock() after the extent
conversion has finished.
I have verified with Christoph's aio-dio test that used to fail after a few
runs on an original kernel but now succeeds on the patched kernel.
See http://thread.gmane.org/gmane.comp.file-systems.ext4/19659 for details.
Signed-off-by: Jiaying Zhang <jiayingz@google.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/ext4.h | 4 | ||||
-rw-r--r-- | fs/ext4/inode.c | 17 |
2 files changed, 15 insertions, 6 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 4c7d4727d6ba..fbb39478df28 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -170,13 +170,15 @@ struct mpage_da_data { | |||
170 | }; | 170 | }; |
171 | #define EXT4_IO_UNWRITTEN 0x1 | 171 | #define EXT4_IO_UNWRITTEN 0x1 |
172 | typedef struct ext4_io_end { | 172 | typedef struct ext4_io_end { |
173 | struct list_head list; /* per-file finished AIO list */ | 173 | struct list_head list; /* per-file finished IO list */ |
174 | struct inode *inode; /* file being written to */ | 174 | struct inode *inode; /* file being written to */ |
175 | unsigned int flag; /* unwritten or not */ | 175 | unsigned int flag; /* unwritten or not */ |
176 | struct page *page; /* page struct for buffer write */ | 176 | struct page *page; /* page struct for buffer write */ |
177 | loff_t offset; /* offset in the file */ | 177 | loff_t offset; /* offset in the file */ |
178 | ssize_t size; /* size of the extent */ | 178 | ssize_t size; /* size of the extent */ |
179 | struct work_struct work; /* data work queue */ | 179 | struct work_struct work; /* data work queue */ |
180 | struct kiocb *iocb; /* iocb struct for AIO */ | ||
181 | int result; /* error value for AIO */ | ||
180 | } ext4_io_end_t; | 182 | } ext4_io_end_t; |
181 | 183 | ||
182 | /* | 184 | /* |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 609159e990de..46d2079373c9 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -3668,6 +3668,8 @@ static int ext4_end_io_nolock(ext4_io_end_t *io) | |||
3668 | return ret; | 3668 | return ret; |
3669 | } | 3669 | } |
3670 | 3670 | ||
3671 | if (io->iocb) | ||
3672 | aio_complete(io->iocb, io->result, 0); | ||
3671 | /* clear the DIO AIO unwritten flag */ | 3673 | /* clear the DIO AIO unwritten flag */ |
3672 | io->flag = 0; | 3674 | io->flag = 0; |
3673 | return ret; | 3675 | return ret; |
@@ -3767,6 +3769,8 @@ static ext4_io_end_t *ext4_init_io_end (struct inode *inode, gfp_t flags) | |||
3767 | io->offset = 0; | 3769 | io->offset = 0; |
3768 | io->size = 0; | 3770 | io->size = 0; |
3769 | io->page = NULL; | 3771 | io->page = NULL; |
3772 | io->iocb = NULL; | ||
3773 | io->result = 0; | ||
3770 | INIT_WORK(&io->work, ext4_end_io_work); | 3774 | INIT_WORK(&io->work, ext4_end_io_work); |
3771 | INIT_LIST_HEAD(&io->list); | 3775 | INIT_LIST_HEAD(&io->list); |
3772 | } | 3776 | } |
@@ -3796,12 +3800,18 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, | |||
3796 | if (io_end->flag != EXT4_IO_UNWRITTEN){ | 3800 | if (io_end->flag != EXT4_IO_UNWRITTEN){ |
3797 | ext4_free_io_end(io_end); | 3801 | ext4_free_io_end(io_end); |
3798 | iocb->private = NULL; | 3802 | iocb->private = NULL; |
3799 | goto out; | 3803 | out: |
3804 | if (is_async) | ||
3805 | aio_complete(iocb, ret, 0); | ||
3806 | return; | ||
3800 | } | 3807 | } |
3801 | 3808 | ||
3802 | io_end->offset = offset; | 3809 | io_end->offset = offset; |
3803 | io_end->size = size; | 3810 | io_end->size = size; |
3804 | io_end->flag = EXT4_IO_UNWRITTEN; | 3811 | if (is_async) { |
3812 | io_end->iocb = iocb; | ||
3813 | io_end->result = ret; | ||
3814 | } | ||
3805 | wq = EXT4_SB(io_end->inode->i_sb)->dio_unwritten_wq; | 3815 | wq = EXT4_SB(io_end->inode->i_sb)->dio_unwritten_wq; |
3806 | 3816 | ||
3807 | /* queue the work to convert unwritten extents to written */ | 3817 | /* queue the work to convert unwritten extents to written */ |
@@ -3813,9 +3823,6 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, | |||
3813 | list_add_tail(&io_end->list, &ei->i_completed_io_list); | 3823 | list_add_tail(&io_end->list, &ei->i_completed_io_list); |
3814 | spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); | 3824 | spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); |
3815 | iocb->private = NULL; | 3825 | iocb->private = NULL; |
3816 | out: | ||
3817 | if (is_async) | ||
3818 | aio_complete(iocb, ret, 0); | ||
3819 | } | 3826 | } |
3820 | 3827 | ||
3821 | static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate) | 3828 | static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate) |