aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-03-29 20:00:56 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-29 20:00:56 -0400
commit6268b325c3066234e7bddb99d2b98bcedb0c0033 (patch)
tree5dca66fae30aa44e314ec6713ab31b773ad788e4 /fs/ext4
parent12679a2d7e3bfbdc7586e3e86d1ca90c46659363 (diff)
Revert "ext4: don't release page refs in ext4_end_bio()"
This reverts commit b43d17f319f2c502b17139d1cf70731b2b62c644. Dave Jones reports that it causes lockups on his laptop, and his debug output showed a lot of processes hung waiting for page_writeback (or more commonly - processes hung waiting for a lock that was held during that writeback wait). The page_writeback hint made Ted suggest that Dave look at this commit, and Dave verified that reverting it makes his problems go away. Ted says: "That commit fixes a race which is seen when you write into fallocated (and hence uninitialized) disk blocks under *very* heavy memory pressure. Furthermore, although theoretically it could trigger under normal direct I/O writes, it only seems to trigger if you are issuing a huge number of AIO writes, such that a just-written page can get evicted from memory, and then read back into memory, before the workqueue has a chance to update the extent tree. This race has been around for a little over a year, and no one noticed until two months ago; it only happens under fairly exotic conditions, and in fact even after trying very hard to create a simple repro under lab conditions, we could only reproduce the problem and confirm the fix on production servers running MySQL on very fast PCIe-attached flash devices. Given that Dave was able to hit this problem pretty quickly, if we confirm that this commit is at fault, the only reasonable thing to do is to revert it IMO." Reported-and-tested-by: Dave Jones <davej@redhat.com> Acked-by: Theodore Ts'o <tytso@mit.edu> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/page-io.c7
1 files changed, 3 insertions, 4 deletions
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index 74cd1f7f1f88..dcdeef169a69 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -60,6 +60,7 @@ void ext4_ioend_wait(struct inode *inode)
60static void put_io_page(struct ext4_io_page *io_page) 60static void put_io_page(struct ext4_io_page *io_page)
61{ 61{
62 if (atomic_dec_and_test(&io_page->p_count)) { 62 if (atomic_dec_and_test(&io_page->p_count)) {
63 end_page_writeback(io_page->p_page);
63 put_page(io_page->p_page); 64 put_page(io_page->p_page);
64 kmem_cache_free(io_page_cachep, io_page); 65 kmem_cache_free(io_page_cachep, io_page);
65 } 66 }
@@ -233,9 +234,9 @@ static void ext4_end_bio(struct bio *bio, int error)
233 } while (bh != head); 234 } while (bh != head);
234 } 235 }
235 236
236 if (atomic_read(&io_end->pages[i]->p_count) == 1) 237 put_io_page(io_end->pages[i]);
237 end_page_writeback(io_end->pages[i]->p_page);
238 } 238 }
239 io_end->num_io_pages = 0;
239 inode = io_end->inode; 240 inode = io_end->inode;
240 241
241 if (error) { 242 if (error) {
@@ -427,8 +428,6 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
427 * PageWriteback bit from the page to prevent the system from 428 * PageWriteback bit from the page to prevent the system from
428 * wedging later on. 429 * wedging later on.
429 */ 430 */
430 if (atomic_read(&io_page->p_count) == 1)
431 end_page_writeback(page);
432 put_io_page(io_page); 431 put_io_page(io_page);
433 return ret; 432 return ret;
434} 433}