jbd2: Remove a large array of bh's from the stack of the checkpoint routine

jbd2_log_do_checkpoint()n is one of the kernel's largest stack users.
Move the array of buffer head's from the stack of jbd2_log_do_checkpoint()
to the in-core journal structure.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
This commit is contained in:
Theodore Ts'o 2008-11-05 00:09:22 -05:00
parent 498e5f2415
commit 1a0d3786dd
3 changed files with 21 additions and 13 deletions

View File

@ -249,16 +249,14 @@ restart:
return ret; return ret;
} }
#define NR_BATCH 64
static void static void
__flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count) __flush_batch(journal_t *journal, int *batch_count)
{ {
int i; int i;
ll_rw_block(SWRITE, *batch_count, bhs); ll_rw_block(SWRITE, *batch_count, journal->j_chkpt_bhs);
for (i = 0; i < *batch_count; i++) { for (i = 0; i < *batch_count; i++) {
struct buffer_head *bh = bhs[i]; struct buffer_head *bh = journal->j_chkpt_bhs[i];
clear_buffer_jwrite(bh); clear_buffer_jwrite(bh);
BUFFER_TRACE(bh, "brelse"); BUFFER_TRACE(bh, "brelse");
__brelse(bh); __brelse(bh);
@ -277,8 +275,7 @@ __flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count)
* Called under jbd_lock_bh_state(jh2bh(jh)), and drops it * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it
*/ */
static int __process_buffer(journal_t *journal, struct journal_head *jh, static int __process_buffer(journal_t *journal, struct journal_head *jh,
struct buffer_head **bhs, int *batch_count, int *batch_count, transaction_t *transaction)
transaction_t *transaction)
{ {
struct buffer_head *bh = jh2bh(jh); struct buffer_head *bh = jh2bh(jh);
int ret = 0; int ret = 0;
@ -325,14 +322,14 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh,
get_bh(bh); get_bh(bh);
J_ASSERT_BH(bh, !buffer_jwrite(bh)); J_ASSERT_BH(bh, !buffer_jwrite(bh));
set_buffer_jwrite(bh); set_buffer_jwrite(bh);
bhs[*batch_count] = bh; journal->j_chkpt_bhs[*batch_count] = bh;
__buffer_relink_io(jh); __buffer_relink_io(jh);
jbd_unlock_bh_state(bh); jbd_unlock_bh_state(bh);
transaction->t_chp_stats.cs_written++; transaction->t_chp_stats.cs_written++;
(*batch_count)++; (*batch_count)++;
if (*batch_count == NR_BATCH) { if (*batch_count == JBD2_NR_BATCH) {
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
__flush_batch(journal, bhs, batch_count); __flush_batch(journal, batch_count);
ret = 1; ret = 1;
} }
} }
@ -388,7 +385,6 @@ restart:
if (journal->j_checkpoint_transactions == transaction && if (journal->j_checkpoint_transactions == transaction &&
transaction->t_tid == this_tid) { transaction->t_tid == this_tid) {
int batch_count = 0; int batch_count = 0;
struct buffer_head *bhs[NR_BATCH];
struct journal_head *jh; struct journal_head *jh;
int retry = 0, err; int retry = 0, err;
@ -402,7 +398,7 @@ restart:
retry = 1; retry = 1;
break; break;
} }
retry = __process_buffer(journal, jh, bhs, &batch_count, retry = __process_buffer(journal, jh, &batch_count,
transaction); transaction);
if (retry < 0 && !result) if (retry < 0 && !result)
result = retry; result = retry;
@ -419,7 +415,7 @@ restart:
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
retry = 1; retry = 1;
} }
__flush_batch(journal, bhs, &batch_count); __flush_batch(journal, &batch_count);
} }
if (retry) { if (retry) {

View File

@ -1477,7 +1477,9 @@ int jbd2_journal_destroy(journal_t *journal)
spin_lock(&journal->j_list_lock); spin_lock(&journal->j_list_lock);
while (journal->j_checkpoint_transactions != NULL) { while (journal->j_checkpoint_transactions != NULL) {
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
mutex_lock(&journal->j_checkpoint_mutex);
jbd2_log_do_checkpoint(journal); jbd2_log_do_checkpoint(journal);
mutex_unlock(&journal->j_checkpoint_mutex);
spin_lock(&journal->j_list_lock); spin_lock(&journal->j_list_lock);
} }

View File

@ -687,6 +687,8 @@ jbd2_time_diff(unsigned long start, unsigned long end)
return end + (MAX_JIFFY_OFFSET - start); return end + (MAX_JIFFY_OFFSET - start);
} }
#define JBD2_NR_BATCH 64
/** /**
* struct journal_s - The journal_s type is the concrete type associated with * struct journal_s - The journal_s type is the concrete type associated with
* journal_t. * journal_t.
@ -830,6 +832,14 @@ struct journal_s
/* Semaphore for locking against concurrent checkpoints */ /* Semaphore for locking against concurrent checkpoints */
struct mutex j_checkpoint_mutex; struct mutex j_checkpoint_mutex;
/*
* List of buffer heads used by the checkpoint routine. This
* was moved from jbd2_log_do_checkpoint() to reduce stack
* usage. Access to this array is controlled by the
* j_checkpoint_mutex. [j_checkpoint_mutex]
*/
struct buffer_head *j_chkpt_bhs[JBD2_NR_BATCH];
/* /*
* Journal head: identifies the first unused block in the journal. * Journal head: identifies the first unused block in the journal.
* [j_state_lock] * [j_state_lock]