static int journal_clean_one_cp_list(struct journal_head *jh, int *released) { struct journal_head *last_jh; struct journal_head *next_jh = jh; int ret, freed = 0; *released = 0; if (!jh) return 0; last_jh = jh->b_cpprev; do { jh = next_jh; next_jh = jh->b_cpnext; ret = __try_to_free_cp_buf(jh); if (ret) { freed++; if (ret == 2) { *released = 1; return freed; } } if (need_resched()) return freed; } while (jh != last_jh); return freed; }
int __journal_clean_checkpoint_list(journal_t *journal) { transaction_t *transaction, *last_transaction, *next_transaction; int ret = 0; transaction = journal->j_checkpoint_transactions; if (transaction == 0) goto out; last_transaction = transaction->t_cpprev; next_transaction = transaction; do { struct journal_head *jh; transaction = next_transaction; next_transaction = transaction->t_cpnext; jh = transaction->t_checkpoint_list; if (jh) { struct journal_head *last_jh = jh->b_cpprev; struct journal_head *next_jh = jh; do { jh = next_jh; next_jh = jh->b_cpnext; ret += __try_to_free_cp_buf(jh); } while (jh != last_jh); } } while (transaction != last_transaction); out: return ret; }
/* * journal_clean_one_cp_list * * Find all the written-back checkpoint buffers in the given list and * release them. If 'destroy' is set, clean all buffers unconditionally. * * Called with j_list_lock held. * Returns 1 if we freed the transaction, 0 otherwise. */ static int journal_clean_one_cp_list(struct journal_head *jh, bool destroy) { struct journal_head *last_jh; struct journal_head *next_jh = jh; int ret; if (!jh) return 0; last_jh = jh->b_cpprev; do { jh = next_jh; next_jh = jh->b_cpnext; if (!destroy) ret = __try_to_free_cp_buf(jh); else ret = __jbd2_journal_remove_checkpoint(jh) + 1; if (!ret) return 0; if (ret == 2) return 1; /* * This function only frees up some memory * if possible so we dont have an obligation * to finish processing. Bail out if preemption * requested: */ if (need_resched()) return 0; } while (jh != last_jh); return 0; }
static int journal_clean_one_cp_list(struct journal_head *jh, int *released) { struct journal_head *last_jh; struct journal_head *next_jh = jh; int ret, freed = 0; *released = 0; if (!jh) return 0; last_jh = jh->b_cpprev; do { jh = next_jh; next_jh = jh->b_cpnext; ret = __try_to_free_cp_buf(jh); if (ret) { freed++; if (ret == 2) { *released = 1; return freed; } } /* * This function only frees up some memory * if possible so we dont have an obligation * to finish processing. Bail out if preemption * requested: */ if (need_resched()) return freed; } while (jh != last_jh); return freed; }
int __journal_clean_checkpoint_list(journal_t *journal) { transaction_t *transaction, *last_transaction, *next_transaction; int ret = 0; transaction = journal->j_checkpoint_transactions; if (transaction == 0) goto out; last_transaction = transaction->t_cpprev; next_transaction = transaction; do { struct journal_head *jh; transaction = next_transaction; next_transaction = transaction->t_cpnext; jh = transaction->t_checkpoint_list; if (jh) { struct journal_head *last_jh = jh->b_cpprev; struct journal_head *next_jh = jh; do { jh = next_jh; next_jh = jh->b_cpnext; /* Use trylock because of the ranknig */ if (jbd_trylock_bh_state(jh2bh(jh))) ret += __try_to_free_cp_buf(jh); } while (jh != last_jh); } } while (transaction != last_transaction); out: return ret; }
static int __flush_buffer (journal_t *journal, struct journal_head *jh, void **bhs, int *batch_count, int *drop_count) { void *bh = jh2bh (jh); int ret = 0; if (bh) { bhs[*batch_count] = bh; (*batch_count)++; if (*batch_count == 64) ret = 1; } else { int last_buffer = 0; if (jh->b_cpnext == jh) last_buffer = 1; if (__try_to_free_cp_buf (jh)) { (*drop_count)++; ret = last_buffer; } } return ret; }
/* * Try to flush one buffer from the checkpoint list to disk. * * Return 1 if something happened which requires us to abort the current * scan of the checkpoint list. * * Called with j_list_lock held. * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it */ static int __flush_buffer(journal_t *journal, struct journal_head *jh, struct buffer_head **bhs, int *batch_count, int *drop_count) { struct buffer_head *bh = jh2bh(jh); int ret = 0; if (buffer_dirty(bh) && !buffer_locked(bh) && jh->b_jlist == BJ_None) { J_ASSERT_JH(jh, jh->b_transaction == NULL); /* * Important: we are about to write the buffer, and * possibly block, while still holding the journal lock. * We cannot afford to let the transaction logic start * messing around with this buffer before we write it to * disk, as that would break recoverability. */ BUFFER_TRACE(bh, "queue"); get_bh(bh); J_ASSERT_BH(bh, !buffer_jwrite(bh)); set_buffer_jwrite(bh); bhs[*batch_count] = bh; jbd_unlock_bh_state(bh); (*batch_count)++; if (*batch_count == NR_BATCH) { __flush_batch(journal, bhs, batch_count); ret = 1; } } else { int last_buffer = 0; if (jh->b_cpnext == jh) { /* We may be about to drop the transaction. Tell the * caller that the lists have changed. */ last_buffer = 1; } if (__try_to_free_cp_buf(jh)) { (*drop_count)++; ret = last_buffer; } } return ret; }
int __journal_clean_checkpoint_list(journal_t *journal) { transaction_t *transaction, *last_transaction, *next_transaction; int ret = 0; transaction = journal->j_checkpoint_transactions; if (transaction == 0) goto out; last_transaction = transaction->t_cpprev; next_transaction = transaction; do { struct journal_head *jh; transaction = next_transaction; next_transaction = transaction->t_cpnext; jh = transaction->t_checkpoint_list; if (jh) { struct journal_head *last_jh = jh->b_cpprev; struct journal_head *next_jh = jh; do { jh = next_jh; next_jh = jh->b_cpnext; /* Use trylock because of the ranknig */ if (jbd_trylock_bh_state(jh2bh(jh))) ret += __try_to_free_cp_buf(jh); /* * This function only frees up some memory * if possible so we dont have an obligation * to finish processing. Bail out if preemption * requested: */ if (need_resched()) goto out; } while (jh != last_jh); } } while (transaction != last_transaction); out: return ret; }