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/xfs/xfs_aops.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/xfs/xfs_aops.c')
-rw-r--r-- | fs/xfs/xfs_aops.c | 28 |
1 files changed, 5 insertions, 23 deletions
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 596ec71da00e..e11d654af786 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c | |||
@@ -86,14 +86,6 @@ xfs_destroy_ioend( | |||
86 | bh->b_end_io(bh, !ioend->io_error); | 86 | bh->b_end_io(bh, !ioend->io_error); |
87 | } | 87 | } |
88 | 88 | ||
89 | if (ioend->io_iocb) { | ||
90 | inode_dio_done(ioend->io_inode); | ||
91 | if (ioend->io_isasync) { | ||
92 | aio_complete(ioend->io_iocb, ioend->io_error ? | ||
93 | ioend->io_error : ioend->io_result, 0); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | mempool_free(ioend, xfs_ioend_pool); | 89 | mempool_free(ioend, xfs_ioend_pool); |
98 | } | 90 | } |
99 | 91 | ||
@@ -281,7 +273,6 @@ xfs_alloc_ioend( | |||
281 | * all the I/O from calling the completion routine too early. | 273 | * all the I/O from calling the completion routine too early. |
282 | */ | 274 | */ |
283 | atomic_set(&ioend->io_remaining, 1); | 275 | atomic_set(&ioend->io_remaining, 1); |
284 | ioend->io_isasync = 0; | ||
285 | ioend->io_isdirect = 0; | 276 | ioend->io_isdirect = 0; |
286 | ioend->io_error = 0; | 277 | ioend->io_error = 0; |
287 | ioend->io_list = NULL; | 278 | ioend->io_list = NULL; |
@@ -291,8 +282,6 @@ xfs_alloc_ioend( | |||
291 | ioend->io_buffer_tail = NULL; | 282 | ioend->io_buffer_tail = NULL; |
292 | ioend->io_offset = 0; | 283 | ioend->io_offset = 0; |
293 | ioend->io_size = 0; | 284 | ioend->io_size = 0; |
294 | ioend->io_iocb = NULL; | ||
295 | ioend->io_result = 0; | ||
296 | ioend->io_append_trans = NULL; | 285 | ioend->io_append_trans = NULL; |
297 | 286 | ||
298 | INIT_WORK(&ioend->io_work, xfs_end_io); | 287 | INIT_WORK(&ioend->io_work, xfs_end_io); |
@@ -1292,8 +1281,10 @@ __xfs_get_blocks( | |||
1292 | if (create || !ISUNWRITTEN(&imap)) | 1281 | if (create || !ISUNWRITTEN(&imap)) |
1293 | xfs_map_buffer(inode, bh_result, &imap, offset); | 1282 | xfs_map_buffer(inode, bh_result, &imap, offset); |
1294 | if (create && ISUNWRITTEN(&imap)) { | 1283 | if (create && ISUNWRITTEN(&imap)) { |
1295 | if (direct) | 1284 | if (direct) { |
1296 | bh_result->b_private = inode; | 1285 | bh_result->b_private = inode; |
1286 | set_buffer_defer_completion(bh_result); | ||
1287 | } | ||
1297 | set_buffer_unwritten(bh_result); | 1288 | set_buffer_unwritten(bh_result); |
1298 | } | 1289 | } |
1299 | } | 1290 | } |
@@ -1390,9 +1381,7 @@ xfs_end_io_direct_write( | |||
1390 | struct kiocb *iocb, | 1381 | struct kiocb *iocb, |
1391 | loff_t offset, | 1382 | loff_t offset, |
1392 | ssize_t size, | 1383 | ssize_t size, |
1393 | void *private, | 1384 | void *private) |
1394 | int ret, | ||
1395 | bool is_async) | ||
1396 | { | 1385 | { |
1397 | struct xfs_ioend *ioend = iocb->private; | 1386 | struct xfs_ioend *ioend = iocb->private; |
1398 | 1387 | ||
@@ -1414,17 +1403,10 @@ xfs_end_io_direct_write( | |||
1414 | 1403 | ||
1415 | ioend->io_offset = offset; | 1404 | ioend->io_offset = offset; |
1416 | ioend->io_size = size; | 1405 | ioend->io_size = size; |
1417 | ioend->io_iocb = iocb; | ||
1418 | ioend->io_result = ret; | ||
1419 | if (private && size > 0) | 1406 | if (private && size > 0) |
1420 | ioend->io_type = XFS_IO_UNWRITTEN; | 1407 | ioend->io_type = XFS_IO_UNWRITTEN; |
1421 | 1408 | ||
1422 | if (is_async) { | 1409 | xfs_finish_ioend_sync(ioend); |
1423 | ioend->io_isasync = 1; | ||
1424 | xfs_finish_ioend(ioend); | ||
1425 | } else { | ||
1426 | xfs_finish_ioend_sync(ioend); | ||
1427 | } | ||
1428 | } | 1410 | } |
1429 | 1411 | ||
1430 | STATIC ssize_t | 1412 | STATIC ssize_t |