Skip to content

Commit a51dca9

Browse files
committed
jbd2: Use atomic variables to avoid taking t_handle_lock in jbd2_journal_stop
By using an atomic_t for t_updates and t_outstanding credits, this should allow us to not need to take transaction t_handle_lock in jbd2_journal_stop(). Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
1 parent 8b67f04 commit a51dca9

File tree

4 files changed

+51
-41
lines changed

4 files changed

+51
-41
lines changed

fs/jbd2/checkpoint.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -775,7 +775,7 @@ void __jbd2_journal_drop_transaction(journal_t *journal, transaction_t *transact
775775
J_ASSERT(transaction->t_log_list == NULL);
776776
J_ASSERT(transaction->t_checkpoint_list == NULL);
777777
J_ASSERT(transaction->t_checkpoint_io_list == NULL);
778-
J_ASSERT(transaction->t_updates == 0);
778+
J_ASSERT(atomic_read(&transaction->t_updates) == 0);
779779
J_ASSERT(journal->j_committing_transaction != transaction);
780780
J_ASSERT(journal->j_running_transaction != transaction);
781781

fs/jbd2/commit.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -417,12 +417,12 @@ void jbd2_journal_commit_transaction(journal_t *journal)
417417
stats.run.rs_locked);
418418

419419
spin_lock(&commit_transaction->t_handle_lock);
420-
while (commit_transaction->t_updates) {
420+
while (atomic_read(&commit_transaction->t_updates)) {
421421
DEFINE_WAIT(wait);
422422

423423
prepare_to_wait(&journal->j_wait_updates, &wait,
424424
TASK_UNINTERRUPTIBLE);
425-
if (commit_transaction->t_updates) {
425+
if (atomic_read(&commit_transaction->t_updates)) {
426426
spin_unlock(&commit_transaction->t_handle_lock);
427427
spin_unlock(&journal->j_state_lock);
428428
schedule();
@@ -433,7 +433,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
433433
}
434434
spin_unlock(&commit_transaction->t_handle_lock);
435435

436-
J_ASSERT (commit_transaction->t_outstanding_credits <=
436+
J_ASSERT (atomic_read(&commit_transaction->t_outstanding_credits) <=
437437
journal->j_max_transaction_buffers);
438438

439439
/*
@@ -527,11 +527,12 @@ void jbd2_journal_commit_transaction(journal_t *journal)
527527
stats.run.rs_logging = jiffies;
528528
stats.run.rs_flushing = jbd2_time_diff(stats.run.rs_flushing,
529529
stats.run.rs_logging);
530-
stats.run.rs_blocks = commit_transaction->t_outstanding_credits;
530+
stats.run.rs_blocks =
531+
atomic_read(&commit_transaction->t_outstanding_credits);
531532
stats.run.rs_blocks_logged = 0;
532533

533534
J_ASSERT(commit_transaction->t_nr_buffers <=
534-
commit_transaction->t_outstanding_credits);
535+
atomic_read(&commit_transaction->t_outstanding_credits));
535536

536537
err = 0;
537538
descriptor = NULL;
@@ -616,7 +617,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
616617
* the free space in the log, but this counter is changed
617618
* by jbd2_journal_next_log_block() also.
618619
*/
619-
commit_transaction->t_outstanding_credits--;
620+
atomic_dec(&commit_transaction->t_outstanding_credits);
620621

621622
/* Bump b_count to prevent truncate from stumbling over
622623
the shadowed buffer! @@@ This can go if we ever get

fs/jbd2/transaction.c

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ jbd2_get_transaction(journal_t *journal, transaction_t *transaction)
5555
transaction->t_tid = journal->j_transaction_sequence++;
5656
transaction->t_expires = jiffies + journal->j_commit_interval;
5757
spin_lock_init(&transaction->t_handle_lock);
58+
atomic_set(&transaction->t_updates, 0);
59+
atomic_set(&transaction->t_outstanding_credits, 0);
5860
INIT_LIST_HEAD(&transaction->t_inode_list);
5961
INIT_LIST_HEAD(&transaction->t_private_list);
6062

@@ -177,7 +179,7 @@ static int start_this_handle(journal_t *journal, handle_t *handle,
177179
* checkpoint to free some more log space.
178180
*/
179181
spin_lock(&transaction->t_handle_lock);
180-
needed = transaction->t_outstanding_credits + nblocks;
182+
needed = atomic_read(&transaction->t_outstanding_credits) + nblocks;
181183

182184
if (needed > journal->j_max_transaction_buffers) {
183185
/*
@@ -240,11 +242,12 @@ static int start_this_handle(journal_t *journal, handle_t *handle,
240242
}
241243

242244
handle->h_transaction = transaction;
243-
transaction->t_outstanding_credits += nblocks;
244-
transaction->t_updates++;
245+
atomic_add(nblocks, &transaction->t_outstanding_credits);
246+
atomic_inc(&transaction->t_updates);
245247
transaction->t_handle_count++;
246248
jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n",
247-
handle, nblocks, transaction->t_outstanding_credits,
249+
handle, nblocks,
250+
atomic_read(&transaction->t_outstanding_credits),
248251
__jbd2_log_space_left(journal));
249252
spin_unlock(&transaction->t_handle_lock);
250253
spin_unlock(&journal->j_state_lock);
@@ -369,7 +372,7 @@ int jbd2_journal_extend(handle_t *handle, int nblocks)
369372
}
370373

371374
spin_lock(&transaction->t_handle_lock);
372-
wanted = transaction->t_outstanding_credits + nblocks;
375+
wanted = atomic_read(&transaction->t_outstanding_credits) + nblocks;
373376

374377
if (wanted > journal->j_max_transaction_buffers) {
375378
jbd_debug(3, "denied handle %p %d blocks: "
@@ -384,7 +387,7 @@ int jbd2_journal_extend(handle_t *handle, int nblocks)
384387
}
385388

386389
handle->h_buffer_credits += nblocks;
387-
transaction->t_outstanding_credits += nblocks;
390+
atomic_add(nblocks, &transaction->t_outstanding_credits);
388391
result = 0;
389392

390393
jbd_debug(3, "extended handle %p by %d\n", handle, nblocks);
@@ -426,15 +429,14 @@ int jbd2__journal_restart(handle_t *handle, int nblocks, int gfp_mask)
426429
* First unlink the handle from its current transaction, and start the
427430
* commit on that.
428431
*/
429-
J_ASSERT(transaction->t_updates > 0);
432+
J_ASSERT(atomic_read(&transaction->t_updates) > 0);
430433
J_ASSERT(journal_current_handle() == handle);
431434

432435
spin_lock(&journal->j_state_lock);
433436
spin_lock(&transaction->t_handle_lock);
434-
transaction->t_outstanding_credits -= handle->h_buffer_credits;
435-
transaction->t_updates--;
436-
437-
if (!transaction->t_updates)
437+
atomic_sub(handle->h_buffer_credits,
438+
&transaction->t_outstanding_credits);
439+
if (atomic_dec_and_test(&transaction->t_updates))
438440
wake_up(&journal->j_wait_updates);
439441
spin_unlock(&transaction->t_handle_lock);
440442

@@ -481,7 +483,7 @@ void jbd2_journal_lock_updates(journal_t *journal)
481483
break;
482484

483485
spin_lock(&transaction->t_handle_lock);
484-
if (!transaction->t_updates) {
486+
if (!atomic_read(&transaction->t_updates)) {
485487
spin_unlock(&transaction->t_handle_lock);
486488
break;
487489
}
@@ -1258,15 +1260,16 @@ int jbd2_journal_stop(handle_t *handle)
12581260
{
12591261
transaction_t *transaction = handle->h_transaction;
12601262
journal_t *journal = transaction->t_journal;
1261-
int err;
1263+
int err, wait_for_commit = 0;
1264+
tid_t tid;
12621265
pid_t pid;
12631266

12641267
J_ASSERT(journal_current_handle() == handle);
12651268

12661269
if (is_handle_aborted(handle))
12671270
err = -EIO;
12681271
else {
1269-
J_ASSERT(transaction->t_updates > 0);
1272+
J_ASSERT(atomic_read(&transaction->t_updates) > 0);
12701273
err = 0;
12711274
}
12721275

@@ -1334,14 +1337,8 @@ int jbd2_journal_stop(handle_t *handle)
13341337
if (handle->h_sync)
13351338
transaction->t_synchronous_commit = 1;
13361339
current->journal_info = NULL;
1337-
spin_lock(&transaction->t_handle_lock);
1338-
transaction->t_outstanding_credits -= handle->h_buffer_credits;
1339-
transaction->t_updates--;
1340-
if (!transaction->t_updates) {
1341-
wake_up(&journal->j_wait_updates);
1342-
if (journal->j_barrier_count)
1343-
wake_up(&journal->j_wait_transaction_locked);
1344-
}
1340+
atomic_sub(handle->h_buffer_credits,
1341+
&transaction->t_outstanding_credits);
13451342

13461343
/*
13471344
* If the handle is marked SYNC, we need to set another commit
@@ -1350,15 +1347,13 @@ int jbd2_journal_stop(handle_t *handle)
13501347
* transaction is too old now.
13511348
*/
13521349
if (handle->h_sync ||
1353-
transaction->t_outstanding_credits >
1354-
journal->j_max_transaction_buffers ||
1355-
time_after_eq(jiffies, transaction->t_expires)) {
1350+
(atomic_read(&transaction->t_outstanding_credits) >
1351+
journal->j_max_transaction_buffers) ||
1352+
time_after_eq(jiffies, transaction->t_expires)) {
13561353
/* Do this even for aborted journals: an abort still
13571354
* completes the commit thread, it just doesn't write
13581355
* anything to disk. */
1359-
tid_t tid = transaction->t_tid;
13601356

1361-
spin_unlock(&transaction->t_handle_lock);
13621357
jbd_debug(2, "transaction too old, requesting commit for "
13631358
"handle %p\n", handle);
13641359
/* This is non-blocking */
@@ -1369,11 +1364,25 @@ int jbd2_journal_stop(handle_t *handle)
13691364
* to wait for the commit to complete.
13701365
*/
13711366
if (handle->h_sync && !(current->flags & PF_MEMALLOC))
1372-
err = jbd2_log_wait_commit(journal, tid);
1373-
} else {
1374-
spin_unlock(&transaction->t_handle_lock);
1367+
wait_for_commit = 1;
13751368
}
13761369

1370+
/*
1371+
* Once we drop t_updates, if it goes to zero the transaction
1372+
* could start commiting on us and eventually disappear. So
1373+
* once we do this, we must not dereference transaction
1374+
* pointer again.
1375+
*/
1376+
tid = transaction->t_tid;
1377+
if (atomic_dec_and_test(&transaction->t_updates)) {
1378+
wake_up(&journal->j_wait_updates);
1379+
if (journal->j_barrier_count)
1380+
wake_up(&journal->j_wait_transaction_locked);
1381+
}
1382+
1383+
if (wait_for_commit)
1384+
err = jbd2_log_wait_commit(journal, tid);
1385+
13771386
lock_map_release(&handle->h_lockdep_map);
13781387

13791388
jbd2_free_handle(handle);

include/linux/jbd2.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -601,13 +601,13 @@ struct transaction_s
601601
* Number of outstanding updates running on this transaction
602602
* [t_handle_lock]
603603
*/
604-
int t_updates;
604+
atomic_t t_updates;
605605

606606
/*
607607
* Number of buffers reserved for use by all handles in this transaction
608608
* handle but not yet modified. [t_handle_lock]
609609
*/
610-
int t_outstanding_credits;
610+
atomic_t t_outstanding_credits;
611611

612612
/*
613613
* Forward and backward links for the circular list of all transactions
@@ -1258,8 +1258,8 @@ static inline int jbd_space_needed(journal_t *journal)
12581258
{
12591259
int nblocks = journal->j_max_transaction_buffers;
12601260
if (journal->j_committing_transaction)
1261-
nblocks += journal->j_committing_transaction->
1262-
t_outstanding_credits;
1261+
nblocks += atomic_read(&journal->j_committing_transaction->
1262+
t_outstanding_credits);
12631263
return nblocks;
12641264
}
12651265

0 commit comments

Comments
 (0)