aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jbd2/transaction.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2008-07-11 19:27:31 -0400
committerTheodore Ts'o <tytso@mit.edu>2008-07-11 19:27:31 -0400
commitc851ed540173736e60d48b53b91a16ea5c903896 (patch)
tree828fe0d71b7f18dc170090dbb2fb5ac9deae4ee0 /fs/jbd2/transaction.c
parentf4c0a0fdfae708f7aa438c27a380ed4071294e11 (diff)
jbd2: Implement data=ordered mode handling via inodes
This patch adds necessary framework into JBD2 to be able to track inodes with each transaction and write-out their dirty data during transaction commit time. This new ordered mode brings all sorts of advantages such as possibility to get rid of journal heads and buffer heads for data buffers in ordered mode, better ordering of writes on transaction commit, simplification of some JBD code, no more anonymous pages when truncate of data being committed happens. Also with this new ordered mode, delayed allocation on ordered mode is much simpler. Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/jbd2/transaction.c')
-rw-r--r--fs/jbd2/transaction.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index ba620c4493d2..98b596d23705 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -51,6 +51,7 @@ jbd2_get_transaction(journal_t *journal, transaction_t *transaction)
51 transaction->t_tid = journal->j_transaction_sequence++; 51 transaction->t_tid = journal->j_transaction_sequence++;
52 transaction->t_expires = jiffies + journal->j_commit_interval; 52 transaction->t_expires = jiffies + journal->j_commit_interval;
53 spin_lock_init(&transaction->t_handle_lock); 53 spin_lock_init(&transaction->t_handle_lock);
54 INIT_LIST_HEAD(&transaction->t_inode_list);
54 55
55 /* Set up the commit timer for the new transaction. */ 56 /* Set up the commit timer for the new transaction. */
56 journal->j_commit_timer.expires = round_jiffies(transaction->t_expires); 57 journal->j_commit_timer.expires = round_jiffies(transaction->t_expires);
@@ -2195,3 +2196,88 @@ void jbd2_journal_refile_buffer(journal_t *journal, struct journal_head *jh)
2195 spin_unlock(&journal->j_list_lock); 2196 spin_unlock(&journal->j_list_lock);
2196 __brelse(bh); 2197 __brelse(bh);
2197} 2198}
2199
2200/*
2201 * File inode in the inode list of the handle's transaction
2202 */
2203int jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *jinode)
2204{
2205 transaction_t *transaction = handle->h_transaction;
2206 journal_t *journal = transaction->t_journal;
2207
2208 if (is_handle_aborted(handle))
2209 return -EIO;
2210
2211 jbd_debug(4, "Adding inode %lu, tid:%d\n", jinode->i_vfs_inode->i_ino,
2212 transaction->t_tid);
2213
2214 /*
2215 * First check whether inode isn't already on the transaction's
2216 * lists without taking the lock. Note that this check is safe
2217 * without the lock as we cannot race with somebody removing inode
2218 * from the transaction. The reason is that we remove inode from the
2219 * transaction only in journal_release_jbd_inode() and when we commit
2220 * the transaction. We are guarded from the first case by holding
2221 * a reference to the inode. We are safe against the second case
2222 * because if jinode->i_transaction == transaction, commit code
2223 * cannot touch the transaction because we hold reference to it,
2224 * and if jinode->i_next_transaction == transaction, commit code
2225 * will only file the inode where we want it.
2226 */
2227 if (jinode->i_transaction == transaction ||
2228 jinode->i_next_transaction == transaction)
2229 return 0;
2230
2231 spin_lock(&journal->j_list_lock);
2232
2233 if (jinode->i_transaction == transaction ||
2234 jinode->i_next_transaction == transaction)
2235 goto done;
2236
2237 /* On some different transaction's list - should be
2238 * the committing one */
2239 if (jinode->i_transaction) {
2240 J_ASSERT(jinode->i_next_transaction == NULL);
2241 J_ASSERT(jinode->i_transaction ==
2242 journal->j_committing_transaction);
2243 jinode->i_next_transaction = transaction;
2244 goto done;
2245 }
2246 /* Not on any transaction list... */
2247 J_ASSERT(!jinode->i_next_transaction);
2248 jinode->i_transaction = transaction;
2249 list_add(&jinode->i_list, &transaction->t_inode_list);
2250done:
2251 spin_unlock(&journal->j_list_lock);
2252
2253 return 0;
2254}
2255
2256/*
2257 * This function must be called when inode is journaled in ordered mode
2258 * before truncation happens. It starts writeout of truncated part in
2259 * case it is in the committing transaction so that we stand to ordered
2260 * mode consistency guarantees.
2261 */
2262int jbd2_journal_begin_ordered_truncate(struct jbd2_inode *inode,
2263 loff_t new_size)
2264{
2265 journal_t *journal;
2266 transaction_t *commit_trans;
2267 int ret = 0;
2268
2269 if (!inode->i_transaction && !inode->i_next_transaction)
2270 goto out;
2271 journal = inode->i_transaction->t_journal;
2272 spin_lock(&journal->j_state_lock);
2273 commit_trans = journal->j_committing_transaction;
2274 spin_unlock(&journal->j_state_lock);
2275 if (inode->i_transaction == commit_trans) {
2276 ret = filemap_fdatawrite_range(inode->i_vfs_inode->i_mapping,
2277 new_size, LLONG_MAX);
2278 if (ret)
2279 jbd2_journal_abort(journal, ret);
2280 }
2281out:
2282 return ret;
2283}