mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 04:31:50 +00:00
[XFS] Fix a race in xfs_submit_ioend() where we can be completing I/O for
a page while we are still submitting other buffers on the same page for I/O. SGI-PV: 948197 SGI-Modid: xfs-linux-melb:xfs-kern:25004a Signed-off-by: David Chinner <dgc@sgi.com> Signed-off-by: Nathan Scott <nathans@sgi.com>
This commit is contained in:
parent
2664b25051
commit
d88992f660
@ -336,24 +336,47 @@ static inline int bio_add_buffer(struct bio *bio, struct buffer_head *bh)
|
||||
}
|
||||
|
||||
/*
|
||||
* Submit all of the bios for all of the ioends we have saved up,
|
||||
* covering the initial writepage page and also any probed pages.
|
||||
* Submit all of the bios for all of the ioends we have saved up, covering the
|
||||
* initial writepage page and also any probed pages.
|
||||
*
|
||||
* Because we may have multiple ioends spanning a page, we need to start
|
||||
* writeback on all the buffers before we submit them for I/O. If we mark the
|
||||
* buffers as we got, then we can end up with a page that only has buffers
|
||||
* marked async write and I/O complete on can occur before we mark the other
|
||||
* buffers async write.
|
||||
*
|
||||
* The end result of this is that we trip a bug in end_page_writeback() because
|
||||
* we call it twice for the one page as the code in end_buffer_async_write()
|
||||
* assumes that all buffers on the page are started at the same time.
|
||||
*
|
||||
* The fix is two passes across the ioend list - one to start writeback on the
|
||||
* bufferheads, and then the second one submit them for I/O.
|
||||
*/
|
||||
STATIC void
|
||||
xfs_submit_ioend(
|
||||
xfs_ioend_t *ioend)
|
||||
{
|
||||
xfs_ioend_t *head = ioend;
|
||||
xfs_ioend_t *next;
|
||||
struct buffer_head *bh;
|
||||
struct bio *bio;
|
||||
sector_t lastblock = 0;
|
||||
|
||||
/* Pass 1 - start writeback */
|
||||
do {
|
||||
next = ioend->io_list;
|
||||
for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) {
|
||||
xfs_start_buffer_writeback(bh);
|
||||
}
|
||||
} while ((ioend = next) != NULL);
|
||||
|
||||
/* Pass 2 - submit I/O */
|
||||
ioend = head;
|
||||
do {
|
||||
next = ioend->io_list;
|
||||
bio = NULL;
|
||||
|
||||
for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) {
|
||||
xfs_start_buffer_writeback(bh);
|
||||
|
||||
if (!bio) {
|
||||
retry:
|
||||
|
Loading…
Reference in New Issue
Block a user