Skip to content

Commit 0705e8d

Browse files
committed
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. Link: https://lore.kernel.org/r/20210705145025.3363130-1-tytso@mit.edu Fixes: 4ba3fcd ("jbd2,ext4: add a shrinker to release checkpointed buffers") Reported-by: Jon Hunter <jonathanh@nvidia.com> Reported-by: Sachin Sant <sachinp@linux.vnet.ibm.com> Tested-by: Sachin Sant <sachinp@linux.vnet.ibm.com> Tested-by: Jon Hunter <jonathanh@nvidia.com> Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
1 parent 0955901 commit 0705e8d

4 files changed

Lines changed: 64 additions & 103 deletions

File tree

fs/ext4/super.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,7 +1184,6 @@ static void ext4_put_super(struct super_block *sb)
11841184
ext4_unregister_sysfs(sb);
11851185

11861186
if (sbi->s_journal) {
1187-
jbd2_journal_unregister_shrinker(sbi->s_journal);
11881187
aborted = is_journal_aborted(sbi->s_journal);
11891188
err = jbd2_journal_destroy(sbi->s_journal);
11901189
sbi->s_journal = NULL;
@@ -5176,7 +5175,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
51765175
sbi->s_ea_block_cache = NULL;
51775176

51785177
if (sbi->s_journal) {
5179-
jbd2_journal_unregister_shrinker(sbi->s_journal);
51805178
jbd2_journal_destroy(sbi->s_journal);
51815179
sbi->s_journal = NULL;
51825180
}
@@ -5502,12 +5500,6 @@ static int ext4_load_journal(struct super_block *sb,
55025500
ext4_commit_super(sb);
55035501
}
55045502

5505-
err = jbd2_journal_register_shrinker(journal);
5506-
if (err) {
5507-
EXT4_SB(sb)->s_journal = NULL;
5508-
goto err_out;
5509-
}
5510-
55115503
return 0;
55125504

55135505
err_out:

fs/jbd2/checkpoint.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,7 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
701701

702702
__buffer_unlink(jh);
703703
jh->b_cp_transaction = NULL;
704-
percpu_counter_dec(&journal->j_jh_shrink_count);
704+
percpu_counter_dec(&journal->j_checkpoint_jh_count);
705705
jbd2_journal_put_journal_head(jh);
706706

707707
/* Is this transaction empty? */
@@ -764,7 +764,7 @@ void __jbd2_journal_insert_checkpoint(struct journal_head *jh,
764764
jh->b_cpnext->b_cpprev = jh;
765765
}
766766
transaction->t_checkpoint_list = jh;
767-
percpu_counter_inc(&transaction->t_journal->j_jh_shrink_count);
767+
percpu_counter_inc(&transaction->t_journal->j_checkpoint_jh_count);
768768
}
769769

