LCOV - code coverage report
Current view: top level - lkbce/fs/jbd - revoke.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 23 269 8.6 %
Date: 2017-01-25 Functions: 2 18 11.1 %

          Line data    Source code
       1             : /*
       2             :  * linux/fs/jbd/revoke.c
       3             :  *
       4             :  * Written by Stephen C. Tweedie <sct@redhat.com>, 2000
       5             :  *
       6             :  * Copyright 2000 Red Hat corp --- All Rights Reserved
       7             :  *
       8             :  * This file is part of the Linux kernel and is made available under
       9             :  * the terms of the GNU General Public License, version 2, or at your
      10             :  * option, any later version, incorporated herein by reference.
      11             :  *
      12             :  * Journal revoke routines for the generic filesystem journaling code;
      13             :  * part of the ext2fs journaling system.
      14             :  *
      15             :  * Revoke is the mechanism used to prevent old log records for deleted
      16             :  * metadata from being replayed on top of newer data using the same
      17             :  * blocks.  The revoke mechanism is used in two separate places:
      18             :  *
      19             :  * + Commit: during commit we write the entire list of the current
      20             :  *   transaction's revoked blocks to the journal
      21             :  *
      22             :  * + Recovery: during recovery we record the transaction ID of all
      23             :  *   revoked blocks.  If there are multiple revoke records in the log
      24             :  *   for a single block, only the last one counts, and if there is a log
      25             :  *   entry for a block beyond the last revoke, then that log entry still
      26             :  *   gets replayed.
      27             :  *
      28             :  * We can get interactions between revokes and new log data within a
      29             :  * single transaction:
      30             :  *
      31             :  * Block is revoked and then journaled:
      32             :  *   The desired end result is the journaling of the new block, so we
      33             :  *   cancel the revoke before the transaction commits.
      34             :  *
      35             :  * Block is journaled and then revoked:
      36             :  *   The revoke must take precedence over the write of the block, so we
      37             :  *   need either to cancel the journal entry or to write the revoke
      38             :  *   later in the log than the log block.  In this case, we choose the
      39             :  *   latter: journaling a block cancels any revoke record for that block
      40             :  *   in the current transaction, so any revoke for that block in the
      41             :  *   transaction must have happened after the block was journaled and so
      42             :  *   the revoke must take precedence.
      43             :  *
      44             :  * Block is revoked and then written as data:
      45             :  *   The data write is allowed to succeed, but the revoke is _not_
      46             :  *   cancelled.  We still need to prevent old log records from
      47             :  *   overwriting the new data.  We don't even need to clear the revoke
      48             :  *   bit here.
      49             :  *
      50             :  * Revoke information on buffers is a tri-state value:
      51             :  *
      52             :  * RevokeValid clear:   no cached revoke status, need to look it up
      53             :  * RevokeValid set, Revoked clear:
      54             :  *                      buffer has not been revoked, and cancel_revoke
      55             :  *                      need do nothing.
      56             :  * RevokeValid set, Revoked set:
      57             :  *                      buffer has been revoked.
      58             :  *
      59             :  * Locking rules:
      60             :  * We keep two hash tables of revoke records. One hashtable belongs to the
      61             :  * running transaction (is pointed to by journal->j_revoke), the other one
      62             :  * belongs to the committing transaction. Accesses to the second hash table
      63             :  * happen only from the kjournald and no other thread touches this table.  Also
      64             :  * journal_switch_revoke_table() which switches which hashtable belongs to the
      65             :  * running and which to the committing transaction is called only from
      66             :  * kjournald. Therefore we need no locks when accessing the hashtable belonging
      67             :  * to the committing transaction.
      68             :  *
      69             :  * All users operating on the hash table belonging to the running transaction
      70             :  * have a handle to the transaction. Therefore they are safe from kjournald
      71             :  * switching hash tables under them. For operations on the lists of entries in
      72             :  * the hash table j_revoke_lock is used.
      73             :  *
      74             :  * Finally, also replay code uses the hash tables but at this moment noone else
      75             :  * can touch them (filesystem isn't mounted yet) and hence no locking is
      76             :  * needed.
      77             :  */
      78             : 
      79             : #ifndef __KERNEL__
      80             : #include "jfs_user.h"
      81             : #else
      82             : #include <linux/time.h>
      83             : #include <linux/fs.h>
      84             : #include <linux/jbd.h>
      85             : #include <linux/errno.h>
      86             : #include <linux/slab.h>
      87             : #include <linux/list.h>
      88             : #include <linux/init.h>
      89             : #include <linux/bio.h>
      90             : #endif
      91             : #include <linux/log2.h>
      92             : 
      93           1 : static struct kmem_cache *revoke_record_cache;
      94           1 : static struct kmem_cache *revoke_table_cache;
      95           1 : 
      96             : /* Each revoke record represents one single revoked block.  During
      97             :    journal replay, this involves recording the transaction ID of the
      98             :    last transaction to revoke this block. */
      99             : 
     100             : struct jbd_revoke_record_s
     101             : {
     102             :         struct list_head  hash;
     103             :         tid_t             sequence;     /* Used for recovery only */
     104             :         unsigned int      blocknr;
     105             : };
     106           1 : 
     107             : 
     108             : /* The revoke table is just a simple hash table of revoke records. */
     109             : struct jbd_revoke_table_s
     110             : {
     111             :         /* It is conceivable that we might want a larger hash table
     112             :          * for recovery.  Must be a power of two. */
     113             :         int               hash_size;
     114             :         int               hash_shift;
     115             :         struct list_head *hash_table;
     116             : };
     117             : 
     118             : 
     119             : #ifdef __KERNEL__
     120             : static void write_one_revoke_record(journal_t *, transaction_t *,
     121             :                                     struct journal_head **, int *,
     122             :                                     struct jbd_revoke_record_s *, int);
     123             : static void flush_descriptor(journal_t *, struct journal_head *, int, int);
     124             : #endif
     125             : 
     126             : /* Utility functions to maintain the revoke table */
     127             : 
     128             : /* Borrowed from buffer.c: this is a tried and tested block hash function */
     129             : static inline int hash(journal_t *journal, unsigned int block)
     130             : {
     131           0 :         struct jbd_revoke_table_s *table = journal->j_revoke;
     132           0 :         int hash_shift = table->hash_shift;
     133             : 
     134           0 :         return ((block << (hash_shift - 6)) ^
     135             :                 (block >> 13) ^
     136             :                 (block << (hash_shift - 12))) & (table->hash_size - 1);
     137             : }
     138             : 
     139             : static int insert_revoke_hash(journal_t *journal, unsigned int blocknr,
     140             :                               tid_t seq)
     141           0 : {
     142           0 :         struct list_head *hash_list;
     143           0 :         struct jbd_revoke_record_s *record;
     144           0 : 
     145             : repeat:
     146           0 :         record = kmem_cache_alloc(revoke_record_cache, GFP_NOFS);
     147           0 :         if (!record)
     148           0 :                 goto oom;
     149             : 
     150           0 :         record->sequence = seq;
     151           0 :         record->blocknr = blocknr;
     152           0 :         hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
     153           0 :         spin_lock(&journal->j_revoke_lock);
     154           0 :         list_add(&record->hash, hash_list);
     155           0 :         spin_unlock(&journal->j_revoke_lock);
     156           0 :         return 0;
     157           0 : 
     158             : oom:
     159             :         if (!journal_oom_retry)
     160             :                 return -ENOMEM;
     161             :         jbd_debug(1, "ENOMEM in %s, retrying\n", __func__);
     162           0 :         yield();
     163           0 :         goto repeat;
     164             : }
     165             : 
     166             : /* Find a revoke record in the journal's hash table. */
     167             : 
     168             : static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal,
     169             :                                                       unsigned int blocknr)
     170           0 : {
     171           0 :         struct list_head *hash_list;
     172           0 :         struct jbd_revoke_record_s *record;
     173             : 
     174           0 :         hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
     175             : 
     176           0 :         spin_lock(&journal->j_revoke_lock);
     177           0 :         record = (struct jbd_revoke_record_s *) hash_list->next;
     178           0 :         while (&(record->hash) != hash_list) {
     179           0 :                 if (record->blocknr == blocknr) {
     180           0 :                         spin_unlock(&journal->j_revoke_lock);
     181           0 :                         return record;
     182             :                 }
     183           0 :                 record = (struct jbd_revoke_record_s *) record->hash.next;
     184           0 :         }
     185           0 :         spin_unlock(&journal->j_revoke_lock);
     186           0 :         return NULL;
     187             : }
     188             : 
     189             : void journal_destroy_revoke_caches(void)
     190             : {
     191           8 :         if (revoke_record_cache) {
     192           4 :                 kmem_cache_destroy(revoke_record_cache);
     193           4 :                 revoke_record_cache = NULL;
     194             :         }
     195           8 :         if (revoke_table_cache) {
     196           4 :                 kmem_cache_destroy(revoke_table_cache);
     197           4 :                 revoke_table_cache = NULL;
     198             :         }
     199           4 : }
     200             : 
     201             : int __init journal_init_revoke_caches(void)
     202             : {
     203           7 :         J_ASSERT(!revoke_record_cache);
     204           7 :         J_ASSERT(!revoke_table_cache);
     205             : 
     206           1 :         revoke_record_cache = kmem_cache_create("revoke_record",
     207             :                                            sizeof(struct jbd_revoke_record_s),
     208             :                                            0,
     209             :                                            SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY,
     210             :                                            NULL);
     211           2 :         if (!revoke_record_cache)
     212           1 :                 goto record_cache_failure;
     213             : 
     214           1 :         revoke_table_cache = kmem_cache_create("revoke_table",
     215             :                                            sizeof(struct jbd_revoke_table_s),
     216             :                                            0, SLAB_TEMPORARY, NULL);
     217           2 :         if (!revoke_table_cache)
     218           1 :                 goto table_cache_failure;
     219             : 
     220           1 :         return 0;
     221           1 : 
     222             : table_cache_failure:
     223           2 :         journal_destroy_revoke_caches();
     224             : record_cache_failure:
     225           3 :         return -ENOMEM;
     226             : }
     227             : 
     228             : static struct jbd_revoke_table_s *journal_init_revoke_table(int hash_size)
     229             : {
     230           0 :         int shift = 0;
     231           0 :         int tmp = hash_size;
     232           0 :         struct jbd_revoke_table_s *table;
     233           0 : 
     234           0 :         table = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL);
     235           0 :         if (!table)
     236           0 :                 goto out;
     237             : 
     238           0 :         while((tmp >>= 1UL) != 0UL)
     239           0 :                 shift++;
     240           0 : 
     241           0 :         table->hash_size = hash_size;
     242           0 :         table->hash_shift = shift;
     243           0 :         table->hash_table =
     244             :                 kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL);
     245           0 :         if (!table->hash_table) {
     246           0 :                 kmem_cache_free(revoke_table_cache, table);
     247           0 :                 table = NULL;
     248           0 :                 goto out;
     249             :         }
     250             : 
     251           0 :         for (tmp = 0; tmp < hash_size; tmp++)
     252           0 :                 INIT_LIST_HEAD(&table->hash_table[tmp]);
     253           0 : 
     254             : out:
     255           0 :         return table;
     256             : }
     257             : 
     258           0 : static void journal_destroy_revoke_table(struct jbd_revoke_table_s *table)
     259             : {
     260           0 :         int i;
     261           0 :         struct list_head *hash_list;
     262           0 : 
     263           0 :         for (i = 0; i < table->hash_size; i++) {
     264           0 :                 hash_list = &table->hash_table[i];
     265           0 :                 J_ASSERT(list_empty(hash_list));
     266             :         }
     267             : 
     268           0 :         kfree(table->hash_table);
     269           0 :         kmem_cache_free(revoke_table_cache, table);
     270           0 : }
     271             : 
     272             : /* Initialise the revoke table for a given journal to a given size. */
     273             : int journal_init_revoke(journal_t *journal, int hash_size)
     274             : {
     275           0 :         J_ASSERT(journal->j_revoke_table[0] == NULL);
     276           0 :         J_ASSERT(is_power_of_2(hash_size));
     277           0 : 
     278           0 :         journal->j_revoke_table[0] = journal_init_revoke_table(hash_size);
     279           0 :         if (!journal->j_revoke_table[0])
     280           0 :                 goto fail0;
     281             : 
     282           0 :         journal->j_revoke_table[1] = journal_init_revoke_table(hash_size);
     283           0 :         if (!journal->j_revoke_table[1])
     284           0 :                 goto fail1;
     285             : 
     286           0 :         journal->j_revoke = journal->j_revoke_table[1];
     287             : 
     288           0 :         spin_lock_init(&journal->j_revoke_lock);
     289             : 
     290           0 :         return 0;
     291           0 : 
     292             : fail1:
     293           0 :         journal_destroy_revoke_table(journal->j_revoke_table[0]);
     294             : fail0:
     295           0 :         return -ENOMEM;
     296             : }
     297             : 
     298             : /* Destroy a journal's revoke table.  The table must already be empty! */
     299             : void journal_destroy_revoke(journal_t *journal)
     300             : {
     301           0 :         journal->j_revoke = NULL;
     302           0 :         if (journal->j_revoke_table[0])
     303           0 :                 journal_destroy_revoke_table(journal->j_revoke_table[0]);
     304           0 :         if (journal->j_revoke_table[1])
     305           0 :                 journal_destroy_revoke_table(journal->j_revoke_table[1]);
     306           0 : }
     307             : 
     308             : 
     309             : #ifdef __KERNEL__
     310             : 
     311             : /*
     312             :  * journal_revoke: revoke a given buffer_head from the journal.  This
     313             :  * prevents the block from being replayed during recovery if we take a
     314             :  * crash after this current transaction commits.  Any subsequent
     315             :  * metadata writes of the buffer in this transaction cancel the
     316             :  * revoke.
     317             :  *
     318             :  * Note that this call may block --- it is up to the caller to make
     319             :  * sure that there are no further calls to journal_write_metadata
     320             :  * before the revoke is complete.  In ext3, this implies calling the
     321             :  * revoke before clearing the block bitmap when we are deleting
     322             :  * metadata.
     323             :  *
     324             :  * Revoke performs a journal_forget on any buffer_head passed in as a
     325             :  * parameter, but does _not_ forget the buffer_head if the bh was only
     326             :  * found implicitly.
     327             :  *
     328             :  * bh_in may not be a journalled buffer - it may have come off
     329             :  * the hash tables without an attached journal_head.
     330             :  *
     331             :  * If bh_in is non-zero, journal_revoke() will decrement its b_count
     332             :  * by one.
     333             :  */
     334             : 
     335             : int journal_revoke(handle_t *handle, unsigned int blocknr,
     336             :                    struct buffer_head *bh_in)
     337           0 : {
     338           0 :         struct buffer_head *bh = NULL;
     339           0 :         journal_t *journal;
     340           0 :         struct block_device *bdev;
     341           0 :         int err;
     342           0 : 
     343           0 :         might_sleep();
     344             :         if (bh_in)
     345             :                 BUFFER_TRACE(bh_in, "enter");
     346             : 
     347           0 :         journal = handle->h_transaction->t_journal;
     348           0 :         if (!journal_set_features(journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)){
     349           0 :                 J_ASSERT (!"Cannot set revoke feature!");
     350           0 :                 return -EINVAL;
     351             :         }
     352             : 
     353           0 :         bdev = journal->j_fs_dev;
     354           0 :         bh = bh_in;
     355             : 
     356           0 :         if (!bh) {
     357           0 :                 bh = __find_get_block(bdev, blocknr, journal->j_blocksize);
     358             :                 if (bh)
     359             :                         BUFFER_TRACE(bh, "found on hash");
     360             :         }
     361             : #ifdef JBD_EXPENSIVE_CHECKING
     362             :         else {
     363             :                 struct buffer_head *bh2;
     364             : 
     365             :                 /* If there is a different buffer_head lying around in
     366             :                  * memory anywhere... */
     367             :                 bh2 = __find_get_block(bdev, blocknr, journal->j_blocksize);
     368             :                 if (bh2) {
     369             :                         /* ... and it has RevokeValid status... */
     370             :                         if (bh2 != bh && buffer_revokevalid(bh2))
     371             :                                 /* ...then it better be revoked too,
     372             :                                  * since it's illegal to create a revoke
     373             :                                  * record against a buffer_head which is
     374             :                                  * not marked revoked --- that would
     375             :                                  * risk missing a subsequent revoke
     376             :                                  * cancel. */
     377             :                                 J_ASSERT_BH(bh2, buffer_revoked(bh2));
     378             :                         put_bh(bh2);
     379             :                 }
     380             :         }
     381             : #endif
     382             : 
     383             :         /* We really ought not ever to revoke twice in a row without
     384             :            first having the revoke cancelled: it's illegal to free a
     385             :            block twice without allocating it in between! */
     386           0 :         if (bh) {
     387           0 :                 if (!J_EXPECT_BH(bh, !buffer_revoked(bh),
     388             :                                  "inconsistent data on disk")) {
     389           0 :                         if (!bh_in)
     390           0 :                                 brelse(bh);
     391           0 :                         return -EIO;
     392             :                 }
     393           0 :                 set_buffer_revoked(bh);
     394           0 :                 set_buffer_revokevalid(bh);
     395           0 :                 if (bh_in) {
     396             :                         BUFFER_TRACE(bh_in, "call journal_forget");
     397           0 :                         journal_forget(handle, bh_in);
     398             :                 } else {
     399             :                         BUFFER_TRACE(bh, "call brelse");
     400           0 :                         __brelse(bh);
     401             :                 }
     402             :         }
     403             : 
     404             :         jbd_debug(2, "insert revoke for block %u, bh_in=%p\n", blocknr, bh_in);
     405           0 :         err = insert_revoke_hash(journal, blocknr,
     406             :                                 handle->h_transaction->t_tid);
     407             :         BUFFER_TRACE(bh_in, "exit");
     408           0 :         return err;
     409             : }
     410             : 
     411             : /*
     412             :  * Cancel an outstanding revoke.  For use only internally by the
     413             :  * journaling code (called from journal_get_write_access).
     414             :  *
     415             :  * We trust buffer_revoked() on the buffer if the buffer is already
     416             :  * being journaled: if there is no revoke pending on the buffer, then we
     417             :  * don't do anything here.
     418             :  *
     419             :  * This would break if it were possible for a buffer to be revoked and
     420             :  * discarded, and then reallocated within the same transaction.  In such
     421             :  * a case we would have lost the revoked bit, but when we arrived here
     422             :  * the second time we would still have a pending revoke to cancel.  So,
     423             :  * do not trust the Revoked bit on buffers unless RevokeValid is also
     424             :  * set.
     425             :  */
     426             : int journal_cancel_revoke(handle_t *handle, struct journal_head *jh)
     427             : {
     428           0 :         struct jbd_revoke_record_s *record;
     429           0 :         journal_t *journal = handle->h_transaction->t_journal;
     430           0 :         int need_cancel;
     431           0 :         int did_revoke = 0;     /* akpm: debug */
     432           0 :         struct buffer_head *bh = jh2bh(jh);
     433           0 : 
     434           0 :         jbd_debug(4, "journal_head %p, cancelling revoke\n", jh);
     435           0 : 
     436             :         /* Is the existing Revoke bit valid?  If so, we trust it, and
     437             :          * only perform the full cancel if the revoke bit is set.  If
     438             :          * not, we can't trust the revoke bit, and we need to do the
     439             :          * full search for a revoke record. */
     440           0 :         if (test_set_buffer_revokevalid(bh)) {
     441           0 :                 need_cancel = test_clear_buffer_revoked(bh);
     442             :         } else {
     443           0 :                 need_cancel = 1;
     444           0 :                 clear_buffer_revoked(bh);
     445             :         }
     446             : 
     447           0 :         if (need_cancel) {
     448           0 :                 record = find_revoke_record(journal, bh->b_blocknr);
     449           0 :                 if (record) {
     450             :                         jbd_debug(4, "cancelled existing revoke on "
     451             :                                   "blocknr %llu\n", (unsigned long long)bh->b_blocknr);
     452           0 :                         spin_lock(&journal->j_revoke_lock);
     453           0 :                         list_del(&record->hash);
     454           0 :                         spin_unlock(&journal->j_revoke_lock);
     455           0 :                         kmem_cache_free(revoke_record_cache, record);
     456           0 :                         did_revoke = 1;
     457             :                 }
     458             :         }
     459             : 
     460             : #ifdef JBD_EXPENSIVE_CHECKING
     461             :         /* There better not be one left behind by now! */
     462             :         record = find_revoke_record(journal, bh->b_blocknr);
     463             :         J_ASSERT_JH(jh, record == NULL);
     464             : #endif
     465             : 
     466             :         /* Finally, have we just cleared revoke on an unhashed
     467             :          * buffer_head?  If so, we'd better make sure we clear the
     468             :          * revoked status on any hashed alias too, otherwise the revoke
     469             :          * state machine will get very upset later on. */
     470           0 :         if (need_cancel) {
     471             :                 struct buffer_head *bh2;
     472           0 :                 bh2 = __find_get_block(bh->b_bdev, bh->b_blocknr, bh->b_size);
     473           0 :                 if (bh2) {
     474           0 :                         if (bh2 != bh)
     475           0 :                                 clear_buffer_revoked(bh2);
     476           0 :                         __brelse(bh2);
     477             :                 }
     478             :         }
     479           0 :         return did_revoke;
     480             : }
     481             : 
     482             : /* journal_switch_revoke table select j_revoke for next transaction
     483             :  * we do not want to suspend any processing until all revokes are
     484             :  * written -bzzz
     485             :  */
     486             : void journal_switch_revoke_table(journal_t *journal)
     487             : {
     488           0 :         int i;
     489             : 
     490           0 :         if (journal->j_revoke == journal->j_revoke_table[0])
     491           0 :                 journal->j_revoke = journal->j_revoke_table[1];
     492             :         else
     493           0 :                 journal->j_revoke = journal->j_revoke_table[0];
     494             : 
     495           0 :         for (i = 0; i < journal->j_revoke->hash_size; i++)
     496           0 :                 INIT_LIST_HEAD(&journal->j_revoke->hash_table[i]);
     497           0 : }
     498             : 
     499             : /*
     500             :  * Write revoke records to the journal for all entries in the current
     501             :  * revoke hash, deleting the entries as we go.
     502           0 :  */
     503             : void journal_write_revoke_records(journal_t *journal,
     504             :                                   transaction_t *transaction, int write_op)
     505             : {
     506           0 :         struct journal_head *descriptor;
     507           0 :         struct jbd_revoke_record_s *record;
     508           0 :         struct jbd_revoke_table_s *revoke;
     509           0 :         struct list_head *hash_list;
     510           0 :         int i, offset, count;
     511           0 : 
     512           0 :         descriptor = NULL;
     513           0 :         offset = 0;
     514           0 :         count = 0;
     515             : 
     516             :         /* select revoke table for committing transaction */
     517           0 :         revoke = journal->j_revoke == journal->j_revoke_table[0] ?
     518             :                 journal->j_revoke_table[1] : journal->j_revoke_table[0];
     519             : 
     520           0 :         for (i = 0; i < revoke->hash_size; i++) {
     521           0 :                 hash_list = &revoke->hash_table[i];
     522           0 : 
     523           0 :                 while (!list_empty(hash_list)) {
     524           0 :                         record = (struct jbd_revoke_record_s *)
     525           0 :                                 hash_list->next;
     526           0 :                         write_one_revoke_record(journal, transaction,
     527             :                                                 &descriptor, &offset,
     528             :                                                 record, write_op);
     529           0 :                         count++;
     530           0 :                         list_del(&record->hash);
     531           0 :                         kmem_cache_free(revoke_record_cache, record);
     532             :                 }
     533           0 :         }
     534           0 :         if (descriptor)
     535           0 :                 flush_descriptor(journal, descriptor, offset, write_op);
     536           0 :         jbd_debug(1, "Wrote %d revoke records\n", count);
     537             : }
     538             : 
     539             : /*
     540             :  * Write out one revoke record.  We need to create a new descriptor
     541             :  * block if the old one is full or if we have not already created one.
     542             :  */
     543             : 
     544             : static void write_one_revoke_record(journal_t *journal,
     545             :                                     transaction_t *transaction,
     546             :                                     struct journal_head **descriptorp,
     547             :                                     int *offsetp,
     548           0 :                                     struct jbd_revoke_record_s *record,
     549           0 :                                     int write_op)
     550           0 : {
     551           0 :         struct journal_head *descriptor;
     552           0 :         int offset;
     553           0 :         journal_header_t *header;
     554           0 : 
     555           0 :         /* If we are already aborting, this all becomes a noop.  We
     556             :            still need to go round the loop in
     557             :            journal_write_revoke_records in order to free all of the
     558             :            revoke records: only the IO to the journal is omitted. */
     559           0 :         if (is_journal_aborted(journal))
     560           0 :                 return;
     561             : 
     562           0 :         descriptor = *descriptorp;
     563           0 :         offset = *offsetp;
     564             : 
     565             :         /* Make sure we have a descriptor with space left for the record */
     566           0 :         if (descriptor) {
     567           0 :                 if (offset == journal->j_blocksize) {
     568           0 :                         flush_descriptor(journal, descriptor, offset, write_op);
     569           0 :                         descriptor = NULL;
     570             :                 }
     571             :         }
     572             : 
     573           0 :         if (!descriptor) {
     574           0 :                 descriptor = journal_get_descriptor_buffer(journal);
     575           0 :                 if (!descriptor)
     576           0 :                         return;
     577           0 :                 header = (journal_header_t *) &jh2bh(descriptor)->b_data[0];
     578           0 :                 header->h_magic     = cpu_to_be32(JFS_MAGIC_NUMBER);
     579           0 :                 header->h_blocktype = cpu_to_be32(JFS_REVOKE_BLOCK);
     580           0 :                 header->h_sequence  = cpu_to_be32(transaction->t_tid);
     581             : 
     582             :                 /* Record it so that we can wait for IO completion later */
     583             :                 JBUFFER_TRACE(descriptor, "file as BJ_LogCtl");
     584           0 :                 journal_file_buffer(descriptor, transaction, BJ_LogCtl);
     585             : 
     586           0 :                 offset = sizeof(journal_revoke_header_t);
     587           0 :                 *descriptorp = descriptor;
     588             :         }
     589             : 
     590           0 :         * ((__be32 *)(&jh2bh(descriptor)->b_data[offset])) =
     591             :                 cpu_to_be32(record->blocknr);
     592           0 :         offset += 4;
     593           0 :         *offsetp = offset;
     594           0 : }
     595             : 
     596             : /*
     597             :  * Flush a revoke descriptor out to the journal.  If we are aborting,
     598             :  * this is a noop; otherwise we are generating a buffer which needs to
     599             :  * be waited for during commit, so it has to go onto the appropriate
     600             :  * journal buffer list.
     601             :  */
     602             : 
     603             : static void flush_descriptor(journal_t *journal,
     604             :                              struct journal_head *descriptor,
     605             :                              int offset, int write_op)
     606           0 : {
     607           0 :         journal_revoke_header_t *header;
     608           0 :         struct buffer_head *bh = jh2bh(descriptor);
     609           0 : 
     610           0 :         if (is_journal_aborted(journal)) {
     611           0 :                 put_bh(bh);
     612           0 :                 return;
     613             :         }
     614             : 
     615           0 :         header = (journal_revoke_header_t *) jh2bh(descriptor)->b_data;
     616           0 :         header->r_count = cpu_to_be32(offset);
     617           0 :         set_buffer_jwrite(bh);
     618             :         BUFFER_TRACE(bh, "write");
     619           0 :         set_buffer_dirty(bh);
     620           0 :         ll_rw_block((write_op == WRITE) ? SWRITE : SWRITE_SYNC_PLUG, 1, &bh);
     621           0 : }
     622             : #endif
     623             : 
     624             : /*
     625             :  * Revoke support for recovery.
     626             :  *
     627             :  * Recovery needs to be able to:
     628             :  *
     629             :  *  record all revoke records, including the tid of the latest instance
     630             :  *  of each revoke in the journal
     631             :  *
     632             :  *  check whether a given block in a given transaction should be replayed
     633             :  *  (ie. has not been revoked by a revoke record in that or a subsequent
     634             :  *  transaction)
     635             :  *
     636             :  *  empty the revoke table after recovery.
     637             :  */
     638             : 
     639             : /*
     640             :  * First, setting revoke records.  We create a new revoke record for
     641             :  * every block ever revoked in the log as we scan it for recovery, and
     642             :  * we update the existing records if we find multiple revokes for a
     643             :  * single block.
     644             :  */
     645             : 
     646             : int journal_set_revoke(journal_t *journal,
     647             :                        unsigned int blocknr,
     648           0 :                        tid_t sequence)
     649           0 : {
     650           0 :         struct jbd_revoke_record_s *record;
     651             : 
     652           0 :         record = find_revoke_record(journal, blocknr);
     653           0 :         if (record) {
     654             :                 /* If we have multiple occurrences, only record the
     655             :                  * latest sequence number in the hashed record */
     656           0 :                 if (tid_gt(sequence, record->sequence))
     657           0 :                         record->sequence = sequence;
     658           0 :                 return 0;
     659             :         }
     660           0 :         return insert_revoke_hash(journal, blocknr, sequence);
     661             : }
     662             : 
     663             : /*
     664             :  * Test revoke records.  For a given block referenced in the log, has
     665             :  * that block been revoked?  A revoke record with a given transaction
     666             :  * sequence number revokes all blocks in that transaction and earlier
     667             :  * ones, but later transactions still need replayed.
     668             :  */
     669             : 
     670             : int journal_test_revoke(journal_t *journal,
     671             :                         unsigned int blocknr,
     672           0 :                         tid_t sequence)
     673           0 : {
     674             :         struct jbd_revoke_record_s *record;
     675             : 
     676           0 :         record = find_revoke_record(journal, blocknr);
     677           0 :         if (!record)
     678           0 :                 return 0;
     679           0 :         if (tid_gt(sequence, record->sequence))
     680           0 :                 return 0;
     681           0 :         return 1;
     682             : }
     683             : 
     684             : /*
     685             :  * Finally, once recovery is over, we need to clear the revoke table so
     686             :  * that it can be reused by the running filesystem.
     687             :  */
     688             : 
     689             : void journal_clear_revoke(journal_t *journal)
     690             : {
     691           0 :         int i;
     692           0 :         struct list_head *hash_list;
     693           0 :         struct jbd_revoke_record_s *record;
     694           0 :         struct jbd_revoke_table_s *revoke;
     695           0 : 
     696           0 :         revoke = journal->j_revoke;
     697             : 
     698           0 :         for (i = 0; i < revoke->hash_size; i++) {
     699           0 :                 hash_list = &revoke->hash_table[i];
     700           0 :                 while (!list_empty(hash_list)) {
     701           0 :                         record = (struct jbd_revoke_record_s*) hash_list->next;
     702           0 :                         list_del(&record->hash);
     703           0 :                         kmem_cache_free(revoke_record_cache, record);
     704             :                 }
     705           0 :         }
     706             : }

Generated by: LCOV version 1.10