diff options
author | Dave Chinner <david@fromorbit.com> | 2009-04-06 12:42:11 -0400 |
---|---|---|
committer | Christoph Hellwig <hch@brick.lst.de> | 2009-04-06 12:42:11 -0400 |
commit | c626d174cfe38e7f0545d074c299527892cd8c45 (patch) | |
tree | 8f7dfa34a77bc415d9dc604d79fbae98ffe47a14 | |
parent | 705db3fd4660174a27418bbcb874d209a76044eb (diff) |
xfs: prevent unwritten extent conversion from blocking I/O completion
Unwritten extent conversion can recurse back into the filesystem due
to memory allocation. Memory reclaim requires I/O completions to be
processed to allow the callers to make progress. If the I/O
completion workqueue thread is doing the recursion, then we have a
deadlock situation.
Move unwritten extent completion into it's own workqueue so it
doesn't block I/O completions for normal delayed allocation or
overwrite data.
Signed-off-by: Dave Chinner <david@fromorbit.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
-rw-r--r-- | fs/xfs/linux-2.6/xfs_aops.c | 38 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_aops.h | 1 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_buf.c | 9 |
3 files changed, 31 insertions, 17 deletions
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index c13f67300fe7..7ec89fc05b2b 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c | |||
@@ -153,23 +153,6 @@ xfs_find_bdev_for_inode( | |||
153 | } | 153 | } |
154 | 154 | ||
155 | /* | 155 | /* |
156 | * Schedule IO completion handling on a xfsdatad if this was | ||
157 | * the final hold on this ioend. If we are asked to wait, | ||
158 | * flush the workqueue. | ||
159 | */ | ||
160 | STATIC void | ||
161 | xfs_finish_ioend( | ||
162 | xfs_ioend_t *ioend, | ||
163 | int wait) | ||
164 | { | ||
165 | if (atomic_dec_and_test(&ioend->io_remaining)) { | ||
166 | queue_work(xfsdatad_workqueue, &ioend->io_work); | ||
167 | if (wait) | ||
168 | flush_workqueue(xfsdatad_workqueue); | ||
169 | } | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * We're now finished for good with this ioend structure. | 156 | * We're now finished for good with this ioend structure. |
174 | * Update the page state via the associated buffer_heads, | 157 | * Update the page state via the associated buffer_heads, |
175 | * release holds on the inode and bio, and finally free | 158 | * release holds on the inode and bio, and finally free |
@@ -310,6 +293,27 @@ xfs_end_bio_read( | |||
310 | } | 293 | } |
311 | 294 | ||
312 | /* | 295 | /* |
296 | * Schedule IO completion handling on a xfsdatad if this was | ||
297 | * the final hold on this ioend. If we are asked to wait, | ||
298 | * flush the workqueue. | ||
299 | */ | ||
300 | STATIC void | ||
301 | xfs_finish_ioend( | ||
302 | xfs_ioend_t *ioend, | ||
303 | int wait) | ||
304 | { | ||
305 | if (atomic_dec_and_test(&ioend->io_remaining)) { | ||
306 | struct workqueue_struct *wq = xfsdatad_workqueue; | ||
307 | if (ioend->io_work.func == xfs_end_bio_unwritten) | ||
308 | wq = xfsconvertd_workqueue; | ||
309 | |||
310 | queue_work(wq, &ioend->io_work); | ||
311 | if (wait) | ||
312 | flush_workqueue(wq); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | /* | ||
313 | * Allocate and initialise an IO completion structure. | 317 | * Allocate and initialise an IO completion structure. |
314 | * We need to track unwritten extent write completion here initially. | 318 | * We need to track unwritten extent write completion here initially. |
315 | * We'll need to extend this for updating the ondisk inode size later | 319 | * We'll need to extend this for updating the ondisk inode size later |
diff --git a/fs/xfs/linux-2.6/xfs_aops.h b/fs/xfs/linux-2.6/xfs_aops.h index 1dd528849755..221b3e66ceef 100644 --- a/fs/xfs/linux-2.6/xfs_aops.h +++ b/fs/xfs/linux-2.6/xfs_aops.h | |||
@@ -19,6 +19,7 @@ | |||
19 | #define __XFS_AOPS_H__ | 19 | #define __XFS_AOPS_H__ |
20 | 20 | ||
21 | extern struct workqueue_struct *xfsdatad_workqueue; | 21 | extern struct workqueue_struct *xfsdatad_workqueue; |
22 | extern struct workqueue_struct *xfsconvertd_workqueue; | ||
22 | extern mempool_t *xfs_ioend_pool; | 23 | extern mempool_t *xfs_ioend_pool; |
23 | 24 | ||
24 | /* | 25 | /* |
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index aa1016bb9134..e28800a9f2b5 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c | |||
@@ -51,6 +51,7 @@ static struct shrinker xfs_buf_shake = { | |||
51 | 51 | ||
52 | static struct workqueue_struct *xfslogd_workqueue; | 52 | static struct workqueue_struct *xfslogd_workqueue; |
53 | struct workqueue_struct *xfsdatad_workqueue; | 53 | struct workqueue_struct *xfsdatad_workqueue; |
54 | struct workqueue_struct *xfsconvertd_workqueue; | ||
54 | 55 | ||
55 | #ifdef XFS_BUF_TRACE | 56 | #ifdef XFS_BUF_TRACE |
56 | void | 57 | void |
@@ -1775,6 +1776,7 @@ xfs_flush_buftarg( | |||
1775 | xfs_buf_t *bp, *n; | 1776 | xfs_buf_t *bp, *n; |
1776 | int pincount = 0; | 1777 | int pincount = 0; |
1777 | 1778 | ||
1779 | xfs_buf_runall_queues(xfsconvertd_workqueue); | ||
1778 | xfs_buf_runall_queues(xfsdatad_workqueue); | 1780 | xfs_buf_runall_queues(xfsdatad_workqueue); |
1779 | xfs_buf_runall_queues(xfslogd_workqueue); | 1781 | xfs_buf_runall_queues(xfslogd_workqueue); |
1780 | 1782 | ||
@@ -1831,9 +1833,15 @@ xfs_buf_init(void) | |||
1831 | if (!xfsdatad_workqueue) | 1833 | if (!xfsdatad_workqueue) |
1832 | goto out_destroy_xfslogd_workqueue; | 1834 | goto out_destroy_xfslogd_workqueue; |
1833 | 1835 | ||
1836 | xfsconvertd_workqueue = create_workqueue("xfsconvertd"); | ||
1837 | if (!xfsconvertd_workqueue) | ||
1838 | goto out_destroy_xfsdatad_workqueue; | ||
1839 | |||
1834 | register_shrinker(&xfs_buf_shake); | 1840 | register_shrinker(&xfs_buf_shake); |
1835 | return 0; | 1841 | return 0; |
1836 | 1842 | ||
1843 | out_destroy_xfsdatad_workqueue: | ||
1844 | destroy_workqueue(xfsdatad_workqueue); | ||
1837 | out_destroy_xfslogd_workqueue: | 1845 | out_destroy_xfslogd_workqueue: |
1838 | destroy_workqueue(xfslogd_workqueue); | 1846 | destroy_workqueue(xfslogd_workqueue); |
1839 | out_free_buf_zone: | 1847 | out_free_buf_zone: |
@@ -1849,6 +1857,7 @@ void | |||
1849 | xfs_buf_terminate(void) | 1857 | xfs_buf_terminate(void) |
1850 | { | 1858 | { |
1851 | unregister_shrinker(&xfs_buf_shake); | 1859 | unregister_shrinker(&xfs_buf_shake); |
1860 | destroy_workqueue(xfsconvertd_workqueue); | ||
1852 | destroy_workqueue(xfsdatad_workqueue); | 1861 | destroy_workqueue(xfsdatad_workqueue); |
1853 | destroy_workqueue(xfslogd_workqueue); | 1862 | destroy_workqueue(xfslogd_workqueue); |
1854 | kmem_zone_destroy(xfs_buf_zone); | 1863 | kmem_zone_destroy(xfs_buf_zone); |