Increase the size of the revoke block hash table to scale with the
size of the journal, so that we don't get long hash chains if there
are a large number of revoke blocks in the journal to replay.
The new hash size will default to 1/16 of the blocks in the journal.
This is about 1 byte per block in the hash table, but there are two
allocated. The total amount of memory allocated for revoke blocks
depends much more on how many are in the journal, and not on the size
of the hash table. The system is regularly using this much memory
for the journal blocks, so the hash table size is not a big factor.
Consolidate duplicate code between recover_ext3_journal() and
ext2fs_open_ext3_journal() in debugfs.c to avoid duplicating logic.
Signed-off-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Alex Zhuravlev <bzzz@whamcloud.com>
Reviewed-by: Li Dongyang <dongyangli@ddn.com>
Change-Id: Ibadf2a28c2f42fa92601f9da39a6ff73a43ebbe5
Reviewed-on: https://review.whamcloud.com/52386
Link: https://lore.kernel.org/r/20250125004220.44607-2-adilger@whamcloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
return retval;
}
-static errcode_t recover_ext3_journal(ext2_filsys fs)
+#define recover_ext3_journal(fs) ext2fs_open_journal(fs, NULL)
+errcode_t ext2fs_open_journal(ext2_filsys fs, journal_t **j)
{
journal_t *journal;
errcode_t retval;
+ long hash_size;
retval = jbd2_journal_init_revoke_record_cache();
if (retval)
if (retval)
goto errout;
- retval = jbd2_journal_init_revoke(journal, 1024);
+ /* The hash table defaults to 2 bytes per journal block (average of
+ * 8 entries in a hash bucket in absolute worst case), but the total
+ * memory usage depends on the number of revoke blocks. The system
+ * should be able to handle this much RAM usage, since it uses at
+ * least this much memory for the journal when running. The max limit
+ * check is to avoid problems if the journal size is wrong somehow. */
+ hash_size = roundup_power_of_two(journal->j_superblock->s_maxlen / 16);
+ if (hash_size > JBD2_MAX_JOURNAL_BLOCKS / 16)
+ hash_size = roundup_power_of_two(JBD2_MAX_JOURNAL_BLOCKS / 16);
+ retval = jbd2_journal_init_revoke(journal, hash_size);
if (retval)
goto errout;
- retval = -jbd2_journal_recover(journal);
- if (retval)
- goto errout;
+ if (!j) {
+ retval = -jbd2_journal_recover(journal);
+ if (retval)
+ goto errout;
+ }
if (journal->j_failed_commit) {
journal->j_superblock->s_errno = -EINVAL;
mark_buffer_dirty(journal->j_sb_buffer);
}
+ if (j) {
+ *j = journal;
+ return 0;
+ }
journal->j_tail_sequence = journal->j_transaction_sequence;
errout:
return retval ? retval : recover_retval;
}
-errcode_t ext2fs_open_journal(ext2_filsys fs, journal_t **j)
-{
- journal_t *journal;
- errcode_t retval;
-
- retval = jbd2_journal_init_revoke_record_cache();
- if (retval)
- return retval;
-
- retval = jbd2_journal_init_revoke_table_cache();
- if (retval)
- return retval;
-
- retval = ext2fs_get_journal(fs, &journal);
- if (retval)
- return retval;
-
- retval = ext2fs_journal_load(journal);
- if (retval)
- goto errout;
-
- retval = jbd2_journal_init_revoke(journal, 1024);
- if (retval)
- goto errout;
-
- if (journal->j_failed_commit) {
- journal->j_superblock->s_errno = -EINVAL;
- mark_buffer_dirty(journal->j_sb_buffer);
- }
-
- *j = journal;
- return 0;
-
-errout:
- jbd2_journal_destroy_revoke(journal);
- jbd2_journal_destroy_revoke_record_cache();
- jbd2_journal_destroy_revoke_table_cache();
- ext2fs_journal_release(fs, journal, 1, 0);
- return retval;
-}
-
errcode_t ext2fs_close_journal(ext2_filsys fs, journal_t **j)
{
journal_t *journal = *j;
extern int jbd2_journal_skip_recovery (journal_t *);
/* revoke.c */
-extern int jbd2_journal_init_revoke(journal_t *, int);
+extern int jbd2_journal_init_revoke(journal_t *, int hash_size);
extern void jbd2_journal_destroy_revoke(journal_t *);
extern void jbd2_journal_destroy_revoke_record_cache(void);
extern void jbd2_journal_destroy_revoke_table_cache(void);
struct problem_context pctx;
journal_t *journal;
errcode_t retval;
+ long hash_size;
clear_problem_context(&pctx);
if (retval)
goto errout;
- retval = jbd2_journal_init_revoke(journal, 1024);
+ /* The hash table defaults to 2 bytes per journal block (average of
+ * 8 entries in a hash chain in absolute worst case), but the total
+ * memory usage depends on the number of revoke blocks. The system
+ * should be able to handle this much RAM usage, since it uses at
+ * least this much memory for the journal when running. The max limit
+ * check is to avoid problems if the journal size is wrong somehow. */
+ hash_size = roundup_power_of_two(journal->j_superblock->s_maxlen / 16);
+ if (hash_size > JBD2_MAX_JOURNAL_BLOCKS / 16)
+ hash_size = roundup_power_of_two(JBD2_MAX_JOURNAL_BLOCKS / 16);
+ retval = jbd2_journal_init_revoke(journal, hash_size);
if (retval)
goto errout;
(__flags), NULL)
#define blkdev_issue_flush(kdev) sync_blockdev(kdev)
-#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
+#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
+#define roundup_power_of_two(n) (1UL << (ext2fs_log2_u32((n) - 1) + 1))
#define pr_emerg(fmt)
#define pr_err(...)
__jbd_kmalloc(__FUNCTION__, (size), (flags), 1)
#define JBD2_MIN_JOURNAL_BLOCKS 1024
+#define JBD2_MAX_JOURNAL_BLOCKS (JBD2_MIN_JOURNAL_BLOCKS * 10000)
#define JBD2_DEFAULT_FAST_COMMIT_BLOCKS 256
/*
#include "e2p/e2p.h"
#include "ext2fs/ext2_fs.h"
#include "ext2fs/ext2fs.h"
+#include "ext2fs/kernel-jbd.h"
#include "support/nls-enable.h"
#include "support/devname.h"
#include "blkid/blkid.h"
void figure_journal_size(struct ext2fs_journal_params *jparams,
int requested_j_size, int requested_fc_size, ext2_filsys fs)
{
- int total_blocks, ret;
+ int ret;
ret = ext2fs_get_journal_params(jparams, fs);
if (ret) {
}
if (requested_j_size > 0 ||
- (ext2fs_has_feature_fast_commit(fs->super) && requested_fc_size > 0)) {
+ (ext2fs_has_feature_fast_commit(fs->super) && requested_fc_size > 0)) {
+ unsigned int total_blocks;
+
if (requested_j_size > 0)
jparams->num_journal_blocks =
jsize_to_blks(fs, requested_j_size);
else if (!ext2fs_has_feature_fast_commit(fs->super))
jparams->num_fc_blocks = 0;
total_blocks = jparams->num_journal_blocks + jparams->num_fc_blocks;
- if (total_blocks < 1024 || total_blocks > 10240000) {
- fprintf(stderr, _("\nThe total requested journal "
- "size is %d blocks; it must be\n"
- "between 1024 and 10240000 blocks. "
- "Aborting.\n"),
- total_blocks);
+ if (total_blocks < JBD2_MIN_JOURNAL_BLOCKS ||
+ total_blocks > JBD2_MAX_JOURNAL_BLOCKS) {
+ fprintf(stderr,
+ _("\nThe total requested journal size is %d blocks;\nit must be between %d and %u blocks. Aborting.\n"),
+ total_blocks, JBD2_MIN_JOURNAL_BLOCKS,
+ JBD2_MAX_JOURNAL_BLOCKS);
exit(1);
}
- if ((unsigned int) total_blocks > ext2fs_free_blocks_count(fs->super) / 2) {
+ if (total_blocks > ext2fs_free_blocks_count(fs->super) / 2) {
fputs(_("\nTotal journal size too big for filesystem.\n"),
stderr);
exit(1);