Received: by 2002:a05:6a10:f3d0:0:0:0:0 with SMTP id a16csp3077992pxv; Sun, 4 Jul 2021 07:05:26 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwfCcp1GtuwR5185REVfMNyVbuz2SQjHx7gUIatwct04JyQPLkIvikWe7fHliGYDBe2Z/2N X-Received: by 2002:a05:6e02:1d12:: with SMTP id i18mr7157471ila.97.1625407526322; Sun, 04 Jul 2021 07:05:26 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1625407526; cv=none; d=google.com; s=arc-20160816; b=wFKxRBZ399VbYZLYQ7dQe/mv5IwklS61F2lNS0JgDZrqe6zXP3tea/RWYXURgH4Oys AX5YveLH1jO69KTlH5Zx8tBZ+MuL+WiqapRyywUefvt1stjc09c9Yqwf8HqefIP+5vpv tfA/S3vxF5SJmtdE/ygrLcM/aKRLJb4MsD+LIdOVDo3wcgEgvGPSfBwO26LYaK3f6loJ 3JQDpe00r54tiJBt226J+vM/CHqNaXt3XUMDJl5ojZZzSbB8cfpT9ePcCz7XiDbbikxx zZ+HrSib/iXaRKHBnFOBpnFwNYDbmGpIueVtO5CobBrSJF9r2JyCGrBJu1rLnTzasSWi D0Pg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:in-reply-to:content-disposition:mime-version :references:message-id:subject:cc:to:from:date; bh=0x1T2G3Xxm4DvC+/cvf0rwStutZ3Qay3PWkeEsWbPC4=; b=LU24Gg4ZqkoSOR+c9FT4+mHi+zxYREc7WzluJHg62uBBebOpt+NR9RQW3gTN1KyEkW 8r9RZaRsTCEzZ/kj7A563EnAvdRBaxzsbOJcOqXJCUOx7zDEvxRAO8stLQnt5JJZgZGn cwoL05+gMx/+i+A+Bx9wAECtHXlx58X0T5BoWDOuIMtuW1t1b8DrfihS5ymfJLsOkdmo 0fdMa9EePaQ6YOAIOlTS+tot8nha1u9G6NgfU0ZoDRoV1SlTZmKgph7coJidGj7lqusG Oys1S/JF3/fVdT8rJwfhIrlF536s/lcubCYTIVvvePTU4CFazerWvprX3ldACnFaFl87 jnsA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-ext4-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-ext4-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id c8si7156370iow.68.2021.07.04.07.05.07; Sun, 04 Jul 2021 07:05:26 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-ext4-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-ext4-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-ext4-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229530AbhGDOHa (ORCPT + 99 others); Sun, 4 Jul 2021 10:07:30 -0400 Received: from outgoing-auth-1.mit.edu ([18.9.28.11]:32884 "EHLO outgoing.mit.edu" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S229492AbhGDOHa (ORCPT ); Sun, 4 Jul 2021 10:07:30 -0400 Received: from cwcc.thunk.org (pool-72-74-133-215.bstnma.fios.verizon.net [72.74.133.215]) (authenticated bits=0) (User authenticated as tytso@ATHENA.MIT.EDU) by outgoing.mit.edu (8.14.7/8.12.4) with ESMTP id 164E4L5N015602 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 4 Jul 2021 10:04:22 -0400 Received: by cwcc.thunk.org (Postfix, from userid 15806) id C388115C3C96; Sun, 4 Jul 2021 10:04:21 -0400 (EDT) Date: Sun, 4 Jul 2021 10:04:21 -0400 From: "Theodore Ts'o" To: Zhang Yi Cc: Jan Kara , linuxppc-dev@lists.ozlabs.org, Guoqing Jiang , Sachin Sant , Ext4 Developers List , "linux-fsdevel@vger.kernel.org" Subject: Re: [powerpc][5.13.0-next-20210701] Kernel crash while running ltp(chdir01) tests Message-ID: References: <26ACA75D-E13D-405B-9BFC-691B5FB64243@linux.vnet.ibm.com> <4cc87ab3-aaa6-ed87-b690-5e5b99de8380@huawei.com> <03f734bd-f36e-f55b-0448-485b8a0d5b75@huawei.com> <36778615-86fd-9a19-9bc9-f93a6f2d5817@huawei.com> <66fb56cd-f1ff-c592-0202-0691372e32f5@huawei.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <66fb56cd-f1ff-c592-0202-0691372e32f5@huawei.com> Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org On Sat, Jul 03, 2021 at 12:55:09PM +0800, Zhang Yi wrote: > Yeah, it sounds good to me. Do you want me to send the fix patch, or you > modify your commit 8f9e16badb8fd in another email directly? I've gone ahead and made the changes; what do you think? I like how it also removes 40 lines of code. :-) - Ted From ef3130d1b0b8ca769252d6a722a2e59a00141383 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 2 Jul 2021 18:05:03 -0400 Subject: [PATCH] ext4: inline jbd2_journal_[un]register_shrinker() The function jbd2_journal_unregister_shrinker() was getting called twice when the file system was getting unmounted. On Power and ARM platforms this was causing kernel crash when unmounting the file system, when a percpu_counter was destroyed twice. Fix this by removing jbd2_journal_[un]register_shrinker() functions, and inlining the shrinker setup and teardown into journal_init_common() and jbd2_journal_destroy(). This means that ext4 and ocfs2 now no longer need to know about registering and unregistering jbd2's shrinker. Also, while we're at it, rename the percpu counter from j_jh_shrink_count to j_checkpoint_jh_count, since this makes it clearer what this counter is intended to track. Fixes: 4ba3fcdde7e3 ("jbd2,ext4: add a shrinker to release checkpointed buffers") Reported-by: Sachin Sant Reported-by: Jon Hunter Signed-off-by: Theodore Ts'o --- fs/ext4/super.c | 8 --- fs/jbd2/checkpoint.c | 4 +- fs/jbd2/journal.c | 148 +++++++++++++++++-------------------------- include/linux/jbd2.h | 6 +- 4 files changed, 63 insertions(+), 103 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index b8ff0399e171..dfa09a277b56 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1184,7 +1184,6 @@ static void ext4_put_super(struct super_block *sb) ext4_unregister_sysfs(sb); if (sbi->s_journal) { - jbd2_journal_unregister_shrinker(sbi->s_journal); aborted = is_journal_aborted(sbi->s_journal); err = jbd2_journal_destroy(sbi->s_journal); sbi->s_journal = NULL; @@ -5176,7 +5175,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) sbi->s_ea_block_cache = NULL; if (sbi->s_journal) { - jbd2_journal_unregister_shrinker(sbi->s_journal); jbd2_journal_destroy(sbi->s_journal); sbi->s_journal = NULL; } @@ -5502,12 +5500,6 @@ static int ext4_load_journal(struct super_block *sb, ext4_commit_super(sb); } - err = jbd2_journal_register_shrinker(journal); - if (err) { - EXT4_SB(sb)->s_journal = NULL; - goto err_out; - } - return 0; err_out: diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index 51d1eb2ffeb9..746132998c57 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c @@ -701,7 +701,7 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh) __buffer_unlink(jh); jh->b_cp_transaction = NULL; - percpu_counter_dec(&journal->j_jh_shrink_count); + percpu_counter_dec(&journal->j_checkpoint_jh_count); jbd2_journal_put_journal_head(jh); /* Is this transaction empty? */ @@ -764,7 +764,7 @@ void __jbd2_journal_insert_checkpoint(struct journal_head *jh, jh->b_cpnext->b_cpprev = jh; } transaction->t_checkpoint_list = jh; - percpu_counter_inc(&transaction->t_journal->j_jh_shrink_count); + percpu_counter_inc(&transaction->t_journal->j_checkpoint_jh_count); } /* diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 152880c298ca..8a9c94dd3599 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1283,6 +1283,48 @@ static int jbd2_min_tag_size(void) return sizeof(journal_block_tag_t) - 4; } +/** + * jbd2_journal_shrink_scan() + * + * Scan the checkpointed buffer on the checkpoint list and release the + * journal_head. + */ +static unsigned long jbd2_journal_shrink_scan(struct shrinker *shrink, + struct shrink_control *sc) +{ + journal_t *journal = container_of(shrink, journal_t, j_shrinker); + unsigned long nr_to_scan = sc->nr_to_scan; + unsigned long nr_shrunk; + unsigned long count; + + count = percpu_counter_read_positive(&journal->j_checkpoint_jh_count); + trace_jbd2_shrink_scan_enter(journal, sc->nr_to_scan, count); + + nr_shrunk = jbd2_journal_shrink_checkpoint_list(journal, &nr_to_scan); + + count = percpu_counter_read_positive(&journal->j_checkpoint_jh_count); + trace_jbd2_shrink_scan_exit(journal, nr_to_scan, nr_shrunk, count); + + return nr_shrunk; +} + +/** + * jbd2_journal_shrink_count() + * + * Count the number of checkpoint buffers on the checkpoint list. + */ +static unsigned long jbd2_journal_shrink_count(struct shrinker *shrink, + struct shrink_control *sc) +{ + journal_t *journal = container_of(shrink, journal_t, j_shrinker); + unsigned long count; + + count = percpu_counter_read_positive(&journal->j_checkpoint_jh_count); + trace_jbd2_shrink_count(journal, sc->nr_to_scan, count); + + return count; +} + /* * Management for journal control blocks: functions to create and * destroy journal_t structures, and to initialise and read existing @@ -1361,6 +1403,19 @@ static journal_t *journal_init_common(struct block_device *bdev, journal->j_sb_buffer = bh; journal->j_superblock = (journal_superblock_t *)bh->b_data; + journal->j_shrink_transaction = NULL; + journal->j_shrinker.scan_objects = jbd2_journal_shrink_scan; + journal->j_shrinker.count_objects = jbd2_journal_shrink_count; + journal->j_shrinker.seeks = DEFAULT_SEEKS; + journal->j_shrinker.batch = journal->j_max_transaction_buffers; + + if (percpu_counter_init(&journal->j_checkpoint_jh_count, 0, GFP_KERNEL)) + goto err_cleanup; + + if (register_shrinker(&journal->j_shrinker)) { + percpu_counter_destroy(&journal->j_checkpoint_jh_count); + goto err_cleanup; + } return journal; err_cleanup: @@ -2050,93 +2105,6 @@ int jbd2_journal_load(journal_t *journal) return -EIO; } -/** - * jbd2_journal_shrink_scan() - * - * Scan the checkpointed buffer on the checkpoint list and release the - * journal_head. - */ -static unsigned long jbd2_journal_shrink_scan(struct shrinker *shrink, - struct shrink_control *sc) -{ - journal_t *journal = container_of(shrink, journal_t, j_shrinker); - unsigned long nr_to_scan = sc->nr_to_scan; - unsigned long nr_shrunk; - unsigned long count; - - count = percpu_counter_read_positive(&journal->j_jh_shrink_count); - trace_jbd2_shrink_scan_enter(journal, sc->nr_to_scan, count); - - nr_shrunk = jbd2_journal_shrink_checkpoint_list(journal, &nr_to_scan); - - count = percpu_counter_read_positive(&journal->j_jh_shrink_count); - trace_jbd2_shrink_scan_exit(journal, nr_to_scan, nr_shrunk, count); - - return nr_shrunk; -} - -/** - * jbd2_journal_shrink_count() - * - * Count the number of checkpoint buffers on the checkpoint list. - */ -static unsigned long jbd2_journal_shrink_count(struct shrinker *shrink, - struct shrink_control *sc) -{ - journal_t *journal = container_of(shrink, journal_t, j_shrinker); - unsigned long count; - - count = percpu_counter_read_positive(&journal->j_jh_shrink_count); - trace_jbd2_shrink_count(journal, sc->nr_to_scan, count); - - return count; -} - -/** - * jbd2_journal_register_shrinker() - * @journal: Journal to act on. - * - * Init a percpu counter to record the checkpointed buffers on the checkpoint - * list and register a shrinker to release their journal_head. - */ -int jbd2_journal_register_shrinker(journal_t *journal) -{ - int err; - - journal->j_shrink_transaction = NULL; - - err = percpu_counter_init(&journal->j_jh_shrink_count, 0, GFP_KERNEL); - if (err) - return err; - - journal->j_shrinker.scan_objects = jbd2_journal_shrink_scan; - journal->j_shrinker.count_objects = jbd2_journal_shrink_count; - journal->j_shrinker.seeks = DEFAULT_SEEKS; - journal->j_shrinker.batch = journal->j_max_transaction_buffers; - - err = register_shrinker(&journal->j_shrinker); - if (err) { - percpu_counter_destroy(&journal->j_jh_shrink_count); - return err; - } - - return 0; -} -EXPORT_SYMBOL(jbd2_journal_register_shrinker); - -/** - * jbd2_journal_unregister_shrinker() - * @journal: Journal to act on. - * - * Unregister the checkpointed buffer shrinker and destroy the percpu counter. - */ -void jbd2_journal_unregister_shrinker(journal_t *journal) -{ - percpu_counter_destroy(&journal->j_jh_shrink_count); - unregister_shrinker(&journal->j_shrinker); -} -EXPORT_SYMBOL(jbd2_journal_unregister_shrinker); - /** * jbd2_journal_destroy() - Release a journal_t structure. * @journal: Journal to act on. @@ -2209,8 +2177,10 @@ int jbd2_journal_destroy(journal_t *journal) brelse(journal->j_sb_buffer); } - jbd2_journal_unregister_shrinker(journal); - + if (journal->j_shrinker.flags & SHRINKER_REGISTERED) { + percpu_counter_destroy(&journal->j_checkpoint_jh_count); + unregister_shrinker(&journal->j_shrinker); + } if (journal->j_proc_entry) jbd2_stats_proc_exit(journal); iput(journal->j_inode); diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index 6cc035321562..fd933c45281a 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h @@ -918,11 +918,11 @@ struct journal_s struct shrinker j_shrinker; /** - * @j_jh_shrink_count: + * @j_checkpoint_jh_count: * * Number of journal buffers on the checkpoint list. [j_list_lock] */ - struct percpu_counter j_jh_shrink_count; + struct percpu_counter j_checkpoint_jh_count; /** * @j_shrink_transaction: @@ -1556,8 +1556,6 @@ extern int jbd2_journal_set_features (journal_t *, unsigned long, unsigned long, unsigned long); extern void jbd2_journal_clear_features (journal_t *, unsigned long, unsigned long, unsigned long); -extern int jbd2_journal_register_shrinker(journal_t *journal); -extern void jbd2_journal_unregister_shrinker(journal_t *journal); extern int jbd2_journal_load (journal_t *journal); extern int jbd2_journal_destroy (journal_t *); extern int jbd2_journal_recover (journal_t *journal); -- 2.31.0