diff options
author | Christoph Hellwig <hch@infradead.org> | 2013-09-04 09:04:39 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-09-04 09:23:46 -0400 |
commit | 7b7a8665edd8db733980389b098530f9e4f630b2 (patch) | |
tree | 968d570a9f0c4d861226aefed2f5f97a131c8d53 /fs/ext4/inode.c | |
parent | 4b6ccca701ef5977d0ffbc2c932430dea88b38b6 (diff) |
direct-io: Implement generic deferred AIO completions
Add support to the core direct-io code to defer AIO completions to user
context using a workqueue. This replaces opencoded and less efficient
code in XFS and ext4 (we save a memory allocation for each direct IO)
and will be needed to properly support O_(D)SYNC for AIO.
The communication between the filesystem and the direct I/O code requires
a new buffer head flag, which is a bit ugly but not avoidable until the
direct I/O code stops abusing the buffer_head structure for communicating
with the filesystems.
Currently this creates a per-superblock unbound workqueue for these
completions, which is taken from an earlier patch by Jan Kara. I'm
not really convinced about this use and would prefer a "normal" global
workqueue with a high concurrency limit, but this needs further discussion.
JK: Fixed ext4 part, dynamic allocation of the workqueue.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r-- | fs/ext4/inode.c | 28 |
1 files changed, 7 insertions, 21 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index c2ca04e67a4f..123bd81692d1 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -727,8 +727,12 @@ static int _ext4_get_block(struct inode *inode, sector_t iblock, | |||
727 | 727 | ||
728 | ret = ext4_map_blocks(handle, inode, &map, flags); | 728 | ret = ext4_map_blocks(handle, inode, &map, flags); |
729 | if (ret > 0) { | 729 | if (ret > 0) { |
730 | ext4_io_end_t *io_end = ext4_inode_aio(inode); | ||
731 | |||
730 | map_bh(bh, inode->i_sb, map.m_pblk); | 732 | map_bh(bh, inode->i_sb, map.m_pblk); |
731 | bh->b_state = (bh->b_state & ~EXT4_MAP_FLAGS) | map.m_flags; | 733 | bh->b_state = (bh->b_state & ~EXT4_MAP_FLAGS) | map.m_flags; |
734 | if (io_end && io_end->flag & EXT4_IO_END_UNWRITTEN) | ||
735 | set_buffer_defer_completion(bh); | ||
732 | bh->b_size = inode->i_sb->s_blocksize * map.m_len; | 736 | bh->b_size = inode->i_sb->s_blocksize * map.m_len; |
733 | ret = 0; | 737 | ret = 0; |
734 | } | 738 | } |
@@ -2991,19 +2995,13 @@ static int ext4_get_block_write_nolock(struct inode *inode, sector_t iblock, | |||
2991 | } | 2995 | } |
2992 | 2996 | ||
2993 | static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, | 2997 | static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, |
2994 | ssize_t size, void *private, int ret, | 2998 | ssize_t size, void *private) |
2995 | bool is_async) | ||
2996 | { | 2999 | { |
2997 | struct inode *inode = file_inode(iocb->ki_filp); | ||
2998 | ext4_io_end_t *io_end = iocb->private; | 3000 | ext4_io_end_t *io_end = iocb->private; |
2999 | 3001 | ||
3000 | /* if not async direct IO just return */ | 3002 | /* if not async direct IO just return */ |
3001 | if (!io_end) { | 3003 | if (!io_end) |
3002 | inode_dio_done(inode); | ||
3003 | if (is_async) | ||
3004 | aio_complete(iocb, ret, 0); | ||
3005 | return; | 3004 | return; |
3006 | } | ||
3007 | 3005 | ||
3008 | ext_debug("ext4_end_io_dio(): io_end 0x%p " | 3006 | ext_debug("ext4_end_io_dio(): io_end 0x%p " |
3009 | "for inode %lu, iocb 0x%p, offset %llu, size %zd\n", | 3007 | "for inode %lu, iocb 0x%p, offset %llu, size %zd\n", |
@@ -3013,11 +3011,7 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, | |||
3013 | iocb->private = NULL; | 3011 | iocb->private = NULL; |
3014 | io_end->offset = offset; | 3012 | io_end->offset = offset; |
3015 | io_end->size = size; | 3013 | io_end->size = size; |
3016 | if (is_async) { | 3014 | ext4_put_io_end(io_end); |
3017 | io_end->iocb = iocb; | ||
3018 | io_end->result = ret; | ||
3019 | } | ||
3020 | ext4_put_io_end_defer(io_end); | ||
3021 | } | 3015 | } |
3022 | 3016 | ||
3023 | /* | 3017 | /* |
@@ -3102,7 +3096,6 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, | |||
3102 | ret = -ENOMEM; | 3096 | ret = -ENOMEM; |
3103 | goto retake_lock; | 3097 | goto retake_lock; |
3104 | } | 3098 | } |
3105 | io_end->flag |= EXT4_IO_END_DIRECT; | ||
3106 | /* | 3099 | /* |
3107 | * Grab reference for DIO. Will be dropped in ext4_end_io_dio() | 3100 | * Grab reference for DIO. Will be dropped in ext4_end_io_dio() |
3108 | */ | 3101 | */ |
@@ -3147,13 +3140,6 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, | |||
3147 | if (ret <= 0 && ret != -EIOCBQUEUED && iocb->private) { | 3140 | if (ret <= 0 && ret != -EIOCBQUEUED && iocb->private) { |
3148 | WARN_ON(iocb->private != io_end); | 3141 | WARN_ON(iocb->private != io_end); |
3149 | WARN_ON(io_end->flag & EXT4_IO_END_UNWRITTEN); | 3142 | WARN_ON(io_end->flag & EXT4_IO_END_UNWRITTEN); |
3150 | WARN_ON(io_end->iocb); | ||
3151 | /* | ||
3152 | * Generic code already did inode_dio_done() so we | ||
3153 | * have to clear EXT4_IO_END_DIRECT to not do it for | ||
3154 | * the second time. | ||
3155 | */ | ||
3156 | io_end->flag = 0; | ||
3157 | ext4_put_io_end(io_end); | 3143 | ext4_put_io_end(io_end); |
3158 | iocb->private = NULL; | 3144 | iocb->private = NULL; |
3159 | } | 3145 | } |