2017-12-18 06:00:59 +03:00
// SPDX-License-Identifier: GPL-2.0+
2006-10-11 12:20:57 +04:00
/*
2007-05-09 09:51:49 +04:00
* linux / fs / jbd2 / recovery . c
2006-10-11 12:20:57 +04:00
*
* Written by Stephen C . Tweedie < sct @ redhat . com > , 1999
*
* Copyright 1999 - 2000 Red Hat Software - - - All Rights Reserved
*
* Journal recovery routines for the generic filesystem journaling code ;
* part of the ext2fs journaling system .
*/
# ifndef __KERNEL__
# include "jfs_user.h"
# else
# include <linux/time.h>
# include <linux/fs.h>
2006-10-11 12:20:59 +04:00
# include <linux/jbd2.h>
2006-10-11 12:20:57 +04:00
# include <linux/errno.h>
2008-01-29 07:58:27 +03:00
# include <linux/crc32.h>
2012-03-14 06:22:54 +04:00
# include <linux/blkdev.h>
2006-10-11 12:20:57 +04:00
# endif
/*
* Maintain information about the progress of the recovery job , so that
* the different passes can carry information between them .
*/
struct recovery_info
{
tid_t start_transaction ;
tid_t end_transaction ;
int nr_replays ;
int nr_revokes ;
int nr_revoke_hits ;
} ;
static int do_one_pass ( journal_t * journal ,
struct recovery_info * info , enum passtype pass ) ;
static int scan_revoke_records ( journal_t * , struct buffer_head * ,
tid_t , struct recovery_info * ) ;
# ifdef __KERNEL__
/* Release readahead buffers after use */
static void journal_brelse_array ( struct buffer_head * b [ ] , int n )
{
while ( - - n > = 0 )
brelse ( b [ n ] ) ;
}
/*
* When reading from the journal , we are going through the block device
* layer directly and so there is no readahead being done for us . We
* need to implement any readahead ourselves if we want it to happen at
* all . Recovery is basically one long sequential read , so make sure we
* do the IO in reasonably large chunks .
*
* This is not so critical that we need to be enormously clever about
* the readahead size , though . 128 K is a purely arbitrary , good - enough
* fixed value .
*/
# define MAXBUF 8
static int do_readahead ( journal_t * journal , unsigned int start )
{
int err ;
unsigned int max , nbufs , next ;
2006-10-11 12:21:13 +04:00
unsigned long long blocknr ;
2006-10-11 12:20:57 +04:00
struct buffer_head * bh ;
struct buffer_head * bufs [ MAXBUF ] ;
/* Do up to 128K of readahead */
max = start + ( 128 * 1024 / journal - > j_blocksize ) ;
2020-11-06 06:58:54 +03:00
if ( max > journal - > j_total_len )
max = journal - > j_total_len ;
2006-10-11 12:20:57 +04:00
/* Do the readahead itself. We'll submit MAXBUF buffer_heads at
* a time to the block device IO layer . */
nbufs = 0 ;
for ( next = start ; next < max ; next + + ) {
2006-10-11 12:20:59 +04:00
err = jbd2_journal_bmap ( journal , next , & blocknr ) ;
2006-10-11 12:20:57 +04:00
if ( err ) {
2011-11-02 03:09:18 +04:00
printk ( KERN_ERR " JBD2: bad block at offset %u \n " ,
2006-10-11 12:20:57 +04:00
next ) ;
goto failed ;
}
bh = __getblk ( journal - > j_dev , blocknr , journal - > j_blocksize ) ;
if ( ! bh ) {
err = - ENOMEM ;
goto failed ;
}
if ( ! buffer_uptodate ( bh ) & & ! buffer_locked ( bh ) ) {
bufs [ nbufs + + ] = bh ;
if ( nbufs = = MAXBUF ) {
2022-09-01 16:34:57 +03:00
bh_readahead_batch ( nbufs , bufs , 0 ) ;
2006-10-11 12:20:57 +04:00
journal_brelse_array ( bufs , nbufs ) ;
nbufs = 0 ;
}
} else
brelse ( bh ) ;
}
if ( nbufs )
2022-09-01 16:34:57 +03:00
bh_readahead_batch ( nbufs , bufs , 0 ) ;
2006-10-11 12:20:57 +04:00
err = 0 ;
failed :
if ( nbufs )
journal_brelse_array ( bufs , nbufs ) ;
return err ;
}
# endif /* __KERNEL__ */
/*
* Read a block from the journal
*/
static int jread ( struct buffer_head * * bhp , journal_t * journal ,
unsigned int offset )
{
int err ;
2006-10-11 12:21:13 +04:00
unsigned long long blocknr ;
2006-10-11 12:20:57 +04:00
struct buffer_head * bh ;
* bhp = NULL ;
2020-11-06 06:58:54 +03:00
if ( offset > = journal - > j_total_len ) {
2011-11-02 03:09:18 +04:00
printk ( KERN_ERR " JBD2: corrupted journal superblock \n " ) ;
2015-10-17 23:16:04 +03:00
return - EFSCORRUPTED ;
2006-10-11 12:20:57 +04:00
}
2006-10-11 12:20:59 +04:00
err = jbd2_journal_bmap ( journal , offset , & blocknr ) ;
2006-10-11 12:20:57 +04:00
if ( err ) {
2011-11-02 03:09:18 +04:00
printk ( KERN_ERR " JBD2: bad block at offset %u \n " ,
2006-10-11 12:20:57 +04:00
offset ) ;
return err ;
}
bh = __getblk ( journal - > j_dev , blocknr , journal - > j_blocksize ) ;
if ( ! bh )
return - ENOMEM ;
if ( ! buffer_uptodate ( bh ) ) {
2022-09-01 16:34:57 +03:00
/*
* If this is a brand new buffer , start readahead .
* Otherwise , we assume we are already reading it .
*/
bool need_readahead = ! buffer_req ( bh ) ;
bh_read_nowait ( bh , 0 ) ;
if ( need_readahead )
2006-10-11 12:20:57 +04:00
do_readahead ( journal , offset ) ;
wait_on_buffer ( bh ) ;
}
if ( ! buffer_uptodate ( bh ) ) {
2011-11-02 03:09:18 +04:00
printk ( KERN_ERR " JBD2: Failed to read block at offset %u \n " ,
2006-10-11 12:20:57 +04:00
offset ) ;
brelse ( bh ) ;
return - EIO ;
}
* bhp = bh ;
return 0 ;
}
2016-02-23 07:19:09 +03:00
static int jbd2_descriptor_block_csum_verify ( journal_t * j , void * buf )
2012-05-27 16:10:22 +04:00
{
struct jbd2_journal_block_tail * tail ;
2013-08-28 22:59:58 +04:00
__be32 provided ;
__u32 calculated ;
2012-05-27 16:10:22 +04:00
2014-08-28 02:40:07 +04:00
if ( ! jbd2_journal_has_csum_v2or3 ( j ) )
2012-05-27 16:10:22 +04:00
return 1 ;
2021-08-10 21:02:33 +03:00
tail = ( struct jbd2_journal_block_tail * ) ( ( char * ) buf +
j - > j_blocksize - sizeof ( struct jbd2_journal_block_tail ) ) ;
2012-05-27 16:10:22 +04:00
provided = tail - > t_checksum ;
tail - > t_checksum = 0 ;
calculated = jbd2_chksum ( j , j - > j_csum_seed , buf , j - > j_blocksize ) ;
tail - > t_checksum = provided ;
2013-08-28 22:59:58 +04:00
return provided = = cpu_to_be32 ( calculated ) ;
2012-05-27 16:10:22 +04:00
}
2006-10-11 12:20:57 +04:00
/*
* Count the number of in - use tags in a journal descriptor block .
*/
2006-10-11 12:21:08 +04:00
static int count_tags ( journal_t * journal , struct buffer_head * bh )
2006-10-11 12:20:57 +04:00
{
char * tagp ;
2021-05-03 22:37:33 +03:00
journal_block_tag_t tag ;
2006-10-11 12:21:08 +04:00
int nr = 0 , size = journal - > j_blocksize ;
int tag_bytes = journal_tag_bytes ( journal ) ;
2006-10-11 12:20:57 +04:00
2014-08-28 02:40:07 +04:00
if ( jbd2_journal_has_csum_v2or3 ( journal ) )
2012-05-27 16:10:22 +04:00
size - = sizeof ( struct jbd2_journal_block_tail ) ;
2006-10-11 12:20:57 +04:00
tagp = & bh - > b_data [ sizeof ( journal_header_t ) ] ;
2006-10-11 12:21:08 +04:00
while ( ( tagp - bh - > b_data + tag_bytes ) < = size ) {
2021-05-03 22:37:33 +03:00
memcpy ( & tag , tagp , sizeof ( tag ) ) ;
2006-10-11 12:20:57 +04:00
nr + + ;
2006-10-11 12:21:08 +04:00
tagp + = tag_bytes ;
2021-05-03 22:37:33 +03:00
if ( ! ( tag . t_flags & cpu_to_be16 ( JBD2_FLAG_SAME_UUID ) ) )
2006-10-11 12:20:57 +04:00
tagp + = 16 ;
2021-05-03 22:37:33 +03:00
if ( tag . t_flags & cpu_to_be16 ( JBD2_FLAG_LAST_TAG ) )
2006-10-11 12:20:57 +04:00
break ;
}
return nr ;
}
/* Make sure we wrap around the log correctly! */
# define wrap(journal, var) \
do { \
2020-10-15 23:37:58 +03:00
unsigned long _wrap_last = \
jbd2_has_feature_fast_commit ( journal ) ? \
( journal ) - > j_fc_last : ( journal ) - > j_last ; \
\
if ( var > = _wrap_last ) \
var - = ( _wrap_last - ( journal ) - > j_first ) ; \
2006-10-11 12:20:57 +04:00
} while ( 0 )
2020-10-15 23:37:58 +03:00
static int fc_do_one_pass ( journal_t * journal ,
struct recovery_info * info , enum passtype pass )
{
unsigned int expected_commit_id = info - > end_transaction ;
unsigned long next_fc_block ;
struct buffer_head * bh ;
int err = 0 ;
next_fc_block = journal - > j_fc_first ;
if ( ! journal - > j_fc_replay_callback )
return 0 ;
while ( next_fc_block < = journal - > j_fc_last ) {
2022-06-08 14:23:48 +03:00
jbd2_debug ( 3 , " Fast commit replay: next block %ld \n " ,
2020-10-15 23:37:58 +03:00
next_fc_block ) ;
err = jread ( & bh , journal , next_fc_block ) ;
if ( err ) {
2022-06-08 14:23:48 +03:00
jbd2_debug ( 3 , " Fast commit replay: read error \n " ) ;
2020-10-15 23:37:58 +03:00
break ;
}
err = journal - > j_fc_replay_callback ( journal , bh , pass ,
next_fc_block - journal - > j_fc_first ,
expected_commit_id ) ;
2022-09-17 12:38:05 +03:00
brelse ( bh ) ;
2020-10-15 23:37:58 +03:00
next_fc_block + + ;
if ( err < 0 | | err = = JBD2_FC_REPLAY_STOP )
break ;
err = 0 ;
}
if ( err )
2022-06-08 14:23:48 +03:00
jbd2_debug ( 3 , " Fast commit replay failed, err = %d \n " , err ) ;
2020-10-15 23:37:58 +03:00
return err ;
}
2006-10-11 12:20:57 +04:00
/**
2006-10-11 12:20:59 +04:00
* jbd2_journal_recover - recovers a on - disk journal
2006-10-11 12:20:57 +04:00
* @ journal : the journal to recover
*
* The primary function for recovering the log contents when mounting a
* journaled device .
*
* Recovery is done in three passes . In the first pass , we look for the
* end of the log . In the second , we assemble the list of revoke
* blocks . In the third and final pass , we replay any un - revoked blocks
* in the log .
*/
2006-10-11 12:20:59 +04:00
int jbd2_journal_recover ( journal_t * journal )
2006-10-11 12:20:57 +04:00
{
2008-10-11 04:29:13 +04:00
int err , err2 ;
2006-10-11 12:20:57 +04:00
journal_superblock_t * sb ;
struct recovery_info info ;
memset ( & info , 0 , sizeof ( info ) ) ;
sb = journal - > j_superblock ;
/*
* The journal superblock ' s s_start field ( the current log head )
* is always zero if , and only if , the journal was cleanly
* unmounted .
*/
if ( ! sb - > s_start ) {
2022-06-08 14:23:48 +03:00
jbd2_debug ( 1 , " No recovery required, last transaction %d \n " ,
2006-10-11 12:20:57 +04:00
be32_to_cpu ( sb - > s_sequence ) ) ;
journal - > j_transaction_sequence = be32_to_cpu ( sb - > s_sequence ) + 1 ;
return 0 ;
}
err = do_one_pass ( journal , & info , PASS_SCAN ) ;
if ( ! err )
err = do_one_pass ( journal , & info , PASS_REVOKE ) ;
if ( ! err )
err = do_one_pass ( journal , & info , PASS_REPLAY ) ;
2022-06-08 14:23:48 +03:00
jbd2_debug ( 1 , " JBD2: recovery, exit status %d, "
2006-10-11 12:20:57 +04:00
" recovered transactions %u to %u \n " ,
err , info . start_transaction , info . end_transaction ) ;
2022-06-08 14:23:48 +03:00
jbd2_debug ( 1 , " JBD2: Replayed %d and revoked %d/%d blocks \n " ,
2006-10-11 12:20:57 +04:00
info . nr_replays , info . nr_revoke_hits , info . nr_revokes ) ;
/* Restart the log at the next transaction ID, thus invalidating
* any existing commit records in the log . */
journal - > j_transaction_sequence = + + info . end_transaction ;
2006-10-11 12:20:59 +04:00
jbd2_journal_clear_revoke ( journal ) ;
2008-10-11 04:29:13 +04:00
err2 = sync_blockdev ( journal - > j_fs_dev ) ;
if ( ! err )
err = err2 ;
2012-03-14 06:22:54 +04:00
/* Make sure all replayed data is on permanent storage */
2012-08-17 17:56:17 +04:00
if ( journal - > j_flags & JBD2_BARRIER ) {
2021-01-26 17:52:35 +03:00
err2 = blkdev_issue_flush ( journal - > j_fs_dev ) ;
2012-08-17 17:56:17 +04:00
if ( ! err )
err = err2 ;
}
2006-10-11 12:20:57 +04:00
return err ;
}
/**
2006-10-11 12:20:59 +04:00
* jbd2_journal_skip_recovery - Start journal and wipe exiting records
2006-10-11 12:20:57 +04:00
* @ journal : journal to startup
*
* Locate any valid recovery information from the journal and set up the
* journal structures in memory to ignore it ( presumably because the
* caller has evidence that it is out of date ) .
2016-02-02 16:31:06 +03:00
* This function doesn ' t appear to be exported . .
2006-10-11 12:20:57 +04:00
*
* We perform one pass over the journal to allow us to tell the user how
* much recovery information is being erased , and to let us initialise
* the journal transaction sequence numbers to the next unused ID .
*/
2006-10-11 12:20:59 +04:00
int jbd2_journal_skip_recovery ( journal_t * journal )
2006-10-11 12:20:57 +04:00
{
int err ;
struct recovery_info info ;
memset ( & info , 0 , sizeof ( info ) ) ;
err = do_one_pass ( journal , & info , PASS_SCAN ) ;
if ( err ) {
2011-11-02 03:09:18 +04:00
printk ( KERN_ERR " JBD2: error %d scanning journal \n " , err ) ;
2006-10-11 12:20:57 +04:00
+ + journal - > j_transaction_sequence ;
} else {
2007-07-18 16:57:06 +04:00
# ifdef CONFIG_JBD2_DEBUG
2010-06-14 21:28:03 +04:00
int dropped = info . end_transaction -
be32_to_cpu ( journal - > j_superblock - > s_sequence ) ;
2022-06-08 14:23:48 +03:00
jbd2_debug ( 1 ,
2011-11-02 03:09:18 +04:00
" JBD2: ignoring %d transaction%s from the journal. \n " ,
2006-10-11 12:20:57 +04:00
dropped , ( dropped = = 1 ) ? " " : " s " ) ;
2010-12-18 21:36:33 +03:00
# endif
2006-10-11 12:20:57 +04:00
journal - > j_transaction_sequence = + + info . end_transaction ;
}
journal - > j_tail = 0 ;
return err ;
}
2014-08-28 02:40:07 +04:00
static inline unsigned long long read_tag_block ( journal_t * journal ,
journal_block_tag_t * tag )
2006-10-11 12:21:08 +04:00
{
2006-10-11 12:21:13 +04:00
unsigned long long block = be32_to_cpu ( tag - > t_blocknr ) ;
2015-10-17 23:18:45 +03:00
if ( jbd2_has_feature_64bit ( journal ) )
2006-10-11 12:21:08 +04:00
block | = ( u64 ) be32_to_cpu ( tag - > t_blocknr_high ) < < 32 ;
return block ;
}
2008-01-29 07:58:27 +03:00
/*
* calc_chksums calculates the checksums for the blocks described in the
* descriptor block .
*/
static int calc_chksums ( journal_t * journal , struct buffer_head * bh ,
unsigned long * next_log_block , __u32 * crc32_sum )
{
int i , num_blks , err ;
unsigned long io_block ;
struct buffer_head * obh ;
num_blks = count_tags ( journal , bh ) ;
/* Calculate checksum of the descriptor block. */
* crc32_sum = crc32_be ( * crc32_sum , ( void * ) bh - > b_data , bh - > b_size ) ;
for ( i = 0 ; i < num_blks ; i + + ) {
io_block = ( * next_log_block ) + + ;
wrap ( journal , * next_log_block ) ;
err = jread ( & obh , journal , io_block ) ;
if ( err ) {
2011-11-02 03:09:18 +04:00
printk ( KERN_ERR " JBD2: IO error %d recovering block "
2008-01-29 07:58:27 +03:00
" %lu in log \n " , err , io_block ) ;
return 1 ;
} else {
* crc32_sum = crc32_be ( * crc32_sum , ( void * ) obh - > b_data ,
obh - > b_size ) ;
}
2008-05-26 18:28:09 +04:00
put_bh ( obh ) ;
2008-01-29 07:58:27 +03:00
}
return 0 ;
}
2012-05-27 16:10:25 +04:00
static int jbd2_commit_block_csum_verify ( journal_t * j , void * buf )
{
struct commit_header * h ;
2013-08-28 22:59:58 +04:00
__be32 provided ;
__u32 calculated ;
2012-05-27 16:10:25 +04:00
2014-08-28 02:40:07 +04:00
if ( ! jbd2_journal_has_csum_v2or3 ( j ) )
2012-05-27 16:10:25 +04:00
return 1 ;
h = buf ;
provided = h - > h_chksum [ 0 ] ;
h - > h_chksum [ 0 ] = 0 ;
calculated = jbd2_chksum ( j , j - > j_csum_seed , buf , j - > j_blocksize ) ;
h - > h_chksum [ 0 ] = provided ;
2013-08-28 22:59:58 +04:00
return provided = = cpu_to_be32 ( calculated ) ;
2012-05-27 16:10:25 +04:00
}
2012-05-27 16:12:12 +04:00
static int jbd2_block_tag_csum_verify ( journal_t * j , journal_block_tag_t * tag ,
2021-05-03 22:37:33 +03:00
journal_block_tag3_t * tag3 ,
2012-05-27 16:12:12 +04:00
void * buf , __u32 sequence )
{
2013-05-28 15:31:59 +04:00
__u32 csum32 ;
2013-08-28 22:59:58 +04:00
__be32 seq ;
2012-05-27 16:12:12 +04:00
2014-08-28 02:40:07 +04:00
if ( ! jbd2_journal_has_csum_v2or3 ( j ) )
2012-05-27 16:12:12 +04:00
return 1 ;
2013-08-28 22:59:58 +04:00
seq = cpu_to_be32 ( sequence ) ;
csum32 = jbd2_chksum ( j , j - > j_csum_seed , ( __u8 * ) & seq , sizeof ( seq ) ) ;
2013-05-28 15:31:59 +04:00
csum32 = jbd2_chksum ( j , csum32 , buf , j - > j_blocksize ) ;
2012-05-27 16:12:12 +04:00
2015-10-17 23:18:45 +03:00
if ( jbd2_has_feature_csum3 ( j ) )
2014-08-28 02:40:07 +04:00
return tag3 - > t_checksum = = cpu_to_be32 ( csum32 ) ;
else
return tag - > t_checksum = = cpu_to_be16 ( csum32 ) ;
2012-05-27 16:12:12 +04:00
}
2006-10-11 12:20:57 +04:00
static int do_one_pass ( journal_t * journal ,
struct recovery_info * info , enum passtype pass )
{
unsigned int first_commit_ID , next_commit_ID ;
unsigned long next_log_block ;
int err , success = 0 ;
journal_superblock_t * sb ;
journal_header_t * tmp ;
struct buffer_head * bh ;
unsigned int sequence ;
int blocktype ;
2006-10-11 12:21:08 +04:00
int tag_bytes = journal_tag_bytes ( journal ) ;
2008-01-29 07:58:27 +03:00
__u32 crc32_sum = ~ 0 ; /* Transactional Checksums */
2012-05-27 16:10:22 +04:00
int descr_csum_size = 0 ;
2014-08-28 02:40:05 +04:00
int block_error = 0 ;
2020-10-12 19:49:00 +03:00
bool need_check_commit_time = false ;
__u64 last_trans_commit_time = 0 , commit_time ;
2006-10-11 12:20:57 +04:00
/*
* First thing is to establish what we expect to find in the log
* ( in terms of transaction IDs ) , and where ( in terms of log
* block offsets ) : query the superblock .
*/
sb = journal - > j_superblock ;
next_commit_ID = be32_to_cpu ( sb - > s_sequence ) ;
next_log_block = be32_to_cpu ( sb - > s_start ) ;
first_commit_ID = next_commit_ID ;
if ( pass = = PASS_SCAN )
info - > start_transaction = first_commit_ID ;
2022-06-08 14:23:48 +03:00
jbd2_debug ( 1 , " Starting recovery pass %d \n " , pass ) ;
2006-10-11 12:20:57 +04:00
/*
* Now we walk through the log , transaction by transaction ,
* making sure that each transaction has a commit block in the
* expected place . Each complete transaction gets replayed back
* into the main filesystem .
*/
while ( 1 ) {
int flags ;
char * tagp ;
2021-05-03 22:37:33 +03:00
journal_block_tag_t tag ;
2006-10-11 12:20:57 +04:00
struct buffer_head * obh ;
struct buffer_head * nbh ;
2008-02-06 12:40:11 +03:00
cond_resched ( ) ;
2006-10-11 12:20:57 +04:00
/* If we already know where to stop the log traversal,
* check right now that we haven ' t gone past the end of
* the log . */
if ( pass ! = PASS_SCAN )
if ( tid_geq ( next_commit_ID , info - > end_transaction ) )
break ;
2022-06-08 14:23:48 +03:00
jbd2_debug ( 2 , " Scanning for sequence ID %u at %lu/%lu \n " ,
2020-10-15 23:37:58 +03:00
next_commit_ID , next_log_block ,
jbd2_has_feature_fast_commit ( journal ) ?
journal - > j_fc_last : journal - > j_last ) ;
2006-10-11 12:20:57 +04:00
/* Skip over each chunk of the transaction looking
* either the next descriptor block or the final commit
* record . */
2022-06-08 14:23:48 +03:00
jbd2_debug ( 3 , " JBD2: checking block %ld \n " , next_log_block ) ;
2006-10-11 12:20:57 +04:00
err = jread ( & bh , journal , next_log_block ) ;
if ( err )
goto failed ;
next_log_block + + ;
wrap ( journal , next_log_block ) ;
/* What kind of buffer is it?
*
* If it is a descriptor block , check that it has the
* expected sequence number . Otherwise , we ' re all done
* here . */
tmp = ( journal_header_t * ) bh - > b_data ;
2006-10-11 12:20:59 +04:00
if ( tmp - > h_magic ! = cpu_to_be32 ( JBD2_MAGIC_NUMBER ) ) {
2006-10-11 12:20:57 +04:00
brelse ( bh ) ;
break ;
}
blocktype = be32_to_cpu ( tmp - > h_blocktype ) ;
sequence = be32_to_cpu ( tmp - > h_sequence ) ;
2022-06-08 14:23:48 +03:00
jbd2_debug ( 3 , " Found magic %d, sequence %d \n " ,
2006-10-11 12:20:57 +04:00
blocktype , sequence ) ;
if ( sequence ! = next_commit_ID ) {
brelse ( bh ) ;
break ;
}
/* OK, we have a valid descriptor block which matches
* all of the sequence number checks . What are we going
* to do with it ? That depends on the pass . . . */
switch ( blocktype ) {
2006-10-11 12:20:59 +04:00
case JBD2_DESCRIPTOR_BLOCK :
2012-05-27 16:10:22 +04:00
/* Verify checksum first */
2014-08-28 02:40:07 +04:00
if ( jbd2_journal_has_csum_v2or3 ( journal ) )
2012-05-27 16:10:22 +04:00
descr_csum_size =
sizeof ( struct jbd2_journal_block_tail ) ;
if ( descr_csum_size > 0 & &
2016-02-23 07:19:09 +03:00
! jbd2_descriptor_block_csum_verify ( journal ,
bh - > b_data ) ) {
2020-10-12 19:49:00 +03:00
/*
* PASS_SCAN can see stale blocks due to lazy
* journal init . Don ' t error out on those yet .
*/
if ( pass ! = PASS_SCAN ) {
pr_err ( " JBD2: Invalid checksum recovering block %lu in log \n " ,
next_log_block ) ;
err = - EFSBADCRC ;
brelse ( bh ) ;
goto failed ;
}
need_check_commit_time = true ;
2022-06-08 14:23:48 +03:00
jbd2_debug ( 1 ,
2020-10-12 19:49:00 +03:00
" invalid descriptor block found in %lu \n " ,
next_log_block ) ;
2012-05-27 16:10:22 +04:00
}
2006-10-11 12:20:57 +04:00
/* If it is a valid descriptor block, replay it
2008-01-29 07:58:27 +03:00
* in pass REPLAY ; if journal_checksums enabled , then
* calculate checksums in PASS_SCAN , otherwise ,
* just skip over the blocks it describes . */
2006-10-11 12:20:57 +04:00
if ( pass ! = PASS_REPLAY ) {
2008-01-29 07:58:27 +03:00
if ( pass = = PASS_SCAN & &
2015-10-17 23:18:45 +03:00
jbd2_has_feature_checksum ( journal ) & &
2020-10-12 19:49:00 +03:00
! need_check_commit_time & &
2008-01-29 07:58:27 +03:00
! info - > end_transaction ) {
if ( calc_chksums ( journal , bh ,
& next_log_block ,
& crc32_sum ) ) {
put_bh ( bh ) ;
break ;
}
put_bh ( bh ) ;
continue ;
}
2006-10-11 12:21:08 +04:00
next_log_block + = count_tags ( journal , bh ) ;
2006-10-11 12:20:57 +04:00
wrap ( journal , next_log_block ) ;
2008-01-29 07:58:27 +03:00
put_bh ( bh ) ;
2006-10-11 12:20:57 +04:00
continue ;
}
/* A descriptor block: we can now write all of
* the data blocks . Yay , useful work is finally
* getting done here ! */
tagp = & bh - > b_data [ sizeof ( journal_header_t ) ] ;
2006-10-11 12:21:08 +04:00
while ( ( tagp - bh - > b_data + tag_bytes )
2012-05-27 16:10:22 +04:00
< = journal - > j_blocksize - descr_csum_size ) {
2006-10-11 12:20:57 +04:00
unsigned long io_block ;
2021-05-03 22:37:33 +03:00
memcpy ( & tag , tagp , sizeof ( tag ) ) ;
flags = be16_to_cpu ( tag . t_flags ) ;
2006-10-11 12:20:57 +04:00
io_block = next_log_block + + ;
wrap ( journal , next_log_block ) ;
err = jread ( & obh , journal , io_block ) ;
if ( err ) {
/* Recover what we can, but
* report failure at the end . */
success = err ;
2011-11-02 03:09:18 +04:00
printk ( KERN_ERR
" JBD2: IO error %d recovering "
2006-10-11 12:20:57 +04:00
" block %ld in log \n " ,
err , io_block ) ;
} else {
2006-10-11 12:21:13 +04:00
unsigned long long blocknr ;
2006-10-11 12:20:57 +04:00
J_ASSERT ( obh ! = NULL ) ;
2014-08-28 02:40:07 +04:00
blocknr = read_tag_block ( journal ,
2021-05-03 22:37:33 +03:00
& tag ) ;
2006-10-11 12:20:57 +04:00
/* If the block has been
* revoked , then we ' re all done
* here . */
2006-10-11 12:20:59 +04:00
if ( jbd2_journal_test_revoke
2006-10-11 12:20:57 +04:00
( journal , blocknr ,
next_commit_ID ) ) {
brelse ( obh ) ;
+ + info - > nr_revoke_hits ;
goto skip_write ;
}
2012-05-27 16:12:12 +04:00
/* Look for block corruption */
if ( ! jbd2_block_tag_csum_verify (
2021-05-03 22:37:33 +03:00
journal , & tag , ( journal_block_tag3_t * ) tagp ,
obh - > b_data , be32_to_cpu ( tmp - > h_sequence ) ) ) {
2012-05-27 16:12:12 +04:00
brelse ( obh ) ;
2015-10-17 23:16:04 +03:00
success = - EFSBADCRC ;
2013-12-09 06:14:59 +04:00
printk ( KERN_ERR " JBD2: Invalid "
2012-05-27 16:12:12 +04:00
" checksum recovering "
2018-02-19 05:33:13 +03:00
" data block %llu in "
" log \n " , blocknr ) ;
2014-08-28 02:40:05 +04:00
block_error = 1 ;
goto skip_write ;
2012-05-27 16:12:12 +04:00
}
2006-10-11 12:20:57 +04:00
/* Find a buffer for the new
* data being restored */
nbh = __getblk ( journal - > j_fs_dev ,
blocknr ,
journal - > j_blocksize ) ;
if ( nbh = = NULL ) {
printk ( KERN_ERR
2011-11-02 03:09:18 +04:00
" JBD2: Out of memory "
2006-10-11 12:20:57 +04:00
" during recovery. \n " ) ;
err = - ENOMEM ;
brelse ( bh ) ;
brelse ( obh ) ;
goto failed ;
}
lock_buffer ( nbh ) ;
memcpy ( nbh - > b_data , obh - > b_data ,
journal - > j_blocksize ) ;
2006-10-11 12:20:59 +04:00
if ( flags & JBD2_FLAG_ESCAPE ) {
2008-03-20 03:00:54 +03:00
* ( ( __be32 * ) nbh - > b_data ) =
2006-10-11 12:20:59 +04:00
cpu_to_be32 ( JBD2_MAGIC_NUMBER ) ;
2006-10-11 12:20:57 +04:00
}
BUFFER_TRACE ( nbh , " marking dirty " ) ;
set_buffer_uptodate ( nbh ) ;
mark_buffer_dirty ( nbh ) ;
BUFFER_TRACE ( nbh , " marking uptodate " ) ;
+ + info - > nr_replays ;
unlock_buffer ( nbh ) ;
brelse ( obh ) ;
brelse ( nbh ) ;
}
skip_write :
2006-10-11 12:21:08 +04:00
tagp + = tag_bytes ;
2006-10-11 12:20:59 +04:00
if ( ! ( flags & JBD2_FLAG_SAME_UUID ) )
2006-10-11 12:20:57 +04:00
tagp + = 16 ;
2006-10-11 12:20:59 +04:00
if ( flags & JBD2_FLAG_LAST_TAG )
2006-10-11 12:20:57 +04:00
break ;
}
brelse ( bh ) ;
continue ;
2006-10-11 12:20:59 +04:00
case JBD2_COMMIT_BLOCK :
2008-01-29 07:58:27 +03:00
/* How to differentiate between interrupted commit
* and journal corruption ?
*
* { nth transaction }
* Checksum Verification Failed
* |
* ____________________
* | |
* async_commit sync_commit
* | |
* | GO TO NEXT " Journal Corruption "
* | TRANSACTION
* |
* { ( n + 1 ) th transanction }
* |
* _______ | ______________
* | |
* Commit block found Commit block not found
* | |
* " Journal Corruption " |
* _____________ | _________
* | |
* nth trans corrupt OR nth trans
* and ( n + 1 ) th interrupted interrupted
* before commit block
* could reach the disk .
* ( Cannot find the difference in above
* mentioned conditions . Hence assume
* " Interrupted Commit " . )
*/
2020-10-12 19:49:00 +03:00
commit_time = be64_to_cpu (
( ( struct commit_header * ) bh - > b_data ) - > h_commit_sec ) ;
/*
* If need_check_commit_time is set , it means we are in
* PASS_SCAN and csum verify failed before . If
* commit_time is increasing , it ' s the same journal ,
* otherwise it is stale journal block , just end this
* recovery .
*/
if ( need_check_commit_time ) {
if ( commit_time > = last_trans_commit_time ) {
pr_err ( " JBD2: Invalid checksum found in transaction %u \n " ,
next_commit_ID ) ;
err = - EFSBADCRC ;
brelse ( bh ) ;
goto failed ;
}
ignore_crc_mismatch :
/*
* It likely does not belong to same journal ,
* just end this recovery with success .
*/
2022-06-08 14:23:48 +03:00
jbd2_debug ( 1 , " JBD2: Invalid checksum ignored in transaction %u, likely stale data \n " ,
2020-10-12 19:49:00 +03:00
next_commit_ID ) ;
brelse ( bh ) ;
goto done ;
}
2008-01-29 07:58:27 +03:00
2020-10-12 19:49:00 +03:00
/*
* Found an expected commit block : if checksums
* are present , verify them in PASS_SCAN ; else not
2008-01-29 07:58:27 +03:00
* much to do other than move on to the next sequence
2020-10-12 19:49:00 +03:00
* number .
*/
2008-01-29 07:58:27 +03:00
if ( pass = = PASS_SCAN & &
2015-10-17 23:18:45 +03:00
jbd2_has_feature_checksum ( journal ) ) {
2008-01-29 07:58:27 +03:00
struct commit_header * cbh =
( struct commit_header * ) bh - > b_data ;
unsigned found_chksum =
be32_to_cpu ( cbh - > h_chksum [ 0 ] ) ;
if ( info - > end_transaction ) {
2008-06-07 01:50:40 +04:00
journal - > j_failed_commit =
info - > end_transaction ;
2008-01-29 07:58:27 +03:00
brelse ( bh ) ;
break ;
}
2020-08-11 05:21:28 +03:00
/* Neither checksum match nor unused? */
if ( ! ( ( crc32_sum = = found_chksum & &
cbh - > h_chksum_type = =
JBD2_CRC32_CHKSUM & &
cbh - > h_chksum_size = =
JBD2_CRC32_CHKSUM_SIZE ) | |
( cbh - > h_chksum_type = = 0 & &
cbh - > h_chksum_size = = 0 & &
found_chksum = = 0 ) ) )
goto chksum_error ;
2008-01-29 07:58:27 +03:00
crc32_sum = ~ 0 ;
}
2012-05-27 16:10:25 +04:00
if ( pass = = PASS_SCAN & &
! jbd2_commit_block_csum_verify ( journal ,
bh - > b_data ) ) {
2020-08-11 05:21:28 +03:00
chksum_error :
2020-10-12 19:49:00 +03:00
if ( commit_time < last_trans_commit_time )
goto ignore_crc_mismatch ;
2012-05-27 16:10:25 +04:00
info - > end_transaction = next_commit_ID ;
2015-10-17 23:18:45 +03:00
if ( ! jbd2_has_feature_async_commit ( journal ) ) {
2012-05-27 16:10:25 +04:00
journal - > j_failed_commit =
next_commit_ID ;
brelse ( bh ) ;
break ;
}
}
2020-10-12 19:49:00 +03:00
if ( pass = = PASS_SCAN )
last_trans_commit_time = commit_time ;
2006-10-11 12:20:57 +04:00
brelse ( bh ) ;
next_commit_ID + + ;
continue ;
2006-10-11 12:20:59 +04:00
case JBD2_REVOKE_BLOCK :
2020-10-12 19:49:00 +03:00
/*
* Check revoke block crc in pass_scan , if csum verify
* failed , check commit block time later .
*/
if ( pass = = PASS_SCAN & &
! jbd2_descriptor_block_csum_verify ( journal ,
bh - > b_data ) ) {
2022-06-08 14:23:48 +03:00
jbd2_debug ( 1 , " JBD2: invalid revoke block found in %lu \n " ,
2020-10-12 19:49:00 +03:00
next_log_block ) ;
need_check_commit_time = true ;
}
2006-10-11 12:20:57 +04:00
/* If we aren't in the REVOKE pass, then we can
* just skip over this block . */
if ( pass ! = PASS_REVOKE ) {
brelse ( bh ) ;
continue ;
}
err = scan_revoke_records ( journal , bh ,
next_commit_ID , info ) ;
brelse ( bh ) ;
if ( err )
goto failed ;
continue ;
default :
2022-06-08 14:23:48 +03:00
jbd2_debug ( 3 , " Unrecognised magic %d, end of scan. \n " ,
2006-10-11 12:20:57 +04:00
blocktype ) ;
brelse ( bh ) ;
goto done ;
}
}
done :
/*
* We broke out of the log scan loop : either we came to the
* known end of the log or we found an unexpected block in the
* log . If the latter happened , then we know that the " current "
* transaction marks the end of the valid log .
*/
2008-01-29 07:58:27 +03:00
if ( pass = = PASS_SCAN ) {
if ( ! info - > end_transaction )
info - > end_transaction = next_commit_ID ;
} else {
2006-10-11 12:20:57 +04:00
/* It's really bad news if different passes end up at
* different places ( but possible due to IO errors ) . */
if ( info - > end_transaction ! = next_commit_ID ) {
2011-11-02 03:09:18 +04:00
printk ( KERN_ERR " JBD2: recovery pass %d ended at "
2006-10-11 12:20:57 +04:00
" transaction %u, expected %u \n " ,
pass , next_commit_ID , info - > end_transaction ) ;
if ( ! success )
success = - EIO ;
}
}
2020-10-15 23:37:58 +03:00
if ( jbd2_has_feature_fast_commit ( journal ) & & pass ! = PASS_REVOKE ) {
err = fc_do_one_pass ( journal , info , pass ) ;
if ( err )
success = err ;
}
2014-08-28 02:40:05 +04:00
if ( block_error & & success = = 0 )
success = - EIO ;
2006-10-11 12:20:57 +04:00
return success ;
failed :
return err ;
}
/* Scan a revoke record, marking all blocks mentioned as revoked. */
static int scan_revoke_records ( journal_t * journal , struct buffer_head * bh ,
tid_t sequence , struct recovery_info * info )
{
2006-10-11 12:20:59 +04:00
jbd2_journal_revoke_header_t * header ;
2006-10-11 12:20:57 +04:00
int offset , max ;
2021-08-10 21:02:33 +03:00
unsigned csum_size = 0 ;
2015-05-15 02:11:50 +03:00
__u32 rcount ;
2006-10-11 12:21:08 +04:00
int record_len = 4 ;
2006-10-11 12:20:57 +04:00
2006-10-11 12:20:59 +04:00
header = ( jbd2_journal_revoke_header_t * ) bh - > b_data ;
offset = sizeof ( jbd2_journal_revoke_header_t ) ;
2015-05-15 02:11:50 +03:00
rcount = be32_to_cpu ( header - > r_count ) ;
2006-10-11 12:20:57 +04:00
2015-05-15 02:11:50 +03:00
if ( jbd2_journal_has_csum_v2or3 ( journal ) )
2016-02-23 07:19:09 +03:00
csum_size = sizeof ( struct jbd2_journal_block_tail ) ;
2015-05-15 02:11:50 +03:00
if ( rcount > journal - > j_blocksize - csum_size )
return - EINVAL ;
max = rcount ;
2015-10-17 23:18:45 +03:00
if ( jbd2_has_feature_64bit ( journal ) )
2006-10-11 12:21:08 +04:00
record_len = 8 ;
while ( offset + record_len < = max ) {
2006-10-11 12:21:13 +04:00
unsigned long long blocknr ;
2006-10-11 12:20:57 +04:00
int err ;
2006-10-11 12:21:08 +04:00
if ( record_len = = 4 )
blocknr = be32_to_cpu ( * ( ( __be32 * ) ( bh - > b_data + offset ) ) ) ;
else
blocknr = be64_to_cpu ( * ( ( __be64 * ) ( bh - > b_data + offset ) ) ) ;
offset + = record_len ;
2006-10-11 12:20:59 +04:00
err = jbd2_journal_set_revoke ( journal , blocknr , sequence ) ;
2006-10-11 12:20:57 +04:00
if ( err )
return err ;
+ + info - > nr_revokes ;
}
return 0 ;
}