diff options
-rw-r--r-- | fs/jbd2/transaction.c | 38 |
1 files changed, 32 insertions, 6 deletions
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index f3d06174b051..a6eec9747c74 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c | |||
@@ -1280,8 +1280,6 @@ void jbd2_buffer_abort_trigger(struct journal_head *jh, | |||
1280 | triggers->t_abort(triggers, jh2bh(jh)); | 1280 | triggers->t_abort(triggers, jh2bh(jh)); |
1281 | } | 1281 | } |
1282 | 1282 | ||
1283 | |||
1284 | |||
1285 | /** | 1283 | /** |
1286 | * int jbd2_journal_dirty_metadata() - mark a buffer as containing dirty metadata | 1284 | * int jbd2_journal_dirty_metadata() - mark a buffer as containing dirty metadata |
1287 | * @handle: transaction to add buffer to. | 1285 | * @handle: transaction to add buffer to. |
@@ -1314,12 +1312,41 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) | |||
1314 | 1312 | ||
1315 | if (is_handle_aborted(handle)) | 1313 | if (is_handle_aborted(handle)) |
1316 | return -EROFS; | 1314 | return -EROFS; |
1317 | journal = transaction->t_journal; | 1315 | if (!buffer_jbd(bh)) { |
1318 | jh = jbd2_journal_grab_journal_head(bh); | ||
1319 | if (!jh) { | ||
1320 | ret = -EUCLEAN; | 1316 | ret = -EUCLEAN; |
1321 | goto out; | 1317 | goto out; |
1322 | } | 1318 | } |
1319 | /* | ||
1320 | * We don't grab jh reference here since the buffer must be part | ||
1321 | * of the running transaction. | ||
1322 | */ | ||
1323 | jh = bh2jh(bh); | ||
1324 | /* | ||
1325 | * This and the following assertions are unreliable since we may see jh | ||
1326 | * in inconsistent state unless we grab bh_state lock. But this is | ||
1327 | * crucial to catch bugs so let's do a reliable check until the | ||
1328 | * lockless handling is fully proven. | ||
1329 | */ | ||
1330 | if (jh->b_transaction != transaction && | ||
1331 | jh->b_next_transaction != transaction) { | ||
1332 | jbd_lock_bh_state(bh); | ||
1333 | J_ASSERT_JH(jh, jh->b_transaction == transaction || | ||
1334 | jh->b_next_transaction == transaction); | ||
1335 | jbd_unlock_bh_state(bh); | ||
1336 | } | ||
1337 | if (jh->b_modified == 1) { | ||
1338 | /* If it's in our transaction it must be in BJ_Metadata list. */ | ||
1339 | if (jh->b_transaction == transaction && | ||
1340 | jh->b_jlist != BJ_Metadata) { | ||
1341 | jbd_lock_bh_state(bh); | ||
1342 | J_ASSERT_JH(jh, jh->b_transaction != transaction || | ||
1343 | jh->b_jlist == BJ_Metadata); | ||
1344 | jbd_unlock_bh_state(bh); | ||
1345 | } | ||
1346 | goto out; | ||
1347 | } | ||
1348 | |||
1349 | journal = transaction->t_journal; | ||
1323 | jbd_debug(5, "journal_head %p\n", jh); | 1350 | jbd_debug(5, "journal_head %p\n", jh); |
1324 | JBUFFER_TRACE(jh, "entry"); | 1351 | JBUFFER_TRACE(jh, "entry"); |
1325 | 1352 | ||
@@ -1410,7 +1437,6 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) | |||
1410 | spin_unlock(&journal->j_list_lock); | 1437 | spin_unlock(&journal->j_list_lock); |
1411 | out_unlock_bh: | 1438 | out_unlock_bh: |
1412 | jbd_unlock_bh_state(bh); | 1439 | jbd_unlock_bh_state(bh); |
1413 | jbd2_journal_put_journal_head(jh); | ||
1414 | out: | 1440 | out: |
1415 | JBUFFER_TRACE(jh, "exit"); | 1441 | JBUFFER_TRACE(jh, "exit"); |
1416 | return ret; | 1442 | return ret; |