diff options
author | Christoph Hellwig <hch@lst.de> | 2010-07-27 11:56:06 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2010-07-27 11:56:06 -0400 |
commit | 552ef8024f909d9b3a7442d0ab0d48a22de24e9e (patch) | |
tree | 868af331b76e12c8d17b8449094065a069e0d759 | |
parent | 5c521830cf3dfcf7638d409d8e02ed21020c064f (diff) |
direct-io: move aio_complete into ->end_io
Filesystems with unwritten extent support must not complete an AIO request
until the transaction to convert the extent has been commited. That means
the aio_complete calls needs to be moved into the ->end_io callback so
that the filesystem can control when to call it exactly.
This makes a bit of a mess out of dio_complete and the ->end_io callback
prototype even more complicated.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r-- | fs/direct-io.c | 26 | ||||
-rw-r--r-- | fs/ext4/inode.c | 10 | ||||
-rw-r--r-- | fs/ocfs2/aops.c | 7 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_aops.c | 7 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_aops.h | 2 | ||||
-rw-r--r-- | include/linux/fs.h | 3 |
6 files changed, 37 insertions, 18 deletions
diff --git a/fs/direct-io.c b/fs/direct-io.c index 7600aacf531d..a10cb91cadea 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c | |||
@@ -218,7 +218,7 @@ static struct page *dio_get_page(struct dio *dio) | |||
218 | * filesystems can use it to hold additional state between get_block calls and | 218 | * filesystems can use it to hold additional state between get_block calls and |
219 | * dio_complete. | 219 | * dio_complete. |
220 | */ | 220 | */ |
221 | static int dio_complete(struct dio *dio, loff_t offset, int ret) | 221 | static int dio_complete(struct dio *dio, loff_t offset, int ret, bool is_async) |
222 | { | 222 | { |
223 | ssize_t transferred = 0; | 223 | ssize_t transferred = 0; |
224 | 224 | ||
@@ -239,14 +239,6 @@ static int dio_complete(struct dio *dio, loff_t offset, int ret) | |||
239 | transferred = dio->i_size - offset; | 239 | transferred = dio->i_size - offset; |
240 | } | 240 | } |
241 | 241 | ||
242 | if (dio->end_io && dio->result) | ||
243 | dio->end_io(dio->iocb, offset, transferred, | ||
244 | dio->map_bh.b_private); | ||
245 | |||
246 | if (dio->flags & DIO_LOCKING) | ||
247 | /* lockdep: non-owner release */ | ||
248 | up_read_non_owner(&dio->inode->i_alloc_sem); | ||
249 | |||
250 | if (ret == 0) | 242 | if (ret == 0) |
251 | ret = dio->page_errors; | 243 | ret = dio->page_errors; |
252 | if (ret == 0) | 244 | if (ret == 0) |
@@ -254,6 +246,17 @@ static int dio_complete(struct dio *dio, loff_t offset, int ret) | |||
254 | if (ret == 0) | 246 | if (ret == 0) |
255 | ret = transferred; | 247 | ret = transferred; |
256 | 248 | ||
249 | if (dio->end_io && dio->result) { | ||
250 | dio->end_io(dio->iocb, offset, transferred, | ||
251 | dio->map_bh.b_private, ret, is_async); | ||
252 | } else if (is_async) { | ||
253 | aio_complete(dio->iocb, ret, 0); | ||
254 | } | ||
255 | |||
256 | if (dio->flags & DIO_LOCKING) | ||
257 | /* lockdep: non-owner release */ | ||
258 | up_read_non_owner(&dio->inode->i_alloc_sem); | ||
259 | |||
257 | return ret; | 260 | return ret; |
258 | } | 261 | } |
259 | 262 | ||
@@ -277,8 +280,7 @@ static void dio_bio_end_aio(struct bio *bio, int error) | |||
277 | spin_unlock_irqrestore(&dio->bio_lock, flags); | 280 | spin_unlock_irqrestore(&dio->bio_lock, flags); |
278 | 281 | ||
279 | if (remaining == 0) { | 282 | if (remaining == 0) { |
280 | int ret = dio_complete(dio, dio->iocb->ki_pos, 0); | 283 | dio_complete(dio, dio->iocb->ki_pos, 0, true); |
281 | aio_complete(dio->iocb, ret, 0); | ||
282 | kfree(dio); | 284 | kfree(dio); |
283 | } | 285 | } |
284 | } | 286 | } |
@@ -1126,7 +1128,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, | |||
1126 | spin_unlock_irqrestore(&dio->bio_lock, flags); | 1128 | spin_unlock_irqrestore(&dio->bio_lock, flags); |
1127 | 1129 | ||
1128 | if (ret2 == 0) { | 1130 | if (ret2 == 0) { |
1129 | ret = dio_complete(dio, offset, ret); | 1131 | ret = dio_complete(dio, offset, ret, false); |
1130 | kfree(dio); | 1132 | kfree(dio); |
1131 | } else | 1133 | } else |
1132 | BUG_ON(ret != -EIOCBQUEUED); | 1134 | BUG_ON(ret != -EIOCBQUEUED); |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 699d1d01c5df..609159e990de 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -3775,7 +3775,8 @@ static ext4_io_end_t *ext4_init_io_end (struct inode *inode, gfp_t flags) | |||
3775 | } | 3775 | } |
3776 | 3776 | ||
3777 | static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, | 3777 | static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, |
3778 | ssize_t size, void *private) | 3778 | ssize_t size, void *private, int ret, |
3779 | bool is_async) | ||
3779 | { | 3780 | { |
3780 | ext4_io_end_t *io_end = iocb->private; | 3781 | ext4_io_end_t *io_end = iocb->private; |
3781 | struct workqueue_struct *wq; | 3782 | struct workqueue_struct *wq; |
@@ -3784,7 +3785,7 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, | |||
3784 | 3785 | ||
3785 | /* if not async direct IO or dio with 0 bytes write, just return */ | 3786 | /* if not async direct IO or dio with 0 bytes write, just return */ |
3786 | if (!io_end || !size) | 3787 | if (!io_end || !size) |
3787 | return; | 3788 | goto out; |
3788 | 3789 | ||
3789 | ext_debug("ext4_end_io_dio(): io_end 0x%p" | 3790 | ext_debug("ext4_end_io_dio(): io_end 0x%p" |
3790 | "for inode %lu, iocb 0x%p, offset %llu, size %llu\n", | 3791 | "for inode %lu, iocb 0x%p, offset %llu, size %llu\n", |
@@ -3795,7 +3796,7 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, | |||
3795 | if (io_end->flag != EXT4_IO_UNWRITTEN){ | 3796 | if (io_end->flag != EXT4_IO_UNWRITTEN){ |
3796 | ext4_free_io_end(io_end); | 3797 | ext4_free_io_end(io_end); |
3797 | iocb->private = NULL; | 3798 | iocb->private = NULL; |
3798 | return; | 3799 | goto out; |
3799 | } | 3800 | } |
3800 | 3801 | ||
3801 | io_end->offset = offset; | 3802 | io_end->offset = offset; |
@@ -3812,6 +3813,9 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, | |||
3812 | list_add_tail(&io_end->list, &ei->i_completed_io_list); | 3813 | list_add_tail(&io_end->list, &ei->i_completed_io_list); |
3813 | spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); | 3814 | spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); |
3814 | iocb->private = NULL; | 3815 | iocb->private = NULL; |
3816 | out: | ||
3817 | if (is_async) | ||
3818 | aio_complete(iocb, ret, 0); | ||
3815 | } | 3819 | } |
3816 | 3820 | ||
3817 | static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate) | 3821 | static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate) |
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 3623ca20cc18..1d2b1f156bcf 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
@@ -609,7 +609,9 @@ bail: | |||
609 | static void ocfs2_dio_end_io(struct kiocb *iocb, | 609 | static void ocfs2_dio_end_io(struct kiocb *iocb, |
610 | loff_t offset, | 610 | loff_t offset, |
611 | ssize_t bytes, | 611 | ssize_t bytes, |
612 | void *private) | 612 | void *private, |
613 | int ret, | ||
614 | bool is_async) | ||
613 | { | 615 | { |
614 | struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; | 616 | struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; |
615 | int level; | 617 | int level; |
@@ -623,6 +625,9 @@ static void ocfs2_dio_end_io(struct kiocb *iocb, | |||
623 | if (!level) | 625 | if (!level) |
624 | up_read(&inode->i_alloc_sem); | 626 | up_read(&inode->i_alloc_sem); |
625 | ocfs2_rw_unlock(inode, level); | 627 | ocfs2_rw_unlock(inode, level); |
628 | |||
629 | if (is_async) | ||
630 | aio_complete(iocb, ret, 0); | ||
626 | } | 631 | } |
627 | 632 | ||
628 | /* | 633 | /* |
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 34640d6dbdcb..5895aaf62ace 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c | |||
@@ -1599,7 +1599,9 @@ xfs_end_io_direct( | |||
1599 | struct kiocb *iocb, | 1599 | struct kiocb *iocb, |
1600 | loff_t offset, | 1600 | loff_t offset, |
1601 | ssize_t size, | 1601 | ssize_t size, |
1602 | void *private) | 1602 | void *private, |
1603 | int ret, | ||
1604 | bool is_async) | ||
1603 | { | 1605 | { |
1604 | xfs_ioend_t *ioend = iocb->private; | 1606 | xfs_ioend_t *ioend = iocb->private; |
1605 | 1607 | ||
@@ -1645,6 +1647,9 @@ xfs_end_io_direct( | |||
1645 | * against double-freeing. | 1647 | * against double-freeing. |
1646 | */ | 1648 | */ |
1647 | iocb->private = NULL; | 1649 | iocb->private = NULL; |
1650 | |||
1651 | if (is_async) | ||
1652 | aio_complete(iocb, ret, 0); | ||
1648 | } | 1653 | } |
1649 | 1654 | ||
1650 | STATIC ssize_t | 1655 | STATIC ssize_t |
diff --git a/fs/xfs/linux-2.6/xfs_aops.h b/fs/xfs/linux-2.6/xfs_aops.h index 4cfc6ea87df8..9f566d92ae3a 100644 --- a/fs/xfs/linux-2.6/xfs_aops.h +++ b/fs/xfs/linux-2.6/xfs_aops.h | |||
@@ -37,6 +37,8 @@ typedef struct xfs_ioend { | |||
37 | size_t io_size; /* size of the extent */ | 37 | size_t io_size; /* size of the extent */ |
38 | xfs_off_t io_offset; /* offset in the file */ | 38 | xfs_off_t io_offset; /* offset in the file */ |
39 | struct work_struct io_work; /* xfsdatad work queue */ | 39 | struct work_struct io_work; /* xfsdatad work queue */ |
40 | struct kiocb *io_iocb; | ||
41 | int io_result; | ||
40 | } xfs_ioend_t; | 42 | } xfs_ioend_t; |
41 | 43 | ||
42 | extern const struct address_space_operations xfs_address_space_operations; | 44 | extern const struct address_space_operations xfs_address_space_operations; |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 471e1ff5079a..a0912f6075e5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -415,7 +415,8 @@ struct buffer_head; | |||
415 | typedef int (get_block_t)(struct inode *inode, sector_t iblock, | 415 | typedef int (get_block_t)(struct inode *inode, sector_t iblock, |
416 | struct buffer_head *bh_result, int create); | 416 | struct buffer_head *bh_result, int create); |
417 | typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset, | 417 | typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset, |
418 | ssize_t bytes, void *private); | 418 | ssize_t bytes, void *private, int ret, |
419 | bool is_async); | ||
419 | 420 | ||
420 | /* | 421 | /* |
421 | * Attribute flags. These should be or-ed together to figure out what | 422 | * Attribute flags. These should be or-ed together to figure out what |