Skip to content

Commit 1ba3726

Browse files
xiaoqiangnktytso
authored andcommitted
jbd2: clear revoked flag on buffers before a new transaction started
Currently, we clear revoked flag only when a block is reused. However, this can tigger a false journal error. Consider a situation when a block is used as a meta block and is deleted(revoked) in ordered mode, then the block is allocated as a data block to a file. At this moment, user changes the file's journal mode from ordered to journaled and truncates the file. The block will be considered re-revoked by journal because it has revoked flag still pending from the last transaction and an assertion triggers. We fix the problem by keeping the revoked status more uptodate - we clear revoked flag when switching revoke tables to reflect there is no revoked buffers in current transaction any more. Signed-off-by: Yongqiang Yang <[email protected]> Signed-off-by: "Theodore Ts'o" <[email protected]>
1 parent 5872dda commit 1ba3726

File tree

3 files changed

+41
-0
lines changed

3 files changed

+41
-0
lines changed

fs/jbd2/commit.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,12 @@ void jbd2_journal_commit_transaction(journal_t *journal)
429429

430430
jbd_debug(3, "JBD2: commit phase 1\n");
431431

432+
/*
433+
* Clear revoked flag to reflect there is no revoked buffers
434+
* in the next transaction which is going to be started.
435+
*/
436+
jbd2_clear_buffer_revoked_flags(journal);
437+
432438
/*
433439
* Switch to a new revoke table.
434440
*/

fs/jbd2/revoke.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@
4747
* overwriting the new data. We don't even need to clear the revoke
4848
* bit here.
4949
*
50+
* We cache revoke status of a buffer in the current transaction in b_states
51+
* bits. As the name says, revokevalid flag indicates that the cached revoke
52+
* status of a buffer is valid and we can rely on the cached status.
53+
*
5054
* Revoke information on buffers is a tri-state value:
5155
*
5256
* RevokeValid clear: no cached revoke status, need to look it up
@@ -478,6 +482,36 @@ int jbd2_journal_cancel_revoke(handle_t *handle, struct journal_head *jh)
478482
return did_revoke;
479483
}
480484

485+
/*
486+
* journal_clear_revoked_flag clears revoked flag of buffers in
487+
* revoke table to reflect there is no revoked buffers in the next
488+
* transaction which is going to be started.
489+
*/
490+
void jbd2_clear_buffer_revoked_flags(journal_t *journal)
491+
{
492+
struct jbd2_revoke_table_s *revoke = journal->j_revoke;
493+
int i = 0;
494+
495+
for (i = 0; i < revoke->hash_size; i++) {
496+
struct list_head *hash_list;
497+
struct list_head *list_entry;
498+
hash_list = &revoke->hash_table[i];
499+
500+
list_for_each(list_entry, hash_list) {
501+
struct jbd2_revoke_record_s *record;
502+
struct buffer_head *bh;
503+
record = (struct jbd2_revoke_record_s *)list_entry;
504+
bh = __find_get_block(journal->j_fs_dev,
505+
record->blocknr,
506+
journal->j_blocksize);
507+
if (bh) {
508+
clear_buffer_revoked(bh);
509+
__brelse(bh);
510+
}
511+
}
512+
}
513+
}
514+
481515
/* journal_switch_revoke table select j_revoke for next transaction
482516
* we do not want to suspend any processing until all revokes are
483517
* written -bzzz

include/linux/jbd2.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,6 +1151,7 @@ extern int jbd2_journal_set_revoke(journal_t *, unsigned long long, tid_t);
11511151
extern int jbd2_journal_test_revoke(journal_t *, unsigned long long, tid_t);
11521152
extern void jbd2_journal_clear_revoke(journal_t *);
11531153
extern void jbd2_journal_switch_revoke_table(journal_t *journal);
1154+
extern void jbd2_clear_buffer_revoked_flags(journal_t *journal);
11541155

11551156
/*
11561157
* The log thread user interface:

0 commit comments

Comments
 (0)