Home | History | Annotate | Download | only in debugfs
      1 /*
      2  * do_journal.c --- Scribble onto the journal!
      3  *
      4  * Copyright (C) 2014 Oracle.  This file may be redistributed
      5  * under the terms of the GNU Public License.
      6  */
      7 
      8 #include "config.h"
      9 #include <stdio.h>
     10 #ifdef HAVE_GETOPT_H
     11 #include <getopt.h>
     12 #else
     13 extern int optind;
     14 extern char *optarg;
     15 #endif
     16 #include <ctype.h>
     17 #include <unistd.h>
     18 #ifdef HAVE_SYS_TIME_H
     19 #include <sys/time.h>
     20 #endif
     21 
     22 #include "debugfs.h"
     23 #include "ext2fs/kernel-jbd.h"
     24 #include "journal.h"
     25 
     26 #undef DEBUG
     27 
     28 #ifdef DEBUG
     29 # define dbg_printf(f, a...)  do {printf("JFS DEBUG: " f, ## a); \
     30 	fflush(stdout); \
     31 } while (0)
     32 #else
     33 # define dbg_printf(f, a...)
     34 #endif
     35 
     36 #define JOURNAL_CHECK_TRANS_MAGIC(x)	\
     37 	do { \
     38 		if ((x)->magic != J_TRANS_MAGIC) \
     39 			return EXT2_ET_INVALID_ARGUMENT; \
     40 	} while (0)
     41 
     42 #define J_TRANS_MAGIC		0xD15EA5ED
     43 #define J_TRANS_OPEN		1
     44 #define J_TRANS_COMMITTED	2
     45 struct journal_transaction_s {
     46 	unsigned int magic;
     47 	ext2_filsys fs;
     48 	journal_t *journal;
     49 	blk64_t block;
     50 	blk64_t start, end;
     51 	tid_t tid;
     52 	int flags;
     53 };
     54 
     55 typedef struct journal_transaction_s journal_transaction_t;
     56 
     57 static journal_t *current_journal = NULL;
     58 
     59 static void journal_dump_trans(journal_transaction_t *trans EXT2FS_ATTR((unused)),
     60 			       const char *tag EXT2FS_ATTR((unused)))
     61 {
     62 	dbg_printf("TRANS %p(%s): tid=%d start=%llu block=%llu end=%llu "
     63 		   "flags=0x%x\n", trans, tag, trans->tid, trans->start,
     64 		   trans->block, trans->end, trans->flags);
     65 }
     66 
     67 static errcode_t journal_commit_trans(journal_transaction_t *trans)
     68 {
     69 	struct buffer_head *bh, *cbh = NULL;
     70 	struct commit_header *commit;
     71 #ifdef HAVE_SYS_TIME_H
     72 	struct timeval tv;
     73 #endif
     74 	errcode_t err;
     75 
     76 	JOURNAL_CHECK_TRANS_MAGIC(trans);
     77 
     78 	if ((trans->flags & J_TRANS_COMMITTED) ||
     79 	    !(trans->flags & J_TRANS_OPEN))
     80 		return EXT2_ET_INVALID_ARGUMENT;
     81 
     82 	bh = getblk(trans->journal->j_dev, 0, trans->journal->j_blocksize);
     83 	if (bh == NULL)
     84 		return ENOMEM;
     85 
     86 	/* write the descriptor block header */
     87 	commit = (struct commit_header *)bh->b_data;
     88 	commit->h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER);
     89 	commit->h_blocktype = ext2fs_cpu_to_be32(JFS_COMMIT_BLOCK);
     90 	commit->h_sequence = ext2fs_cpu_to_be32(trans->tid);
     91 	if (jfs_has_feature_checksum(trans->journal)) {
     92 		__u32 csum_v1 = ~0;
     93 		blk64_t cblk;
     94 
     95 		cbh = getblk(trans->journal->j_dev, 0,
     96 			     trans->journal->j_blocksize);
     97 		if (cbh == NULL) {
     98 			err = ENOMEM;
     99 			goto error;
    100 		}
    101 
    102 		for (cblk = trans->start; cblk < trans->block; cblk++) {
    103 			err = journal_bmap(trans->journal, cblk,
    104 					   &cbh->b_blocknr);
    105 			if (err)
    106 				goto error;
    107 			mark_buffer_uptodate(cbh, 0);
    108 			ll_rw_block(READ, 1, &cbh);
    109 			err = cbh->b_err;
    110 			if (err)
    111 				goto error;
    112 			csum_v1 = ext2fs_crc32_be(csum_v1,
    113 					(unsigned char const *)cbh->b_data,
    114 					cbh->b_size);
    115 		}
    116 
    117 		commit->h_chksum_type = JFS_CRC32_CHKSUM;
    118 		commit->h_chksum_size = JFS_CRC32_CHKSUM_SIZE;
    119 		commit->h_chksum[0] = ext2fs_cpu_to_be32(csum_v1);
    120 	} else {
    121 		commit->h_chksum_type = 0;
    122 		commit->h_chksum_size = 0;
    123 		commit->h_chksum[0] = 0;
    124 	}
    125 #ifdef HAVE_SYS_TIME_H
    126 	gettimeofday(&tv, NULL);
    127 	commit->h_commit_sec = ext2fs_cpu_to_be32(tv.tv_sec);
    128 	commit->h_commit_nsec = ext2fs_cpu_to_be32(tv.tv_usec * 1000);
    129 #else
    130 	commit->h_commit_sec = 0;
    131 	commit->h_commit_nsec = 0;
    132 #endif
    133 
    134 	/* Write block */
    135 	jbd2_commit_block_csum_set(trans->journal, bh);
    136 	err = journal_bmap(trans->journal, trans->block, &bh->b_blocknr);
    137 	if (err)
    138 		goto error;
    139 
    140 	dbg_printf("Writing commit block at %llu:%llu\n", trans->block,
    141 		   bh->b_blocknr);
    142 	mark_buffer_dirty(bh);
    143 	ll_rw_block(WRITE, 1, &bh);
    144 	err = bh->b_err;
    145 	if (err)
    146 		goto error;
    147 	trans->flags |= J_TRANS_COMMITTED;
    148 	trans->flags &= ~J_TRANS_OPEN;
    149 	trans->block++;
    150 
    151 	ext2fs_set_feature_journal_needs_recovery(trans->fs->super);
    152 	ext2fs_mark_super_dirty(trans->fs);
    153 error:
    154 	if (cbh)
    155 		brelse(cbh);
    156 	brelse(bh);
    157 	return err;
    158 }
    159 
    160 static errcode_t journal_add_revoke_to_trans(journal_transaction_t *trans,
    161 					     blk64_t *revoke_list,
    162 					     size_t revoke_len)
    163 {
    164 	journal_revoke_header_t *jrb;
    165 	void *buf;
    166 	size_t i, offset;
    167 	blk64_t curr_blk;
    168 	unsigned int sz;
    169 	unsigned csum_size = 0;
    170 	struct buffer_head *bh;
    171 	errcode_t err;
    172 
    173 	JOURNAL_CHECK_TRANS_MAGIC(trans);
    174 
    175 	if ((trans->flags & J_TRANS_COMMITTED) ||
    176 	    !(trans->flags & J_TRANS_OPEN))
    177 		return EXT2_ET_INVALID_ARGUMENT;
    178 
    179 	if (revoke_len == 0)
    180 		return 0;
    181 
    182 	/* Do we need to leave space at the end for a checksum? */
    183 	if (journal_has_csum_v2or3(trans->journal))
    184 		csum_size = sizeof(struct journal_revoke_tail);
    185 
    186 	curr_blk = trans->block;
    187 
    188 	bh = getblk(trans->journal->j_dev, curr_blk,
    189 		    trans->journal->j_blocksize);
    190 	if (bh == NULL)
    191 		return ENOMEM;
    192 	jrb = buf = bh->b_data;
    193 	jrb->r_header.h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER);
    194 	jrb->r_header.h_blocktype = ext2fs_cpu_to_be32(JFS_REVOKE_BLOCK);
    195 	jrb->r_header.h_sequence = ext2fs_cpu_to_be32(trans->tid);
    196 	offset = sizeof(*jrb);
    197 
    198 	if (jfs_has_feature_64bit(trans->journal))
    199 		sz = 8;
    200 	else
    201 		sz = 4;
    202 
    203 	for (i = 0; i < revoke_len; i++) {
    204 		/* Block full, write to journal */
    205 		if (offset + sz > trans->journal->j_blocksize - csum_size) {
    206 			jrb->r_count = ext2fs_cpu_to_be32(offset);
    207 			jbd2_revoke_csum_set(trans->journal, bh);
    208 
    209 			err = journal_bmap(trans->journal, curr_blk,
    210 					   &bh->b_blocknr);
    211 			if (err)
    212 				goto error;
    213 			dbg_printf("Writing revoke block at %llu:%llu\n",
    214 				   curr_blk, bh->b_blocknr);
    215 			mark_buffer_dirty(bh);
    216 			ll_rw_block(WRITE, 1, &bh);
    217 			err = bh->b_err;
    218 			if (err)
    219 				goto error;
    220 
    221 			offset = sizeof(*jrb);
    222 			curr_blk++;
    223 		}
    224 
    225 		if (revoke_list[i] >=
    226 		    ext2fs_blocks_count(trans->journal->j_fs_dev->k_fs->super)) {
    227 			err = EXT2_ET_BAD_BLOCK_NUM;
    228 			goto error;
    229 		}
    230 
    231 		if (jfs_has_feature_64bit(trans->journal))
    232 			*((__u64 *)(&((char *)buf)[offset])) =
    233 				ext2fs_cpu_to_be64(revoke_list[i]);
    234 		else
    235 			*((__u32 *)(&((char *)buf)[offset])) =
    236 				ext2fs_cpu_to_be32(revoke_list[i]);
    237 		offset += sz;
    238 	}
    239 
    240 	if (offset > 0) {
    241 		jrb->r_count = ext2fs_cpu_to_be32(offset);
    242 		jbd2_revoke_csum_set(trans->journal, bh);
    243 
    244 		err = journal_bmap(trans->journal, curr_blk, &bh->b_blocknr);
    245 		if (err)
    246 			goto error;
    247 		dbg_printf("Writing revoke block at %llu:%llu\n",
    248 			   curr_blk, bh->b_blocknr);
    249 		mark_buffer_dirty(bh);
    250 		ll_rw_block(WRITE, 1, &bh);
    251 		err = bh->b_err;
    252 		if (err)
    253 			goto error;
    254 		curr_blk++;
    255 	}
    256 
    257 error:
    258 	trans->block = curr_blk;
    259 	brelse(bh);
    260 	return err;
    261 }
    262 
    263 static errcode_t journal_add_blocks_to_trans(journal_transaction_t *trans,
    264 				      blk64_t *block_list, size_t block_len,
    265 				      FILE *fp)
    266 {
    267 	blk64_t curr_blk, jdb_blk;
    268 	size_t i, j;
    269 	int csum_size = 0;
    270 	journal_header_t *jdb;
    271 	journal_block_tag_t *jdbt;
    272 	int tag_bytes;
    273 	void *buf = NULL, *jdb_buf = NULL;
    274 	struct buffer_head *bh = NULL, *data_bh;
    275 	errcode_t err;
    276 
    277 	JOURNAL_CHECK_TRANS_MAGIC(trans);
    278 
    279 	if ((trans->flags & J_TRANS_COMMITTED) ||
    280 	    !(trans->flags & J_TRANS_OPEN))
    281 		return EXT2_ET_INVALID_ARGUMENT;
    282 
    283 	if (block_len == 0)
    284 		return 0;
    285 
    286 	/* Do we need to leave space at the end for a checksum? */
    287 	if (journal_has_csum_v2or3(trans->journal))
    288 		csum_size = sizeof(struct journal_block_tail);
    289 
    290 	curr_blk = jdb_blk = trans->block;
    291 
    292 	data_bh = getblk(trans->journal->j_dev, curr_blk,
    293 			 trans->journal->j_blocksize);
    294 	if (data_bh == NULL)
    295 		return ENOMEM;
    296 	buf = data_bh->b_data;
    297 
    298 	/* write the descriptor block header */
    299 	bh = getblk(trans->journal->j_dev, curr_blk,
    300 		    trans->journal->j_blocksize);
    301 	if (bh == NULL) {
    302 		err = ENOMEM;
    303 		goto error;
    304 	}
    305 	jdb = jdb_buf = bh->b_data;
    306 	jdb->h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER);
    307 	jdb->h_blocktype = ext2fs_cpu_to_be32(JFS_DESCRIPTOR_BLOCK);
    308 	jdb->h_sequence = ext2fs_cpu_to_be32(trans->tid);
    309 	jdbt = (journal_block_tag_t *)(jdb + 1);
    310 
    311 	curr_blk++;
    312 	for (i = 0; i < block_len; i++) {
    313 		j = fread(data_bh->b_data, trans->journal->j_blocksize, 1, fp);
    314 		if (j != 1) {
    315 			err = errno;
    316 			goto error;
    317 		}
    318 
    319 		tag_bytes = journal_tag_bytes(trans->journal);
    320 
    321 		/* No space left in descriptor block, write it out */
    322 		if ((char *)jdbt + tag_bytes >
    323 		    (char *)jdb_buf + trans->journal->j_blocksize - csum_size) {
    324 			jbd2_descr_block_csum_set(trans->journal, bh);
    325 			err = journal_bmap(trans->journal, jdb_blk,
    326 					   &bh->b_blocknr);
    327 			if (err)
    328 				goto error;
    329 			dbg_printf("Writing descriptor block at %llu:%llu\n",
    330 				   jdb_blk, bh->b_blocknr);
    331 			mark_buffer_dirty(bh);
    332 			ll_rw_block(WRITE, 1, &bh);
    333 			err = bh->b_err;
    334 			if (err)
    335 				goto error;
    336 
    337 			jdbt = (journal_block_tag_t *)(jdb + 1);
    338 			jdb_blk = curr_blk;
    339 			curr_blk++;
    340 		}
    341 
    342 		if (block_list[i] >=
    343 		    ext2fs_blocks_count(trans->journal->j_fs_dev->k_fs->super)) {
    344 			err = EXT2_ET_BAD_BLOCK_NUM;
    345 			goto error;
    346 		}
    347 
    348 		/* Fill out the block tag */
    349 		jdbt->t_blocknr = ext2fs_cpu_to_be32(block_list[i] & 0xFFFFFFFF);
    350 		jdbt->t_flags = 0;
    351 		if (jdbt != (journal_block_tag_t *)(jdb + 1))
    352 			jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_SAME_UUID);
    353 		else {
    354 			memcpy(jdbt + tag_bytes,
    355 			       trans->journal->j_superblock->s_uuid,
    356 			       sizeof(trans->journal->j_superblock->s_uuid));
    357 			tag_bytes += 16;
    358 		}
    359 		if (i == block_len - 1)
    360 			jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_LAST_TAG);
    361 		if (*((__u32 *)buf) == ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER)) {
    362 			*((__u32 *)buf) = 0;
    363 			jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_ESCAPE);
    364 		}
    365 		if (jfs_has_feature_64bit(trans->journal))
    366 			jdbt->t_blocknr_high = ext2fs_cpu_to_be32(block_list[i] >> 32);
    367 		jbd2_block_tag_csum_set(trans->journal, jdbt, data_bh,
    368 					trans->tid);
    369 
    370 		/* Write the data block */
    371 		err = journal_bmap(trans->journal, curr_blk,
    372 				   &data_bh->b_blocknr);
    373 		if (err)
    374 			goto error;
    375 		dbg_printf("Writing data block %llu at %llu:%llu tag %d\n",
    376 			   block_list[i], curr_blk, data_bh->b_blocknr,
    377 			   tag_bytes);
    378 		mark_buffer_dirty(data_bh);
    379 		ll_rw_block(WRITE, 1, &data_bh);
    380 		err = data_bh->b_err;
    381 		if (err)
    382 			goto error;
    383 
    384 		curr_blk++;
    385 		jdbt = (journal_block_tag_t *)(((char *)jdbt) + tag_bytes);
    386 	}
    387 
    388 	/* Write out the last descriptor block */
    389 	if (jdbt != (journal_block_tag_t *)(jdb + 1)) {
    390 		jbd2_descr_block_csum_set(trans->journal, bh);
    391 		err = journal_bmap(trans->journal, jdb_blk, &bh->b_blocknr);
    392 		if (err)
    393 			goto error;
    394 		dbg_printf("Writing descriptor block at %llu:%llu\n",
    395 			   jdb_blk, bh->b_blocknr);
    396 		mark_buffer_dirty(bh);
    397 		ll_rw_block(WRITE, 1, &bh);
    398 		err = bh->b_err;
    399 		if (err)
    400 			goto error;
    401 	}
    402 
    403 error:
    404 	trans->block = curr_blk;
    405 	if (bh)
    406 		brelse(bh);
    407 	brelse(data_bh);
    408 	return err;
    409 }
    410 
    411 static blk64_t journal_guess_blocks(journal_t *journal, blk64_t data_blocks,
    412 				    blk64_t revoke_blocks)
    413 {
    414 	blk64_t ret = 1;
    415 	unsigned int bs, sz;
    416 
    417 	/* Estimate # of revoke blocks */
    418 	bs = journal->j_blocksize;
    419 	if (journal_has_csum_v2or3(journal))
    420 		bs -= sizeof(struct journal_revoke_tail);
    421 	sz = jfs_has_feature_64bit(journal) ? sizeof(__u64) : sizeof(__u32);
    422 	ret += revoke_blocks * sz / bs;
    423 
    424 	/* Estimate # of data blocks */
    425 	bs = journal->j_blocksize - 16;
    426 	if (journal_has_csum_v2or3(journal))
    427 		bs -= sizeof(struct journal_block_tail);
    428 	sz = journal_tag_bytes(journal);
    429 	ret += data_blocks * sz / bs;
    430 
    431 	ret += data_blocks;
    432 
    433 	return ret;
    434 }
    435 
    436 static errcode_t journal_open_trans(journal_t *journal,
    437 				    journal_transaction_t *trans,
    438 				    blk64_t blocks)
    439 {
    440 	trans->fs = journal->j_fs_dev->k_fs;
    441 	trans->journal = journal;
    442 	trans->flags = J_TRANS_OPEN;
    443 
    444 	if (journal->j_tail == 0) {
    445 		/* Clean journal, start at the tail */
    446 		trans->tid = journal->j_tail_sequence;
    447 		trans->start = journal->j_first;
    448 	} else {
    449 		/* Put new transaction at the head of the list */
    450 		trans->tid = journal->j_transaction_sequence;
    451 		trans->start = journal->j_head;
    452 	}
    453 
    454 	trans->block = trans->start;
    455 	if (trans->start + blocks > journal->j_last)
    456 		return ENOSPC;
    457 	trans->end = trans->block + blocks;
    458 	journal_dump_trans(trans, "new transaction");
    459 
    460 	trans->magic = J_TRANS_MAGIC;
    461 	return 0;
    462 }
    463 
    464 static errcode_t journal_close_trans(journal_transaction_t *trans)
    465 {
    466 	journal_t *journal;
    467 
    468 	JOURNAL_CHECK_TRANS_MAGIC(trans);
    469 
    470 	if (!(trans->flags & J_TRANS_COMMITTED))
    471 		return 0;
    472 
    473 	journal = trans->journal;
    474 	if (journal->j_tail == 0) {
    475 		/* Update the tail */
    476 		journal->j_tail_sequence = trans->tid;
    477 		journal->j_tail = trans->start;
    478 		journal->j_superblock->s_start = ext2fs_cpu_to_be32(trans->start);
    479 	}
    480 
    481 	/* Update the head */
    482 	journal->j_head = trans->end + 1;
    483 	journal->j_transaction_sequence = trans->tid + 1;
    484 
    485 	trans->magic = 0;
    486 
    487 	/* Mark ourselves as needing recovery */
    488 	if (!ext2fs_has_feature_journal_needs_recovery(trans->fs->super)) {
    489 		ext2fs_set_feature_journal_needs_recovery(trans->fs->super);
    490 		ext2fs_mark_super_dirty(trans->fs);
    491 	}
    492 
    493 	return 0;
    494 }
    495 
    496 #define JOURNAL_WRITE_NO_COMMIT		1
    497 static errcode_t journal_write(journal_t *journal,
    498 			       int flags, blk64_t *block_list,
    499 			       size_t block_len, blk64_t *revoke_list,
    500 			       size_t revoke_len, FILE *fp)
    501 {
    502 	blk64_t blocks;
    503 	journal_transaction_t trans;
    504 	errcode_t err;
    505 
    506 	if (revoke_len > 0) {
    507 		jfs_set_feature_revoke(journal);
    508 		mark_buffer_dirty(journal->j_sb_buffer);
    509 	}
    510 
    511 	blocks = journal_guess_blocks(journal, block_len, revoke_len);
    512 	err = journal_open_trans(journal, &trans, blocks);
    513 	if (err)
    514 		goto error;
    515 
    516 	err = journal_add_blocks_to_trans(&trans, block_list, block_len, fp);
    517 	if (err)
    518 		goto error;
    519 
    520 	err = journal_add_revoke_to_trans(&trans, revoke_list, revoke_len);
    521 	if (err)
    522 		goto error;
    523 
    524 	if (!(flags & JOURNAL_WRITE_NO_COMMIT)) {
    525 		err = journal_commit_trans(&trans);
    526 		if (err)
    527 			goto error;
    528 	}
    529 
    530 	err = journal_close_trans(&trans);
    531 	if (err)
    532 		goto error;
    533 error:
    534 	return err;
    535 }
    536 
    537 void do_journal_write(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
    538 		      void *infop EXT2FS_ATTR((unused)))
    539 {
    540 	blk64_t *blist = NULL, *rlist = NULL;
    541 	size_t bn = 0, rn = 0;
    542 	FILE *fp = NULL;
    543 	int opt;
    544 	int flags = 0;
    545 	errcode_t err;
    546 
    547 	if (current_journal == NULL) {
    548 		printf("Journal not open.\n");
    549 		return;
    550 	}
    551 
    552 	reset_getopt();
    553 	while ((opt = getopt(argc, argv, "b:r:c")) != -1) {
    554 		switch (opt) {
    555 		case 'b':
    556 			err = read_list(optarg, &blist, &bn);
    557 			if (err)
    558 				com_err(argv[0], err,
    559 					"while reading block list");
    560 			break;
    561 		case 'r':
    562 			err = read_list(optarg, &rlist, &rn);
    563 			if (err)
    564 				com_err(argv[0], err,
    565 					"while reading revoke list");
    566 			break;
    567 		case 'c':
    568 			flags |= JOURNAL_WRITE_NO_COMMIT;
    569 			break;
    570 		default:
    571 			printf("%s [-b blocks] [-r revoke] [-c] file\n",
    572 			       argv[0]);
    573 			printf("-b: Write these blocks into transaction.\n");
    574 			printf("-c: Do not commit transaction.\n");
    575 			printf("-r: Revoke these blocks from transaction.\n");
    576 
    577 			goto out;
    578 		}
    579 	}
    580 
    581 	if (bn > 0 && optind != argc - 1) {
    582 		printf("Need a file to read blocks from.\n");
    583 		return;
    584 	}
    585 
    586 	if (bn > 0) {
    587 		fp = fopen(argv[optind], "r");
    588 		if (fp == NULL) {
    589 			com_err(argv[0], errno,
    590 				"while opening journal data file");
    591 			goto out;
    592 		}
    593 	}
    594 
    595 	err = journal_write(current_journal, flags, blist, bn,
    596 			    rlist, rn, fp);
    597 	if (err)
    598 		com_err("journal_write", err, "while writing journal");
    599 
    600 	if (fp)
    601 		fclose(fp);
    602 out:
    603 	if (blist)
    604 		free(blist);
    605 	if (rlist)
    606 		free(rlist);
    607 }
    608 
    609 /* Make sure we wrap around the log correctly! */
    610 #define wrap(journal, var)						\
    611 do {									\
    612 	if (var >= (journal)->j_last)					\
    613 		var -= ((journal)->j_last - (journal)->j_first);	\
    614 } while (0)
    615 
    616 /*
    617  * Count the number of in-use tags in a journal descriptor block.
    618  */
    619 
    620 static int count_tags(journal_t *journal, char *buf)
    621 {
    622 	char			*tagp;
    623 	journal_block_tag_t	*tag;
    624 	int			nr = 0, size = journal->j_blocksize;
    625 	int			tag_bytes = journal_tag_bytes(journal);
    626 
    627 	if (journal_has_csum_v2or3(journal))
    628 		size -= sizeof(struct journal_block_tail);
    629 
    630 	tagp = buf + sizeof(journal_header_t);
    631 
    632 	while ((tagp - buf + tag_bytes) <= size) {
    633 		tag = (journal_block_tag_t *) tagp;
    634 
    635 		nr++;
    636 		tagp += tag_bytes;
    637 		if (!(tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_SAME_UUID)))
    638 			tagp += 16;
    639 
    640 		if (tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_LAST_TAG))
    641 			break;
    642 	}
    643 
    644 	return nr;
    645 }
    646 
    647 static errcode_t journal_find_head(journal_t *journal)
    648 {
    649 	unsigned int		next_commit_ID;
    650 	blk64_t			next_log_block, head_block;
    651 	int			err;
    652 	journal_superblock_t	*sb;
    653 	journal_header_t	*tmp;
    654 	struct buffer_head	*bh;
    655 	unsigned int		sequence;
    656 	int			blocktype;
    657 
    658 	/*
    659 	 * First thing is to establish what we expect to find in the log
    660 	 * (in terms of transaction IDs), and where (in terms of log
    661 	 * block offsets): query the superblock.
    662 	 */
    663 
    664 	sb = journal->j_superblock;
    665 	next_commit_ID = ext2fs_be32_to_cpu(sb->s_sequence);
    666 	next_log_block = ext2fs_be32_to_cpu(sb->s_start);
    667 	head_block = next_log_block;
    668 
    669 	if (next_log_block == 0)
    670 		return 0;
    671 
    672 	bh = getblk(journal->j_dev, 0, journal->j_blocksize);
    673 	if (bh == NULL)
    674 		return ENOMEM;
    675 
    676 	/*
    677 	 * Now we walk through the log, transaction by transaction,
    678 	 * making sure that each transaction has a commit block in the
    679 	 * expected place.  Each complete transaction gets replayed back
    680 	 * into the main filesystem.
    681 	 */
    682 	while (1) {
    683 		dbg_printf("Scanning for sequence ID %u at %lu/%lu\n",
    684 			  next_commit_ID, (unsigned long)next_log_block,
    685 			  journal->j_last);
    686 
    687 		/* Skip over each chunk of the transaction looking
    688 		 * either the next descriptor block or the final commit
    689 		 * record. */
    690 		err = journal_bmap(journal, next_log_block, &bh->b_blocknr);
    691 		if (err)
    692 			goto err;
    693 		mark_buffer_uptodate(bh, 0);
    694 		ll_rw_block(READ, 1, &bh);
    695 		err = bh->b_err;
    696 		if (err)
    697 			goto err;
    698 
    699 		next_log_block++;
    700 		wrap(journal, next_log_block);
    701 
    702 		/* What kind of buffer is it?
    703 		 *
    704 		 * If it is a descriptor block, check that it has the
    705 		 * expected sequence number.  Otherwise, we're all done
    706 		 * here. */
    707 
    708 		tmp = (journal_header_t *)bh->b_data;
    709 
    710 		if (tmp->h_magic != ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER)) {
    711 			dbg_printf("JBD2: wrong magic 0x%x\n", tmp->h_magic);
    712 			goto err;
    713 		}
    714 
    715 		blocktype = ext2fs_be32_to_cpu(tmp->h_blocktype);
    716 		sequence = ext2fs_be32_to_cpu(tmp->h_sequence);
    717 		dbg_printf("Found magic %d, sequence %d\n",
    718 			  blocktype, sequence);
    719 
    720 		if (sequence != next_commit_ID) {
    721 			dbg_printf("JBD2: Wrong sequence %d (wanted %d)\n",
    722 				   sequence, next_commit_ID);
    723 			goto err;
    724 		}
    725 
    726 		/* OK, we have a valid descriptor block which matches
    727 		 * all of the sequence number checks.  What are we going
    728 		 * to do with it?  That depends on the pass... */
    729 
    730 		switch (blocktype) {
    731 		case JFS_DESCRIPTOR_BLOCK:
    732 			next_log_block += count_tags(journal, bh->b_data);
    733 			wrap(journal, next_log_block);
    734 			continue;
    735 
    736 		case JFS_COMMIT_BLOCK:
    737 			head_block = next_log_block;
    738 			next_commit_ID++;
    739 			continue;
    740 
    741 		case JFS_REVOKE_BLOCK:
    742 			continue;
    743 
    744 		default:
    745 			dbg_printf("Unrecognised magic %d, end of scan.\n",
    746 				  blocktype);
    747 			err = -EINVAL;
    748 			goto err;
    749 		}
    750 	}
    751 
    752 err:
    753 	if (err == 0) {
    754 		dbg_printf("head seq=%d blk=%llu\n", next_commit_ID,
    755 			   head_block);
    756 		journal->j_transaction_sequence = next_commit_ID;
    757 		journal->j_head = head_block;
    758 	}
    759 	brelse(bh);
    760 	return err;
    761 }
    762 
    763 static void update_journal_csum(journal_t *journal, int ver)
    764 {
    765 	journal_superblock_t *jsb;
    766 
    767 	if (journal->j_format_version < 2)
    768 		return;
    769 
    770 	if (journal->j_tail != 0 ||
    771 	    ext2fs_has_feature_journal_needs_recovery(
    772 					journal->j_fs_dev->k_fs->super)) {
    773 		printf("Journal needs recovery, will not add csums.\n");
    774 		return;
    775 	}
    776 
    777 	/* metadata_csum implies journal csum v3 */
    778 	jsb = journal->j_superblock;
    779 	if (ext2fs_has_feature_metadata_csum(journal->j_fs_dev->k_fs->super)) {
    780 		printf("Setting csum v%d\n", ver);
    781 		switch (ver) {
    782 		case 2:
    783 			jfs_clear_feature_csum3(journal);
    784 			jfs_set_feature_csum2(journal);
    785 			jfs_clear_feature_checksum(journal);
    786 			break;
    787 		case 3:
    788 			jfs_set_feature_csum3(journal);
    789 			jfs_clear_feature_csum2(journal);
    790 			jfs_clear_feature_checksum(journal);
    791 			break;
    792 		default:
    793 			printf("Unknown checksum v%d\n", ver);
    794 			break;
    795 		}
    796 		journal->j_superblock->s_checksum_type = JBD2_CRC32C_CHKSUM;
    797 		journal->j_csum_seed = jbd2_chksum(journal, ~0, jsb->s_uuid,
    798 						   sizeof(jsb->s_uuid));
    799 	} else {
    800 		jfs_clear_feature_csum3(journal);
    801 		jfs_clear_feature_csum2(journal);
    802 		jfs_set_feature_checksum(journal);
    803 	}
    804 }
    805 
    806 static void update_uuid(journal_t *journal)
    807 {
    808 	size_t z;
    809 	ext2_filsys fs;
    810 
    811 	if (journal->j_format_version < 2)
    812 		return;
    813 
    814 	for (z = 0; z < sizeof(journal->j_superblock->s_uuid); z++)
    815 		if (journal->j_superblock->s_uuid[z])
    816 			break;
    817 	if (z == 0)
    818 		return;
    819 
    820 	fs = journal->j_fs_dev->k_fs;
    821 	if (!ext2fs_has_feature_64bit(fs->super))
    822 		return;
    823 
    824 	if (jfs_has_feature_64bit(journal) &&
    825 	    ext2fs_has_feature_64bit(fs->super))
    826 		return;
    827 
    828 	if (journal->j_tail != 0 ||
    829 	    ext2fs_has_feature_journal_needs_recovery(fs->super)) {
    830 		printf("Journal needs recovery, will not set 64bit.\n");
    831 		return;
    832 	}
    833 
    834 	memcpy(journal->j_superblock->s_uuid, fs->super->s_uuid,
    835 	       sizeof(fs->super->s_uuid));
    836 }
    837 
    838 static void update_64bit_flag(journal_t *journal)
    839 {
    840 	if (journal->j_format_version < 2)
    841 		return;
    842 
    843 	if (!ext2fs_has_feature_64bit(journal->j_fs_dev->k_fs->super))
    844 		return;
    845 
    846 	if (jfs_has_feature_64bit(journal) &&
    847 	    ext2fs_has_feature_64bit(journal->j_fs_dev->k_fs->super))
    848 		return;
    849 
    850 	if (journal->j_tail != 0 ||
    851 	    ext2fs_has_feature_journal_needs_recovery(
    852 				journal->j_fs_dev->k_fs->super)) {
    853 		printf("Journal needs recovery, will not set 64bit.\n");
    854 		return;
    855 	}
    856 
    857 	jfs_set_feature_64bit(journal);
    858 }
    859 
    860 void do_journal_open(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
    861 		     void *infop EXT2FS_ATTR((unused)))
    862 {
    863 	int opt, enable_csum = 0, csum_ver = 3;
    864 	journal_t *journal;
    865 	errcode_t err;
    866 
    867 	if (check_fs_open(argv[0]))
    868 		return;
    869 	if (check_fs_read_write(argv[0]))
    870 		return;
    871 	if (check_fs_bitmaps(argv[0]))
    872 		return;
    873 	if (current_journal) {
    874 		printf("Journal is already open.\n");
    875 		return;
    876 	}
    877 	if (!ext2fs_has_feature_journal(current_fs->super)) {
    878 		printf("Journalling is not enabled on this filesystem.\n");
    879 		return;
    880 	}
    881 
    882 	reset_getopt();
    883 	while ((opt = getopt(argc, argv, "cv:f:")) != -1) {
    884 		switch (opt) {
    885 		case 'c':
    886 			enable_csum = 1;
    887 			break;
    888 		case 'f':
    889 			if (current_fs->journal_name)
    890 				free(current_fs->journal_name);
    891 			current_fs->journal_name = strdup(optarg);
    892 			break;
    893 		case 'v':
    894 			csum_ver = atoi(optarg);
    895 			if (csum_ver != 2 && csum_ver != 3) {
    896 				printf("Unknown journal csum v%d\n", csum_ver);
    897 				csum_ver = 3;
    898 			}
    899 			break;
    900 		default:
    901 			printf("%s: [-c] [-v ver] [-f ext_jnl]\n", argv[0]);
    902 			printf("-c: Enable journal checksumming.\n");
    903 			printf("-v: Use this version checksum format.\n");
    904 			printf("-f: Load this external journal.\n");
    905 		}
    906 	}
    907 
    908 	err = ext2fs_open_journal(current_fs, &current_journal);
    909 	if (err) {
    910 		com_err(argv[0], err, "while opening journal");
    911 		return;
    912 	}
    913 	journal = current_journal;
    914 
    915 	dbg_printf("JOURNAL: seq=%d tailseq=%d start=%lu first=%lu "
    916 		   "maxlen=%lu\n", journal->j_tail_sequence,
    917 		   journal->j_transaction_sequence, journal->j_tail,
    918 		   journal->j_first, journal->j_last);
    919 
    920 	update_uuid(journal);
    921 	update_64bit_flag(journal);
    922 	if (enable_csum)
    923 		update_journal_csum(journal, csum_ver);
    924 
    925 	err = journal_find_head(journal);
    926 	if (err)
    927 		com_err(argv[0], err, "while examining journal");
    928 }
    929 
    930 void do_journal_close(int argc EXT2FS_ATTR((unused)),
    931 		      char *argv[] EXT2FS_ATTR((unused)),
    932 		      int sci_idx EXT2FS_ATTR((unused)),
    933 		      void *infop EXT2FS_ATTR((unused)))
    934 {
    935 	if (current_journal == NULL) {
    936 		printf("Journal not open.\n");
    937 		return;
    938 	}
    939 
    940 	ext2fs_close_journal(current_fs, &current_journal);
    941 }
    942 
    943 void do_journal_run(int argc EXT2FS_ATTR((unused)), char *argv[],
    944 		    int sci_idx EXT2FS_ATTR((unused)),
    945 		    void *infop EXT2FS_ATTR((unused)))
    946 {
    947 	errcode_t err;
    948 
    949 	if (check_fs_open(argv[0]))
    950 		return;
    951 	if (check_fs_read_write(argv[0]))
    952 		return;
    953 	if (check_fs_bitmaps(argv[0]))
    954 		return;
    955 	if (current_journal) {
    956 		printf("Please close the journal before recovering it.\n");
    957 		return;
    958 	}
    959 
    960 	err = ext2fs_run_ext3_journal(&current_fs);
    961 	if (err)
    962 		com_err("journal_run", err, "while recovering journal");
    963 	else {
    964 		ext2fs_clear_feature_journal_needs_recovery(current_fs->super);
    965 		ext2fs_mark_super_dirty(current_fs);
    966 	}
    967 }
    968