Release 4.10 fs/jbd2/transaction.c
/*
* linux/fs/jbd2/transaction.c
*
* Written by Stephen C. Tweedie <sct@redhat.com>, 1998
*
* Copyright 1998 Red Hat corp --- All Rights Reserved
*
* This file is part of the Linux kernel and is made available under
* the terms of the GNU General Public License, version 2, or at your
* option, any later version, incorporated herein by reference.
*
* Generic filesystem transaction handling code; part of the ext2fs
* journaling system.
*
* This file manages transactions (compound commits managed by the
* journaling code) and handles (individual atomic operations by the
* filesystem).
*/
#include <linux/time.h>
#include <linux/fs.h>
#include <linux/jbd2.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/hrtimer.h>
#include <linux/backing-dev.h>
#include <linux/bug.h>
#include <linux/module.h>
#include <trace/events/jbd2.h>
static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh);
static void __jbd2_journal_unfile_buffer(struct journal_head *jh);
static struct kmem_cache *transaction_cache;
int __init jbd2_journal_init_transaction_cache(void)
{
J_ASSERT(!transaction_cache);
transaction_cache = kmem_cache_create("jbd2_transaction_s",
sizeof(transaction_t),
0,
SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY,
NULL);
if (transaction_cache)
return 0;
return -ENOMEM;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
yongqiang yang | yongqiang yang | 45 | 100.00% | 1 | 100.00% |
| Total | 45 | 100.00% | 1 | 100.00% |
void jbd2_journal_destroy_transaction_cache(void)
{
if (transaction_cache) {
kmem_cache_destroy(transaction_cache);
transaction_cache = NULL;
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
yongqiang yang | yongqiang yang | 22 | 100.00% | 1 | 100.00% |
| Total | 22 | 100.00% | 1 | 100.00% |
void jbd2_journal_free_transaction(transaction_t *transaction)
{
if (unlikely(ZERO_OR_NULL_PTR(transaction)))
return;
kmem_cache_free(transaction_cache, transaction);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
yongqiang yang | yongqiang yang | 27 | 100.00% | 1 | 100.00% |
| Total | 27 | 100.00% | 1 | 100.00% |
/*
* jbd2_get_transaction: obtain a new transaction_t object.
*
* Simply allocate and initialise a new transaction. Create it in
* RUNNING state and add it to the current journal (which should not
* have an existing running transaction: we only make a new transaction
* once we have started to commit the old one).
*
* Preconditions:
* The journal MUST be locked. We don't perform atomic mallocs on the
* new transaction and we can't block without protecting against other
* processes trying to touch the journal while it is in transition.
*
*/
static transaction_t *
jbd2_get_transaction(journal_t *journal, transaction_t *transaction)
{
transaction->t_journal = journal;
transaction->t_state = T_RUNNING;
transaction->t_start_time = ktime_get();
transaction->t_tid = journal->j_transaction_sequence++;
transaction->t_expires = jiffies + journal->j_commit_interval;
spin_lock_init(&transaction->t_handle_lock);
atomic_set(&transaction->t_updates, 0);
atomic_set(&transaction->t_outstanding_credits,
atomic_read(&journal->j_reserved_credits));
atomic_set(&transaction->t_handle_count, 0);
INIT_LIST_HEAD(&transaction->t_inode_list);
INIT_LIST_HEAD(&transaction->t_private_list);
/* Set up the commit timer for the new transaction. */
journal->j_commit_timer.expires = round_jiffies_up(transaction->t_expires);
add_timer(&journal->j_commit_timer);
J_ASSERT(journal->j_running_transaction == NULL);
journal->j_running_transaction = transaction;
transaction->t_max_wait = 0;
transaction->t_start = jiffies;
transaction->t_requested = 0;
return transaction;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dave kleikamp | dave kleikamp | 90 | 52.63% | 1 | 8.33% |
theodore tso | theodore tso | 43 | 25.15% | 4 | 33.33% |
jan kara | jan kara | 15 | 8.77% | 2 | 16.67% |
johann lombardi | johann lombardi | 12 | 7.02% | 1 | 8.33% |
josef bacik | josef bacik | 7 | 4.09% | 1 | 8.33% |
mingming cao | mingming cao | 3 | 1.75% | 2 | 16.67% |
andreas dilger | andreas dilger | 1 | 0.58% | 1 | 8.33% |
| Total | 171 | 100.00% | 12 | 100.00% |
/*
* Handle management.
*
* A handle_t is an object which represents a single atomic update to a
* filesystem, and which tracks all of the modifications which form part
* of that one update.
*/
/*
* Update transaction's maximum wait time, if debugging is enabled.
*
* In order for t_max_wait to be reliable, it must be protected by a
* lock. But doing so will mean that start_this_handle() can not be
* run in parallel on SMP systems, which limits our scalability. So
* unless debugging is enabled, we no longer update t_max_wait, which
* means that maximum wait time reported by the jbd2_run_stats
* tracepoint will always be zero.
*/
static inline void update_t_max_wait(transaction_t *transaction,
unsigned long ts)
{
#ifdef CONFIG_JBD2_DEBUG
if (jbd2_journal_enable_debug &&
time_after(transaction->t_start, ts)) {
ts = jbd2_time_diff(ts, transaction->t_start);
spin_lock(&transaction->t_handle_lock);
if (ts > transaction->t_max_wait)
transaction->t_max_wait = ts;
spin_unlock(&transaction->t_handle_lock);
}
#endif
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
theodore tso | theodore tso | 72 | 94.74% | 1 | 50.00% |
tao ma | tao ma | 4 | 5.26% | 1 | 50.00% |
| Total | 76 | 100.00% | 2 | 100.00% |
/*
* Wait until running transaction passes T_LOCKED state. Also starts the commit
* if needed. The function expects running transaction to exist and releases
* j_state_lock.
*/
static void wait_transaction_locked(journal_t *journal)
__releases(journal->j_state_lock)
{
DEFINE_WAIT(wait);
int need_to_start;
tid_t tid = journal->j_running_transaction->t_tid;
prepare_to_wait(&journal->j_wait_transaction_locked, &wait,
TASK_UNINTERRUPTIBLE);
need_to_start = !tid_geq(journal->j_commit_request, tid);
read_unlock(&journal->j_state_lock);
if (need_to_start)
jbd2_log_start_commit(journal, tid);
jbd2_might_wait_for_commit(journal);
schedule();
finish_wait(&journal->j_wait_transaction_locked, &wait);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jan kara | jan kara | 60 | 62.50% | 2 | 33.33% |
dave kleikamp | dave kleikamp | 30 | 31.25% | 1 | 16.67% |
theodore tso | theodore tso | 5 | 5.21% | 2 | 33.33% |
tao ma | tao ma | 1 | 1.04% | 1 | 16.67% |
| Total | 96 | 100.00% | 6 | 100.00% |
static void sub_reserved_credits(journal_t *journal, int blocks)
{
atomic_sub(blocks, &journal->j_reserved_credits);
wake_up(&journal->j_wait_reserved);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jan kara | jan kara | 20 | 64.52% | 1 | 33.33% |
dave kleikamp | dave kleikamp | 6 | 19.35% | 1 | 33.33% |
theodore tso | theodore tso | 5 | 16.13% | 1 | 33.33% |
| Total | 31 | 100.00% | 3 | 100.00% |
/*
* Wait until we can add credits for handle to the running transaction. Called
* with j_state_lock held for reading. Returns 0 if handle joined the running
* transaction. Returns 1 if we had to wait, j_state_lock is dropped, and
* caller must retry.
*/
static int add_transaction_credits(journal_t *journal, int blocks,
int rsv_blocks)
{
transaction_t *t = journal->j_running_transaction;
int needed;
int total = blocks + rsv_blocks;
/*
* If the current transaction is locked down for commit, wait
* for the lock to be released.
*/
if (t->t_state == T_LOCKED) {
wait_transaction_locked(journal);
return 1;
}
/*
* 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.
*/
needed = atomic_add_return(total, &t->t_outstanding_credits);
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.
*/
atomic_sub(total, &t->t_outstanding_credits);
/*
* Is the number of reserved credits in the current transaction too
* big to fit this handle? Wait until reserved credits are freed.
*/
if (atomic_read(&journal->j_reserved_credits) + total >
journal->j_max_transaction_buffers) {
read_unlock(&journal->j_state_lock);
jbd2_might_wait_for_commit(journal);
wait_event(journal->j_wait_reserved,
atomic_read(&journal->j_reserved_credits) + total <=
journal->j_max_transaction_buffers);
return 1;
}
wait_transaction_locked(journal);
return 1;
}
/*
* 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.
*/
if (jbd2_log_space_left(journal) < jbd2_space_needed(journal)) {
atomic_sub(total, &t->t_outstanding_credits);
read_unlock(&journal->j_state_lock);
jbd2_might_wait_for_commit(journal);
write_lock(&journal->j_state_lock);
if (jbd2_log_space_left(journal) < jbd2_space_needed(journal))
__jbd2_log_wait_for_space(journal);
write_unlock(&journal->j_state_lock);
return 1;
}
/* No reservation? We are done... */
if (!rsv_blocks)
return 0;
needed = atomic_add_return(rsv_blocks, &journal->j_reserved_credits);
/* We allow at most half of a transaction to be reserved */
if (needed > journal->j_max_transaction_buffers / 2) {
sub_reserved_credits(journal, rsv_blocks);
atomic_sub(total, &t->t_outstanding_credits);
read_unlock(&journal->j_state_lock);
jbd2_might_wait_for_commit(journal);
wait_event(journal->j_wait_reserved,
atomic_read(&journal->j_reserved_credits) + rsv_blocks
<= journal->j_max_transaction_buffers / 2);
return 1;
}
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jan kara | jan kara | 167 | 52.52% | 3 | 42.86% |
dave kleikamp | dave kleikamp | 73 | 22.96% | 1 | 14.29% |
lukas czerner | lukas czerner | 51 | 16.04% | 1 | 14.29% |
theodore tso | theodore tso | 27 | 8.49% | 2 | 28.57% |
| Total | 318 | 100.00% | 7 | 100.00% |
/*
* start_this_handle: Given a handle, deal with any locking or stalling
* needed to make sure that there is enough journal space for the handle
* to begin. Attach the handle to a transaction and set up the
* transaction's buffer credits.
*/
static int start_this_handle(journal_t *journal, handle_t *handle,
gfp_t gfp_mask)
{
transaction_t *transaction, *new_transaction = NULL;
int blocks = handle->h_buffer_credits;
int rsv_blocks = 0;
unsigned long ts = jiffies;
if (handle->h_rsv_handle)
rsv_blocks = handle->h_rsv_handle->h_buffer_credits;
/*
* Limit the number of reserved credits to 1/2 of maximum transaction
* size and limit the number of total credits to not exceed maximum
* transaction size per operation.
*/
if ((rsv_blocks > journal->j_max_transaction_buffers / 2) ||
(rsv_blocks + blocks > journal->j_max_transaction_buffers)) {
printk(KERN_ERR "JBD2: %s wants too many credits "
"credits:%d rsv_credits:%d max:%d\n",
current->comm, blocks, rsv_blocks,
journal->j_max_transaction_buffers);
WARN_ON(1);
return -ENOSPC;
}
alloc_transaction:
if (!journal->j_running_transaction) {
/*
* If __GFP_FS is not present, then we may be being called from
* inside the fs writeback layer, so we MUST NOT fail.
*/
if ((gfp_mask & __GFP_FS) == 0)
gfp_mask |= __GFP_NOFAIL;
new_transaction = kmem_cache_zalloc(transaction_cache,
gfp_mask);
if (!new_transaction)
return -ENOMEM;
}
jbd_debug(3, "New handle %p going live.\n", handle);
/*
* We need to hold j_state_lock until t_updates has been incremented,
* for proper journal barrier handling
*/
repeat:
read_lock(&journal->j_state_lock);
BUG_ON(journal->j_flags & JBD2_UNMOUNT);
if (is_journal_aborted(journal) ||
(journal->j_errno != 0 && !(journal->j_flags & JBD2_ACK_ERR))) {
read_unlock(&journal->j_state_lock);
jbd2_journal_free_transaction(new_transaction);
return -EROFS;
}
/*
* Wait on the journal's transaction barrier if necessary. Specifically
* we allow reserved handles to proceed because otherwise commit could
* deadlock on page writeback not being able to complete.
*/
if (!handle->h_reserved && journal->j_barrier_count) {
read_unlock(&journal->j_state_lock);
wait_event(journal->j_wait_transaction_locked,
journal->j_barrier_count == 0);
goto repeat;
}
if (!journal->j_running_transaction) {
read_unlock(&journal->j_state_lock);
if (!new_transaction)
goto alloc_transaction;
write_lock(&journal->j_state_lock);
if (!journal->j_running_transaction &&
(handle->h_reserved || !journal->j_barrier_count)) {
jbd2_get_transaction(journal, new_transaction);
new_transaction = NULL;
}
write_unlock(&journal->j_state_lock);
goto repeat;
}
transaction = journal->j_running_transaction;
if (!handle->h_reserved) {
/* We may have dropped j_state_lock - restart in that case */
if (add_transaction_credits(journal, blocks, rsv_blocks))
goto repeat;
} else {
/*
* We have handle reserved so we are allowed to join T_LOCKED
* transaction and we don't have to check for transaction size
* and journal space.
*/
sub_reserved_credits(journal, blocks);
handle->h_reserved = 0;
}
/* OK, account for the buffers that this operation expects to
* use and add the handle to the running transaction.
*/
update_t_max_wait(transaction, ts);
handle->h_transaction = transaction;
handle->h_requested_credits = blocks;
handle->h_start_jiffies = jiffies;
atomic_inc(&transaction->t_updates);
atomic_inc(&transaction->t_handle_count);
jbd_debug(4, "Handle %p given %d credits (total %d, free %lu)\n",
handle, blocks,
atomic_read(&transaction->t_outstanding_credits),
jbd2_log_space_left(journal));
read_unlock(&journal->j_state_lock);
current->journal_info = handle;
rwsem_acquire_read(&journal->j_trans_commit_map, 0, 0, _THIS_IP_);
jbd2_journal_free_transaction(new_transaction);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jan kara | jan kara | 252 | 51.53% | 4 | 22.22% |
dave kleikamp | dave kleikamp | 102 | 20.86% | 1 | 5.56% |
theodore tso | theodore tso | 78 | 15.95% | 8 | 44.44% |
lukas czerner | lukas czerner | 37 | 7.57% | 1 | 5.56% |
michal hocko | michal hocko | 15 | 3.07% | 1 | 5.56% |
johann lombardi | johann lombardi | 2 | 0.41% | 1 | 5.56% |
tao ma | tao ma | 2 | 0.41% | 1 | 5.56% |
yongqiang yang | yongqiang yang | 1 | 0.20% | 1 | 5.56% |
| Total | 489 | 100.00% | 18 | 100.00% |
/* Allocate a new handle. This should probably be in a slab... */
static handle_t *new_handle(int nblocks)
{
handle_t *handle = jbd2_alloc_handle(GFP_NOFS);
if (!handle)
return NULL;
handle->h_buffer_credits = nblocks;
handle->h_ref = 1;
return handle;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dave kleikamp | dave kleikamp | 41 | 97.62% | 1 | 50.00% |
mingming cao | mingming cao | 1 | 2.38% | 1 | 50.00% |
| Total | 42 | 100.00% | 2 | 100.00% |
/**
* handle_t *jbd2_journal_start() - Obtain a new handle.
* @journal: Journal to start transaction on.
* @nblocks: number of block buffer we might modify
*
* We make sure that the transaction can guarantee at least nblocks of
* modified buffers in the log. We block until the log can guarantee
* that much space. Additionally, if rsv_blocks > 0, we also create another
* handle with rsv_blocks reserved blocks in the journal. This handle is
* is stored in h_rsv_handle. It is not attached to any particular transaction
* and thus doesn't block transaction commit. If the caller uses this reserved
* handle, it has to set h_rsv_handle to NULL as otherwise jbd2_journal_stop()
* on the parent handle will dispose the reserved one. Reserved handle has to
* be converted to a normal handle using jbd2_journal_start_reserved() before
* it can be used.
*
* Return a pointer to a newly allocated handle, or an ERR_PTR() value
* on failure.
*/
handle_t *jbd2__journal_start(journal_t *journal, int nblocks, int rsv_blocks,
gfp_t gfp_mask, unsigned int type,
unsigned int line_no)
{
handle_t *handle = journal_current_handle();
int err;
if (!journal)
return ERR_PTR(-EROFS);
if (handle) {
J_ASSERT(handle->h_transaction->t_journal == journal);
handle->h_ref++;
return handle;
}
handle = new_handle(nblocks);
if (!handle)
return ERR_PTR(-ENOMEM);
if (rsv_blocks) {
handle_t *rsv_handle;
rsv_handle = new_handle(rsv_blocks);
if (!rsv_handle) {
jbd2_free_handle(handle);
return ERR_PTR(-ENOMEM);
}
rsv_handle->h_reserved = 1;
rsv_handle->h_journal = journal;
handle->h_rsv_handle = rsv_handle;
}
err = start_this_handle(journal, handle, gfp_mask);
if (err < 0) {
if (handle->h_rsv_handle)
jbd2_free_handle(handle->h_rsv_handle);
jbd2_free_handle(handle);
return ERR_PTR(err);
}
handle->h_type = type;
handle->h_line_no = line_no;
trace_jbd2_handle_start(journal->j_fs_dev->bd_dev,
handle->h_transaction->t_tid, type,
line_no, nblocks);
return handle;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dave kleikamp | dave kleikamp | 106 | 46.90% | 1 | 14.29% |
jan kara | jan kara | 70 | 30.97% | 1 | 14.29% |
theodore tso | theodore tso | 46 | 20.35% | 2 | 28.57% |
dmitriy monakhov | dmitriy monakhov | 2 | 0.88% | 1 | 14.29% |
mingming cao | mingming cao | 1 | 0.44% | 1 | 14.29% |
dan carpenter | dan carpenter | 1 | 0.44% | 1 | 14.29% |
| Total | 226 | 100.00% | 7 | 100.00% |
EXPORT_SYMBOL(jbd2__journal_start);
handle_t *jbd2_journal_start(journal_t *journal, int nblocks)
{
return jbd2__journal_start(journal, nblocks, 0, GFP_NOFS, 0, 0);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
theodore tso | theodore tso | 27 | 93.10% | 2 | 66.67% |
jan kara | jan kara | 2 | 6.90% | 1 | 33.33% |
| Total | 29 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL(jbd2_journal_start);
void jbd2_journal_free_reserved(handle_t *handle)
{
journal_t *journal = handle->h_journal;
WARN_ON(!handle->h_reserved);
sub_reserved_credits(journal, handle->h_buffer_credits);
jbd2_free_handle(handle);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jan kara | jan kara | 39 | 100.00% | 1 | 100.00% |
| Total | 39 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL(jbd2_journal_free_reserved);
/**
* int jbd2_journal_start_reserved(handle_t *handle) - start reserved handle
* @handle: handle to start
*
* Start handle that has been previously reserved with jbd2_journal_reserve().
* This attaches @handle to the running transaction (or creates one if there's
* not transaction running). Unlike jbd2_journal_start() this function cannot
* block on journal commit, checkpointing, or similar stuff. It can block on
* memory allocation or frozen journal though.
*
* Return 0 on success, non-zero on error - handle is freed in that case.
*/
int jbd2_journal_start_reserved(handle_t *handle, unsigned int type,
unsigned int line_no)
{
journal_t *journal = handle->h_journal;
int ret = -EIO;
if (WARN_ON(!handle->h_reserved)) {
/* Someone passed in normal handle? Just stop it. */
jbd2_journal_stop(handle);
return ret;
}
/*
* Usefulness of mixing of reserved and unreserved handles is
* questionable. So far nobody seems to need it so just error out.
*/
if (WARN_ON(current->journal_info)) {
jbd2_journal_free_reserved(handle);
return ret;
}
handle->h_journal = NULL;
/*
* GFP_NOFS is here because callers are likely from writeback or
* similarly constrained call sites
*/
ret = start_this_handle(journal, handle, GFP_NOFS);
if (ret < 0) {
jbd2_journal_free_reserved(handle);
return ret;
}
handle->h_type = type;
handle->h_line_no = line_no;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jan kara | jan kara | 115 | 95.04% | 1 | 50.00% |
dan carpenter | dan carpenter | 6 | 4.96% | 1 | 50.00% |
| Total | 121 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(jbd2_journal_start_reserved);
/**
* int jbd2_journal_extend() - extend buffer credits.
* @handle: handle to 'extend'
* @nblocks: nr blocks to try to extend by.
*
* Some transactions, such as large extends and truncates, can be done
* atomically all at once or in several stages. The operation requests
* a credit for a number of buffer modifications in advance, but can
* extend its credit if it needs more.
*
* jbd2_journal_extend tries to give the running handle more buffer credits.
* It does not guarantee that allocation - this is a best-effort only.
* The calling process MUST be able to deal cleanly with a failure to
* extend here.
*
* Return 0 on success, non-zero on failure.
*
* return code < 0 implies an error
* return code > 0 implies normal transaction-full status.
*/
int jbd2_journal_extend(handle_t *handle, int nblocks)
{
transaction_t *transaction = handle->h_transaction;
journal_t *journal;
int result;
int wanted;
if (is_handle_aborted(handle))
return -EROFS;
journal = transaction->t_journal;
result = 1;
read_lock(&journal->j_state_lock);
/* Don't extend a locked-down transaction! */
if (transaction->t_state != T_RUNNING) {
jbd_debug(3, "denied handle %p %d blocks: "
"transaction not running\n", handle, nblocks);
goto error_out;
}
spin_lock(&transaction->t_handle_lock);
wanted = atomic_add_return(nblocks,
&transaction->t_outstanding_credits);
if (wanted > journal->j_max_transaction_buffers) {
jbd_debug(3, "denied handle %p %d blocks: "
"transaction too large\n", handle, nblocks);
atomic_sub(nblocks, &transaction->t_outstanding_credits);
goto unlock;
}
if (wanted + (wanted >> JBD2_CONTROL_BLOCKS_SHIFT) >
jbd2_log_space_left(journal)) {
jbd_debug(3, "denied handle %p %d blocks: "
"insufficient log space\n", handle, nblocks);
atomic_sub(nblocks, &transaction->t_outstanding_credits);
goto unlock;
}
trace_jbd2_handle_extend(journal->j_fs_dev->bd_dev,
transaction->t_tid,
handle->h_type, handle->h_line_no,
handle->h_buffer_credits,
nblocks);
handle->h_buffer_credits += nblocks;
handle->h_requested_credits += nblocks;
result = 0;
jbd_debug(3, "extended handle %p by %d\n", handle, nblocks);
unlock:
spin_unlock(&transaction->t_handle_lock);
error_out:
read_unlock(&journal->j_state_lock);
return result;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dave kleikamp | dave kleikamp | 179 | 69.11% | 1 | 12.50% |
theodore tso | theodore tso | 49 | 18.92% | 4 | 50.00% |
jan kara | jan kara | 30 | 11.58% | 2 | 25.00% |
mingming cao | mingming cao | 1 | 0.39% | 1 | 12.50% |
| Total | 259 | 100.00% | 8 | 100.00% |
/**
* int jbd2_journal_restart() - restart a handle .
* @handle: handle to restart
* @nblocks: nr credits requested
*
* Restart a handle for a multi-transaction filesystem
* operation.
*
* If the jbd2_journal_extend() call above fails to grant new buffer credits
* to a running handle, a call to jbd2_journal_restart will commit the
* handle's transaction so far and reattach the handle to a new
* transaction capable of guaranteeing the requested number of
* credits. We preserve reserved handle if there's any attached to the
* passed in handle.
*/
int jbd2__journal_restart(handle_t *handle, int nblocks, gfp_t gfp_mask)
{
transaction_t *transaction = handle->h_transaction;
journal_t *journal;
tid_t tid;
int need_to_start, 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;
journal = transaction->t_journal;
/*
* First unlink the handle from its current transaction, and start the
* commit on that.
*/
J_ASSERT(atomic_read(&transaction->t_updates) > 0);
J_ASSERT(journal_current_handle() == handle);
read_lock(&journal->j_state_lock);
spin_lock(&transaction->t_handle_lock);
atomic_sub(handle->h_buffer_credits,
&transaction->t_outstanding_credits);
if (handle->h_rsv_handle) {
sub_reserved_credits(journal,
handle->h_rsv_handle->h_buffer_credits);
}
if (atomic_dec_and_test(&transaction->t_updates))
wake_up(&journal->j_wait_updates);
tid = transaction->t_tid;
spin_unlock(&transaction->t_handle_lock);
handle->h_transaction = NULL;
current->journal_info = NULL;
jbd_debug(2, "restarting handle %p\n", handle);
need_to_start = !tid_geq(journal->j_commit_request, tid);
read_unlock(&journal->j_state_lock);
if (need_to_start)
jbd2_log_start_commit(journal, tid);
rwsem_release(&journal->j_trans_commit_map, 1, _THIS_IP_);
handle->h_buffer_credits = nblocks;
ret = start_this_handle(journal, handle, gfp_mask);
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dave kleikamp | dave kleikamp | 134 | 56.54% | 1 | 9.09% |
theodore tso | theodore tso | 71 | 29.96% | 6 | 54.55% |
jan kara | jan kara | 31 | 13.08% | 3 | 27.27% |
dan carpenter | dan carpenter | 1 | 0.42% | 1 | 9.09% |
| Total | 237 | 100.00% | 11 | 100.00% |
EXPORT_SYMBOL(jbd2__journal_restart);
int jbd2_journal_restart(handle_t *handle, int nblocks)
{
return jbd2__journal_restart(handle, nblocks, GFP_NOFS);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
theodore tso | theodore tso | 22 | 100.00% | 1 | 100.00% |
| Total | 22 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL(jbd2_journal_restart);
/**
* void jbd2_journal_lock_updates () - establish a transaction barrier.
* @journal: Journal to establish a barrier on.
*
* This locks out any further updates from being started, and blocks
* until all existing updates have completed, returning only once the
* journal is in a quiescent state with no updates running.
*
* The journal lock should not be held on entry.
*/
void jbd2_journal_lock_updates(journal_t *journal)
{
DEFINE_WAIT(wait);
jbd2_might_wait_for_commit(journal);
write_lock(&journal->j_state_lock);
++journal->j_barrier_count;
/* Wait until there are no reserved handles */
if (atomic_read(&journal->j_reserved_credits)) {
write_unlock(&journal->j_state_lock);
wait_event(journal->j_wait_reserved,
atomic_read(&journal->j_reserved_credits) == 0);
write_lock(&journal->j_state_lock);
}
/* Wait until there are no running updates */
while (1) {
transaction_t *transaction = journal->j_running_transaction;
if (!transaction)
break;
spin_lock(&transaction->t_handle_lock);
prepare_to_wait(&journal->j_wait_updates, &wait,
TASK_UNINTERRUPTIBLE);
if (!atomic_read(&transaction->t_updates)) {
spin_unlock(&transaction->t_handle_lock);
finish_wait(&journal->j_wait_updates, &wait);
break;
}
spin_unlock(&transaction->t_handle_lock);
write_unlock(&journal->j_state_lock);
schedule();
finish_wait(&journal->j_wait_updates, &wait);
write_lock(&journal->j_state_lock);
}
write_unlock(&journal->j_state_lock);
/*
* We have now established a barrier against other normal updates, but
* we also need to barrier against other jbd2_journal_lock_updates() calls
* to make sure that we serialise special journal-locked operations
* too.
*/
mutex_lock(&journal->j_barrier);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dave kleikamp | dave kleikamp | 131 | 62.98% | 1 | 14.29% |
jan kara | jan kara | 67 | 32.21% | 3 | 42.86% |
theodore tso | theodore tso | 8 | 3.85% | 2 | 28.57% |
mingming cao | mingming cao | 2 | 0.96% | 1 | 14.29% |
| Total | 208 | 100.00% | 7 | 100.00% |
/**
* void jbd2_journal_unlock_updates (journal_t* journal) - release barrier
* @journal: Journal to release the barrier on.
*
* Release a transaction barrier obtained with jbd2_journal_lock_updates().
*
* Should be called without the journal lock held.
*/
void jbd2_journal_unlock_updates (journal_t *journal)
{
J_ASSERT(journal->j_barrier_count != 0);
mutex_unlock(&journal->j_barrier);
write_lock(&journal->j_state_lock);
--journal->j_barrier_count;
write_unlock(&journal->j_state_lock);
wake_up(&journal->j_wait_transaction_locked);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dave kleikamp | dave kleikamp | 52 | 94.55% | 1 | 33.33% |
theodore tso | theodore tso | 2 | 3.64% | 1 | 33.33% |
mingming cao | mingming cao | 1 | 1.82% | 1 | 33.33% |
| Total | 55 | 100.00% | 3 | 100.00% |
static void warn_dirty_buffer(struct buffer_head *bh)
{
printk(KERN_WARNING
"JBD2: Spotted dirty metadata buffer (dev = %pg, blocknr = %llu). "
"There's a risk of filesystem corruption in case of system "
"crash.\n",
bh->b_bdev, (unsigned long long)bh->b_blocknr);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jan kara | jan kara | 18 | 56.25% | 1 | 33.33% |
dave kleikamp | dave kleikamp | 13 | 40.62% | 1 | 33.33% |
dmitriy monakhov | dmitriy monakhov | 1 | 3.12% | 1 | 33.33% |
| Total | 32 | 100.00% | 3 | 100.00% |
/* Call t_frozen trigger and copy buffer data into jh->b_frozen_data. */
static void jbd2_freeze_jh_data(struct journal_head *jh)
{
struct page *page;
int offset;
char *source;
struct buffer_head *bh = jh2bh(jh);
J_EXPECT_JH(jh, buffer_uptodate(bh), "Possible IO failure.\n");
page = bh->b_page;
offset = offset_in_page(bh->b_data);
source = kmap_atomic(page);
/* Fire data frozen trigger just before we copy the data */
jbd2_buffer_frozen_trigger(jh, source + offset, jh->b_triggers);
memcpy(jh->b_frozen_data, source + offset, bh->b_size);
kunmap_atomic(source);
/*
* Now that the frozen data is saved off, we need to store any matching
* triggers.
*/
jh->b_frozen_triggers = jh->b_triggers;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jan kara | jan kara | 110 | 100.00% | 1 | 100.00% |
| Total | 110 | 100.00% | 1 | 100.00% |
/*
* If the buffer is already part of the current transaction, then there
* is nothing we need to do. If it is already part of a prior
* transaction which we are still committing to disk, then we need to
* make sure that we do not overwrite the old copy: we do copy-out to
* preserve the copy going to disk. We also account the buffer against
* the handle's metadata buffer credits (unless the buffer is already
* part of the transaction, that is).
*
*/
static int
do_get_write_access(handle_t *handle, struct journal_head *jh,
int force_copy)
{
struct buffer_head *bh;
transaction_t *transaction = handle->h_transaction;
journal_t *journal;
int error;
char *frozen_buffer = NULL;
unsigned long start_lock, time_lock;
if (is_handle_aborted(handle))
return -EROFS;
journal = transaction->t_journal;
jbd_debug(5, "journal_head %p, force_copy %d\n", jh, force_copy);
JBUFFER_TRACE(jh, "entry");
repeat:
bh = jh2bh(jh);
/* @@@ Need to check for errors here at some point. */
start_lock = jiffies;
lock_buffer(bh);
jbd_lock_bh_state(bh);
/* If it takes too long to lock the buffer, trace it */
time_lock = jbd2_time_diff(start_lock, jiffies);
if (time_lock > HZ/10)
trace_jbd2_lock_buffer_stall(bh->b_bdev->bd_dev,
jiffies_to_msecs(time_lock