diff options
author | Christoph Hellwig <hch@infradead.org> | 2013-09-04 09:04:40 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-09-04 09:23:46 -0400 |
commit | 02afc27faec94c9e068517a22acf55400976c698 (patch) | |
tree | 45de9689088ea99e1197c3f20f08cb9835a66410 | |
parent | 7b7a8665edd8db733980389b098530f9e4f630b2 (diff) |
direct-io: Handle O_(D)SYNC AIO
Call generic_write_sync() from the deferred I/O completion handler if
O_DSYNC is set for a write request. Also make sure various callers
don't call generic_write_sync if the direct I/O code returns
-EIOCBQUEUED.
Based on an earlier patch from Jan Kara <jack@suse.cz> with updates from
Jeff Moyer <jmoyer@redhat.com> and Darrick J. Wong <darrick.wong@oracle.com>.
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>
-rw-r--r-- | fs/block_dev.c | 2 | ||||
-rw-r--r-- | fs/btrfs/file.c | 2 | ||||
-rw-r--r-- | fs/cifs/file.c | 2 | ||||
-rw-r--r-- | fs/direct-io.c | 45 | ||||
-rw-r--r-- | fs/ext4/file.c | 2 | ||||
-rw-r--r-- | mm/filemap.c | 2 |
6 files changed, 41 insertions, 14 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index c7bda5cd3da7..1173a4ee0830 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -1519,7 +1519,7 @@ ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
1519 | 1519 | ||
1520 | blk_start_plug(&plug); | 1520 | blk_start_plug(&plug); |
1521 | ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); | 1521 | ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); |
1522 | if (ret > 0 || ret == -EIOCBQUEUED) { | 1522 | if (ret > 0) { |
1523 | ssize_t err; | 1523 | ssize_t err; |
1524 | 1524 | ||
1525 | err = generic_write_sync(file, pos, ret); | 1525 | err = generic_write_sync(file, pos, ret); |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 8e686a427ce2..4d2eb6417145 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -1727,7 +1727,7 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, | |||
1727 | */ | 1727 | */ |
1728 | BTRFS_I(inode)->last_trans = root->fs_info->generation + 1; | 1728 | BTRFS_I(inode)->last_trans = root->fs_info->generation + 1; |
1729 | BTRFS_I(inode)->last_sub_trans = root->log_transid; | 1729 | BTRFS_I(inode)->last_sub_trans = root->log_transid; |
1730 | if (num_written > 0 || num_written == -EIOCBQUEUED) { | 1730 | if (num_written > 0) { |
1731 | err = generic_write_sync(file, pos, num_written); | 1731 | err = generic_write_sync(file, pos, num_written); |
1732 | if (err < 0 && num_written > 0) | 1732 | if (err < 0 && num_written > 0) |
1733 | num_written = err; | 1733 | num_written = err; |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 7e36ae34e947..9d0dd952ad79 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -2553,7 +2553,7 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov, | |||
2553 | mutex_unlock(&inode->i_mutex); | 2553 | mutex_unlock(&inode->i_mutex); |
2554 | } | 2554 | } |
2555 | 2555 | ||
2556 | if (rc > 0 || rc == -EIOCBQUEUED) { | 2556 | if (rc > 0) { |
2557 | ssize_t err; | 2557 | ssize_t err; |
2558 | 2558 | ||
2559 | err = generic_write_sync(file, pos, rc); | 2559 | err = generic_write_sync(file, pos, rc); |
diff --git a/fs/direct-io.c b/fs/direct-io.c index 8b31b9f449f4..1782023bd68a 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c | |||
@@ -266,8 +266,18 @@ static ssize_t dio_complete(struct dio *dio, loff_t offset, ssize_t ret, | |||
266 | dio->end_io(dio->iocb, offset, transferred, dio->private); | 266 | dio->end_io(dio->iocb, offset, transferred, dio->private); |
267 | 267 | ||
268 | inode_dio_done(dio->inode); | 268 | inode_dio_done(dio->inode); |
269 | if (is_async) | 269 | if (is_async) { |
270 | if (dio->rw & WRITE) { | ||
271 | int err; | ||
272 | |||
273 | err = generic_write_sync(dio->iocb->ki_filp, offset, | ||
274 | transferred); | ||
275 | if (err < 0 && ret > 0) | ||
276 | ret = err; | ||
277 | } | ||
278 | |||
270 | aio_complete(dio->iocb, ret, 0); | 279 | aio_complete(dio->iocb, ret, 0); |
280 | } | ||
271 | 281 | ||
272 | kmem_cache_free(dio_cache, dio); | 282 | kmem_cache_free(dio_cache, dio); |
273 | return ret; | 283 | return ret; |
@@ -1183,11 +1193,6 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, | |||
1183 | } | 1193 | } |
1184 | 1194 | ||
1185 | /* | 1195 | /* |
1186 | * Will be decremented at I/O completion time. | ||
1187 | */ | ||
1188 | atomic_inc(&inode->i_dio_count); | ||
1189 | |||
1190 | /* | ||
1191 | * For file extending writes updating i_size before data | 1196 | * For file extending writes updating i_size before data |
1192 | * writeouts complete can expose uninitialized blocks. So | 1197 | * writeouts complete can expose uninitialized blocks. So |
1193 | * even for AIO, we need to wait for i/o to complete before | 1198 | * even for AIO, we need to wait for i/o to complete before |
@@ -1195,11 +1200,33 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, | |||
1195 | */ | 1200 | */ |
1196 | dio->is_async = !is_sync_kiocb(iocb) && !((rw & WRITE) && | 1201 | dio->is_async = !is_sync_kiocb(iocb) && !((rw & WRITE) && |
1197 | (end > i_size_read(inode))); | 1202 | (end > i_size_read(inode))); |
1198 | |||
1199 | retval = 0; | ||
1200 | |||
1201 | dio->inode = inode; | 1203 | dio->inode = inode; |
1202 | dio->rw = rw; | 1204 | dio->rw = rw; |
1205 | |||
1206 | /* | ||
1207 | * For AIO O_(D)SYNC writes we need to defer completions to a workqueue | ||
1208 | * so that we can call ->fsync. | ||
1209 | */ | ||
1210 | if (dio->is_async && (rw & WRITE) && | ||
1211 | ((iocb->ki_filp->f_flags & O_DSYNC) || | ||
1212 | IS_SYNC(iocb->ki_filp->f_mapping->host))) { | ||
1213 | retval = dio_set_defer_completion(dio); | ||
1214 | if (retval) { | ||
1215 | /* | ||
1216 | * We grab i_mutex only for reads so we don't have | ||
1217 | * to release it here | ||
1218 | */ | ||
1219 | kmem_cache_free(dio_cache, dio); | ||
1220 | goto out; | ||
1221 | } | ||
1222 | } | ||
1223 | |||
1224 | /* | ||
1225 | * Will be decremented at I/O completion time. | ||
1226 | */ | ||
1227 | atomic_inc(&inode->i_dio_count); | ||
1228 | |||
1229 | retval = 0; | ||
1203 | sdio.blkbits = blkbits; | 1230 | sdio.blkbits = blkbits; |
1204 | sdio.blkfactor = i_blkbits - blkbits; | 1231 | sdio.blkfactor = i_blkbits - blkbits; |
1205 | sdio.block_in_file = offset >> blkbits; | 1232 | sdio.block_in_file = offset >> blkbits; |
diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 319c9d26279a..3da21945ff1f 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c | |||
@@ -149,7 +149,7 @@ ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov, | |||
149 | ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); | 149 | ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); |
150 | mutex_unlock(&inode->i_mutex); | 150 | mutex_unlock(&inode->i_mutex); |
151 | 151 | ||
152 | if (ret > 0 || ret == -EIOCBQUEUED) { | 152 | if (ret > 0) { |
153 | ssize_t err; | 153 | ssize_t err; |
154 | 154 | ||
155 | err = generic_write_sync(file, pos, ret); | 155 | err = generic_write_sync(file, pos, ret); |
diff --git a/mm/filemap.c b/mm/filemap.c index 4b51ac1acae7..731a2c24532d 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -2550,7 +2550,7 @@ ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
2550 | ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); | 2550 | ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); |
2551 | mutex_unlock(&inode->i_mutex); | 2551 | mutex_unlock(&inode->i_mutex); |
2552 | 2552 | ||
2553 | if (ret > 0 || ret == -EIOCBQUEUED) { | 2553 | if (ret > 0) { |
2554 | ssize_t err; | 2554 | ssize_t err; |
2555 | 2555 | ||
2556 | err = generic_write_sync(file, pos, ret); | 2556 | err = generic_write_sync(file, pos, ret); |