diff options
| -rw-r--r-- | fs/jbd2/transaction.c | 33 |
1 files changed, 27 insertions, 6 deletions
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index f3d06174b051..cbe8b3aece5b 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,36 @@ 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 | J_ASSERT_JH(jh, jh->b_transaction == transaction || | ||
| 1325 | jh->b_next_transaction == transaction); | ||
| 1326 | if (jh->b_modified == 1) { | ||
| 1327 | /* | ||
| 1328 | * If it's in our transaction it must be in BJ_Metadata list. | ||
| 1329 | * The assertion is unreliable since we may see jh in | ||
| 1330 | * inconsistent state unless we grab bh_state lock. But this | ||
| 1331 | * is crutial to catch bugs so let's do a reliable check until | ||
| 1332 | * the lockless handling is fully proven. | ||
| 1333 | */ | ||
| 1334 | if (jh->b_transaction == transaction && | ||
| 1335 | jh->b_jlist != BJ_Metadata) { | ||
| 1336 | jbd_lock_bh_state(bh); | ||
| 1337 | J_ASSERT_JH(jh, jh->b_transaction != transaction || | ||
| 1338 | jh->b_jlist == BJ_Metadata); | ||
| 1339 | jbd_unlock_bh_state(bh); | ||
| 1340 | } | ||
| 1341 | goto out; | ||
| 1342 | } | ||
| 1343 | |||
| 1344 | journal = transaction->t_journal; | ||
| 1323 | jbd_debug(5, "journal_head %p\n", jh); | 1345 | jbd_debug(5, "journal_head %p\n", jh); |
| 1324 | JBUFFER_TRACE(jh, "entry"); | 1346 | JBUFFER_TRACE(jh, "entry"); |
| 1325 | 1347 | ||
| @@ -1410,7 +1432,6 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) | |||
| 1410 | spin_unlock(&journal->j_list_lock); | 1432 | spin_unlock(&journal->j_list_lock); |
| 1411 | out_unlock_bh: | 1433 | out_unlock_bh: |
| 1412 | jbd_unlock_bh_state(bh); | 1434 | jbd_unlock_bh_state(bh); |
| 1413 | jbd2_journal_put_journal_head(jh); | ||
| 1414 | out: | 1435 | out: |
| 1415 | JBUFFER_TRACE(jh, "exit"); | 1436 | JBUFFER_TRACE(jh, "exit"); |
| 1416 | return ret; | 1437 | return ret; |
