Index: linux-4.18.0-425.3.1.el8/fs/jbd2/recovery.c =================================================================== --- linux-4.18.0-425.3.1.el8.orig/fs/jbd2/recovery.c +++ linux-4.18.0-425.3.1.el8/fs/jbd2/recovery.c @@ -19,6 +19,7 @@ #include #include #include +#include #endif /* @@ -251,6 +252,10 @@ int jbd2_journal_recover(journal_t *jour memset(&info, 0, sizeof(info)); sb = journal->j_superblock; + err = jbd2_journal_init_recovery_revoke(journal); + if (err) + return err; + /* * The journal superblock's s_start field (the current log head) * is always zero if, and only if, the journal was cleanly Index: linux-4.18.0-425.3.1.el8/fs/jbd2/revoke.c =================================================================== --- linux-4.18.0-425.3.1.el8.orig/fs/jbd2/revoke.c +++ linux-4.18.0-425.3.1.el8/fs/jbd2/revoke.c @@ -90,6 +90,7 @@ #include #include #include +#include #endif static struct kmem_cache *jbd2_revoke_record_cache; @@ -101,7 +102,10 @@ static struct kmem_cache *jbd2_revoke_ta struct jbd2_revoke_record_s { - struct list_head hash; + union { + struct list_head hash; + struct rhash_head linkage; + }; tid_t sequence; /* Used for recovery only */ unsigned long long blocknr; }; @@ -680,13 +684,21 @@ static void flush_descriptor(journal_t * * single block. */ +static const struct rhashtable_params revoke_rhashtable_params = { + .key_len = sizeof(unsigned long long), + .key_offset = offsetof(struct jbd2_revoke_record_s, blocknr), + .head_offset = offsetof(struct jbd2_revoke_record_s, linkage), +}; + int jbd2_journal_set_revoke(journal_t *journal, unsigned long long blocknr, tid_t sequence) { - struct jbd2_revoke_record_s *record; + struct jbd2_revoke_record_s *record, *old; + gfp_t gfp_mask = GFP_NOFS; - record = find_revoke_record(journal, blocknr); + record = rhashtable_lookup(&journal->j_revoke_rhtable, &blocknr, + revoke_rhashtable_params); if (record) { /* If we have multiple occurrences, only record the * latest sequence number in the hashed record */ @@ -694,7 +706,24 @@ int jbd2_journal_set_revoke(journal_t *j record->sequence = sequence; return 0; } - return insert_revoke_hash(journal, blocknr, sequence); + + if (journal_oom_retry) + gfp_mask |= __GFP_NOFAIL; + record = kmem_cache_alloc(jbd2_revoke_record_cache, gfp_mask); + if (!record) + return -ENOMEM; + + record->sequence = sequence; + record->blocknr = blocknr; + old = rhashtable_lookup_get_insert_fast(&journal->j_revoke_rhtable, + &record->linkage, revoke_rhashtable_params); + if (IS_ERR(old)) { + kmem_cache_free(jbd2_revoke_record_cache, record); + return PTR_ERR(old); + } + BUG_ON(old != NULL); + + return 0; } /* @@ -710,7 +739,8 @@ int jbd2_journal_test_revoke(journal_t * { struct jbd2_revoke_record_s *record; - record = find_revoke_record(journal, blocknr); + record = rhashtable_lookup(&journal->j_revoke_rhtable, &blocknr, + revoke_rhashtable_params); if (!record) return 0; if (tid_gt(sequence, record->sequence)) @@ -718,6 +748,17 @@ int jbd2_journal_test_revoke(journal_t * return 1; } +int jbd2_journal_init_recovery_revoke(journal_t *journal) +{ + return rhashtable_init(&journal->j_revoke_rhtable, + &revoke_rhashtable_params); +} + +static void jbd2_revoke_record_free(void *ptr, void *arg) +{ + kmem_cache_free(jbd2_revoke_record_cache, ptr); +} + /* * Finally, once recovery is over, we need to clear the revoke table so * that it can be reused by the running filesystem. @@ -725,19 +766,6 @@ int jbd2_journal_test_revoke(journal_t * void jbd2_journal_clear_revoke(journal_t *journal) { - int i; - struct list_head *hash_list; - struct jbd2_revoke_record_s *record; - struct jbd2_revoke_table_s *revoke; - - revoke = journal->j_revoke; - - for (i = 0; i < revoke->hash_size; i++) { - hash_list = &revoke->hash_table[i]; - while (!list_empty(hash_list)) { - record = (struct jbd2_revoke_record_s*) hash_list->next; - list_del(&record->hash); - kmem_cache_free(jbd2_revoke_record_cache, record); - } - } + rhashtable_free_and_destroy(&journal->j_revoke_rhtable, + jbd2_revoke_record_free, NULL); } Index: linux-4.18.0-425.3.1.el8/include/linux/jbd2.h =================================================================== --- linux-4.18.0-425.3.1.el8.orig/include/linux/jbd2.h +++ linux-4.18.0-425.3.1.el8/include/linux/jbd2.h @@ -1084,6 +1084,11 @@ struct journal_s struct jbd2_revoke_table_s *j_revoke_table[2]; /** + * @j_revoke_rhtable: rhashtable for revoke records during recovery + */ + struct rhashtable j_revoke_rhtable; + + /** * @j_wbuf: Array of bhs for jbd2_journal_commit_transaction. */ struct buffer_head **j_wbuf; @@ -1508,6 +1513,7 @@ extern void jbd2_journal_write_revoke /* Recovery revoke support */ extern int jbd2_journal_set_revoke(journal_t *, unsigned long long, tid_t); extern int jbd2_journal_test_revoke(journal_t *, unsigned long long, tid_t); +extern int jbd2_journal_init_recovery_revoke(journal_t *); extern void jbd2_journal_clear_revoke(journal_t *); extern void jbd2_journal_switch_revoke_table(journal_t *journal); extern void jbd2_clear_buffer_revoked_flags(journal_t *journal);