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>
This commit is contained in:

committed by
Al Viro

parent
4b6ccca701
commit
7b7a8665ed
@@ -86,14 +86,6 @@ xfs_destroy_ioend(
|
||||
bh->b_end_io(bh, !ioend->io_error);
|
||||
}
|
||||
|
||||
if (ioend->io_iocb) {
|
||||
inode_dio_done(ioend->io_inode);
|
||||
if (ioend->io_isasync) {
|
||||
aio_complete(ioend->io_iocb, ioend->io_error ?
|
||||
ioend->io_error : ioend->io_result, 0);
|
||||
}
|
||||
}
|
||||
|
||||
mempool_free(ioend, xfs_ioend_pool);
|
||||
}
|
||||
|
||||
@@ -281,7 +273,6 @@ xfs_alloc_ioend(
|
||||
* all the I/O from calling the completion routine too early.
|
||||
*/
|
||||
atomic_set(&ioend->io_remaining, 1);
|
||||
ioend->io_isasync = 0;
|
||||
ioend->io_isdirect = 0;
|
||||
ioend->io_error = 0;
|
||||
ioend->io_list = NULL;
|
||||
@@ -291,8 +282,6 @@ xfs_alloc_ioend(
|
||||
ioend->io_buffer_tail = NULL;
|
||||
ioend->io_offset = 0;
|
||||
ioend->io_size = 0;
|
||||
ioend->io_iocb = NULL;
|
||||
ioend->io_result = 0;
|
||||
ioend->io_append_trans = NULL;
|
||||
|
||||
INIT_WORK(&ioend->io_work, xfs_end_io);
|
||||
@@ -1292,8 +1281,10 @@ __xfs_get_blocks(
|
||||
if (create || !ISUNWRITTEN(&imap))
|
||||
xfs_map_buffer(inode, bh_result, &imap, offset);
|
||||
if (create && ISUNWRITTEN(&imap)) {
|
||||
if (direct)
|
||||
if (direct) {
|
||||
bh_result->b_private = inode;
|
||||
set_buffer_defer_completion(bh_result);
|
||||
}
|
||||
set_buffer_unwritten(bh_result);
|
||||
}
|
||||
}
|
||||
@@ -1390,9 +1381,7 @@ xfs_end_io_direct_write(
|
||||
struct kiocb *iocb,
|
||||
loff_t offset,
|
||||
ssize_t size,
|
||||
void *private,
|
||||
int ret,
|
||||
bool is_async)
|
||||
void *private)
|
||||
{
|
||||
struct xfs_ioend *ioend = iocb->private;
|
||||
|
||||
@@ -1414,17 +1403,10 @@ xfs_end_io_direct_write(
|
||||
|
||||
ioend->io_offset = offset;
|
||||
ioend->io_size = size;
|
||||
ioend->io_iocb = iocb;
|
||||
ioend->io_result = ret;
|
||||
if (private && size > 0)
|
||||
ioend->io_type = XFS_IO_UNWRITTEN;
|
||||
|
||||
if (is_async) {
|
||||
ioend->io_isasync = 1;
|
||||
xfs_finish_ioend(ioend);
|
||||
} else {
|
||||
xfs_finish_ioend_sync(ioend);
|
||||
}
|
||||
xfs_finish_ioend_sync(ioend);
|
||||
}
|
||||
|
||||
STATIC ssize_t
|
||||
|
Reference in New Issue
Block a user