diff options
author | Christoph Hellwig <hch@infradead.org> | 2012-02-29 04:53:48 -0500 |
---|---|---|
committer | Ben Myers <bpm@sgi.com> | 2012-03-05 12:07:42 -0500 |
commit | aa6bf01d391935a8929333bc2e243084ea0c58db (patch) | |
tree | 686c204328f00ae91466267a9f1e85c3c8d767cb /fs | |
parent | 4b217ed9e30f94b6e8e5e262020ef0ceab6113af (diff) |
xfs: use per-filesystem I/O completion workqueues
The new concurrency managed workqueues are cheap enough that we can create
per-filesystem instead of global workqueues. This allows us to remove the
trylock or defer scheme on the ilock, which is not helpful once we have
outstanding log reservations until finishing a size update.
Also allow the default concurrency on this workqueues so that I/O completions
blocking on the ilock for one inode do not block process for another inode.
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/xfs_aops.c | 39 | ||||
-rw-r--r-- | fs/xfs/xfs_aops.h | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_buf.c | 17 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.h | 3 | ||||
-rw-r--r-- | fs/xfs/xfs_super.c | 39 |
5 files changed, 51 insertions, 49 deletions
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 74b9baf36ac3..540a01742c6d 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c | |||
@@ -126,21 +126,15 @@ static inline bool xfs_ioend_is_append(struct xfs_ioend *ioend) | |||
126 | 126 | ||
127 | /* | 127 | /* |
128 | * Update on-disk file size now that data has been written to disk. | 128 | * Update on-disk file size now that data has been written to disk. |
129 | * | ||
130 | * This function does not block as blocking on the inode lock in IO completion | ||
131 | * can lead to IO completion order dependency deadlocks.. If it can't get the | ||
132 | * inode ilock it will return EAGAIN. Callers must handle this. | ||
133 | */ | 129 | */ |
134 | STATIC int | 130 | STATIC void |
135 | xfs_setfilesize( | 131 | xfs_setfilesize( |
136 | xfs_ioend_t *ioend) | 132 | struct xfs_ioend *ioend) |
137 | { | 133 | { |
138 | xfs_inode_t *ip = XFS_I(ioend->io_inode); | 134 | struct xfs_inode *ip = XFS_I(ioend->io_inode); |
139 | xfs_fsize_t isize; | 135 | xfs_fsize_t isize; |
140 | 136 | ||
141 | if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) | 137 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
142 | return EAGAIN; | ||
143 | |||
144 | isize = xfs_ioend_new_eof(ioend); | 138 | isize = xfs_ioend_new_eof(ioend); |
145 | if (isize) { | 139 | if (isize) { |
146 | trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size); | 140 | trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size); |
@@ -149,7 +143,6 @@ xfs_setfilesize( | |||
149 | } | 143 | } |
150 | 144 | ||
151 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 145 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
152 | return 0; | ||
153 | } | 146 | } |
154 | 147 | ||
155 | /* | 148 | /* |
@@ -163,10 +156,12 @@ xfs_finish_ioend( | |||
163 | struct xfs_ioend *ioend) | 156 | struct xfs_ioend *ioend) |
164 | { | 157 | { |
165 | if (atomic_dec_and_test(&ioend->io_remaining)) { | 158 | if (atomic_dec_and_test(&ioend->io_remaining)) { |
159 | struct xfs_mount *mp = XFS_I(ioend->io_inode)->i_mount; | ||
160 | |||
166 | if (ioend->io_type == IO_UNWRITTEN) | 161 | if (ioend->io_type == IO_UNWRITTEN) |
167 | queue_work(xfsconvertd_workqueue, &ioend->io_work); | 162 | queue_work(mp->m_unwritten_workqueue, &ioend->io_work); |
168 | else if (xfs_ioend_is_append(ioend)) | 163 | else if (xfs_ioend_is_append(ioend)) |
169 | queue_work(xfsdatad_workqueue, &ioend->io_work); | 164 | queue_work(mp->m_data_workqueue, &ioend->io_work); |
170 | else | 165 | else |
171 | xfs_destroy_ioend(ioend); | 166 | xfs_destroy_ioend(ioend); |
172 | } | 167 | } |
@@ -207,23 +202,9 @@ xfs_end_io( | |||
207 | * We might have to update the on-disk file size after extending | 202 | * We might have to update the on-disk file size after extending |
208 | * writes. | 203 | * writes. |
209 | */ | 204 | */ |
210 | error = xfs_setfilesize(ioend); | 205 | xfs_setfilesize(ioend); |
211 | ASSERT(!error || error == EAGAIN); | ||
212 | |||
213 | done: | 206 | done: |
214 | /* | 207 | xfs_destroy_ioend(ioend); |
215 | * If we didn't complete processing of the ioend, requeue it to the | ||
216 | * tail of the workqueue for another attempt later. Otherwise destroy | ||
217 | * it. | ||
218 | */ | ||
219 | if (error == EAGAIN) { | ||
220 | atomic_inc(&ioend->io_remaining); | ||
221 | xfs_finish_ioend(ioend); | ||
222 | /* ensure we don't spin on blocked ioends */ | ||
223 | delay(1); | ||
224 | } else { | ||
225 | xfs_destroy_ioend(ioend); | ||
226 | } | ||
227 | } | 208 | } |
228 | 209 | ||
229 | /* | 210 | /* |
diff --git a/fs/xfs/xfs_aops.h b/fs/xfs/xfs_aops.h index 116dd5c37034..06e4caf38203 100644 --- a/fs/xfs/xfs_aops.h +++ b/fs/xfs/xfs_aops.h | |||
@@ -18,8 +18,6 @@ | |||
18 | #ifndef __XFS_AOPS_H__ | 18 | #ifndef __XFS_AOPS_H__ |
19 | #define __XFS_AOPS_H__ | 19 | #define __XFS_AOPS_H__ |
20 | 20 | ||
21 | extern struct workqueue_struct *xfsdatad_workqueue; | ||
22 | extern struct workqueue_struct *xfsconvertd_workqueue; | ||
23 | extern mempool_t *xfs_ioend_pool; | 21 | extern mempool_t *xfs_ioend_pool; |
24 | 22 | ||
25 | /* | 23 | /* |
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index 4dff85c7d7eb..6819b5163e33 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c | |||
@@ -45,8 +45,6 @@ static kmem_zone_t *xfs_buf_zone; | |||
45 | STATIC int xfsbufd(void *); | 45 | STATIC int xfsbufd(void *); |
46 | 46 | ||
47 | static struct workqueue_struct *xfslogd_workqueue; | 47 | static struct workqueue_struct *xfslogd_workqueue; |
48 | struct workqueue_struct *xfsdatad_workqueue; | ||
49 | struct workqueue_struct *xfsconvertd_workqueue; | ||
50 | 48 | ||
51 | #ifdef XFS_BUF_LOCK_TRACKING | 49 | #ifdef XFS_BUF_LOCK_TRACKING |
52 | # define XB_SET_OWNER(bp) ((bp)->b_last_holder = current->pid) | 50 | # define XB_SET_OWNER(bp) ((bp)->b_last_holder = current->pid) |
@@ -1793,21 +1791,8 @@ xfs_buf_init(void) | |||
1793 | if (!xfslogd_workqueue) | 1791 | if (!xfslogd_workqueue) |
1794 | goto out_free_buf_zone; | 1792 | goto out_free_buf_zone; |
1795 | 1793 | ||
1796 | xfsdatad_workqueue = alloc_workqueue("xfsdatad", WQ_MEM_RECLAIM, 1); | ||
1797 | if (!xfsdatad_workqueue) | ||
1798 | goto out_destroy_xfslogd_workqueue; | ||
1799 | |||
1800 | xfsconvertd_workqueue = alloc_workqueue("xfsconvertd", | ||
1801 | WQ_MEM_RECLAIM, 1); | ||
1802 | if (!xfsconvertd_workqueue) | ||
1803 | goto out_destroy_xfsdatad_workqueue; | ||
1804 | |||
1805 | return 0; | 1794 | return 0; |
1806 | 1795 | ||
1807 | out_destroy_xfsdatad_workqueue: | ||
1808 | destroy_workqueue(xfsdatad_workqueue); | ||
1809 | out_destroy_xfslogd_workqueue: | ||
1810 | destroy_workqueue(xfslogd_workqueue); | ||
1811 | out_free_buf_zone: | 1796 | out_free_buf_zone: |
1812 | kmem_zone_destroy(xfs_buf_zone); | 1797 | kmem_zone_destroy(xfs_buf_zone); |
1813 | out: | 1798 | out: |
@@ -1817,8 +1802,6 @@ xfs_buf_init(void) | |||
1817 | void | 1802 | void |
1818 | xfs_buf_terminate(void) | 1803 | xfs_buf_terminate(void) |
1819 | { | 1804 | { |
1820 | destroy_workqueue(xfsconvertd_workqueue); | ||
1821 | destroy_workqueue(xfsdatad_workqueue); | ||
1822 | destroy_workqueue(xfslogd_workqueue); | 1805 | destroy_workqueue(xfslogd_workqueue); |
1823 | kmem_zone_destroy(xfs_buf_zone); | 1806 | kmem_zone_destroy(xfs_buf_zone); |
1824 | } | 1807 | } |
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index c082e44dad2d..9eba73887829 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
@@ -211,6 +211,9 @@ typedef struct xfs_mount { | |||
211 | struct shrinker m_inode_shrink; /* inode reclaim shrinker */ | 211 | struct shrinker m_inode_shrink; /* inode reclaim shrinker */ |
212 | int64_t m_low_space[XFS_LOWSP_MAX]; | 212 | int64_t m_low_space[XFS_LOWSP_MAX]; |
213 | /* low free space thresholds */ | 213 | /* low free space thresholds */ |
214 | |||
215 | struct workqueue_struct *m_data_workqueue; | ||
216 | struct workqueue_struct *m_unwritten_workqueue; | ||
214 | } xfs_mount_t; | 217 | } xfs_mount_t; |
215 | 218 | ||
216 | /* | 219 | /* |
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 5e0d43f231a4..c7f7bc2855a4 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c | |||
@@ -759,6 +759,36 @@ xfs_setup_devices( | |||
759 | return 0; | 759 | return 0; |
760 | } | 760 | } |
761 | 761 | ||
762 | STATIC int | ||
763 | xfs_init_mount_workqueues( | ||
764 | struct xfs_mount *mp) | ||
765 | { | ||
766 | mp->m_data_workqueue = alloc_workqueue("xfs-data/%s", | ||
767 | WQ_MEM_RECLAIM, 0, mp->m_fsname); | ||
768 | if (!mp->m_data_workqueue) | ||
769 | goto out; | ||
770 | |||
771 | mp->m_unwritten_workqueue = alloc_workqueue("xfs-conv/%s", | ||
772 | WQ_MEM_RECLAIM, 0, mp->m_fsname); | ||
773 | if (!mp->m_unwritten_workqueue) | ||
774 | goto out_destroy_data_iodone_queue; | ||
775 | |||
776 | return 0; | ||
777 | |||
778 | out_destroy_data_iodone_queue: | ||
779 | destroy_workqueue(mp->m_data_workqueue); | ||
780 | out: | ||
781 | return -ENOMEM; | ||
782 | } | ||
783 | |||
784 | STATIC void | ||
785 | xfs_destroy_mount_workqueues( | ||
786 | struct xfs_mount *mp) | ||
787 | { | ||
788 | destroy_workqueue(mp->m_data_workqueue); | ||
789 | destroy_workqueue(mp->m_unwritten_workqueue); | ||
790 | } | ||
791 | |||
762 | /* Catch misguided souls that try to use this interface on XFS */ | 792 | /* Catch misguided souls that try to use this interface on XFS */ |
763 | STATIC struct inode * | 793 | STATIC struct inode * |
764 | xfs_fs_alloc_inode( | 794 | xfs_fs_alloc_inode( |
@@ -982,6 +1012,7 @@ xfs_fs_put_super( | |||
982 | xfs_unmountfs(mp); | 1012 | xfs_unmountfs(mp); |
983 | xfs_freesb(mp); | 1013 | xfs_freesb(mp); |
984 | xfs_icsb_destroy_counters(mp); | 1014 | xfs_icsb_destroy_counters(mp); |
1015 | xfs_destroy_mount_workqueues(mp); | ||
985 | xfs_close_devices(mp); | 1016 | xfs_close_devices(mp); |
986 | xfs_free_fsname(mp); | 1017 | xfs_free_fsname(mp); |
987 | kfree(mp); | 1018 | kfree(mp); |
@@ -1308,10 +1339,14 @@ xfs_fs_fill_super( | |||
1308 | if (error) | 1339 | if (error) |
1309 | goto out_free_fsname; | 1340 | goto out_free_fsname; |
1310 | 1341 | ||
1311 | error = xfs_icsb_init_counters(mp); | 1342 | error = xfs_init_mount_workqueues(mp); |
1312 | if (error) | 1343 | if (error) |
1313 | goto out_close_devices; | 1344 | goto out_close_devices; |
1314 | 1345 | ||
1346 | error = xfs_icsb_init_counters(mp); | ||
1347 | if (error) | ||
1348 | goto out_destroy_workqueues; | ||
1349 | |||
1315 | error = xfs_readsb(mp, flags); | 1350 | error = xfs_readsb(mp, flags); |
1316 | if (error) | 1351 | if (error) |
1317 | goto out_destroy_counters; | 1352 | goto out_destroy_counters; |
@@ -1374,6 +1409,8 @@ xfs_fs_fill_super( | |||
1374 | xfs_freesb(mp); | 1409 | xfs_freesb(mp); |
1375 | out_destroy_counters: | 1410 | out_destroy_counters: |
1376 | xfs_icsb_destroy_counters(mp); | 1411 | xfs_icsb_destroy_counters(mp); |
1412 | out_destroy_workqueues: | ||
1413 | xfs_destroy_mount_workqueues(mp); | ||
1377 | out_close_devices: | 1414 | out_close_devices: |
1378 | xfs_close_devices(mp); | 1415 | xfs_close_devices(mp); |
1379 | out_free_fsname: | 1416 | out_free_fsname: |