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