lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date:	Fri, 5 Sep 2014 22:52:59 -0700
From:	"Darrick J. Wong" <darrick.wong@...cle.com>
To:	tytso@....edu
Cc:	linux-ext4@...r.kernel.org
Subject: Re: [PATCH 14/27] debugfs: add the ability to write transactions to
 the journal

On Sat, Aug 16, 2014 at 04:47:23PM -0700, Darrick J. Wong wrote:
> Extend debugfs with the ability to create transactions and replay the
> journal.  This will eventually be used to test kernel recovery and
> metadata_csum recovery.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@...cle.com>
> ---

<snip>

> +#define DEBUG

Probably ought to be #undef DEBUG...

<snip>

> +static errcode_t journal_add_revoke_to_trans(journal_transaction_t *trans,
> +					     blk64_t *revoke_list,
> +					     size_t revoke_len)
> +{
> +	journal_revoke_header_t *jrb;
> +	void *buf;
> +	size_t i, offset;
> +	blk64_t curr_blk;
> +	int csum_size = 0;
> +	struct buffer_head *bh;
> +	errcode_t err;
> +
> +	JOURNAL_CHECK_TRANS_MAGIC(trans);
> +
> +	if ((trans->flags & J_TRANS_COMMITTED) ||
> +	    !(trans->flags & J_TRANS_OPEN))
> +		return EXT2_ET_INVALID_ARGUMENT;
> +
> +	if (revoke_len == 0)
> +		return 0;
> +
> +	/* Do we need to leave space at the end for a checksum? */
> +	if (journal_has_csum_v2or3(trans->journal))
> +		csum_size = sizeof(struct journal_revoke_tail);
> +
> +	curr_blk = trans->block;
> +
> +	bh = getblk(trans->journal->j_dev, curr_blk,
> +		    trans->journal->j_blocksize);
> +	if (bh == NULL)
> +		return ENOMEM;
> +	jrb = buf = bh->b_data;
> +	jrb->r_header.h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER);
> +	jrb->r_header.h_blocktype = ext2fs_cpu_to_be32(JFS_REVOKE_BLOCK);
> +	jrb->r_header.h_sequence = ext2fs_cpu_to_be32(trans->tid);
> +	offset = sizeof(*jrb);
> +
> +	for (i = 0; i < revoke_len; i++) {
> +		/* Block full, write to journal */
> +		if (offset > trans->journal->j_blocksize - csum_size) {
> +			jrb->r_count = ext2fs_cpu_to_be32(offset);
> +			jbd2_revoke_csum_set(trans->journal, bh);
> +
> +			err = journal_bmap(trans->journal, curr_blk,
> +					   &bh->b_blocknr);
> +			if (err)
> +				goto error;
> +			dbg_printf("Writing revoke block at %llu:%llu\n",
> +				   curr_blk, bh->b_blocknr);
> +			mark_buffer_dirty(bh);
> +			ll_rw_block(WRITE, 1, &bh);
> +			err = bh->b_err;
> +			if (err)
> +				goto error;
> +
> +			offset = sizeof(*jrb);
> +			curr_blk++;
> +		}
> +
> +		if (revoke_list[i] >=
> +		    ext2fs_blocks_count(trans->journal->j_inode->i_fs->super)) {

This (and all other journal->j_inode dereference chains) ought to be
journal->j_fs_dev->k_fs->super because j_inode is NULL if we have an
external journal.

Will send out updated patch (with more test cases) shortly.

--D

> +			err = EXT2_ET_BAD_BLOCK_NUM;
> +			goto error;
> +		}
> +
> +		if (JFS_HAS_INCOMPAT_FEATURE(trans->journal,
> +					     JFS_FEATURE_INCOMPAT_64BIT)) {
> +			* ((__u64 *)(&((char *)buf)[offset])) =
> +				ext2fs_cpu_to_be64(revoke_list[i]);
> +			offset += 8;
> +
> +		} else {
> +			* ((__u32 *)(&((char *)buf)[offset])) =
> +				ext2fs_cpu_to_be32(revoke_list[i]);
> +			offset += 4;
> +		}
> +	}
> +
> +	if (offset > 0) {
> +		jrb->r_count = ext2fs_cpu_to_be32(offset);
> +		jbd2_revoke_csum_set(trans->journal, bh);
> +
> +		err = journal_bmap(trans->journal, curr_blk, &bh->b_blocknr);
> +		if (err)
> +			goto error;
> +		dbg_printf("Writing revoke block at %llu:%llu\n",
> +			   curr_blk, bh->b_blocknr);
> +		mark_buffer_dirty(bh);
> +		ll_rw_block(WRITE, 1, &bh);
> +		err = bh->b_err;
> +		if (err)
> +			goto error;
> +		curr_blk++;
> +	}
> +
> +error:
> +	trans->block = curr_blk;
> +	brelse(bh);
> +	return err;
> +}
> +
> +static errcode_t journal_add_blocks_to_trans(journal_transaction_t *trans,
> +				      blk64_t *block_list, size_t block_len,
> +				      FILE *fp)
> +{
> +	blk64_t curr_blk, jdb_blk;
> +	size_t i, j;
> +	int csum_size = 0;
> +	journal_header_t *jdb;
> +	journal_block_tag_t *jdbt;
> +	int tag_bytes;
> +	void *buf = NULL, *jdb_buf = NULL;
> +	struct buffer_head *bh = NULL, *data_bh;
> +	errcode_t err;
> +
> +	JOURNAL_CHECK_TRANS_MAGIC(trans);
> +
> +	if ((trans->flags & J_TRANS_COMMITTED) ||
> +	    !(trans->flags & J_TRANS_OPEN))
> +		return EXT2_ET_INVALID_ARGUMENT;
> +
> +	if (block_len == 0)
> +		return 0;
> +
> +	/* Do we need to leave space at the end for a checksum? */
> +	if (journal_has_csum_v2or3(trans->journal))
> +		csum_size = sizeof(struct journal_block_tail);
> +
> +	curr_blk = jdb_blk = trans->block;
> +
> +	data_bh = getblk(trans->journal->j_dev, curr_blk,
> +			 trans->journal->j_blocksize);
> +	if (data_bh == NULL)
> +		return ENOMEM;
> +	buf = data_bh->b_data;
> +
> +	/* write the descriptor block header */
> +	bh = getblk(trans->journal->j_dev, curr_blk,
> +		    trans->journal->j_blocksize);
> +	if (bh == NULL) {
> +		err = ENOMEM;
> +		goto error;
> +	}
> +	jdb = jdb_buf = bh->b_data;
> +	jdb->h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER);
> +	jdb->h_blocktype = ext2fs_cpu_to_be32(JFS_DESCRIPTOR_BLOCK);
> +	jdb->h_sequence = ext2fs_cpu_to_be32(trans->tid);
> +	jdbt = (journal_block_tag_t *)(jdb + 1);
> +
> +	curr_blk++;
> +	for (i = 0; i < block_len; i++) {
> +		j = fread(data_bh->b_data, trans->journal->j_blocksize, 1, fp);
> +		if (j != 1) {
> +			err = errno;
> +			goto error;
> +		}
> +
> +		tag_bytes = journal_tag_bytes(trans->journal);
> +
> +		/* No space left in descriptor block, write it out */
> +		if ((char *)jdbt + tag_bytes >
> +		    (char *)jdb_buf + trans->journal->j_blocksize - csum_size) {
> +			jbd2_descr_block_csum_set(trans->journal, bh);
> +			err = journal_bmap(trans->journal, jdb_blk,
> +					   &bh->b_blocknr);
> +			if (err)
> +				goto error;
> +			dbg_printf("Writing descriptor block at %llu:%llu\n",
> +				   jdb_blk, bh->b_blocknr);
> +			mark_buffer_dirty(bh);
> +			ll_rw_block(WRITE, 1, &bh);
> +			err = bh->b_err;
> +			if (err)
> +				goto error;
> +
> +			jdbt = (journal_block_tag_t *)(jdb + 1);
> +			jdb_blk = curr_blk;
> +			curr_blk++;
> +		}
> +
> +		if (block_list[i] >=
> +		    ext2fs_blocks_count(trans->journal->j_inode->i_fs->super)) {
> +			err = EXT2_ET_BAD_BLOCK_NUM;
> +			goto error;
> +		}
> +
> +		/* Fill out the block tag */
> +		jdbt->t_blocknr = ext2fs_cpu_to_be32(block_list[i] & 0xFFFFFFFF);
> +		jdbt->t_flags = 0;
> +		if (jdbt != (journal_block_tag_t *)(jdb + 1))
> +			jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_SAME_UUID);
> +		else {
> +			memcpy(jdbt + tag_bytes,
> +			       trans->journal->j_superblock->s_uuid,
> +			       sizeof(trans->journal->j_superblock->s_uuid));
> +			tag_bytes += 16;
> +		}
> +		if (i == block_len - 1)
> +			jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_LAST_TAG);
> +		if (*((__u32 *)buf) == ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER)) {
> +			*((__u32 *)buf) = 0;
> +			jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_ESCAPE);
> +		}
> +		if (JFS_HAS_INCOMPAT_FEATURE(trans->journal,
> +					     JFS_FEATURE_INCOMPAT_64BIT))
> +			jdbt->t_blocknr_high = ext2fs_cpu_to_be32(block_list[i] >> 32);
> +		jbd2_block_tag_csum_set(trans->journal, jdbt, data_bh,
> +					trans->tid);
> +
> +		/* Write the data block */
> +		err = journal_bmap(trans->journal, curr_blk,
> +				   &data_bh->b_blocknr);
> +		if (err)
> +			goto error;
> +		dbg_printf("Writing data block %llu at %llu:%llu tag %d\n",
> +			   block_list[i], curr_blk, data_bh->b_blocknr,
> +			   tag_bytes);
> +		mark_buffer_dirty(data_bh);
> +		ll_rw_block(WRITE, 1, &data_bh);
> +		err = data_bh->b_err;
> +		if (err)
> +			goto error;
> +
> +		curr_blk++;
> +		jdbt = (journal_block_tag_t *)(((char *)jdbt) + tag_bytes);
> +	}
> +
> +	/* Write out the last descriptor block */
> +	if (jdbt != (journal_block_tag_t *)(jdb + 1)) {
> +		jbd2_descr_block_csum_set(trans->journal, bh);
> +		err = journal_bmap(trans->journal, jdb_blk, &bh->b_blocknr);
> +		if (err)
> +			goto error;
> +		dbg_printf("Writing descriptor block at %llu:%llu\n",
> +			   jdb_blk, bh->b_blocknr);
> +		mark_buffer_dirty(bh);
> +		ll_rw_block(WRITE, 1, &bh);
> +		err = bh->b_err;
> +		if (err)
> +			goto error;
> +	}
> +
> +error:
> +	trans->block = curr_blk;
> +	if (bh)
> +		brelse(bh);
> +	brelse(data_bh);
> +	return err;
> +}
> +
> +static blk64_t journal_guess_blocks(journal_t *journal, blk64_t data_blocks,
> +				    blk64_t revoke_blocks)
> +{
> +	blk64_t ret = 1;
> +	unsigned int bs, sz;
> +
> +	/* Estimate # of revoke blocks */
> +	bs = journal->j_blocksize;
> +	if (journal_has_csum_v2or3(journal))
> +		bs -= sizeof(struct journal_revoke_tail);
> +	sz = JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT) ?
> +				sizeof(__u64) : sizeof(__u32);
> +	ret += revoke_blocks * sz / bs;
> +
> +	/* Estimate # of data blocks */
> +	bs = journal->j_blocksize - 16;
> +	if (journal_has_csum_v2or3(journal))
> +		bs -= sizeof(struct journal_block_tail);
> +	sz = journal_tag_bytes(journal);
> +	ret += data_blocks * sz / bs;
> +
> +	ret += data_blocks;
> +
> +	return ret;
> +}
> +
> +static errcode_t journal_open_trans(journal_t *journal,
> +				    journal_transaction_t *trans,
> +				    blk64_t blocks)
> +{
> +	trans->fs = journal->j_inode->i_fs;
> +	trans->journal = journal;
> +	trans->flags = J_TRANS_OPEN;
> +
> +	if (journal->j_tail == 0) {
> +		/* Clean journal, start at the tail */
> +		trans->tid = journal->j_tail_sequence;
> +		trans->start = 1;
> +	} else {
> +		/* Put new transaction at the head of the list */
> +		trans->tid = journal->j_transaction_sequence;
> +		trans->start = journal->j_head;
> +	}
> +
> +	trans->block = trans->start;
> +	if (trans->start + blocks > journal->j_last)
> +		return ENOSPC;
> +	trans->end = trans->block + blocks;
> +	journal_dump_trans(trans, "new transaction");
> +
> +	trans->magic = J_TRANS_MAGIC;
> +	return 0;
> +}
> +
> +static errcode_t journal_close_trans(journal_transaction_t *trans)
> +{
> +	journal_t *journal;
> +
> +	JOURNAL_CHECK_TRANS_MAGIC(trans);
> +
> +	if (!(trans->flags & J_TRANS_COMMITTED))
> +		return 0;
> +
> +	journal = trans->journal;
> +	if (journal->j_tail == 0) {
> +		/* Update the tail */
> +		journal->j_tail_sequence = trans->tid;
> +		journal->j_tail = trans->start;
> +		journal->j_superblock->s_start = ext2fs_cpu_to_be32(trans->start);
> +	}
> +
> +	/* Update the head */
> +	journal->j_head = trans->end + 1;
> +	journal->j_transaction_sequence = trans->tid + 1;
> +
> +	trans->magic = 0;
> +
> +	/* Mark ourselves as needing recovery */
> +	if (!(EXT2_HAS_INCOMPAT_FEATURE(trans->fs->super,
> +					EXT3_FEATURE_INCOMPAT_RECOVER))) {
> +		trans->fs->super->s_feature_incompat |=
> +					EXT3_FEATURE_INCOMPAT_RECOVER;
> +		ext2fs_mark_super_dirty(trans->fs);
> +	}
> +
> +	return 0;
> +}
> +
> +#define JOURNAL_WRITE_NO_COMMIT		1
> +static errcode_t journal_write(journal_t *journal,
> +			       int flags, blk64_t *block_list,
> +			       size_t block_len, blk64_t *revoke_list,
> +			       size_t revoke_len, FILE *fp)
> +{
> +	blk64_t blocks;
> +	journal_transaction_t trans;
> +	errcode_t err;
> +
> +	if (revoke_len > 0) {
> +		journal->j_superblock->s_feature_incompat |=
> +				ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_REVOKE);
> +		mark_buffer_dirty(journal->j_sb_buffer);
> +	}
> +
> +	blocks = journal_guess_blocks(journal, block_len, revoke_len);
> +	err = journal_open_trans(journal, &trans, blocks);
> +	if (err)
> +		goto error;
> +
> +	err = journal_add_blocks_to_trans(&trans, block_list, block_len, fp);
> +	if (err)
> +		goto error;
> +
> +	err = journal_add_revoke_to_trans(&trans, revoke_list, revoke_len);
> +	if (err)
> +		goto error;
> +
> +	if (!(flags & JOURNAL_WRITE_NO_COMMIT)) {
> +		err = journal_commit_trans(&trans);
> +		if (err)
> +			goto error;
> +	}
> +
> +	err = journal_close_trans(&trans);
> +	if (err)
> +		goto error;
> +error:
> +	return err;
> +}
> +
> +void do_journal_write(int argc, char *argv[])
> +{
> +	blk64_t *blist = NULL, *rlist = NULL;
> +	size_t bn = 0, rn = 0;
> +	FILE *fp = NULL;
> +	int opt;
> +	int flags = 0;
> +	errcode_t err;
> +
> +	if (current_journal == NULL) {
> +		printf("Journal not open.\n");
> +		return;
> +	}
> +
> +	reset_getopt();
> +	while ((opt = getopt(argc, argv, "b:r:c")) != -1) {
> +		switch (opt) {
> +		case 'b':
> +			err = read_list(optarg, &blist, &bn);
> +			if (err)
> +				com_err(argv[0], err,
> +					"while reading block list");
> +			break;
> +		case 'r':
> +			err = read_list(optarg, &rlist, &rn);
> +			if (err)
> +				com_err(argv[0], err,
> +					"while reading revoke list");
> +			break;
> +		case 'c':
> +			flags |= JOURNAL_WRITE_NO_COMMIT;
> +			break;
> +		default:
> +			printf("%s [-b blocks] [-r revoke] [-c] file\n",
> +			       argv[0]);
> +			printf("-b: Write these blocks into transaction.\n");
> +			printf("-c: Do not commit transaction.\n");
> +			printf("-r: Revoke these blocks from transaction.\n");
> +
> +			goto out;
> +		}
> +	}
> +
> +	if (bn > 0 && optind != argc - 1) {
> +		printf("Need a file to read blocks from.\n");
> +		return;
> +	}
> +
> +	if (bn > 0) {
> +		fp = fopen(argv[optind], "r");
> +		if (fp == NULL) {
> +			com_err(argv[0], errno,
> +				"while opening journal data file");
> +			goto out;
> +		}
> +	}
> +
> +	err = journal_write(current_journal, flags, blist, bn,
> +			    rlist, rn, fp);
> +	if (err)
> +		com_err("journal_write", err, "while writing journal");
> +
> +	if (fp)
> +		fclose(fp);
> +out:
> +	if (blist)
> +		free(blist);
> +	if (rlist)
> +		free(rlist);
> +}
> +
> +/* Make sure we wrap around the log correctly! */
> +#define wrap(journal, var)						\
> +do {									\
> +	if (var >= (journal)->j_last)					\
> +		var -= ((journal)->j_last - (journal)->j_first);	\
> +} while (0)
> +
> +/*
> + * Count the number of in-use tags in a journal descriptor block.
> + */
> +
> +static int count_tags(journal_t *journal, char *buf)
> +{
> +	char *			tagp;
> +	journal_block_tag_t *	tag;
> +	int			nr = 0, size = journal->j_blocksize;
> +	int			tag_bytes = journal_tag_bytes(journal);
> +
> +	if (journal_has_csum_v2or3(journal))
> +		size -= sizeof(struct journal_block_tail);
> +
> +	tagp = buf + sizeof(journal_header_t);
> +
> +	while ((tagp - buf + tag_bytes) <= size) {
> +		tag = (journal_block_tag_t *) tagp;
> +
> +		nr++;
> +		tagp += tag_bytes;
> +		if (!(tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_SAME_UUID)))
> +			tagp += 16;
> +
> +		if (tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_LAST_TAG))
> +			break;
> +	}
> +
> +	return nr;
> +}
> +
> +errcode_t journal_find_head(journal_t *journal)
> +{
> +	unsigned int		next_commit_ID;
> +	blk64_t			next_log_block, head_block;
> +	int			err;
> +	journal_superblock_t *	sb;
> +	journal_header_t *	tmp;
> +	struct buffer_head *	bh;
> +	unsigned int		sequence;
> +	int			blocktype;
> +
> +	/*
> +	 * 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 = ext2fs_be32_to_cpu(sb->s_sequence);
> +	next_log_block = ext2fs_be32_to_cpu(sb->s_start);
> +	head_block = next_log_block;
> +
> +	if (next_log_block == 0)
> +		return 0;
> +
> +	bh = getblk(journal->j_dev, 0, journal->j_blocksize);
> +	if (bh == NULL)
> +		return ENOMEM;
> +
> +	/*
> +	 * 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) {
> +		dbg_printf("Scanning for sequence ID %u at %lu/%lu\n",
> +			  next_commit_ID, (unsigned long)next_log_block,
> +			  journal->j_last);
> +
> +		/* Skip over each chunk of the transaction looking
> +		 * either the next descriptor block or the final commit
> +		 * record. */
> +		err = journal_bmap(journal, next_log_block, &bh->b_blocknr);
> +		if (err)
> +			goto err;
> +		mark_buffer_uptodate(bh, 0);
> +		ll_rw_block(READ, 1, &bh);
> +		err = bh->b_err;
> +		if (err)
> +			goto err;
> +
> +		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;
> +
> +		if (tmp->h_magic != ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER)) {
> +			dbg_printf("JBD2: wrong magic 0x%x\n", tmp->h_magic);
> +			goto err;
> +		}
> +
> +		blocktype = ext2fs_be32_to_cpu(tmp->h_blocktype);
> +		sequence = ext2fs_be32_to_cpu(tmp->h_sequence);
> +		dbg_printf("Found magic %d, sequence %d\n",
> +			  blocktype, sequence);
> +
> +		if (sequence != next_commit_ID) {
> +			dbg_printf("JBD2: Wrong sequence %d (wanted %d)\n",
> +				   sequence, next_commit_ID);
> +			goto err;
> +		}
> +
> +		/* 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) {
> +		case JFS_DESCRIPTOR_BLOCK:
> +			next_log_block += count_tags(journal, bh->b_data);
> +			wrap(journal, next_log_block);
> +			continue;
> +
> +		case JFS_COMMIT_BLOCK:
> +			head_block = next_log_block;
> +			next_commit_ID++;
> +			continue;
> +
> +		case JFS_REVOKE_BLOCK:
> +			continue;
> +
> +		default:
> +			dbg_printf("Unrecognised magic %d, end of scan.\n",
> +				  blocktype);
> +			err = -EINVAL;
> +			goto err;
> +		}
> +	}
> +
> +err:
> +	if (err == 0) {
> +		dbg_printf("head seq=%d blk=%llu\n", next_commit_ID,
> +			   head_block);
> +		journal->j_transaction_sequence = next_commit_ID;
> +		journal->j_head = head_block;
> +	}
> +	brelse(bh);
> +	return err;
> +}
> +
> +static void update_journal_csum(journal_t *journal, int ver)
> +{
> +	journal_superblock_t *jsb;
> +
> +	if (journal->j_format_version < 2)
> +		return;
> +
> +	if (journal->j_tail != 0 ||
> +	    EXT2_HAS_INCOMPAT_FEATURE(journal->j_inode->i_fs->super,
> +				      EXT3_FEATURE_INCOMPAT_RECOVER)) {
> +		printf("Journal needs recovery, will not add csums.\n");
> +		return;
> +	}
> +
> +	/* metadata_csum implies journal csum v3 */
> +	jsb = journal->j_superblock;
> +	if (EXT2_HAS_RO_COMPAT_FEATURE(journal->j_inode->i_fs->super,
> +				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
> +		printf("Setting csum v%d\n", ver);
> +		switch (ver) {
> +		case 2:
> +			journal->j_superblock->s_feature_incompat &=
> +				ext2fs_cpu_to_be32(~JFS_FEATURE_INCOMPAT_CSUM_V3);
> +			journal->j_superblock->s_feature_incompat |=
> +				ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V2);
> +			journal->j_superblock->s_feature_compat &=
> +				ext2fs_cpu_to_be32(~JFS_FEATURE_COMPAT_CHECKSUM);
> +			break;
> +		case 3:
> +			journal->j_superblock->s_feature_incompat &=
> +				ext2fs_cpu_to_be32(~JFS_FEATURE_INCOMPAT_CSUM_V2);
> +			journal->j_superblock->s_feature_incompat |=
> +				ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V3);
> +			journal->j_superblock->s_feature_compat &=
> +				ext2fs_cpu_to_be32(~JFS_FEATURE_COMPAT_CHECKSUM);
> +			break;
> +		default:
> +			printf("Unknown checksum v%d\n", ver);
> +			break;
> +		}
> +		journal->j_superblock->s_checksum_type = JBD2_CRC32C_CHKSUM;
> +		journal->j_csum_seed = jbd2_chksum(journal, ~0, jsb->s_uuid,
> +						   sizeof(jsb->s_uuid));
> +	} else {
> +		journal->j_superblock->s_feature_compat |=
> +			ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_CHECKSUM);
> +		journal->j_superblock->s_feature_incompat &=
> +			ext2fs_cpu_to_be32(~(JFS_FEATURE_INCOMPAT_CSUM_V2 |
> +					     JFS_FEATURE_INCOMPAT_CSUM_V3));
> +	}
> +}
> +
> +static void update_uuid(journal_t *journal)
> +{
> +	size_t z;
> +	ext2_filsys fs;
> +
> +	if (journal->j_format_version < 2)
> +		return;
> +
> +	for (z = 0; z < sizeof(journal->j_superblock->s_uuid); z++)
> +		if (journal->j_superblock->s_uuid[z])
> +			break;
> +	if (z == 0)
> +		return;
> +
> +	fs = journal->j_inode->i_fs;
> +	if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super,
> +				       EXT4_FEATURE_INCOMPAT_64BIT))
> +		return;
> +
> +	if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT) &&
> +	    EXT2_HAS_INCOMPAT_FEATURE(fs->super,
> +				      EXT4_FEATURE_INCOMPAT_64BIT))
> +		return;
> +
> +	if (journal->j_tail != 0 ||
> +	    EXT2_HAS_INCOMPAT_FEATURE(fs->super,
> +				      EXT3_FEATURE_INCOMPAT_RECOVER)) {
> +		printf("Journal needs recovery, will not set 64bit.\n");
> +		return;
> +	}
> +
> +	memcpy(journal->j_superblock->s_uuid, fs->super->s_uuid,
> +	       sizeof(fs->super->s_uuid));
> +}
> +
> +static void update_64bit_flag(journal_t *journal)
> +{
> +	if (journal->j_format_version < 2)
> +		return;
> +
> +	if (!EXT2_HAS_INCOMPAT_FEATURE(journal->j_inode->i_fs->super,
> +				       EXT4_FEATURE_INCOMPAT_64BIT))
> +		return;
> +
> +	if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT) &&
> +	    EXT2_HAS_INCOMPAT_FEATURE(journal->j_inode->i_fs->super,
> +				      EXT4_FEATURE_INCOMPAT_64BIT))
> +		return;
> +
> +	if (journal->j_tail != 0 ||
> +	    EXT2_HAS_INCOMPAT_FEATURE(journal->j_inode->i_fs->super,
> +				      EXT3_FEATURE_INCOMPAT_RECOVER)) {
> +		printf("Journal needs recovery, will not set 64bit.\n");
> +		return;
> +	}
> +
> +	journal->j_superblock->s_feature_incompat |=
> +				ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_64BIT);
> +}
> +
> +void do_journal_open(int argc, char *argv[])
> +{
> +	int opt, enable_csum = 0, csum_ver = 3;
> +	journal_t *journal;
> +	errcode_t err;
> +
> +	if (check_fs_open(argv[0]))
> +		return;
> +	if (check_fs_read_write(argv[0]))
> +		return;
> +	if (check_fs_bitmaps(argv[0]))
> +		return;
> +	if (current_journal) {
> +		printf("Journal is already open.\n");
> +		return;
> +	}
> +	if (!EXT2_HAS_COMPAT_FEATURE(current_fs->super,
> +				     EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
> +		printf("Journalling is not enabled on this filesystem.\n");
> +		return;
> +	}
> +
> +	reset_getopt();
> +	while ((opt = getopt(argc, argv, "cv:")) != -1) {
> +		switch (opt) {
> +		case 'c':
> +			enable_csum = 1;
> +			break;
> +		case 'v':
> +			csum_ver = atoi(optarg);
> +			if (csum_ver != 2 && csum_ver != 3) {
> +				printf("Unknown journal csum v%d\n", csum_ver);
> +				csum_ver = 3;
> +			}
> +			break;
> +		default:
> +			printf("%s: [-c] [-v ver]\n", argv[0]);
> +			printf("-c: Enable journal checksumming.\n");
> +			printf("-v: Use this version checksum format.\n");
> +		}
> +	}
> +
> +	err = ext2fs_open_journal(current_fs, &current_journal);
> +	if (err) {
> +		com_err(argv[0], err, "while opening journal");
> +		return;
> +	}
> +	journal = current_journal;
> +
> +	dbg_printf("JOURNAL: seq=%d tailseq=%d start=%lu first=%lu maxlen=%lu\n",
> +		   journal->j_tail_sequence, journal->j_transaction_sequence,
> +		   journal->j_tail, journal->j_first, journal->j_last);
> +
> +	update_uuid(journal);
> +	update_64bit_flag(journal);
> +	if (enable_csum)
> +		update_journal_csum(journal, csum_ver);
> +
> +	err = journal_find_head(journal);
> +	if (err)
> +		com_err(argv[0], err, "while examining journal");
> +}
> +
> +void do_journal_close(int argc, char *argv[])
> +{
> +	if (current_journal == NULL) {
> +		printf("Journal not open.\n");
> +		return;
> +	}
> +
> +	ext2fs_close_journal(current_fs, &current_journal);
> +}
> +
> +void do_journal_run(int argc, char *argv[])
> +{
> +	errcode_t err;
> +
> +	if (check_fs_open(argv[0]))
> +		return;
> +	if (check_fs_read_write(argv[0]))
> +		return;
> +	if (check_fs_bitmaps(argv[0]))
> +		return;
> +	if (current_journal) {
> +		printf("Please close the journal before recovering it.\n");
> +		return;
> +	}
> +
> +	err = ext2fs_run_ext3_journal(&current_fs);
> +	if (err)
> +		com_err("journal_run", err, "while recovering journal");
> +}
> diff --git a/debugfs/util.c b/debugfs/util.c
> index 6c48fba..470f5fb 100644
> --- a/debugfs/util.c
> +++ b/debugfs/util.c
> @@ -497,3 +497,38 @@ int ext2_file_type(unsigned int mode)
>  
>  	return 0;
>  }
> +
> +errcode_t read_list(const char *str, blk64_t **list, size_t *len)
> +{
> +	blk64_t *lst = *list;
> +	size_t ln = *len;
> +	char *tok, *p = optarg;
> +	while ((tok = strtok(p, ","))) {
> +		blk64_t *l;
> +		blk64_t x, y;
> +		char *e;
> +
> +		errno = 0;
> +		y = x = strtoull(tok, &e, 0);
> +		if (errno)
> +			return errno;
> +		if (*e == '-') {
> +			y = strtoull(e + 1, NULL, 0);
> +			if (errno)
> +				return errno;
> +		} else if (*e != 0)
> +			return EINVAL;
> +
> +		l = realloc(lst, sizeof(blk64_t) * (ln + y - x + 1));
> +		if (l == NULL)
> +			return ENOMEM;
> +		lst = l;
> +		for (; x <= y; x++)
> +			lst[ln++] = x;
> +		p = NULL;
> +	}
> +
> +	*list = lst;
> +	*len = ln;
> +	return 0;
> +}
> diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
> index 058eb64..6597e2d 100644
> --- a/lib/ext2fs/Makefile.in
> +++ b/lib/ext2fs/Makefile.in
> @@ -20,7 +20,7 @@ DEBUG_OBJS= debug_cmds.o extent_cmds.o tst_cmds.o debugfs.o util.o \
>  	ncheck.o icheck.o ls.o lsdel.o dump.o set_fields.o logdump.o \
>  	htree.o unused.o e2freefrag.o filefrag.o extent_inode.o zap.o \
>  	xattrs.o quota.o tst_libext2fs.o create_inode.o journal.o \
> -	revoke.o recovery.o
> +	revoke.o recovery.o do_journal.o
>  
>  DEBUG_SRCS= debug_cmds.c extent_cmds.c tst_cmds.c \
>  	$(top_srcdir)/debugfs/debugfs.c \
> @@ -43,7 +43,8 @@ DEBUG_SRCS= debug_cmds.c extent_cmds.c tst_cmds.c \
>  	$(top_srcdir)/misc/create_inode.c \
>  	$(top_srcdir)/debugfs/journal.c \
>  	$(top_srcdir)/debugfs/revoke.c \
> -	$(top_srcdir)/debugfs/recovery.c
> +	$(top_srcdir)/debugfs/recovery.c \
> +	$(top_srcdir)/debugfs/do_journal.c
>  
>  OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \
>  	$(TEST_IO_LIB_OBJS) \
> @@ -407,6 +408,10 @@ recovery.o: $(top_srcdir)/debugfs/recovery.c
>  	$(E) "	CC $<"
>  	$(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@
>  
> +do_journal.o: $(top_srcdir)/debugfs/do_journal.c
> +	$(E) "	CC $<"
> +	$(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@
> +
>  xattrs.o: $(top_srcdir)/debugfs/xattrs.c
>  	$(E) "	CC $<"
>  	$(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@...r.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