From nobody Sun Feb 8 08:22:47 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E5CB2C433F5 for ; Mon, 23 May 2022 17:34:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241296AbiEWRen (ORCPT ); Mon, 23 May 2022 13:34:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42814 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240330AbiEWRXj (ORCPT ); Mon, 23 May 2022 13:23:39 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AD54971D94; Mon, 23 May 2022 10:20:45 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id D828660C1D; Mon, 23 May 2022 17:18:33 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id DE0F2C385A9; Mon, 23 May 2022 17:18:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1653326313; bh=vmFV3+jew1i1W4R7jm9slUQWqdqRJc4StEDG2Gln6PA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gpUlJizu/siJEvQjfZln+uTpAaGkklWDy8WEyo4PPNL+OM8zK+oYr/22NMyeGLVcF uTro49wYiYRMBgxZ38owpt8VjpAptxUS7dk3MZ1ZxK5XN9sNAo8MyBhwf3+FdbO0sU t0t64VTpSOdsm0j8c3bA5MyKGFt6LMfFvWFEO6WU= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Ryusuke Konishi , Matthew Wilcox , David Hildenbrand , Hao Sun , Andrew Morton , Linus Torvalds , Sasha Levin Subject: [PATCH 5.15 043/132] nilfs2: fix lockdep warnings during disk space reclamation Date: Mon, 23 May 2022 19:04:12 +0200 Message-Id: <20220523165830.456148678@linuxfoundation.org> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20220523165823.492309987@linuxfoundation.org> References: <20220523165823.492309987@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Ryusuke Konishi [ Upstream commit 6e211930f79aa45d422009a5f2e5467d2369ffe5 ] During disk space reclamation, nilfs2 still emits the following lockdep warning due to page/folio operations on shadowed page caches that nilfs2 uses to get a snapshot of DAT file in memory: WARNING: CPU: 0 PID: 2643 at include/linux/backing-dev.h:272 __folio_mark= _dirty+0x645/0x670 ... RIP: 0010:__folio_mark_dirty+0x645/0x670 ... Call Trace: filemap_dirty_folio+0x74/0xd0 __set_page_dirty_nobuffers+0x85/0xb0 nilfs_copy_dirty_pages+0x288/0x510 [nilfs2] nilfs_mdt_save_to_shadow_map+0x50/0xe0 [nilfs2] nilfs_clean_segments+0xee/0x5d0 [nilfs2] nilfs_ioctl_clean_segments.isra.19+0xb08/0xf40 [nilfs2] nilfs_ioctl+0xc52/0xfb0 [nilfs2] __x64_sys_ioctl+0x11d/0x170 This fixes the remaining warning by using inode objects to hold those page caches. Link: https://lkml.kernel.org/r/1647867427-30498-3-git-send-email-konishi.r= yusuke@gmail.com Signed-off-by: Ryusuke Konishi Tested-by: Ryusuke Konishi Cc: Matthew Wilcox Cc: David Hildenbrand Cc: Hao Sun Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin --- fs/nilfs2/dat.c | 4 ++- fs/nilfs2/inode.c | 63 ++++++++++++++++++++++++++++++++++++++++++++--- fs/nilfs2/mdt.c | 38 +++++++++++++++++++--------- fs/nilfs2/mdt.h | 6 ++--- fs/nilfs2/nilfs.h | 2 ++ 5 files changed, 92 insertions(+), 21 deletions(-) diff --git a/fs/nilfs2/dat.c b/fs/nilfs2/dat.c index 8bccdf1158fc..1a3d183027b9 100644 --- a/fs/nilfs2/dat.c +++ b/fs/nilfs2/dat.c @@ -497,7 +497,9 @@ int nilfs_dat_read(struct super_block *sb, size_t entry= _size, di =3D NILFS_DAT_I(dat); lockdep_set_class(&di->mi.mi_sem, &dat_lock_key); nilfs_palloc_setup_cache(dat, &di->palloc_cache); - nilfs_mdt_setup_shadow_map(dat, &di->shadow); + err =3D nilfs_mdt_setup_shadow_map(dat, &di->shadow); + if (err) + goto failed; =20 err =3D nilfs_read_inode_common(dat, raw_inode); if (err) diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 7b2bc4173313..2466f8b8be95 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -30,6 +30,7 @@ * @root: pointer on NILFS root object (mounted checkpoint) * @for_gc: inode for GC flag * @for_btnc: inode for B-tree node cache flag + * @for_shadow: inode for shadowed page cache flag */ struct nilfs_iget_args { u64 ino; @@ -37,6 +38,7 @@ struct nilfs_iget_args { struct nilfs_root *root; bool for_gc; bool for_btnc; + bool for_shadow; }; =20 static int nilfs_iget_test(struct inode *inode, void *opaque); @@ -317,7 +319,7 @@ static int nilfs_insert_inode_locked(struct inode *inod= e, { struct nilfs_iget_args args =3D { .ino =3D ino, .root =3D root, .cno =3D 0, .for_gc =3D false, - .for_btnc =3D false + .for_btnc =3D false, .for_shadow =3D false }; =20 return insert_inode_locked4(inode, ino, nilfs_iget_test, &args); @@ -536,6 +538,12 @@ static int nilfs_iget_test(struct inode *inode, void *= opaque) } else if (args->for_btnc) { return 0; } + if (test_bit(NILFS_I_SHADOW, &ii->i_state)) { + if (!args->for_shadow) + return 0; + } else if (args->for_shadow) { + return 0; + } =20 if (!test_bit(NILFS_I_GCINODE, &ii->i_state)) return !args->for_gc; @@ -557,6 +565,8 @@ static int nilfs_iget_set(struct inode *inode, void *op= aque) NILFS_I(inode)->i_state =3D BIT(NILFS_I_GCINODE); if (args->for_btnc) NILFS_I(inode)->i_state |=3D BIT(NILFS_I_BTNC); + if (args->for_shadow) + NILFS_I(inode)->i_state |=3D BIT(NILFS_I_SHADOW); return 0; } =20 @@ -565,7 +575,7 @@ struct inode *nilfs_ilookup(struct super_block *sb, str= uct nilfs_root *root, { struct nilfs_iget_args args =3D { .ino =3D ino, .root =3D root, .cno =3D 0, .for_gc =3D false, - .for_btnc =3D false + .for_btnc =3D false, .for_shadow =3D false }; =20 return ilookup5(sb, ino, nilfs_iget_test, &args); @@ -576,7 +586,7 @@ struct inode *nilfs_iget_locked(struct super_block *sb,= struct nilfs_root *root, { struct nilfs_iget_args args =3D { .ino =3D ino, .root =3D root, .cno =3D 0, .for_gc =3D false, - .for_btnc =3D false + .for_btnc =3D false, .for_shadow =3D false }; =20 return iget5_locked(sb, ino, nilfs_iget_test, nilfs_iget_set, &args); @@ -608,7 +618,7 @@ struct inode *nilfs_iget_for_gc(struct super_block *sb,= unsigned long ino, { struct nilfs_iget_args args =3D { .ino =3D ino, .root =3D NULL, .cno =3D cno, .for_gc =3D true, - .for_btnc =3D false + .for_btnc =3D false, .for_shadow =3D false }; struct inode *inode; int err; @@ -655,6 +665,7 @@ int nilfs_attach_btree_node_cache(struct inode *inode) args.cno =3D ii->i_cno; args.for_gc =3D test_bit(NILFS_I_GCINODE, &ii->i_state) !=3D 0; args.for_btnc =3D true; + args.for_shadow =3D test_bit(NILFS_I_SHADOW, &ii->i_state) !=3D 0; =20 btnc_inode =3D iget5_locked(inode->i_sb, inode->i_ino, nilfs_iget_test, nilfs_iget_set, &args); @@ -690,6 +701,50 @@ void nilfs_detach_btree_node_cache(struct inode *inode) } } =20 +/** + * nilfs_iget_for_shadow - obtain inode for shadow mapping + * @inode: inode object that uses shadow mapping + * + * nilfs_iget_for_shadow() allocates a pair of inodes that holds page + * caches for shadow mapping. The page cache for data pages is set up + * in one inode and the one for b-tree node pages is set up in the + * other inode, which is attached to the former inode. + * + * Return Value: On success, a pointer to the inode for data pages is + * returned. On errors, one of the following negative error code is return= ed + * in a pointer type. + * + * %-ENOMEM - Insufficient memory available. + */ +struct inode *nilfs_iget_for_shadow(struct inode *inode) +{ + struct nilfs_iget_args args =3D { + .ino =3D inode->i_ino, .root =3D NULL, .cno =3D 0, .for_gc =3D false, + .for_btnc =3D false, .for_shadow =3D true + }; + struct inode *s_inode; + int err; + + s_inode =3D iget5_locked(inode->i_sb, inode->i_ino, nilfs_iget_test, + nilfs_iget_set, &args); + if (unlikely(!s_inode)) + return ERR_PTR(-ENOMEM); + if (!(s_inode->i_state & I_NEW)) + return inode; + + NILFS_I(s_inode)->i_flags =3D 0; + memset(NILFS_I(s_inode)->i_bmap, 0, sizeof(struct nilfs_bmap)); + mapping_set_gfp_mask(s_inode->i_mapping, GFP_NOFS); + + err =3D nilfs_attach_btree_node_cache(s_inode); + if (unlikely(err)) { + iget_failed(s_inode); + return ERR_PTR(err); + } + unlock_new_inode(s_inode); + return s_inode; +} + void nilfs_write_inode_common(struct inode *inode, struct nilfs_inode *raw_inode, int has_bmap) { diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 21acd2d4b4d4..131b5add32ee 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -470,9 +470,18 @@ int nilfs_mdt_init(struct inode *inode, gfp_t gfp_mask= , size_t objsz) void nilfs_mdt_clear(struct inode *inode) { struct nilfs_mdt_info *mdi =3D NILFS_MDT(inode); + struct nilfs_shadow_map *shadow =3D mdi->mi_shadow; =20 if (mdi->mi_palloc_cache) nilfs_palloc_destroy_cache(inode); + + if (shadow) { + struct inode *s_inode =3D shadow->inode; + + shadow->inode =3D NULL; + iput(s_inode); + mdi->mi_shadow =3D NULL; + } } =20 /** @@ -506,12 +515,15 @@ int nilfs_mdt_setup_shadow_map(struct inode *inode, struct nilfs_shadow_map *shadow) { struct nilfs_mdt_info *mi =3D NILFS_MDT(inode); + struct inode *s_inode; =20 INIT_LIST_HEAD(&shadow->frozen_buffers); - address_space_init_once(&shadow->frozen_data); - nilfs_mapping_init(&shadow->frozen_data, inode); - address_space_init_once(&shadow->frozen_btnodes); - nilfs_mapping_init(&shadow->frozen_btnodes, inode); + + s_inode =3D nilfs_iget_for_shadow(inode); + if (IS_ERR(s_inode)) + return PTR_ERR(s_inode); + + shadow->inode =3D s_inode; mi->mi_shadow =3D shadow; return 0; } @@ -525,13 +537,14 @@ int nilfs_mdt_save_to_shadow_map(struct inode *inode) struct nilfs_mdt_info *mi =3D NILFS_MDT(inode); struct nilfs_inode_info *ii =3D NILFS_I(inode); struct nilfs_shadow_map *shadow =3D mi->mi_shadow; + struct inode *s_inode =3D shadow->inode; int ret; =20 - ret =3D nilfs_copy_dirty_pages(&shadow->frozen_data, inode->i_mapping); + ret =3D nilfs_copy_dirty_pages(s_inode->i_mapping, inode->i_mapping); if (ret) goto out; =20 - ret =3D nilfs_copy_dirty_pages(&shadow->frozen_btnodes, + ret =3D nilfs_copy_dirty_pages(NILFS_I(s_inode)->i_assoc_inode->i_mapping, ii->i_assoc_inode->i_mapping); if (ret) goto out; @@ -548,7 +561,7 @@ int nilfs_mdt_freeze_buffer(struct inode *inode, struct= buffer_head *bh) struct page *page; int blkbits =3D inode->i_blkbits; =20 - page =3D grab_cache_page(&shadow->frozen_data, bh->b_page->index); + page =3D grab_cache_page(shadow->inode->i_mapping, bh->b_page->index); if (!page) return -ENOMEM; =20 @@ -580,7 +593,7 @@ nilfs_mdt_get_frozen_buffer(struct inode *inode, struct= buffer_head *bh) struct page *page; int n; =20 - page =3D find_lock_page(&shadow->frozen_data, bh->b_page->index); + page =3D find_lock_page(shadow->inode->i_mapping, bh->b_page->index); if (page) { if (page_has_buffers(page)) { n =3D bh_offset(bh) >> inode->i_blkbits; @@ -621,11 +634,11 @@ void nilfs_mdt_restore_from_shadow_map(struct inode *= inode) nilfs_palloc_clear_cache(inode); =20 nilfs_clear_dirty_pages(inode->i_mapping, true); - nilfs_copy_back_pages(inode->i_mapping, &shadow->frozen_data); + nilfs_copy_back_pages(inode->i_mapping, shadow->inode->i_mapping); =20 nilfs_clear_dirty_pages(ii->i_assoc_inode->i_mapping, true); nilfs_copy_back_pages(ii->i_assoc_inode->i_mapping, - &shadow->frozen_btnodes); + NILFS_I(shadow->inode)->i_assoc_inode->i_mapping); =20 nilfs_bmap_restore(ii->i_bmap, &shadow->bmap_store); =20 @@ -640,10 +653,11 @@ void nilfs_mdt_clear_shadow_map(struct inode *inode) { struct nilfs_mdt_info *mi =3D NILFS_MDT(inode); struct nilfs_shadow_map *shadow =3D mi->mi_shadow; + struct inode *shadow_btnc_inode =3D NILFS_I(shadow->inode)->i_assoc_inode; =20 down_write(&mi->mi_sem); nilfs_release_frozen_buffers(shadow); - truncate_inode_pages(&shadow->frozen_data, 0); - truncate_inode_pages(&shadow->frozen_btnodes, 0); + truncate_inode_pages(shadow->inode->i_mapping, 0); + truncate_inode_pages(shadow_btnc_inode->i_mapping, 0); up_write(&mi->mi_sem); } diff --git a/fs/nilfs2/mdt.h b/fs/nilfs2/mdt.h index e77aea4bb921..9d8ac0d27c16 100644 --- a/fs/nilfs2/mdt.h +++ b/fs/nilfs2/mdt.h @@ -18,14 +18,12 @@ /** * struct nilfs_shadow_map - shadow mapping of meta data file * @bmap_store: shadow copy of bmap state - * @frozen_data: shadowed dirty data pages - * @frozen_btnodes: shadowed dirty b-tree nodes' pages + * @inode: holder of page caches used in shadow mapping * @frozen_buffers: list of frozen buffers */ struct nilfs_shadow_map { struct nilfs_bmap_store bmap_store; - struct address_space frozen_data; - struct address_space frozen_btnodes; + struct inode *inode; struct list_head frozen_buffers; }; =20 diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 6c5148de84ff..7dcb77d38759 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h @@ -92,6 +92,7 @@ enum { NILFS_I_BMAP, /* has bmap and btnode_cache */ NILFS_I_GCINODE, /* inode for GC, on memory only */ NILFS_I_BTNC, /* inode for btree node cache */ + NILFS_I_SHADOW, /* inode for shadowed page cache */ }; =20 /* @@ -263,6 +264,7 @@ extern struct inode *nilfs_iget_for_gc(struct super_blo= ck *sb, unsigned long ino, __u64 cno); int nilfs_attach_btree_node_cache(struct inode *inode); void nilfs_detach_btree_node_cache(struct inode *inode); +struct inode *nilfs_iget_for_shadow(struct inode *inode); extern void nilfs_update_inode(struct inode *, struct buffer_head *, int); extern void nilfs_truncate(struct inode *); extern void nilfs_evict_inode(struct inode *); --=20 2.35.1