Re: iomap_writepages WARN_ON_ONCE(PF_MEMALLOC)

Shakeel Butt <[email protected]> Fri, 3 Jul 2026 21:40:06 -0700
Newsgroups dev.linux.lists.gfs2,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-xfs
Message-ID <[email protected]>
On Wed, Jul 01, 2026 at 10:51:06PM +0200, Andreas Gruenbacher wrote:
> Hi Christoph,
> 
> I'm running into a problem with the following check in
> iomap_writepages() on gfs2 in RHEL-8:
> 
>         /*
>          * Writeback from reclaim context should never happen except in the case
>          * of a VM regression so warn about it and refuse to write the data.
>          */
>         if (WARN_ON_ONCE((current->flags & (PF_MEMALLOC | PF_KSWAPD)) ==
>                         PF_MEMALLOC))
>                 return -EIO;
> 
> In my case, reclaim is triggered by the following command:
> 
>   echo anything > /sys/fs/cgroup/memory/.../memory.force_empty
> 
> And we end up on this code path:
> 
> mem_cgroup_force_empty_write -> mem_cgroup_force_empty ->
> try_to_free_mem_cgroup_pages -> do_try_to_free_pages ->
> shrink_zones -> shrink_node -> shrink_node_memcgs -> shrink_slab ->
> do_shrink_slab -> super_cache_scan -> prune_icache_sb -> dispose_list ->
> evict -> gfs2_evict_inode -> evict_linked_inode -> gfs2_log_flush ->
> gfs2_ordered_write -> filemap_fdatawrite -> __filemap_fdatawrite ->
> __filemap_fdatawrite_range -> do_writepages -> gfs2_writepages ->
> iomap_writepages

I don't see anything specific to memcg here as the same code path as above can
be taken in the global reclaim. The main question is why gfs2 is evicting a
dirty inode from reclaim. If you check prune_icache_sb which uses
inode_lru_isolate() to select inodes to evict and inode_lru_isolate() has
(inode_state_read(inode) & ~I_REFERENCED) check to filter dirty inodes.

It seems to me that gfs2 and VFS are not agreeing if an inode is dirty or not
and a simple search in gfs2 shows that it is doing (inode->i_flags & I_DIRTY)
instead of (inode_state_read(inode) & I_DIRTY)). Since core vfs code is using
inode_state_read() wrapper to check inode state, I am assuming that is the right
way to do it.