/* * Start a commit of the current running transaction (if any). Returns true * if a transaction is going to be committed (or is currently already * committing), and fills its tid in at *ptid */ int journal_start_commit(journal_t *journal, tid_t *ptid) { int ret = 0; spin_lock(&journal->j_state_lock); if (journal->j_running_transaction) { tid_t tid = journal->j_running_transaction->t_tid; __log_start_commit(journal, tid); /* There's a running transaction and we've just made sure * it's commit has been scheduled. */ if (ptid) *ptid = tid; ret = 1; } else if (journal->j_committing_transaction) { /* * If commit has been started, then we have to wait for * completion of that transaction. */ if (ptid) *ptid = journal->j_committing_transaction->t_tid; ret = 1; } spin_unlock(&journal->j_state_lock); return ret; }
int log_start_commit(journal_t *journal, tid_t tid) { int ret; jbd_lock(&journal->j_state_lock); ret = __log_start_commit(journal, tid); jbd_unlock(&journal->j_state_lock); return ret; }
/* * Quick version for internal journal use (doesn't lock the journal). * Aborts hard --- we mark the abort as occurred, but do _nothing_ else, * and don't attempt to make any other journal updates. */ static void __journal_abort_hard(journal_t *journal) { transaction_t *transaction; if (journal->j_flags & JFS_ABORT) return; jbd_lock(&journal->j_state_lock); journal->j_flags |= JFS_ABORT; transaction = journal->j_running_transaction; if (transaction) __log_start_commit(journal, transaction->t_tid); jbd_unlock(&journal->j_state_lock); }
/* * Force and wait upon a commit if the calling process is not within * transaction. This is used for forcing out undo-protected data which contains * bitmaps, when the fs is running out of space. * * We can only force the running transaction if we don't have an active handle; * otherwise, we will deadlock. * * Returns true if a transaction was started. */ int journal_force_commit_nested(journal_t *journal) { transaction_t *transaction = NULL; tid_t tid; spin_lock(&journal->j_state_lock); if (journal->j_running_transaction && !current->journal_info) { transaction = journal->j_running_transaction; __log_start_commit(journal, transaction->t_tid); } else if (journal->j_committing_transaction) transaction = journal->j_committing_transaction; if (!transaction) { spin_unlock(&journal->j_state_lock); return 0; /* Nothing to retry */ } tid = transaction->t_tid; spin_unlock(&journal->j_state_lock); log_wait_commit(journal, tid); return 1; }
int journal_restart(handle_t *handle, int nblocks) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; int ret; /* If we've had an abort of any type, don't even think about * actually doing the restart! */ if (is_handle_aborted(handle)) return 0; /* * First unlink the handle from its current transaction, and start the * commit on that. */ J_ASSERT(transaction->t_updates > 0); J_ASSERT(journal_current_handle() == handle); spin_lock(&journal->j_state_lock); spin_lock(&transaction->t_handle_lock); transaction->t_outstanding_credits -= handle->h_buffer_credits; transaction->t_updates--; if (!transaction->t_updates) wake_up(&journal->j_wait_updates); spin_unlock(&transaction->t_handle_lock); jbd_debug(2, "restarting handle %p\n", handle); __log_start_commit(journal, transaction->t_tid); spin_unlock(&journal->j_state_lock); lock_map_release(&handle->h_lockdep_map); handle->h_buffer_credits = nblocks; ret = start_this_handle(journal, handle); return ret; }
static int start_this_handle(journal_t *journal, handle_t *handle) { transaction_t *transaction; int needed; int nblocks = handle->h_buffer_credits; transaction_t *new_transaction = NULL; int ret = 0; if (nblocks > journal->j_max_transaction_buffers) { printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n", current->comm, nblocks, journal->j_max_transaction_buffers); ret = -ENOSPC; goto out; } alloc_transaction: if (!journal->j_running_transaction) { new_transaction = kzalloc(sizeof(*new_transaction), GFP_NOFS|__GFP_NOFAIL); if (!new_transaction) { ret = -ENOMEM; goto out; } } jbd_debug(3, "New handle %p going live.\n", handle); repeat: /* * We need to hold j_state_lock until t_updates has been incremented, * for proper journal barrier handling */ spin_lock(&journal->j_state_lock); repeat_locked: if (is_journal_aborted(journal) || (journal->j_errno != 0 && !(journal->j_flags & JFS_ACK_ERR))) { spin_unlock(&journal->j_state_lock); ret = -EROFS; goto out; } /* Wait on the journal's transaction barrier if necessary */ if (journal->j_barrier_count) { spin_unlock(&journal->j_state_lock); wait_event(journal->j_wait_transaction_locked, journal->j_barrier_count == 0); goto repeat; } if (!journal->j_running_transaction) { if (!new_transaction) { spin_unlock(&journal->j_state_lock); goto alloc_transaction; } get_transaction(journal, new_transaction); new_transaction = NULL; } transaction = journal->j_running_transaction; /* * If the current transaction is locked down for commit, wait for the * lock to be released. */ if (transaction->t_state == T_LOCKED) { DEFINE_WAIT(wait); prepare_to_wait(&journal->j_wait_transaction_locked, &wait, TASK_UNINTERRUPTIBLE); spin_unlock(&journal->j_state_lock); schedule(); finish_wait(&journal->j_wait_transaction_locked, &wait); goto repeat; } /* * If there is not enough space left in the log to write all potential * buffers requested by this operation, we need to stall pending a log * checkpoint to free some more log space. */ spin_lock(&transaction->t_handle_lock); needed = transaction->t_outstanding_credits + nblocks; if (needed > journal->j_max_transaction_buffers) { /* * If the current transaction is already too large, then start * to commit it: we can then go back and attach this handle to * a new transaction. */ DEFINE_WAIT(wait); jbd_debug(2, "Handle %p starting new commit...\n", handle); spin_unlock(&transaction->t_handle_lock); prepare_to_wait(&journal->j_wait_transaction_locked, &wait, TASK_UNINTERRUPTIBLE); __log_start_commit(journal, transaction->t_tid); spin_unlock(&journal->j_state_lock); schedule(); finish_wait(&journal->j_wait_transaction_locked, &wait); goto repeat; } /* * The commit code assumes that it can get enough log space * without forcing a checkpoint. This is *critical* for * correctness: a checkpoint of a buffer which is also * associated with a committing transaction creates a deadlock, * so commit simply cannot force through checkpoints. * * We must therefore ensure the necessary space in the journal * *before* starting to dirty potentially checkpointed buffers * in the new transaction. * * The worst part is, any transaction currently committing can * reduce the free space arbitrarily. Be careful to account for * those buffers when checkpointing. */ /* * @@@ AKPM: This seems rather over-defensive. We're giving commit * a _lot_ of headroom: 1/4 of the journal plus the size of * the committing transaction. Really, we only need to give it * committing_transaction->t_outstanding_credits plus "enough" for * the log control blocks. * Also, this test is inconsitent with the matching one in * journal_extend(). */ if (__log_space_left(journal) < jbd_space_needed(journal)) { jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle); spin_unlock(&transaction->t_handle_lock); __log_wait_for_space(journal); goto repeat_locked; } /* OK, account for the buffers that this operation expects to * use and add the handle to the running transaction. */ handle->h_transaction = transaction; transaction->t_outstanding_credits += nblocks; transaction->t_updates++; transaction->t_handle_count++; jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n", handle, nblocks, transaction->t_outstanding_credits, __log_space_left(journal)); spin_unlock(&transaction->t_handle_lock); spin_unlock(&journal->j_state_lock); lock_map_acquire(&handle->h_lockdep_map); out: if (unlikely(new_transaction)) /* It's usually NULL */ kfree(new_transaction); return ret; }
int journal_stop(handle_t *handle) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; int err; pid_t pid; J_ASSERT(journal_current_handle() == handle); if (is_handle_aborted(handle)) err = -EIO; else { J_ASSERT(transaction->t_updates > 0); err = 0; } if (--handle->h_ref > 0) { jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1, handle->h_ref); return err; } jbd_debug(4, "Handle %p going down\n", handle); /* * Implement synchronous transaction batching. If the handle * was synchronous, don't force a commit immediately. Let's * yield and let another thread piggyback onto this transaction. * Keep doing that while new threads continue to arrive. * It doesn't cost much - we're about to run a commit and sleep * on IO anyway. Speeds up many-threaded, many-dir operations * by 30x or more... * * We try and optimize the sleep time against what the underlying disk * can do, instead of having a static sleep time. This is usefull for * the case where our storage is so fast that it is more optimal to go * ahead and force a flush and wait for the transaction to be committed * than it is to wait for an arbitrary amount of time for new writers to * join the transaction. We achieve this by measuring how long it takes * to commit a transaction, and compare it with how long this * transaction has been running, and if run time < commit time then we * sleep for the delta and commit. This greatly helps super fast disks * that would see slowdowns as more threads started doing fsyncs. * * But don't do this if this process was the most recent one to * perform a synchronous write. We do this to detect the case where a * single process is doing a stream of sync writes. No point in waiting * for joiners in that case. */ pid = current->pid; if (handle->h_sync && journal->j_last_sync_writer != pid) { u64 commit_time, trans_time; journal->j_last_sync_writer = pid; spin_lock(&journal->j_state_lock); commit_time = journal->j_average_commit_time; spin_unlock(&journal->j_state_lock); trans_time = ktime_to_ns(ktime_sub(ktime_get(), transaction->t_start_time)); commit_time = min_t(u64, commit_time, 1000*jiffies_to_usecs(1)); if (trans_time < commit_time) { ktime_t expires = ktime_add_ns(ktime_get(), commit_time); set_current_state(TASK_UNINTERRUPTIBLE); schedule_hrtimeout(&expires, HRTIMER_MODE_ABS); } } if (handle->h_sync) transaction->t_synchronous_commit = 1; current->journal_info = NULL; spin_lock(&journal->j_state_lock); spin_lock(&transaction->t_handle_lock); transaction->t_outstanding_credits -= handle->h_buffer_credits; transaction->t_updates--; if (!transaction->t_updates) { wake_up(&journal->j_wait_updates); if (journal->j_barrier_count) wake_up(&journal->j_wait_transaction_locked); } /* * If the handle is marked SYNC, we need to set another commit * going! We also want to force a commit if the current * transaction is occupying too much of the log, or if the * transaction is too old now. */ if (handle->h_sync || transaction->t_outstanding_credits > journal->j_max_transaction_buffers || time_after_eq(jiffies, transaction->t_expires)) { /* Do this even for aborted journals: an abort still * completes the commit thread, it just doesn't write * anything to disk. */ tid_t tid = transaction->t_tid; spin_unlock(&transaction->t_handle_lock); jbd_debug(2, "transaction too old, requesting commit for " "handle %p\n", handle); /* This is non-blocking */ __log_start_commit(journal, transaction->t_tid); spin_unlock(&journal->j_state_lock); /* * Special case: JFS_SYNC synchronous updates require us * to wait for the commit to complete. */ if (handle->h_sync && !(current->flags & PF_MEMALLOC)) err = log_wait_commit(journal, tid); } else { spin_unlock(&transaction->t_handle_lock); spin_unlock(&journal->j_state_lock); } lock_map_release(&handle->h_lockdep_map); jbd_free_handle(handle); return err; }