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 /fs/direct-io.c | |
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>
Diffstat (limited to 'fs/direct-io.c')
-rw-r--r-- | fs/direct-io.c | 45 |
1 files changed, 36 insertions, 9 deletions
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; |