summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2018-12-03 23:16:07 -0500
committerTheodore Ts'o <tytso@mit.edu>2018-12-03 23:16:07 -0500
commit96f1e097457506f215adfe3c47aacc15a88f6dd7 (patch)
tree60a2865f4e0f909fdea3b069ba80534148200ab0 /fs
parentfb265c9cb49e2074ddcdd4de99728aefdd3b3592 (diff)
jbd2: avoid long hold times of j_state_lock while committing a transaction
We can hold j_state_lock for writing at the beginning of jbd2_journal_commit_transaction() for a rather long time (reportedly for 30 ms) due cleaning revoke bits of all revoked buffers under it. The handling of revoke tables as well as cleaning of t_reserved_list, and checkpoint lists does not need j_state_lock for anything. It is only needed to prevent new handles from joining the transaction. Generally T_LOCKED transaction state prevents new handles from joining the transaction - except for reserved handles which have to allowed to join while we wait for other handles to complete. To prevent reserved handles from joining the transaction while cleaning up lists, add new transaction state T_SWITCH and watch for it when starting reserved handles. With this we can just drop the lock for operations that don't need it. Reported-and-tested-by: Adrian Hunter <adrian.hunter@intel.com> Suggested-by: "Theodore Y. Ts'o" <tytso@mit.edu> Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'fs')
-rw-r--r--fs/jbd2/commit.c3
-rw-r--r--fs/jbd2/transaction.c43
2 files changed, 41 insertions, 5 deletions
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 150cc030b4d7..2eb55c3361a8 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -439,6 +439,8 @@ void jbd2_journal_commit_transaction(journal_t *journal)
439 finish_wait(&journal->j_wait_updates, &wait); 439 finish_wait(&journal->j_wait_updates, &wait);
440 } 440 }
441 spin_unlock(&commit_transaction->t_handle_lock); 441 spin_unlock(&commit_transaction->t_handle_lock);
442 commit_transaction->t_state = T_SWITCH;
443 write_unlock(&journal->j_state_lock);
442 444
443 J_ASSERT (atomic_read(&commit_transaction->t_outstanding_credits) <= 445 J_ASSERT (atomic_read(&commit_transaction->t_outstanding_credits) <=
444 journal->j_max_transaction_buffers); 446 journal->j_max_transaction_buffers);
@@ -505,6 +507,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
505 atomic_sub(atomic_read(&journal->j_reserved_credits), 507 atomic_sub(atomic_read(&journal->j_reserved_credits),
506 &commit_transaction->t_outstanding_credits); 508 &commit_transaction->t_outstanding_credits);
507 509
510 write_lock(&journal->j_state_lock);
508 trace_jbd2_commit_flushing(journal, commit_transaction); 511 trace_jbd2_commit_flushing(journal, commit_transaction);
509 stats.run.rs_flushing = jiffies; 512 stats.run.rs_flushing = jiffies;
510 stats.run.rs_locked = jbd2_time_diff(stats.run.rs_locked, 513 stats.run.rs_locked = jbd2_time_diff(stats.run.rs_locked,
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index c0b66a7a795b..116d8251fbff 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -138,9 +138,9 @@ static inline void update_t_max_wait(transaction_t *transaction,
138} 138}
139 139
140/* 140/*
141 * Wait until running transaction passes T_LOCKED state. Also starts the commit 141 * Wait until running transaction passes to T_FLUSH state and new transaction
142 * if needed. The function expects running transaction to exist and releases 142 * can thus be started. Also starts the commit if needed. The function expects
143 * j_state_lock. 143 * running transaction to exist and releases j_state_lock.
144 */ 144 */
145static void wait_transaction_locked(journal_t *journal) 145static void wait_transaction_locked(journal_t *journal)
146 __releases(journal->j_state_lock) 146 __releases(journal->j_state_lock)
@@ -160,6 +160,32 @@ static void wait_transaction_locked(journal_t *journal)
160 finish_wait(&journal->j_wait_transaction_locked, &wait); 160 finish_wait(&journal->j_wait_transaction_locked, &wait);
161} 161}
162 162
163/*
164 * Wait until running transaction transitions from T_SWITCH to T_FLUSH
165 * state and new transaction can thus be started. The function releases
166 * j_state_lock.
167 */
168static void wait_transaction_switching(journal_t *journal)
169 __releases(journal->j_state_lock)
170{
171 DEFINE_WAIT(wait);
172
173 if (WARN_ON(!journal->j_running_transaction ||
174 journal->j_running_transaction->t_state != T_SWITCH))
175 return;
176 prepare_to_wait(&journal->j_wait_transaction_locked, &wait,
177 TASK_UNINTERRUPTIBLE);
178 read_unlock(&journal->j_state_lock);
179 /*
180 * We don't call jbd2_might_wait_for_commit() here as there's no
181 * waiting for outstanding handles happening anymore in T_SWITCH state
182 * and handling of reserved handles actually relies on that for
183 * correctness.
184 */
185 schedule();
186 finish_wait(&journal->j_wait_transaction_locked, &wait);
187}
188
163static void sub_reserved_credits(journal_t *journal, int blocks) 189static void sub_reserved_credits(journal_t *journal, int blocks)
164{ 190{
165 atomic_sub(blocks, &journal->j_reserved_credits); 191 atomic_sub(blocks, &journal->j_reserved_credits);
@@ -183,7 +209,8 @@ static int add_transaction_credits(journal_t *journal, int blocks,
183 * If the current transaction is locked down for commit, wait 209 * If the current transaction is locked down for commit, wait
184 * for the lock to be released. 210 * for the lock to be released.
185 */ 211 */
186 if (t->t_state == T_LOCKED) { 212 if (t->t_state != T_RUNNING) {
213 WARN_ON_ONCE(t->t_state >= T_FLUSH);
187 wait_transaction_locked(journal); 214 wait_transaction_locked(journal);
188 return 1; 215 return 1;
189 } 216 }
@@ -360,8 +387,14 @@ repeat:
360 /* 387 /*
361 * We have handle reserved so we are allowed to join T_LOCKED 388 * We have handle reserved so we are allowed to join T_LOCKED
362 * transaction and we don't have to check for transaction size 389 * transaction and we don't have to check for transaction size
363 * and journal space. 390 * and journal space. But we still have to wait while running
391 * transaction is being switched to a committing one as it
392 * won't wait for any handles anymore.
364 */ 393 */
394 if (transaction->t_state == T_SWITCH) {
395 wait_transaction_switching(journal);
396 goto repeat;
397 }
365 sub_reserved_credits(journal, blocks); 398 sub_reserved_credits(journal, blocks);
366 handle->h_reserved = 0; 399 handle->h_reserved = 0;
367 } 400 }