diff options
Diffstat (limited to 'fs/ocfs2/file.c')
-rw-r--r-- | fs/ocfs2/file.c | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index b1e35a392ca5..145f4533a936 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -2038,6 +2038,23 @@ out: | |||
2038 | return ret; | 2038 | return ret; |
2039 | } | 2039 | } |
2040 | 2040 | ||
2041 | static void ocfs2_aiodio_wait(struct inode *inode) | ||
2042 | { | ||
2043 | wait_queue_head_t *wq = ocfs2_ioend_wq(inode); | ||
2044 | |||
2045 | wait_event(*wq, (atomic_read(&OCFS2_I(inode)->ip_unaligned_aio) == 0)); | ||
2046 | } | ||
2047 | |||
2048 | static int ocfs2_is_io_unaligned(struct inode *inode, size_t count, loff_t pos) | ||
2049 | { | ||
2050 | int blockmask = inode->i_sb->s_blocksize - 1; | ||
2051 | loff_t final_size = pos + count; | ||
2052 | |||
2053 | if ((pos & blockmask) || (final_size & blockmask)) | ||
2054 | return 1; | ||
2055 | return 0; | ||
2056 | } | ||
2057 | |||
2041 | static int ocfs2_prepare_inode_for_refcount(struct inode *inode, | 2058 | static int ocfs2_prepare_inode_for_refcount(struct inode *inode, |
2042 | struct file *file, | 2059 | struct file *file, |
2043 | loff_t pos, size_t count, | 2060 | loff_t pos, size_t count, |
@@ -2216,6 +2233,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, | |||
2216 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | 2233 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
2217 | int full_coherency = !(osb->s_mount_opt & | 2234 | int full_coherency = !(osb->s_mount_opt & |
2218 | OCFS2_MOUNT_COHERENCY_BUFFERED); | 2235 | OCFS2_MOUNT_COHERENCY_BUFFERED); |
2236 | int unaligned_dio = 0; | ||
2219 | 2237 | ||
2220 | trace_ocfs2_file_aio_write(inode, file, file->f_path.dentry, | 2238 | trace_ocfs2_file_aio_write(inode, file, file->f_path.dentry, |
2221 | (unsigned long long)OCFS2_I(inode)->ip_blkno, | 2239 | (unsigned long long)OCFS2_I(inode)->ip_blkno, |
@@ -2284,6 +2302,10 @@ relock: | |||
2284 | goto out; | 2302 | goto out; |
2285 | } | 2303 | } |
2286 | 2304 | ||
2305 | if (direct_io && !is_sync_kiocb(iocb)) | ||
2306 | unaligned_dio = ocfs2_is_io_unaligned(inode, iocb->ki_left, | ||
2307 | *ppos); | ||
2308 | |||
2287 | /* | 2309 | /* |
2288 | * We can't complete the direct I/O as requested, fall back to | 2310 | * We can't complete the direct I/O as requested, fall back to |
2289 | * buffered I/O. | 2311 | * buffered I/O. |
@@ -2299,6 +2321,18 @@ relock: | |||
2299 | goto relock; | 2321 | goto relock; |
2300 | } | 2322 | } |
2301 | 2323 | ||
2324 | if (unaligned_dio) { | ||
2325 | /* | ||
2326 | * Wait on previous unaligned aio to complete before | ||
2327 | * proceeding. | ||
2328 | */ | ||
2329 | ocfs2_aiodio_wait(inode); | ||
2330 | |||
2331 | /* Mark the iocb as needing a decrement in ocfs2_dio_end_io */ | ||
2332 | atomic_inc(&OCFS2_I(inode)->ip_unaligned_aio); | ||
2333 | ocfs2_iocb_set_unaligned_aio(iocb); | ||
2334 | } | ||
2335 | |||
2302 | /* | 2336 | /* |
2303 | * To later detect whether a journal commit for sync writes is | 2337 | * To later detect whether a journal commit for sync writes is |
2304 | * necessary, we sample i_size, and cluster count here. | 2338 | * necessary, we sample i_size, and cluster count here. |
@@ -2371,8 +2405,12 @@ out_dio: | |||
2371 | if ((ret == -EIOCBQUEUED) || (!ocfs2_iocb_is_rw_locked(iocb))) { | 2405 | if ((ret == -EIOCBQUEUED) || (!ocfs2_iocb_is_rw_locked(iocb))) { |
2372 | rw_level = -1; | 2406 | rw_level = -1; |
2373 | have_alloc_sem = 0; | 2407 | have_alloc_sem = 0; |
2408 | unaligned_dio = 0; | ||
2374 | } | 2409 | } |
2375 | 2410 | ||
2411 | if (unaligned_dio) | ||
2412 | atomic_dec(&OCFS2_I(inode)->ip_unaligned_aio); | ||
2413 | |||
2376 | out: | 2414 | out: |
2377 | if (rw_level != -1) | 2415 | if (rw_level != -1) |
2378 | ocfs2_rw_unlock(inode, rw_level); | 2416 | ocfs2_rw_unlock(inode, rw_level); |