162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/fs/jbd2/revoke.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Written by Stephen C. Tweedie <sct@redhat.com>, 2000
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright 2000 Red Hat corp --- All Rights Reserved
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Journal revoke routines for the generic filesystem journaling code;
1062306a36Sopenharmony_ci * part of the ext2fs journaling system.
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Revoke is the mechanism used to prevent old log records for deleted
1362306a36Sopenharmony_ci * metadata from being replayed on top of newer data using the same
1462306a36Sopenharmony_ci * blocks.  The revoke mechanism is used in two separate places:
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * + Commit: during commit we write the entire list of the current
1762306a36Sopenharmony_ci *   transaction's revoked blocks to the journal
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * + Recovery: during recovery we record the transaction ID of all
2062306a36Sopenharmony_ci *   revoked blocks.  If there are multiple revoke records in the log
2162306a36Sopenharmony_ci *   for a single block, only the last one counts, and if there is a log
2262306a36Sopenharmony_ci *   entry for a block beyond the last revoke, then that log entry still
2362306a36Sopenharmony_ci *   gets replayed.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * We can get interactions between revokes and new log data within a
2662306a36Sopenharmony_ci * single transaction:
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * Block is revoked and then journaled:
2962306a36Sopenharmony_ci *   The desired end result is the journaling of the new block, so we
3062306a36Sopenharmony_ci *   cancel the revoke before the transaction commits.
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci * Block is journaled and then revoked:
3362306a36Sopenharmony_ci *   The revoke must take precedence over the write of the block, so we
3462306a36Sopenharmony_ci *   need either to cancel the journal entry or to write the revoke
3562306a36Sopenharmony_ci *   later in the log than the log block.  In this case, we choose the
3662306a36Sopenharmony_ci *   latter: journaling a block cancels any revoke record for that block
3762306a36Sopenharmony_ci *   in the current transaction, so any revoke for that block in the
3862306a36Sopenharmony_ci *   transaction must have happened after the block was journaled and so
3962306a36Sopenharmony_ci *   the revoke must take precedence.
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci * Block is revoked and then written as data:
4262306a36Sopenharmony_ci *   The data write is allowed to succeed, but the revoke is _not_
4362306a36Sopenharmony_ci *   cancelled.  We still need to prevent old log records from
4462306a36Sopenharmony_ci *   overwriting the new data.  We don't even need to clear the revoke
4562306a36Sopenharmony_ci *   bit here.
4662306a36Sopenharmony_ci *
4762306a36Sopenharmony_ci * We cache revoke status of a buffer in the current transaction in b_states
4862306a36Sopenharmony_ci * bits.  As the name says, revokevalid flag indicates that the cached revoke
4962306a36Sopenharmony_ci * status of a buffer is valid and we can rely on the cached status.
5062306a36Sopenharmony_ci *
5162306a36Sopenharmony_ci * Revoke information on buffers is a tri-state value:
5262306a36Sopenharmony_ci *
5362306a36Sopenharmony_ci * RevokeValid clear:	no cached revoke status, need to look it up
5462306a36Sopenharmony_ci * RevokeValid set, Revoked clear:
5562306a36Sopenharmony_ci *			buffer has not been revoked, and cancel_revoke
5662306a36Sopenharmony_ci *			need do nothing.
5762306a36Sopenharmony_ci * RevokeValid set, Revoked set:
5862306a36Sopenharmony_ci *			buffer has been revoked.
5962306a36Sopenharmony_ci *
6062306a36Sopenharmony_ci * Locking rules:
6162306a36Sopenharmony_ci * We keep two hash tables of revoke records. One hashtable belongs to the
6262306a36Sopenharmony_ci * running transaction (is pointed to by journal->j_revoke), the other one
6362306a36Sopenharmony_ci * belongs to the committing transaction. Accesses to the second hash table
6462306a36Sopenharmony_ci * happen only from the kjournald and no other thread touches this table.  Also
6562306a36Sopenharmony_ci * journal_switch_revoke_table() which switches which hashtable belongs to the
6662306a36Sopenharmony_ci * running and which to the committing transaction is called only from
6762306a36Sopenharmony_ci * kjournald. Therefore we need no locks when accessing the hashtable belonging
6862306a36Sopenharmony_ci * to the committing transaction.
6962306a36Sopenharmony_ci *
7062306a36Sopenharmony_ci * All users operating on the hash table belonging to the running transaction
7162306a36Sopenharmony_ci * have a handle to the transaction. Therefore they are safe from kjournald
7262306a36Sopenharmony_ci * switching hash tables under them. For operations on the lists of entries in
7362306a36Sopenharmony_ci * the hash table j_revoke_lock is used.
7462306a36Sopenharmony_ci *
7562306a36Sopenharmony_ci * Finally, also replay code uses the hash tables but at this moment no one else
7662306a36Sopenharmony_ci * can touch them (filesystem isn't mounted yet) and hence no locking is
7762306a36Sopenharmony_ci * needed.
7862306a36Sopenharmony_ci */
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci#ifndef __KERNEL__
8162306a36Sopenharmony_ci#include "jfs_user.h"
8262306a36Sopenharmony_ci#else
8362306a36Sopenharmony_ci#include <linux/time.h>
8462306a36Sopenharmony_ci#include <linux/fs.h>
8562306a36Sopenharmony_ci#include <linux/jbd2.h>
8662306a36Sopenharmony_ci#include <linux/errno.h>
8762306a36Sopenharmony_ci#include <linux/slab.h>
8862306a36Sopenharmony_ci#include <linux/list.h>
8962306a36Sopenharmony_ci#include <linux/init.h>
9062306a36Sopenharmony_ci#include <linux/bio.h>
9162306a36Sopenharmony_ci#include <linux/log2.h>
9262306a36Sopenharmony_ci#include <linux/hash.h>
9362306a36Sopenharmony_ci#endif
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic struct kmem_cache *jbd2_revoke_record_cache;
9662306a36Sopenharmony_cistatic struct kmem_cache *jbd2_revoke_table_cache;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/* Each revoke record represents one single revoked block.  During
9962306a36Sopenharmony_ci   journal replay, this involves recording the transaction ID of the
10062306a36Sopenharmony_ci   last transaction to revoke this block. */
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistruct jbd2_revoke_record_s
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	struct list_head  hash;
10562306a36Sopenharmony_ci	tid_t		  sequence;	/* Used for recovery only */
10662306a36Sopenharmony_ci	unsigned long long	  blocknr;
10762306a36Sopenharmony_ci};
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci/* The revoke table is just a simple hash table of revoke records. */
11162306a36Sopenharmony_cistruct jbd2_revoke_table_s
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	/* It is conceivable that we might want a larger hash table
11462306a36Sopenharmony_ci	 * for recovery.  Must be a power of two. */
11562306a36Sopenharmony_ci	int		  hash_size;
11662306a36Sopenharmony_ci	int		  hash_shift;
11762306a36Sopenharmony_ci	struct list_head *hash_table;
11862306a36Sopenharmony_ci};
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci#ifdef __KERNEL__
12262306a36Sopenharmony_cistatic void write_one_revoke_record(transaction_t *,
12362306a36Sopenharmony_ci				    struct list_head *,
12462306a36Sopenharmony_ci				    struct buffer_head **, int *,
12562306a36Sopenharmony_ci				    struct jbd2_revoke_record_s *);
12662306a36Sopenharmony_cistatic void flush_descriptor(journal_t *, struct buffer_head *, int);
12762306a36Sopenharmony_ci#endif
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/* Utility functions to maintain the revoke table */
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic inline int hash(journal_t *journal, unsigned long long block)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	return hash_64(block, journal->j_revoke->hash_shift);
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic int insert_revoke_hash(journal_t *journal, unsigned long long blocknr,
13762306a36Sopenharmony_ci			      tid_t seq)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	struct list_head *hash_list;
14062306a36Sopenharmony_ci	struct jbd2_revoke_record_s *record;
14162306a36Sopenharmony_ci	gfp_t gfp_mask = GFP_NOFS;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	if (journal_oom_retry)
14462306a36Sopenharmony_ci		gfp_mask |= __GFP_NOFAIL;
14562306a36Sopenharmony_ci	record = kmem_cache_alloc(jbd2_revoke_record_cache, gfp_mask);
14662306a36Sopenharmony_ci	if (!record)
14762306a36Sopenharmony_ci		return -ENOMEM;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	record->sequence = seq;
15062306a36Sopenharmony_ci	record->blocknr = blocknr;
15162306a36Sopenharmony_ci	hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
15262306a36Sopenharmony_ci	spin_lock(&journal->j_revoke_lock);
15362306a36Sopenharmony_ci	list_add(&record->hash, hash_list);
15462306a36Sopenharmony_ci	spin_unlock(&journal->j_revoke_lock);
15562306a36Sopenharmony_ci	return 0;
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci/* Find a revoke record in the journal's hash table. */
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic struct jbd2_revoke_record_s *find_revoke_record(journal_t *journal,
16162306a36Sopenharmony_ci						      unsigned long long blocknr)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	struct list_head *hash_list;
16462306a36Sopenharmony_ci	struct jbd2_revoke_record_s *record;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	spin_lock(&journal->j_revoke_lock);
16962306a36Sopenharmony_ci	record = (struct jbd2_revoke_record_s *) hash_list->next;
17062306a36Sopenharmony_ci	while (&(record->hash) != hash_list) {
17162306a36Sopenharmony_ci		if (record->blocknr == blocknr) {
17262306a36Sopenharmony_ci			spin_unlock(&journal->j_revoke_lock);
17362306a36Sopenharmony_ci			return record;
17462306a36Sopenharmony_ci		}
17562306a36Sopenharmony_ci		record = (struct jbd2_revoke_record_s *) record->hash.next;
17662306a36Sopenharmony_ci	}
17762306a36Sopenharmony_ci	spin_unlock(&journal->j_revoke_lock);
17862306a36Sopenharmony_ci	return NULL;
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_civoid jbd2_journal_destroy_revoke_record_cache(void)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	kmem_cache_destroy(jbd2_revoke_record_cache);
18462306a36Sopenharmony_ci	jbd2_revoke_record_cache = NULL;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_civoid jbd2_journal_destroy_revoke_table_cache(void)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	kmem_cache_destroy(jbd2_revoke_table_cache);
19062306a36Sopenharmony_ci	jbd2_revoke_table_cache = NULL;
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ciint __init jbd2_journal_init_revoke_record_cache(void)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	J_ASSERT(!jbd2_revoke_record_cache);
19662306a36Sopenharmony_ci	jbd2_revoke_record_cache = KMEM_CACHE(jbd2_revoke_record_s,
19762306a36Sopenharmony_ci					SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	if (!jbd2_revoke_record_cache) {
20062306a36Sopenharmony_ci		pr_emerg("JBD2: failed to create revoke_record cache\n");
20162306a36Sopenharmony_ci		return -ENOMEM;
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci	return 0;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ciint __init jbd2_journal_init_revoke_table_cache(void)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	J_ASSERT(!jbd2_revoke_table_cache);
20962306a36Sopenharmony_ci	jbd2_revoke_table_cache = KMEM_CACHE(jbd2_revoke_table_s,
21062306a36Sopenharmony_ci					     SLAB_TEMPORARY);
21162306a36Sopenharmony_ci	if (!jbd2_revoke_table_cache) {
21262306a36Sopenharmony_ci		pr_emerg("JBD2: failed to create revoke_table cache\n");
21362306a36Sopenharmony_ci		return -ENOMEM;
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci	return 0;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic struct jbd2_revoke_table_s *jbd2_journal_init_revoke_table(int hash_size)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	int shift = 0;
22162306a36Sopenharmony_ci	int tmp = hash_size;
22262306a36Sopenharmony_ci	struct jbd2_revoke_table_s *table;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	table = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL);
22562306a36Sopenharmony_ci	if (!table)
22662306a36Sopenharmony_ci		goto out;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	while((tmp >>= 1UL) != 0UL)
22962306a36Sopenharmony_ci		shift++;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	table->hash_size = hash_size;
23262306a36Sopenharmony_ci	table->hash_shift = shift;
23362306a36Sopenharmony_ci	table->hash_table =
23462306a36Sopenharmony_ci		kmalloc_array(hash_size, sizeof(struct list_head), GFP_KERNEL);
23562306a36Sopenharmony_ci	if (!table->hash_table) {
23662306a36Sopenharmony_ci		kmem_cache_free(jbd2_revoke_table_cache, table);
23762306a36Sopenharmony_ci		table = NULL;
23862306a36Sopenharmony_ci		goto out;
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	for (tmp = 0; tmp < hash_size; tmp++)
24262306a36Sopenharmony_ci		INIT_LIST_HEAD(&table->hash_table[tmp]);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ciout:
24562306a36Sopenharmony_ci	return table;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic void jbd2_journal_destroy_revoke_table(struct jbd2_revoke_table_s *table)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	int i;
25162306a36Sopenharmony_ci	struct list_head *hash_list;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	for (i = 0; i < table->hash_size; i++) {
25462306a36Sopenharmony_ci		hash_list = &table->hash_table[i];
25562306a36Sopenharmony_ci		J_ASSERT(list_empty(hash_list));
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	kfree(table->hash_table);
25962306a36Sopenharmony_ci	kmem_cache_free(jbd2_revoke_table_cache, table);
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci/* Initialise the revoke table for a given journal to a given size. */
26362306a36Sopenharmony_ciint jbd2_journal_init_revoke(journal_t *journal, int hash_size)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	J_ASSERT(journal->j_revoke_table[0] == NULL);
26662306a36Sopenharmony_ci	J_ASSERT(is_power_of_2(hash_size));
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	journal->j_revoke_table[0] = jbd2_journal_init_revoke_table(hash_size);
26962306a36Sopenharmony_ci	if (!journal->j_revoke_table[0])
27062306a36Sopenharmony_ci		goto fail0;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	journal->j_revoke_table[1] = jbd2_journal_init_revoke_table(hash_size);
27362306a36Sopenharmony_ci	if (!journal->j_revoke_table[1])
27462306a36Sopenharmony_ci		goto fail1;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	journal->j_revoke = journal->j_revoke_table[1];
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	spin_lock_init(&journal->j_revoke_lock);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	return 0;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cifail1:
28362306a36Sopenharmony_ci	jbd2_journal_destroy_revoke_table(journal->j_revoke_table[0]);
28462306a36Sopenharmony_ci	journal->j_revoke_table[0] = NULL;
28562306a36Sopenharmony_cifail0:
28662306a36Sopenharmony_ci	return -ENOMEM;
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci/* Destroy a journal's revoke table.  The table must already be empty! */
29062306a36Sopenharmony_civoid jbd2_journal_destroy_revoke(journal_t *journal)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	journal->j_revoke = NULL;
29362306a36Sopenharmony_ci	if (journal->j_revoke_table[0])
29462306a36Sopenharmony_ci		jbd2_journal_destroy_revoke_table(journal->j_revoke_table[0]);
29562306a36Sopenharmony_ci	if (journal->j_revoke_table[1])
29662306a36Sopenharmony_ci		jbd2_journal_destroy_revoke_table(journal->j_revoke_table[1]);
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci#ifdef __KERNEL__
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci/*
30362306a36Sopenharmony_ci * jbd2_journal_revoke: revoke a given buffer_head from the journal.  This
30462306a36Sopenharmony_ci * prevents the block from being replayed during recovery if we take a
30562306a36Sopenharmony_ci * crash after this current transaction commits.  Any subsequent
30662306a36Sopenharmony_ci * metadata writes of the buffer in this transaction cancel the
30762306a36Sopenharmony_ci * revoke.
30862306a36Sopenharmony_ci *
30962306a36Sopenharmony_ci * Note that this call may block --- it is up to the caller to make
31062306a36Sopenharmony_ci * sure that there are no further calls to journal_write_metadata
31162306a36Sopenharmony_ci * before the revoke is complete.  In ext3, this implies calling the
31262306a36Sopenharmony_ci * revoke before clearing the block bitmap when we are deleting
31362306a36Sopenharmony_ci * metadata.
31462306a36Sopenharmony_ci *
31562306a36Sopenharmony_ci * Revoke performs a jbd2_journal_forget on any buffer_head passed in as a
31662306a36Sopenharmony_ci * parameter, but does _not_ forget the buffer_head if the bh was only
31762306a36Sopenharmony_ci * found implicitly.
31862306a36Sopenharmony_ci *
31962306a36Sopenharmony_ci * bh_in may not be a journalled buffer - it may have come off
32062306a36Sopenharmony_ci * the hash tables without an attached journal_head.
32162306a36Sopenharmony_ci *
32262306a36Sopenharmony_ci * If bh_in is non-zero, jbd2_journal_revoke() will decrement its b_count
32362306a36Sopenharmony_ci * by one.
32462306a36Sopenharmony_ci */
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ciint jbd2_journal_revoke(handle_t *handle, unsigned long long blocknr,
32762306a36Sopenharmony_ci		   struct buffer_head *bh_in)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	struct buffer_head *bh = NULL;
33062306a36Sopenharmony_ci	journal_t *journal;
33162306a36Sopenharmony_ci	struct block_device *bdev;
33262306a36Sopenharmony_ci	int err;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	might_sleep();
33562306a36Sopenharmony_ci	if (bh_in)
33662306a36Sopenharmony_ci		BUFFER_TRACE(bh_in, "enter");
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	journal = handle->h_transaction->t_journal;
33962306a36Sopenharmony_ci	if (!jbd2_journal_set_features(journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)){
34062306a36Sopenharmony_ci		J_ASSERT (!"Cannot set revoke feature!");
34162306a36Sopenharmony_ci		return -EINVAL;
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	bdev = journal->j_fs_dev;
34562306a36Sopenharmony_ci	bh = bh_in;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if (!bh) {
34862306a36Sopenharmony_ci		bh = __find_get_block(bdev, blocknr, journal->j_blocksize);
34962306a36Sopenharmony_ci		if (bh)
35062306a36Sopenharmony_ci			BUFFER_TRACE(bh, "found on hash");
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci#ifdef JBD2_EXPENSIVE_CHECKING
35362306a36Sopenharmony_ci	else {
35462306a36Sopenharmony_ci		struct buffer_head *bh2;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci		/* If there is a different buffer_head lying around in
35762306a36Sopenharmony_ci		 * memory anywhere... */
35862306a36Sopenharmony_ci		bh2 = __find_get_block(bdev, blocknr, journal->j_blocksize);
35962306a36Sopenharmony_ci		if (bh2) {
36062306a36Sopenharmony_ci			/* ... and it has RevokeValid status... */
36162306a36Sopenharmony_ci			if (bh2 != bh && buffer_revokevalid(bh2))
36262306a36Sopenharmony_ci				/* ...then it better be revoked too,
36362306a36Sopenharmony_ci				 * since it's illegal to create a revoke
36462306a36Sopenharmony_ci				 * record against a buffer_head which is
36562306a36Sopenharmony_ci				 * not marked revoked --- that would
36662306a36Sopenharmony_ci				 * risk missing a subsequent revoke
36762306a36Sopenharmony_ci				 * cancel. */
36862306a36Sopenharmony_ci				J_ASSERT_BH(bh2, buffer_revoked(bh2));
36962306a36Sopenharmony_ci			put_bh(bh2);
37062306a36Sopenharmony_ci		}
37162306a36Sopenharmony_ci	}
37262306a36Sopenharmony_ci#endif
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	if (WARN_ON_ONCE(handle->h_revoke_credits <= 0)) {
37562306a36Sopenharmony_ci		if (!bh_in)
37662306a36Sopenharmony_ci			brelse(bh);
37762306a36Sopenharmony_ci		return -EIO;
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci	/* We really ought not ever to revoke twice in a row without
38062306a36Sopenharmony_ci           first having the revoke cancelled: it's illegal to free a
38162306a36Sopenharmony_ci           block twice without allocating it in between! */
38262306a36Sopenharmony_ci	if (bh) {
38362306a36Sopenharmony_ci		if (!J_EXPECT_BH(bh, !buffer_revoked(bh),
38462306a36Sopenharmony_ci				 "inconsistent data on disk")) {
38562306a36Sopenharmony_ci			if (!bh_in)
38662306a36Sopenharmony_ci				brelse(bh);
38762306a36Sopenharmony_ci			return -EIO;
38862306a36Sopenharmony_ci		}
38962306a36Sopenharmony_ci		set_buffer_revoked(bh);
39062306a36Sopenharmony_ci		set_buffer_revokevalid(bh);
39162306a36Sopenharmony_ci		if (bh_in) {
39262306a36Sopenharmony_ci			BUFFER_TRACE(bh_in, "call jbd2_journal_forget");
39362306a36Sopenharmony_ci			jbd2_journal_forget(handle, bh_in);
39462306a36Sopenharmony_ci		} else {
39562306a36Sopenharmony_ci			BUFFER_TRACE(bh, "call brelse");
39662306a36Sopenharmony_ci			__brelse(bh);
39762306a36Sopenharmony_ci		}
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci	handle->h_revoke_credits--;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	jbd2_debug(2, "insert revoke for block %llu, bh_in=%p\n",blocknr, bh_in);
40262306a36Sopenharmony_ci	err = insert_revoke_hash(journal, blocknr,
40362306a36Sopenharmony_ci				handle->h_transaction->t_tid);
40462306a36Sopenharmony_ci	BUFFER_TRACE(bh_in, "exit");
40562306a36Sopenharmony_ci	return err;
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci/*
40962306a36Sopenharmony_ci * Cancel an outstanding revoke.  For use only internally by the
41062306a36Sopenharmony_ci * journaling code (called from jbd2_journal_get_write_access).
41162306a36Sopenharmony_ci *
41262306a36Sopenharmony_ci * We trust buffer_revoked() on the buffer if the buffer is already
41362306a36Sopenharmony_ci * being journaled: if there is no revoke pending on the buffer, then we
41462306a36Sopenharmony_ci * don't do anything here.
41562306a36Sopenharmony_ci *
41662306a36Sopenharmony_ci * This would break if it were possible for a buffer to be revoked and
41762306a36Sopenharmony_ci * discarded, and then reallocated within the same transaction.  In such
41862306a36Sopenharmony_ci * a case we would have lost the revoked bit, but when we arrived here
41962306a36Sopenharmony_ci * the second time we would still have a pending revoke to cancel.  So,
42062306a36Sopenharmony_ci * do not trust the Revoked bit on buffers unless RevokeValid is also
42162306a36Sopenharmony_ci * set.
42262306a36Sopenharmony_ci */
42362306a36Sopenharmony_ciint jbd2_journal_cancel_revoke(handle_t *handle, struct journal_head *jh)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	struct jbd2_revoke_record_s *record;
42662306a36Sopenharmony_ci	journal_t *journal = handle->h_transaction->t_journal;
42762306a36Sopenharmony_ci	int need_cancel;
42862306a36Sopenharmony_ci	int did_revoke = 0;	/* akpm: debug */
42962306a36Sopenharmony_ci	struct buffer_head *bh = jh2bh(jh);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	jbd2_debug(4, "journal_head %p, cancelling revoke\n", jh);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	/* Is the existing Revoke bit valid?  If so, we trust it, and
43462306a36Sopenharmony_ci	 * only perform the full cancel if the revoke bit is set.  If
43562306a36Sopenharmony_ci	 * not, we can't trust the revoke bit, and we need to do the
43662306a36Sopenharmony_ci	 * full search for a revoke record. */
43762306a36Sopenharmony_ci	if (test_set_buffer_revokevalid(bh)) {
43862306a36Sopenharmony_ci		need_cancel = test_clear_buffer_revoked(bh);
43962306a36Sopenharmony_ci	} else {
44062306a36Sopenharmony_ci		need_cancel = 1;
44162306a36Sopenharmony_ci		clear_buffer_revoked(bh);
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	if (need_cancel) {
44562306a36Sopenharmony_ci		record = find_revoke_record(journal, bh->b_blocknr);
44662306a36Sopenharmony_ci		if (record) {
44762306a36Sopenharmony_ci			jbd2_debug(4, "cancelled existing revoke on "
44862306a36Sopenharmony_ci				  "blocknr %llu\n", (unsigned long long)bh->b_blocknr);
44962306a36Sopenharmony_ci			spin_lock(&journal->j_revoke_lock);
45062306a36Sopenharmony_ci			list_del(&record->hash);
45162306a36Sopenharmony_ci			spin_unlock(&journal->j_revoke_lock);
45262306a36Sopenharmony_ci			kmem_cache_free(jbd2_revoke_record_cache, record);
45362306a36Sopenharmony_ci			did_revoke = 1;
45462306a36Sopenharmony_ci		}
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci#ifdef JBD2_EXPENSIVE_CHECKING
45862306a36Sopenharmony_ci	/* There better not be one left behind by now! */
45962306a36Sopenharmony_ci	record = find_revoke_record(journal, bh->b_blocknr);
46062306a36Sopenharmony_ci	J_ASSERT_JH(jh, record == NULL);
46162306a36Sopenharmony_ci#endif
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	/* Finally, have we just cleared revoke on an unhashed
46462306a36Sopenharmony_ci	 * buffer_head?  If so, we'd better make sure we clear the
46562306a36Sopenharmony_ci	 * revoked status on any hashed alias too, otherwise the revoke
46662306a36Sopenharmony_ci	 * state machine will get very upset later on. */
46762306a36Sopenharmony_ci	if (need_cancel) {
46862306a36Sopenharmony_ci		struct buffer_head *bh2;
46962306a36Sopenharmony_ci		bh2 = __find_get_block(bh->b_bdev, bh->b_blocknr, bh->b_size);
47062306a36Sopenharmony_ci		if (bh2) {
47162306a36Sopenharmony_ci			if (bh2 != bh)
47262306a36Sopenharmony_ci				clear_buffer_revoked(bh2);
47362306a36Sopenharmony_ci			__brelse(bh2);
47462306a36Sopenharmony_ci		}
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci	return did_revoke;
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci/*
48062306a36Sopenharmony_ci * journal_clear_revoked_flag clears revoked flag of buffers in
48162306a36Sopenharmony_ci * revoke table to reflect there is no revoked buffers in the next
48262306a36Sopenharmony_ci * transaction which is going to be started.
48362306a36Sopenharmony_ci */
48462306a36Sopenharmony_civoid jbd2_clear_buffer_revoked_flags(journal_t *journal)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	struct jbd2_revoke_table_s *revoke = journal->j_revoke;
48762306a36Sopenharmony_ci	int i = 0;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	for (i = 0; i < revoke->hash_size; i++) {
49062306a36Sopenharmony_ci		struct list_head *hash_list;
49162306a36Sopenharmony_ci		struct list_head *list_entry;
49262306a36Sopenharmony_ci		hash_list = &revoke->hash_table[i];
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci		list_for_each(list_entry, hash_list) {
49562306a36Sopenharmony_ci			struct jbd2_revoke_record_s *record;
49662306a36Sopenharmony_ci			struct buffer_head *bh;
49762306a36Sopenharmony_ci			record = (struct jbd2_revoke_record_s *)list_entry;
49862306a36Sopenharmony_ci			bh = __find_get_block(journal->j_fs_dev,
49962306a36Sopenharmony_ci					      record->blocknr,
50062306a36Sopenharmony_ci					      journal->j_blocksize);
50162306a36Sopenharmony_ci			if (bh) {
50262306a36Sopenharmony_ci				clear_buffer_revoked(bh);
50362306a36Sopenharmony_ci				__brelse(bh);
50462306a36Sopenharmony_ci			}
50562306a36Sopenharmony_ci		}
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci/* journal_switch_revoke table select j_revoke for next transaction
51062306a36Sopenharmony_ci * we do not want to suspend any processing until all revokes are
51162306a36Sopenharmony_ci * written -bzzz
51262306a36Sopenharmony_ci */
51362306a36Sopenharmony_civoid jbd2_journal_switch_revoke_table(journal_t *journal)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	int i;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	if (journal->j_revoke == journal->j_revoke_table[0])
51862306a36Sopenharmony_ci		journal->j_revoke = journal->j_revoke_table[1];
51962306a36Sopenharmony_ci	else
52062306a36Sopenharmony_ci		journal->j_revoke = journal->j_revoke_table[0];
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	for (i = 0; i < journal->j_revoke->hash_size; i++)
52362306a36Sopenharmony_ci		INIT_LIST_HEAD(&journal->j_revoke->hash_table[i]);
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci/*
52762306a36Sopenharmony_ci * Write revoke records to the journal for all entries in the current
52862306a36Sopenharmony_ci * revoke hash, deleting the entries as we go.
52962306a36Sopenharmony_ci */
53062306a36Sopenharmony_civoid jbd2_journal_write_revoke_records(transaction_t *transaction,
53162306a36Sopenharmony_ci				       struct list_head *log_bufs)
53262306a36Sopenharmony_ci{
53362306a36Sopenharmony_ci	journal_t *journal = transaction->t_journal;
53462306a36Sopenharmony_ci	struct buffer_head *descriptor;
53562306a36Sopenharmony_ci	struct jbd2_revoke_record_s *record;
53662306a36Sopenharmony_ci	struct jbd2_revoke_table_s *revoke;
53762306a36Sopenharmony_ci	struct list_head *hash_list;
53862306a36Sopenharmony_ci	int i, offset, count;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	descriptor = NULL;
54162306a36Sopenharmony_ci	offset = 0;
54262306a36Sopenharmony_ci	count = 0;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	/* select revoke table for committing transaction */
54562306a36Sopenharmony_ci	revoke = journal->j_revoke == journal->j_revoke_table[0] ?
54662306a36Sopenharmony_ci		journal->j_revoke_table[1] : journal->j_revoke_table[0];
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	for (i = 0; i < revoke->hash_size; i++) {
54962306a36Sopenharmony_ci		hash_list = &revoke->hash_table[i];
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci		while (!list_empty(hash_list)) {
55262306a36Sopenharmony_ci			record = (struct jbd2_revoke_record_s *)
55362306a36Sopenharmony_ci				hash_list->next;
55462306a36Sopenharmony_ci			write_one_revoke_record(transaction, log_bufs,
55562306a36Sopenharmony_ci						&descriptor, &offset, record);
55662306a36Sopenharmony_ci			count++;
55762306a36Sopenharmony_ci			list_del(&record->hash);
55862306a36Sopenharmony_ci			kmem_cache_free(jbd2_revoke_record_cache, record);
55962306a36Sopenharmony_ci		}
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci	if (descriptor)
56262306a36Sopenharmony_ci		flush_descriptor(journal, descriptor, offset);
56362306a36Sopenharmony_ci	jbd2_debug(1, "Wrote %d revoke records\n", count);
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci/*
56762306a36Sopenharmony_ci * Write out one revoke record.  We need to create a new descriptor
56862306a36Sopenharmony_ci * block if the old one is full or if we have not already created one.
56962306a36Sopenharmony_ci */
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_cistatic void write_one_revoke_record(transaction_t *transaction,
57262306a36Sopenharmony_ci				    struct list_head *log_bufs,
57362306a36Sopenharmony_ci				    struct buffer_head **descriptorp,
57462306a36Sopenharmony_ci				    int *offsetp,
57562306a36Sopenharmony_ci				    struct jbd2_revoke_record_s *record)
57662306a36Sopenharmony_ci{
57762306a36Sopenharmony_ci	journal_t *journal = transaction->t_journal;
57862306a36Sopenharmony_ci	int csum_size = 0;
57962306a36Sopenharmony_ci	struct buffer_head *descriptor;
58062306a36Sopenharmony_ci	int sz, offset;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	/* If we are already aborting, this all becomes a noop.  We
58362306a36Sopenharmony_ci           still need to go round the loop in
58462306a36Sopenharmony_ci           jbd2_journal_write_revoke_records in order to free all of the
58562306a36Sopenharmony_ci           revoke records: only the IO to the journal is omitted. */
58662306a36Sopenharmony_ci	if (is_journal_aborted(journal))
58762306a36Sopenharmony_ci		return;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	descriptor = *descriptorp;
59062306a36Sopenharmony_ci	offset = *offsetp;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	/* Do we need to leave space at the end for a checksum? */
59362306a36Sopenharmony_ci	if (jbd2_journal_has_csum_v2or3(journal))
59462306a36Sopenharmony_ci		csum_size = sizeof(struct jbd2_journal_block_tail);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	if (jbd2_has_feature_64bit(journal))
59762306a36Sopenharmony_ci		sz = 8;
59862306a36Sopenharmony_ci	else
59962306a36Sopenharmony_ci		sz = 4;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	/* Make sure we have a descriptor with space left for the record */
60262306a36Sopenharmony_ci	if (descriptor) {
60362306a36Sopenharmony_ci		if (offset + sz > journal->j_blocksize - csum_size) {
60462306a36Sopenharmony_ci			flush_descriptor(journal, descriptor, offset);
60562306a36Sopenharmony_ci			descriptor = NULL;
60662306a36Sopenharmony_ci		}
60762306a36Sopenharmony_ci	}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	if (!descriptor) {
61062306a36Sopenharmony_ci		descriptor = jbd2_journal_get_descriptor_buffer(transaction,
61162306a36Sopenharmony_ci							JBD2_REVOKE_BLOCK);
61262306a36Sopenharmony_ci		if (!descriptor)
61362306a36Sopenharmony_ci			return;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci		/* Record it so that we can wait for IO completion later */
61662306a36Sopenharmony_ci		BUFFER_TRACE(descriptor, "file in log_bufs");
61762306a36Sopenharmony_ci		jbd2_file_log_bh(log_bufs, descriptor);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci		offset = sizeof(jbd2_journal_revoke_header_t);
62062306a36Sopenharmony_ci		*descriptorp = descriptor;
62162306a36Sopenharmony_ci	}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	if (jbd2_has_feature_64bit(journal))
62462306a36Sopenharmony_ci		* ((__be64 *)(&descriptor->b_data[offset])) =
62562306a36Sopenharmony_ci			cpu_to_be64(record->blocknr);
62662306a36Sopenharmony_ci	else
62762306a36Sopenharmony_ci		* ((__be32 *)(&descriptor->b_data[offset])) =
62862306a36Sopenharmony_ci			cpu_to_be32(record->blocknr);
62962306a36Sopenharmony_ci	offset += sz;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	*offsetp = offset;
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci/*
63562306a36Sopenharmony_ci * Flush a revoke descriptor out to the journal.  If we are aborting,
63662306a36Sopenharmony_ci * this is a noop; otherwise we are generating a buffer which needs to
63762306a36Sopenharmony_ci * be waited for during commit, so it has to go onto the appropriate
63862306a36Sopenharmony_ci * journal buffer list.
63962306a36Sopenharmony_ci */
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_cistatic void flush_descriptor(journal_t *journal,
64262306a36Sopenharmony_ci			     struct buffer_head *descriptor,
64362306a36Sopenharmony_ci			     int offset)
64462306a36Sopenharmony_ci{
64562306a36Sopenharmony_ci	jbd2_journal_revoke_header_t *header;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	if (is_journal_aborted(journal))
64862306a36Sopenharmony_ci		return;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	header = (jbd2_journal_revoke_header_t *)descriptor->b_data;
65162306a36Sopenharmony_ci	header->r_count = cpu_to_be32(offset);
65262306a36Sopenharmony_ci	jbd2_descriptor_block_csum_set(journal, descriptor);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	set_buffer_jwrite(descriptor);
65562306a36Sopenharmony_ci	BUFFER_TRACE(descriptor, "write");
65662306a36Sopenharmony_ci	set_buffer_dirty(descriptor);
65762306a36Sopenharmony_ci	write_dirty_buffer(descriptor, REQ_SYNC);
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ci#endif
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci/*
66262306a36Sopenharmony_ci * Revoke support for recovery.
66362306a36Sopenharmony_ci *
66462306a36Sopenharmony_ci * Recovery needs to be able to:
66562306a36Sopenharmony_ci *
66662306a36Sopenharmony_ci *  record all revoke records, including the tid of the latest instance
66762306a36Sopenharmony_ci *  of each revoke in the journal
66862306a36Sopenharmony_ci *
66962306a36Sopenharmony_ci *  check whether a given block in a given transaction should be replayed
67062306a36Sopenharmony_ci *  (ie. has not been revoked by a revoke record in that or a subsequent
67162306a36Sopenharmony_ci *  transaction)
67262306a36Sopenharmony_ci *
67362306a36Sopenharmony_ci *  empty the revoke table after recovery.
67462306a36Sopenharmony_ci */
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci/*
67762306a36Sopenharmony_ci * First, setting revoke records.  We create a new revoke record for
67862306a36Sopenharmony_ci * every block ever revoked in the log as we scan it for recovery, and
67962306a36Sopenharmony_ci * we update the existing records if we find multiple revokes for a
68062306a36Sopenharmony_ci * single block.
68162306a36Sopenharmony_ci */
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ciint jbd2_journal_set_revoke(journal_t *journal,
68462306a36Sopenharmony_ci		       unsigned long long blocknr,
68562306a36Sopenharmony_ci		       tid_t sequence)
68662306a36Sopenharmony_ci{
68762306a36Sopenharmony_ci	struct jbd2_revoke_record_s *record;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	record = find_revoke_record(journal, blocknr);
69062306a36Sopenharmony_ci	if (record) {
69162306a36Sopenharmony_ci		/* If we have multiple occurrences, only record the
69262306a36Sopenharmony_ci		 * latest sequence number in the hashed record */
69362306a36Sopenharmony_ci		if (tid_gt(sequence, record->sequence))
69462306a36Sopenharmony_ci			record->sequence = sequence;
69562306a36Sopenharmony_ci		return 0;
69662306a36Sopenharmony_ci	}
69762306a36Sopenharmony_ci	return insert_revoke_hash(journal, blocknr, sequence);
69862306a36Sopenharmony_ci}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci/*
70162306a36Sopenharmony_ci * Test revoke records.  For a given block referenced in the log, has
70262306a36Sopenharmony_ci * that block been revoked?  A revoke record with a given transaction
70362306a36Sopenharmony_ci * sequence number revokes all blocks in that transaction and earlier
70462306a36Sopenharmony_ci * ones, but later transactions still need replayed.
70562306a36Sopenharmony_ci */
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ciint jbd2_journal_test_revoke(journal_t *journal,
70862306a36Sopenharmony_ci			unsigned long long blocknr,
70962306a36Sopenharmony_ci			tid_t sequence)
71062306a36Sopenharmony_ci{
71162306a36Sopenharmony_ci	struct jbd2_revoke_record_s *record;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	record = find_revoke_record(journal, blocknr);
71462306a36Sopenharmony_ci	if (!record)
71562306a36Sopenharmony_ci		return 0;
71662306a36Sopenharmony_ci	if (tid_gt(sequence, record->sequence))
71762306a36Sopenharmony_ci		return 0;
71862306a36Sopenharmony_ci	return 1;
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci/*
72262306a36Sopenharmony_ci * Finally, once recovery is over, we need to clear the revoke table so
72362306a36Sopenharmony_ci * that it can be reused by the running filesystem.
72462306a36Sopenharmony_ci */
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_civoid jbd2_journal_clear_revoke(journal_t *journal)
72762306a36Sopenharmony_ci{
72862306a36Sopenharmony_ci	int i;
72962306a36Sopenharmony_ci	struct list_head *hash_list;
73062306a36Sopenharmony_ci	struct jbd2_revoke_record_s *record;
73162306a36Sopenharmony_ci	struct jbd2_revoke_table_s *revoke;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	revoke = journal->j_revoke;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	for (i = 0; i < revoke->hash_size; i++) {
73662306a36Sopenharmony_ci		hash_list = &revoke->hash_table[i];
73762306a36Sopenharmony_ci		while (!list_empty(hash_list)) {
73862306a36Sopenharmony_ci			record = (struct jbd2_revoke_record_s*) hash_list->next;
73962306a36Sopenharmony_ci			list_del(&record->hash);
74062306a36Sopenharmony_ci			kmem_cache_free(jbd2_revoke_record_cache, record);
74162306a36Sopenharmony_ci		}
74262306a36Sopenharmony_ci	}
74362306a36Sopenharmony_ci}
744