From 841d22e26e9532473a954e29520f3eb6497ad710 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Wed, 7 Apr 2021 14:27:16 -0700 Subject: [PATCH] Disable task reclaim flags for block cache vmalloc Even though we can pass in gfp flags to vmalloc it eventually calls pte alloc functions which ignore the caller's flags and use user gfp flags. This risks reclaim re-entering fs paths during allocations in the block cache. These allocs that allowed reclaim deep in the fs was causing lockdep to add RECLAIM dependencies between locks and holler about deadlocks. We apply the same pattern that xfs does for disabling reclaim while allocating vmalloced block payloads. Setting PF_MEMALLOC_NOIO causes reclaim in that task to clear __GFP_IO and __GFP_FS, regardless of the individual allocation flags in the task, preventing recursion. Signed-off-by: Zach Brown --- kmod/src/block.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/kmod/src/block.c b/kmod/src/block.c index 43dc2a66..53578725 100644 --- a/kmod/src/block.c +++ b/kmod/src/block.c @@ -128,6 +128,7 @@ static __le32 block_calc_crc(struct scoutfs_block_header *hdr, u32 size) static struct block_private *block_alloc(struct super_block *sb, u64 blkno) { struct block_private *bp; + unsigned int noio_flags; /* * If we had multiple blocks per page we'd need to be a little @@ -147,8 +148,19 @@ static struct block_private *block_alloc(struct super_block *sb, u64 blkno) set_bit(BLOCK_BIT_PAGE_ALLOC, &bp->bits); bp->bl.data = page_address(bp->page); } else { - bp->virt = __vmalloc(SCOUTFS_BLOCK_LG_SIZE, - GFP_NOFS | __GFP_HIGHMEM, PAGE_KERNEL); + /* + * __vmalloc doesn't pass the gfp flags down to pte + * allocs, they're done with user alloc flags. + * Unfortunately, some lockdep doesn't know that + * PF_NOMEMALLOC prevents __GFP_FS reclaim and generates + * spurious reclaim-on dependencies and warnings. + */ + lockdep_off(); + noio_flags = memalloc_noio_save(); + bp->virt = __vmalloc(SCOUTFS_BLOCK_LG_SIZE, GFP_NOFS | __GFP_HIGHMEM, PAGE_KERNEL); + memalloc_noio_restore(noio_flags); + lockdep_on(); + if (!bp->virt) { kfree(bp); bp = NULL;