/* * __log_wait_for_space: wait until there is space in the journal. * * Called under j-state_lock *only*. It will be unlocked if we have to wait * for a checkpoint to free up some space in the log. */ void __log_wait_for_space(journal_t *journal) { int nblocks, space_left; assert_spin_locked(&journal->j_state_lock); nblocks = jbd_space_needed(journal); while (__log_space_left(journal) < nblocks) { if (journal->j_flags & JFS_ABORT) return; spin_unlock(&journal->j_state_lock); mutex_lock(&journal->j_checkpoint_mutex); /* * Test again, another process may have checkpointed while we * were waiting for the checkpoint lock. If there are no * transactions ready to be checkpointed, try to recover * journal space by calling cleanup_journal_tail(), and if * that doesn't work, by waiting for the currently committing * transaction to complete. If there is absolutely no way * to make progress, this is either a BUG or corrupted * filesystem, so abort the journal and leave a stack * trace for forensic evidence. */ spin_lock(&journal->j_state_lock); spin_lock(&journal->j_list_lock); nblocks = jbd_space_needed(journal); space_left = __log_space_left(journal); if (space_left < nblocks) { int chkpt = journal->j_checkpoint_transactions != NULL; tid_t tid = 0; if (journal->j_committing_transaction) tid = journal->j_committing_transaction->t_tid; spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_state_lock); if (chkpt) { log_do_checkpoint(journal); } else if (cleanup_journal_tail(journal) == 0) { /* We were able to recover space; yay! */ ; } else if (tid) { log_wait_commit(journal, tid); } else { printk(KERN_ERR "%s: needed %d blocks and " "only had %d space available\n", __func__, nblocks, space_left); printk(KERN_ERR "%s: no way to get more " "journal space\n", __func__); WARN_ON(1); journal_abort(journal, 0); } spin_lock(&journal->j_state_lock); } else { spin_unlock(&journal->j_list_lock); } mutex_unlock(&journal->j_checkpoint_mutex); } }
void __log_wait_for_space(journal_t *journal) { int nblocks, space_left; assert_spin_locked(&journal->j_state_lock); nblocks = jbd_space_needed(journal); while (__log_space_left(journal) < nblocks) { if (journal->j_flags & JFS_ABORT) return; spin_unlock(&journal->j_state_lock); mutex_lock(&journal->j_checkpoint_mutex); /* */ spin_lock(&journal->j_state_lock); spin_lock(&journal->j_list_lock); nblocks = jbd_space_needed(journal); space_left = __log_space_left(journal); if (space_left < nblocks) { int chkpt = journal->j_checkpoint_transactions != NULL; tid_t tid = 0; if (journal->j_committing_transaction) tid = journal->j_committing_transaction->t_tid; spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_state_lock); if (chkpt) { log_do_checkpoint(journal); } else if (cleanup_journal_tail(journal) == 0) { /* */ ; } else if (tid) { log_wait_commit(journal, tid); } else { printk(KERN_ERR "%s: needed %d blocks and " "only had %d space available\n", __func__, nblocks, space_left); printk(KERN_ERR "%s: no way to get more " "journal space\n", __func__); WARN_ON(1); journal_abort(journal, 0); } spin_lock(&journal->j_state_lock); } else { spin_unlock(&journal->j_list_lock); } mutex_unlock(&journal->j_checkpoint_mutex); } }
/* @@@ `nblocks' is unused. Should it be used? */ int log_do_checkpoint (journal_t *journal, int nblocks) { transaction_t *transaction, *last_transaction, *next_transaction; int result; int target; int batch_count = 0; struct buffer_head *bhs[NR_BATCH]; jbd_debug(1, "Start checkpoint\n"); /* * First thing: if there are any transactions in the log which * don't need checkpointing, just eliminate them from the * journal straight away. */ result = cleanup_journal_tail(journal); jbd_debug(1, "cleanup_journal_tail returned %d\n", result); if (result <= 0) return result; /* * OK, we need to start writing disk blocks. Try to free up a * quarter of the log in a single checkpoint if we can. */ /* * AKPM: check this code. I had a feeling a while back that it * degenerates into a busy loop at unmount time. */ target = (journal->j_last - journal->j_first) / 4; spin_lock(&journal_datalist_lock); repeat: transaction = journal->j_checkpoint_transactions; if (transaction == NULL) goto done; last_transaction = transaction->t_cpprev; next_transaction = transaction; do { struct journal_head *jh, *last_jh, *next_jh; int drop_count = 0; int cleanup_ret, retry = 0; transaction = next_transaction; next_transaction = transaction->t_cpnext; jh = transaction->t_checkpoint_list; last_jh = jh->b_cpprev; next_jh = jh; do { jh = next_jh; next_jh = jh->b_cpnext; retry = __flush_buffer(journal, jh, bhs, &batch_count, &drop_count); } while (jh != last_jh && !retry); if (batch_count) { __flush_batch(bhs, &batch_count); goto repeat; } if (retry) goto repeat; /* * We have walked the whole transaction list without * finding anything to write to disk. We had better be * able to make some progress or we are in trouble. */ cleanup_ret = __cleanup_transaction(journal, transaction); J_ASSERT(drop_count != 0 || cleanup_ret != 0); goto repeat; /* __cleanup may have dropped lock */ } while (transaction != last_transaction); done: spin_unlock(&journal_datalist_lock); result = cleanup_journal_tail(journal); if (result < 0) return result; return 0; }
/* * Perform an actual checkpoint. We don't write out only enough to * satisfy the current blocked requests: rather we submit a reasonably * sized chunk of the outstanding data to disk at once for * efficiency. __log_wait_for_space() will retry if we didn't free enough. * * However, we _do_ take into account the amount requested so that once * the IO has been queued, we can return as soon as enough of it has * completed to disk. * * The journal should be locked before calling this function. */ int log_do_checkpoint(journal_t *journal) { int result; int batch_count = 0; struct buffer_head *bhs[NR_BATCH]; jbd_debug(1, "Start checkpoint\n"); /* * First thing: if there are any transactions in the log which * don't need checkpointing, just eliminate them from the * journal straight away. */ result = cleanup_journal_tail(journal); jbd_debug(1, "cleanup_journal_tail returned %d\n", result); if (result <= 0) return result; /* * OK, we need to start writing disk blocks. Try to free up a * quarter of the log in a single checkpoint if we can. */ /* * AKPM: check this code. I had a feeling a while back that it * degenerates into a busy loop at unmount time. */ spin_lock(&journal->j_list_lock); while (journal->j_checkpoint_transactions) { transaction_t *transaction; struct journal_head *jh, *last_jh, *next_jh; int drop_count = 0; int cleanup_ret, retry = 0; tid_t this_tid; transaction = journal->j_checkpoint_transactions; this_tid = transaction->t_tid; jh = transaction->t_checkpoint_list; last_jh = jh->b_cpprev; next_jh = jh; do { struct buffer_head *bh; jh = next_jh; next_jh = jh->b_cpnext; bh = jh2bh(jh); if (!jbd_trylock_bh_state(bh)) { jbd_sync_bh(journal, bh); spin_lock(&journal->j_list_lock); retry = 1; break; } retry = __flush_buffer(journal, jh, bhs, &batch_count, &drop_count); if (cond_resched_lock(&journal->j_list_lock)) { retry = 1; break; } } while (jh != last_jh && !retry); if (batch_count) { __flush_batch(journal, bhs, &batch_count); retry = 1; } /* * If someone cleaned up this transaction while we slept, we're * done */ if (journal->j_checkpoint_transactions != transaction) break; if (retry) continue; /* * Maybe it's a new transaction, but it fell at the same * address */ if (transaction->t_tid != this_tid) continue; /* * We have walked the whole transaction list without * finding anything to write to disk. We had better be * able to make some progress or we are in trouble. */ cleanup_ret = __cleanup_transaction(journal, transaction); J_ASSERT(drop_count != 0 || cleanup_ret != 0); if (journal->j_checkpoint_transactions != transaction) break; } spin_unlock(&journal->j_list_lock); result = cleanup_journal_tail(journal); if (result < 0) return result; return 0; }
/* * Perform an actual checkpoint. We take the first transaction on the * list of transactions to be checkpointed and send all its buffers * to disk. We submit larger chunks of data at once. * * The journal should be locked before calling this function. */ int log_do_checkpoint(journal_t *journal) { transaction_t *transaction; tid_t this_tid; int result; jbd_debug(1, "Start checkpoint\n"); /* * First thing: if there are any transactions in the log which * don't need checkpointing, just eliminate them from the * journal straight away. */ result = cleanup_journal_tail(journal); jbd_debug(1, "cleanup_journal_tail returned %d\n", result); if (result <= 0) return result; /* * OK, we need to start writing disk blocks. Take one transaction * and write it. */ spin_lock(&journal->j_list_lock); if (!journal->j_checkpoint_transactions) goto out; transaction = journal->j_checkpoint_transactions; this_tid = transaction->t_tid; restart: /* * If someone cleaned up this transaction while we slept, we're * done (maybe it's a new transaction, but it fell at the same * address). */ if (journal->j_checkpoint_transactions == transaction && transaction->t_tid == this_tid) { int batch_count = 0; struct buffer_head *bhs[NR_BATCH]; struct journal_head *jh; int retry = 0; while (!retry && transaction->t_checkpoint_list) { struct buffer_head *bh; jh = transaction->t_checkpoint_list; bh = jh2bh(jh); if (!jbd_trylock_bh_state(bh)) { jbd_sync_bh(journal, bh); retry = 1; break; } retry = __process_buffer(journal, jh, bhs,&batch_count); if (!retry && lock_need_resched(&journal->j_list_lock)){ spin_unlock(&journal->j_list_lock); retry = 1; break; } } if (batch_count) { if (!retry) { spin_unlock(&journal->j_list_lock); retry = 1; } __flush_batch(journal, bhs, &batch_count); } if (retry) { spin_lock(&journal->j_list_lock); goto restart; } /* * Now we have cleaned up the first transaction's checkpoint * list. Let's clean up the second one */ __wait_cp_io(journal, transaction); } out: spin_unlock(&journal->j_list_lock); result = cleanup_journal_tail(journal); if (result < 0) return result; return 0; }