From cfc9a5c88f91f7b4d606fce89505e1f404691ea5 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Tue, 19 Jul 2011 11:48:46 -0700 Subject: [PATCH] Fix zpl_writepage() deadlock Disable the normal reclaim path for zpl_putpage(). This ensures that all memory allocations under this call path will never enter direct reclaim. If this were to happen the VM might try to write out additional pages by calling zpl_putpage() again resulting in a deadlock. This sitution is typically handled in Linux by marking each offending allocation GFP_NOFS. However, since much of the code used is common it makes more sense to use PF_MEMALLOC to flag the entire call tree. Alternately, the code could be updated to pass the needed allocation flags but that's a more invasive change. The following example of the above described deadlock was triggered by test 074 in the xfstest suite. Call Trace: [] down_write+0x32/0x40 [] dnode_new_blkid+0x94/0x2d0 [zfs] [] dbuf_dirty+0x556/0x750 [zfs] [] dmu_buf_will_dirty+0x81/0xd0 [zfs] [] dmu_write+0x90/0x170 [zfs] [] zfs_putpage+0x2ce/0x360 [zfs] [] zpl_putpage+0x1e/0x60 [zfs] [] zpl_writepage+0x12/0x20 [zfs] [] writeout+0xa7/0xd0 [] move_to_new_page+0x13b/0x170 [] migrate_pages+0x434/0x4c0 [] compact_zone+0x4fb/0x780 [] compact_zone_order+0xa1/0xe0 [] try_to_compact_pages+0x11c/0x190 [] __alloc_pages_nodemask+0x5eb/0x8b0 [] alloc_pages_current+0xaa/0x110 [] __get_free_pages+0xe/0x50 [] kv_alloc+0x3f/0xb0 [spl] [] spl_kmem_cache_alloc+0x339/0x660 [spl] [] dbuf_create+0x43/0x370 [zfs] [] __dbuf_hold_impl+0x241/0x480 [zfs] [] dbuf_hold_impl+0x86/0xc0 [zfs] [] dbuf_hold_level+0x1f/0x30 [zfs] [] dmu_tx_check_ioerr+0x4e/0x110 [zfs] [] dmu_tx_count_write+0x359/0x6f0 [zfs] [] dmu_tx_hold_write+0x4f/0x70 [zfs] [] zfs_putpage+0x23d/0x360 [zfs] [] zpl_putpage+0x1e/0x60 [zfs] [] write_cache_pages+0x1c9/0x4a0 [] zpl_writepages+0x18/0x20 [zfs] [] do_writepages+0x21/0x40 [] writeback_single_inode+0xdd/0x2c0 [] writeback_sb_inodes+0xce/0x180 [] writeback_inodes_wb+0xab/0x1b0 [] wb_writeback+0x29b/0x3f0 [] wb_do_writeback+0xbb/0x240 [] bdi_forker_task+0x6a/0x310 [] kthread+0x96/0xa0 Signed-off-by: Brian Behlendorf Closes #327 --- module/zfs/zpl_file.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/module/zfs/zpl_file.c b/module/zfs/zpl_file.c index fc2b81329..c2e3a6bdc 100644 --- a/module/zfs/zpl_file.c +++ b/module/zfs/zpl_file.c @@ -354,7 +354,16 @@ zpl_putpage(struct page *pp, struct writeback_control *wbc, void *data) { int error; + /* + * Disable the normal reclaim path for zpl_putpage(). This + * ensures that all memory allocations under this call path + * will never enter direct reclaim. If this were to happen + * the VM might try to write out additional pages by calling + * zpl_putpage() again resulting in a deadlock. + */ + current->flags |= PF_MEMALLOC; error = -zfs_putpage(pp, wbc, data); + current->flags &= ~PF_MEMALLOC; if (error) { SetPageError(pp);