770770
/*

fs/jbd2/journal.c

Lines changed: 60 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,6 +1283,48 @@ static int jbd2_min_tag_size(void)
12831283
return sizeof(journal_block_tag_t) - 4;
12841284
}
12851285

1286+
/**
1287+
* jbd2_journal_shrink_scan()
1288+
*
1289+
* Scan the checkpointed buffer on the checkpoint list and release the
1290+
* journal_head.
1291+
*/
1292+
static unsigned long jbd2_journal_shrink_scan(struct shrinker *shrink,
1293+
struct shrink_control *sc)
1294+
{
1295+
journal_t *journal = container_of(shrink, journal_t, j_shrinker);
1296+
unsigned long nr_to_scan = sc->nr_to_scan;
1297+
unsigned long nr_shrunk;
1298+
unsigned long count;
1299+
1300+
count = percpu_counter_read_positive(&journal->j_checkpoint_jh_count);
1301+
trace_jbd2_shrink_scan_enter(journal, sc->nr_to_scan, count);
1302+
1303+
nr_shrunk = jbd2_journal_shrink_checkpoint_list(journal, &nr_to_scan);
1304+
1305+
count = percpu_counter_read_positive(&journal->j_checkpoint_jh_count);
1306+
trace_jbd2_shrink_scan_exit(journal, nr_to_scan, nr_shrunk, count);
1307+
1308+
return nr_shrunk;
1309+
}
1310+
1311+
/**
1312+
* jbd2_journal_shrink_count()
1313+
*
1314+
* Count the number of checkpoint buffers on the checkpoint list.
1315+
*/
1316+
static unsigned long jbd2_journal_shrink_count(struct shrinker *shrink,
1317+
struct shrink_control *sc)
1318+
{
1319+
journal_t *journal = container_of(shrink, journal_t, j_shrinker);
1320+
unsigned long count;
1321+
1322+
count = percpu_counter_read_positive(&journal->j_checkpoint_jh_count);
1323+
trace_jbd2_shrink_count(journal, sc->nr_to_scan, count);
1324+
1325+
return count;
1326+
}
1327+
12861328
/*
12871329
* Management for journal control blocks: functions to create and
12881330
* destroy journal_t structures, and to initialise and read existing
@@ -1361,9 +1403,23 @@ static journal_t *journal_init_common(struct block_device *bdev,
13611403
journal->j_sb_buffer = bh;
13621404
journal->j_superblock = (journal_superblock_t *)bh->b_data;
13631405

1406+
journal->j_shrink_transaction = NULL;
1407+
journal->j_shrinker.scan_objects = jbd2_journal_shrink_scan;
1408+
journal->j_shrinker.count_objects = jbd2_journal_shrink_count;
1409+
journal->j_shrinker.seeks = DEFAULT_SEEKS;
1410+
journal->j_shrinker.batch = journal->j_max_transaction_buffers;
1411+
1412+
if (percpu_counter_init(&journal->j_checkpoint_jh_count, 0, GFP_KERNEL))
1413+
goto err_cleanup;
1414+
1415+
if (register_shrinker(&journal->j_shrinker)) {
1416+
percpu_counter_destroy(&journal->j_checkpoint_jh_count);
1417+
goto err_cleanup;
1418+
}
13641419
return journal;
13651420

13661421
err_cleanup:
1422+
brelse(journal->j_sb_buffer);
13671423
kfree(journal->j_wbuf);
13681424
jbd2_journal_destroy_revoke(journal);
13691425
kfree(journal);
@@ -2050,93 +2106,6 @@ int jbd2_journal_load(journal_t *journal)
20502106
return -EIO;
20512107
}
20522108

2053-
/**
2054-
* jbd2_journal_shrink_scan()
2055-
*
2056-
* Scan the checkpointed buffer on the checkpoint list and release the
2057-
* journal_head.
2058-
*/
2059-
static unsigned long jbd2_journal_shrink_scan(struct shrinker *shrink,
2060-
struct shrink_control *sc)
2061-
{
2062-
journal_t *journal = container_of(shrink, journal_t, j_shrinker);
2063-
unsigned long nr_to_scan = sc->nr_to_scan;
2064-
unsigned long nr_shrunk;
2065-
unsigned long count;
2066-
2067-
count = percpu_counter_read_positive(&journal->j_jh_shrink_count);
2068-
trace_jbd2_shrink_scan_enter(journal, sc->nr_to_scan, count);
2069-
2070-
nr_shrunk = jbd2_journal_shrink_checkpoint_list(journal, &nr_to_scan);
2071-
2072-
count = percpu_counter_read_positive(&journal->j_jh_shrink_count);
2073-
trace_jbd2_shrink_scan_exit(journal, nr_to_scan, nr_shrunk, count);
2074-
2075-
return nr_shrunk;
2076-
}
2077-
2078-
/**
2079-
* jbd2_journal_shrink_count()
2080-
*
2081-
* Count the number of checkpoint buffers on the checkpoint list.
2082-
*/
2083-
static unsigned long jbd2_journal_shrink_count(struct shrinker *shrink,
2084-
struct shrink_control *sc)
2085-
{
2086-
journal_t *journal = container_of(shrink, journal_t, j_shrinker);
2087-
unsigned long count;
2088-
2089-
count = percpu_counter_read_positive(&journal->j_jh_shrink_count);
2090-
trace_jbd2_shrink_count(journal, sc->nr_to_scan, count);
2091-
2092-
return count;
2093-
}
2094-
2095-
/**
2096-
* jbd2_journal_register_shrinker()
2097-
* @journal: Journal to act on.
2098-
*
2099-
* Init a percpu counter to record the checkpointed buffers on the checkpoint
2100-
* list and register a shrinker to release their journal_head.
2101-
*/
2102-
int jbd2_journal_register_shrinker(journal_t *journal)
2103-
{
2104-
int err;
2105-
2106-
journal->j_shrink_transaction = NULL;
2107-
2108-
err = percpu_counter_init(&journal->j_jh_shrink_count, 0, GFP_KERNEL);
2109-
if (err)
2110-
return err;
2111-
2112-
journal->j_shrinker.scan_objects = jbd2_journal_shrink_scan;
2113-
journal->j_shrinker.count_objects = jbd2_journal_shrink_count;
2114-
journal->j_shrinker.seeks = DEFAULT_SEEKS;
2115-
journal->j_shrinker.batch = journal->j_max_transaction_buffers;
2116-
2117-
err = register_shrinker(&journal->j_shrinker);
2118-
if (err) {
2119-
percpu_counter_destroy(&journal->j_jh_shrink_count);
2120-
return err;
2121-
}
2122-
2123-
return 0;
2124-
}
2125-
EXPORT_SYMBOL(jbd2_journal_register_shrinker);
2126-
2127-
/**
2128-
* jbd2_journal_unregister_shrinker()
2129-
* @journal: Journal to act on.
2130-
*
2131-
* Unregister the checkpointed buffer shrinker and destroy the percpu counter.
2132-
*/
2133-
void jbd2_journal_unregister_shrinker(journal_t *journal)
2134-
{
2135-
percpu_counter_destroy(&journal->j_jh_shrink_count);
2136-
unregister_shrinker(&journal->j_shrinker);
2137-
}
2138-
EXPORT_SYMBOL(jbd2_journal_unregister_shrinker);
2139-
21402109
/**
21412110
* jbd2_journal_destroy() - Release a journal_t structure.
21422111
* @journal: Journal to act on.
@@ -2209,8 +2178,10 @@ int jbd2_journal_destroy(journal_t *journal)
22092178
brelse(journal->j_sb_buffer);
22102179
}
22112180

2212-
jbd2_journal_unregister_shrinker(journal);
2213-
2181+
if (journal->j_shrinker.flags & SHRINKER_REGISTERED) {
2182+
percpu_counter_destroy(&journal->j_checkpoint_jh_count);
2183+
unregister_shrinker(&journal->j_shrinker);
2184+
}
22142185
if (journal->j_proc_entry)
22152186
jbd2_stats_proc_exit(journal);
22162187
iput(journal->j_inode);

include/linux/jbd2.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -918,11 +918,11 @@ struct journal_s
918918
struct shrinker j_shrinker;
919919

920920
/**
921-
* @j_jh_shrink_count:
921+
* @j_checkpoint_jh_count:
922922
*
923923
* Number of journal buffers on the checkpoint list. [j_list_lock]
924924
*/
925-
struct percpu_counter j_jh_shrink_count;
925+
struct percpu_counter j_checkpoint_jh_count;
926926

927927
/**
928928
* @j_shrink_transaction:
@@ -1556,8 +1556,6 @@ extern int jbd2_journal_set_features
15561556
(journal_t *, unsigned long, unsigned long, unsigned long);
15571557
extern void jbd2_journal_clear_features
15581558
(journal_t *, unsigned long, unsigned long, unsigned long);
1559-
extern int jbd2_journal_register_shrinker(journal_t *journal);
1560-
extern void jbd2_journal_unregister_shrinker(journal_t *journal);
15611559
extern int jbd2_journal_load (journal_t *journal);
15621560
extern int jbd2_journal_destroy (journal_t *);
15631561
extern int jbd2_journal_recover (journal_t *journal);

0 commit comments

Comments
 (0)