diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/aops.c | 10 | ||||
-rw-r--r-- | fs/ocfs2/aops.h | 14 | ||||
-rw-r--r-- | fs/ocfs2/file.c | 38 | ||||
-rw-r--r-- | fs/ocfs2/inode.h | 3 | ||||
-rw-r--r-- | fs/ocfs2/super.c | 10 |
5 files changed, 73 insertions, 2 deletions
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index ac97bca282d2..4c1ec8f2d8c1 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
@@ -564,6 +564,7 @@ static void ocfs2_dio_end_io(struct kiocb *iocb, | |||
564 | { | 564 | { |
565 | struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; | 565 | struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; |
566 | int level; | 566 | int level; |
567 | wait_queue_head_t *wq = ocfs2_ioend_wq(inode); | ||
567 | 568 | ||
568 | /* this io's submitter should not have unlocked this before we could */ | 569 | /* this io's submitter should not have unlocked this before we could */ |
569 | BUG_ON(!ocfs2_iocb_is_rw_locked(iocb)); | 570 | BUG_ON(!ocfs2_iocb_is_rw_locked(iocb)); |
@@ -573,6 +574,15 @@ static void ocfs2_dio_end_io(struct kiocb *iocb, | |||
573 | ocfs2_iocb_clear_sem_locked(iocb); | 574 | ocfs2_iocb_clear_sem_locked(iocb); |
574 | } | 575 | } |
575 | 576 | ||
577 | if (ocfs2_iocb_is_unaligned_aio(iocb)) { | ||
578 | ocfs2_iocb_clear_unaligned_aio(iocb); | ||
579 | |||
580 | if (atomic_dec_and_test(&OCFS2_I(inode)->ip_unaligned_aio) && | ||
581 | waitqueue_active(wq)) { | ||
582 | wake_up_all(wq); | ||
583 | } | ||
584 | } | ||
585 | |||
576 | ocfs2_iocb_clear_rw_locked(iocb); | 586 | ocfs2_iocb_clear_rw_locked(iocb); |
577 | 587 | ||
578 | level = ocfs2_iocb_rw_locked_level(iocb); | 588 | level = ocfs2_iocb_rw_locked_level(iocb); |
diff --git a/fs/ocfs2/aops.h b/fs/ocfs2/aops.h index 75cf3ad987a6..ffb2da370a99 100644 --- a/fs/ocfs2/aops.h +++ b/fs/ocfs2/aops.h | |||
@@ -78,6 +78,7 @@ enum ocfs2_iocb_lock_bits { | |||
78 | OCFS2_IOCB_RW_LOCK = 0, | 78 | OCFS2_IOCB_RW_LOCK = 0, |
79 | OCFS2_IOCB_RW_LOCK_LEVEL, | 79 | OCFS2_IOCB_RW_LOCK_LEVEL, |
80 | OCFS2_IOCB_SEM, | 80 | OCFS2_IOCB_SEM, |
81 | OCFS2_IOCB_UNALIGNED_IO, | ||
81 | OCFS2_IOCB_NUM_LOCKS | 82 | OCFS2_IOCB_NUM_LOCKS |
82 | }; | 83 | }; |
83 | 84 | ||
@@ -91,4 +92,17 @@ enum ocfs2_iocb_lock_bits { | |||
91 | clear_bit(OCFS2_IOCB_SEM, (unsigned long *)&iocb->private) | 92 | clear_bit(OCFS2_IOCB_SEM, (unsigned long *)&iocb->private) |
92 | #define ocfs2_iocb_is_sem_locked(iocb) \ | 93 | #define ocfs2_iocb_is_sem_locked(iocb) \ |
93 | test_bit(OCFS2_IOCB_SEM, (unsigned long *)&iocb->private) | 94 | test_bit(OCFS2_IOCB_SEM, (unsigned long *)&iocb->private) |
95 | |||
96 | #define ocfs2_iocb_set_unaligned_aio(iocb) \ | ||
97 | set_bit(OCFS2_IOCB_UNALIGNED_IO, (unsigned long *)&iocb->private) | ||
98 | #define ocfs2_iocb_clear_unaligned_aio(iocb) \ | ||
99 | clear_bit(OCFS2_IOCB_UNALIGNED_IO, (unsigned long *)&iocb->private) | ||
100 | #define ocfs2_iocb_is_unaligned_aio(iocb) \ | ||
101 | test_bit(OCFS2_IOCB_UNALIGNED_IO, (unsigned long *)&iocb->private) | ||
102 | |||
103 | #define OCFS2_IOEND_WQ_HASH_SZ 37 | ||
104 | #define ocfs2_ioend_wq(v) (&ocfs2__ioend_wq[((unsigned long)(v)) %\ | ||
105 | OCFS2_IOEND_WQ_HASH_SZ]) | ||
106 | extern wait_queue_head_t ocfs2__ioend_wq[OCFS2_IOEND_WQ_HASH_SZ]; | ||
107 | |||
94 | #endif /* OCFS2_FILE_H */ | 108 | #endif /* OCFS2_FILE_H */ |
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); |
diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h index 1c508b149b3a..88924a3133fa 100644 --- a/fs/ocfs2/inode.h +++ b/fs/ocfs2/inode.h | |||
@@ -43,6 +43,9 @@ struct ocfs2_inode_info | |||
43 | /* protects extended attribute changes on this inode */ | 43 | /* protects extended attribute changes on this inode */ |
44 | struct rw_semaphore ip_xattr_sem; | 44 | struct rw_semaphore ip_xattr_sem; |
45 | 45 | ||
46 | /* Number of outstanding AIO's which are not page aligned */ | ||
47 | atomic_t ip_unaligned_aio; | ||
48 | |||
46 | /* These fields are protected by ip_lock */ | 49 | /* These fields are protected by ip_lock */ |
47 | spinlock_t ip_lock; | 50 | spinlock_t ip_lock; |
48 | u32 ip_open_count; | 51 | u32 ip_open_count; |
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 029c4cd8a691..603f5fe9f816 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c | |||
@@ -54,6 +54,7 @@ | |||
54 | #include "ocfs1_fs_compat.h" | 54 | #include "ocfs1_fs_compat.h" |
55 | 55 | ||
56 | #include "alloc.h" | 56 | #include "alloc.h" |
57 | #include "aops.h" | ||
57 | #include "blockcheck.h" | 58 | #include "blockcheck.h" |
58 | #include "dlmglue.h" | 59 | #include "dlmglue.h" |
59 | #include "export.h" | 60 | #include "export.h" |
@@ -1616,12 +1617,17 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt) | |||
1616 | return 0; | 1617 | return 0; |
1617 | } | 1618 | } |
1618 | 1619 | ||
1620 | wait_queue_head_t ocfs2__ioend_wq[OCFS2_IOEND_WQ_HASH_SZ]; | ||
1621 | |||
1619 | static int __init ocfs2_init(void) | 1622 | static int __init ocfs2_init(void) |
1620 | { | 1623 | { |
1621 | int status; | 1624 | int status, i; |
1622 | 1625 | ||
1623 | ocfs2_print_version(); | 1626 | ocfs2_print_version(); |
1624 | 1627 | ||
1628 | for (i = 0; i < OCFS2_IOEND_WQ_HASH_SZ; i++) | ||
1629 | init_waitqueue_head(&ocfs2__ioend_wq[i]); | ||
1630 | |||
1625 | status = init_ocfs2_uptodate_cache(); | 1631 | status = init_ocfs2_uptodate_cache(); |
1626 | if (status < 0) { | 1632 | if (status < 0) { |
1627 | mlog_errno(status); | 1633 | mlog_errno(status); |
@@ -1760,7 +1766,7 @@ static void ocfs2_inode_init_once(void *data) | |||
1760 | ocfs2_extent_map_init(&oi->vfs_inode); | 1766 | ocfs2_extent_map_init(&oi->vfs_inode); |
1761 | INIT_LIST_HEAD(&oi->ip_io_markers); | 1767 | INIT_LIST_HEAD(&oi->ip_io_markers); |
1762 | oi->ip_dir_start_lookup = 0; | 1768 | oi->ip_dir_start_lookup = 0; |
1763 | 1769 | atomic_set(&oi->ip_unaligned_aio, 0); | |
1764 | init_rwsem(&oi->ip_alloc_sem); | 1770 | init_rwsem(&oi->ip_alloc_sem); |
1765 | init_rwsem(&oi->ip_xattr_sem); | 1771 | init_rwsem(&oi->ip_xattr_sem); |
1766 | mutex_init(&oi->ip_io_mutex); | 1772 | mutex_init(&oi->ip_io_mutex); |