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:
parent
498e5f2415
commit
1a0d3786dd
@ -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) {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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]
|
||||||
|
Loading…
Reference in New Issue
Block a user