Ejemplo n.º 1
0
/**
 *  journal_t * journal_init_inode () - creates a journal which maps to a inode.
 *  @inode: An inode to create the journal in
 *
 * journal_init_inode creates a journal which maps an on-disk inode as
 * the journal.  The inode must exist already, must support bmap() and
 * must have all data blocks preallocated.
 */
journal_t * journal_init_inode (struct inode *inode)
{
    struct buffer_head *bh;
    journal_t *journal = journal_init_common();
    int err;
    int n;
    unsigned long blocknr;

    if (!journal)
        return NULL;

    journal->j_dev = journal->j_fs_dev = inode->i_sb->s_bdev;
    journal->j_inode = inode;
    jbd_debug(1,
              "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n",
              journal, inode->i_sb->s_id, inode->i_ino,
              (s64) inode->i_size,
              inode->i_sb->s_blocksize_bits, inode->i_sb->s_blocksize);

    journal->j_maxlen = (unsigned int)(inode->i_size >> inode->i_sb->s_blocksize_bits);
    journal->j_blocksize = inode->i_sb->s_blocksize;

    /* journal descriptor can store up to n blocks -bzzz */
    n = journal->j_blocksize / sizeof(journal_block_tag_t);
    journal->j_wbufsize = n;
    journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
    if (!journal->j_wbuf) {
        printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
               __FUNCTION__);

        J_ASSERT(journal->j_revoke != NULL);
        if (journal->j_revoke)
            journal_destroy_revoke(journal);

        kfree(journal);
        return NULL;
    }

    err = journal_bmap(journal, 0, &blocknr);
    /* If that failed, give up */
    if (err) {
        printk(KERN_ERR "%s: Cannnot locate journal superblock\n",
               __FUNCTION__);

        J_ASSERT(journal->j_revoke != NULL);
        if (journal->j_revoke)
            journal_destroy_revoke(journal);
        J_ASSERT(journal->j_wbuf != NULL);
        kfree(journal->j_wbuf);
        kfree(journal);
        return NULL;
    }

    bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
    J_ASSERT(bh != NULL);
    journal->j_sb_buffer = bh;
    journal->j_superblock = (journal_superblock_t *)bh->b_data;

    return journal;
}
Ejemplo n.º 2
0
static int do_readahead(journal_t *journal, unsigned int start)
{
	int err;
	unsigned int max, nbufs, next;
	unsigned long blocknr;
	struct buffer_head *bh;

	struct buffer_head * bufs[MAXBUF];

	/* Do up to 128K of readahead */
	max = start + (128 * 1024 / journal->j_blocksize);
	if (max > journal->j_maxlen)
		max = journal->j_maxlen;

	/* 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++) {
		err = journal_bmap(journal, next, &blocknr);

		if (err) {
			printk (KERN_ERR "JBD: bad block at offset %u\n",
				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) {
				ll_rw_block(READ, nbufs, bufs);
				journal_brelse_array(bufs, nbufs);
				nbufs = 0;
			}
		} else
			brelse(bh);
	}

	if (nbufs)
		ll_rw_block(READ, nbufs, bufs);
	err = 0;

failed:
	if (nbufs) 
		journal_brelse_array(bufs, nbufs);
	return err;
}
Ejemplo n.º 3
0
int journal_next_log_block(journal_t *journal, unsigned long *retp)
{
    unsigned long blocknr;

    jbd_lock(&journal->j_state_lock);
    J_ASSERT(journal->j_free > 1);

    blocknr = journal->j_head;
    journal->j_head++;
    journal->j_free--;
    if (journal->j_head == journal->j_last)
        journal->j_head = journal->j_first;
    jbd_unlock(&journal->j_state_lock);
    return journal_bmap(journal, blocknr, retp);
}
Ejemplo n.º 4
0
static int jread(struct buffer_head **bhp, journal_t *journal, 
		 unsigned int offset)
{
	int err;
	unsigned long blocknr;
	struct buffer_head *bh;

	*bhp = NULL;

	if (offset >= journal->j_maxlen) {
		printk(KERN_ERR "JBD: corrupted journal superblock\n");
		return -EIO;
	}

	err = journal_bmap(journal, offset, &blocknr);

	if (err) {
		printk (KERN_ERR "JBD: bad block at offset %u\n",
			offset);
		return err;
	}

	bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
	if (!bh)
		return -ENOMEM;

	if (!buffer_uptodate(bh)) {
		/* If this is a brand new buffer, start readahead.
                   Otherwise, we assume we are already reading it.  */
		if (!buffer_req(bh))
			do_readahead(journal, offset);
		wait_on_buffer(bh);
	}

	if (!buffer_uptodate(bh)) {
		printk (KERN_ERR "JBD: Failed to read block at offset %u\n",
			offset);
		brelse(bh);
		return -EIO;
	}

	*bhp = bh;
	return 0;
}
Ejemplo n.º 5
0
static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
{
	struct ext2_super_block *sb = ctx->fs->super;
	struct ext2_super_block jsuper;
	struct problem_context	pctx;
	struct buffer_head 	*bh;
	struct inode		*j_inode = NULL;
	struct kdev_s		*dev_fs = NULL, *dev_journal;
	const char		*journal_name = 0;
	journal_t		*journal = NULL;
	errcode_t		retval = 0;
	io_manager		io_ptr = 0;
	unsigned long		start = 0;
	blk_t			blk;
	int			ext_journal = 0;
	int			tried_backup_jnl = 0;
	int			i;
		
	clear_problem_context(&pctx);
	
	journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal");
	if (!journal) {
		return EXT2_ET_NO_MEMORY;
	}

	dev_fs = e2fsck_allocate_memory(ctx, 2*sizeof(struct kdev_s), "kdev");
	if (!dev_fs) {
		retval = EXT2_ET_NO_MEMORY;
		goto errout;
	}
	dev_journal = dev_fs+1;
	
	dev_fs->k_ctx = dev_journal->k_ctx = ctx;
	dev_fs->k_dev = K_DEV_FS;
	dev_journal->k_dev = K_DEV_JOURNAL;
	
	journal->j_dev = dev_journal;
	journal->j_fs_dev = dev_fs;
	journal->j_inode = NULL;
	journal->j_blocksize = ctx->fs->blocksize;

	if (uuid_is_null(sb->s_journal_uuid)) {
		if (!sb->s_journal_inum)
			return EXT2_ET_BAD_INODE_NUM;
		j_inode = e2fsck_allocate_memory(ctx, sizeof(*j_inode),
						 "journal inode");
		if (!j_inode) {
			retval = EXT2_ET_NO_MEMORY;
			goto errout;
		}

		j_inode->i_ctx = ctx;
		j_inode->i_ino = sb->s_journal_inum;
		
		if ((retval = ext2fs_read_inode(ctx->fs,
						sb->s_journal_inum,
						&j_inode->i_ext2))) {
		try_backup_journal:
			if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS ||
			    tried_backup_jnl)
				goto errout;
			memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode));
			memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks, 
			       EXT2_N_BLOCKS*4);
			j_inode->i_ext2.i_size = sb->s_jnl_blocks[16];
			j_inode->i_ext2.i_links_count = 1;
			j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600;
			tried_backup_jnl++;
		}
		if (!j_inode->i_ext2.i_links_count ||
		    !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) {
			retval = EXT2_ET_NO_JOURNAL;
			goto try_backup_journal;
		}
		if (j_inode->i_ext2.i_size / journal->j_blocksize <
		    JFS_MIN_JOURNAL_BLOCKS) {
			retval = EXT2_ET_JOURNAL_TOO_SMALL;
			goto try_backup_journal;
		}
		for (i=0; i < EXT2_N_BLOCKS; i++) {
			blk = j_inode->i_ext2.i_block[i];
			if (!blk) {
				if (i < EXT2_NDIR_BLOCKS) {
					retval = EXT2_ET_JOURNAL_TOO_SMALL;
					goto try_backup_journal;
				}
				continue;
			}
			if (blk < sb->s_first_data_block ||
			    blk >= sb->s_blocks_count) {
				retval = EXT2_ET_BAD_BLOCK_NUM;
				goto try_backup_journal;
			}
		}
		journal->j_maxlen = j_inode->i_ext2.i_size / journal->j_blocksize;

#ifdef USE_INODE_IO
		retval = ext2fs_inode_io_intern2(ctx->fs, sb->s_journal_inum,
						 &j_inode->i_ext2,
						 &journal_name);
		if (retval)
			goto errout;

		io_ptr = inode_io_manager;
#else
		journal->j_inode = j_inode;
		ctx->journal_io = ctx->fs->io;
		if ((retval = journal_bmap(journal, 0, &start)) != 0)
			goto errout;
#endif
	} else {
		ext_journal = 1;
		if (!ctx->journal_name) {
			char uuid[37];

			uuid_unparse(sb->s_journal_uuid, uuid);
			ctx->journal_name = blkid_get_devname(ctx->blkid,
							      "UUID", uuid);
			if (!ctx->journal_name)
				ctx->journal_name = blkid_devno_to_devname(sb->s_journal_dev);
		}
		journal_name = ctx->journal_name;
			
		if (!journal_name) {
			fix_problem(ctx, PR_0_CANT_FIND_JOURNAL, &pctx);
			return EXT2_ET_LOAD_EXT_JOURNAL;
		}
		
		jfs_debug(1, "Using journal file %s\n", journal_name);
		io_ptr = unix_io_manager;
	}

#if 0
	test_io_backing_manager = io_ptr;
	io_ptr = test_io_manager;
#endif
#ifndef USE_INODE_IO
	if (ext_journal)
#endif
		retval = io_ptr->open(journal_name, IO_FLAG_RW,
				      &ctx->journal_io);
	if (retval)
		goto errout;

	io_channel_set_blksize(ctx->journal_io, ctx->fs->blocksize);

	if (ext_journal) {
		if (ctx->fs->blocksize == 1024)
			start = 1;
		bh = getblk(dev_journal, start, ctx->fs->blocksize);
		if (!bh) {
			retval = EXT2_ET_NO_MEMORY;
			goto errout;
		}
		ll_rw_block(READ, 1, &bh);
		if ((retval = bh->b_err) != 0) {
			brelse(bh);
			goto errout;
		}
		memcpy(&jsuper, start ? bh->b_data :  bh->b_data + 1024,
		       sizeof(jsuper));
		brelse(bh);
#ifdef EXT2FS_ENABLE_SWAPFS
		if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) 
			ext2fs_swap_super(&jsuper);
#endif
		if (jsuper.s_magic != EXT2_SUPER_MAGIC ||
		    !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
			fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx);
			retval = EXT2_ET_LOAD_EXT_JOURNAL;
			goto errout;
		}
		/* Make sure the journal UUID is correct */
		if (memcmp(jsuper.s_uuid, ctx->fs->super->s_journal_uuid,
			   sizeof(jsuper.s_uuid))) {
			fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx);
			retval = EXT2_ET_LOAD_EXT_JOURNAL;
			goto errout;
		}
		
		journal->j_maxlen = jsuper.s_blocks_count;
		start++;
	}

	if (!(bh = getblk(dev_journal, start, journal->j_blocksize))) {
		retval = EXT2_ET_NO_MEMORY;
		goto errout;
	}
	
	journal->j_sb_buffer = bh;
	journal->j_superblock = (journal_superblock_t *)bh->b_data;
	
#ifdef USE_INODE_IO
	if (j_inode)
		ext2fs_free_mem(&j_inode);
#endif

	*ret_journal = journal;
	return 0;

errout:
	if (dev_fs)
		ext2fs_free_mem(&dev_fs);
	if (j_inode)
		ext2fs_free_mem(&j_inode);
	if (journal)
		ext2fs_free_mem(&journal);
	return retval;
	
}
Ejemplo n.º 6
0
static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
{
	struct process_block_struct pb;
	struct ext2_super_block *sb = ctx->fs->super;
	struct ext2_super_block jsuper;
	struct problem_context	pctx;
	struct buffer_head 	*bh;
	struct inode		*j_inode = NULL;
	struct kdev_s		*dev_fs = NULL, *dev_journal;
	const char		*journal_name = 0;
	journal_t		*journal = NULL;
	errcode_t		retval = 0;
	io_manager		io_ptr = 0;
	unsigned long long	start = 0;
	int			ext_journal = 0;
	int			tried_backup_jnl = 0;

	clear_problem_context(&pctx);

	journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal");
	if (!journal) {
		return EXT2_ET_NO_MEMORY;
	}

	dev_fs = e2fsck_allocate_memory(ctx, 2*sizeof(struct kdev_s), "kdev");
	if (!dev_fs) {
		retval = EXT2_ET_NO_MEMORY;
		goto errout;
	}
	dev_journal = dev_fs+1;

	dev_fs->k_ctx = dev_journal->k_ctx = ctx;
	dev_fs->k_dev = K_DEV_FS;
	dev_journal->k_dev = K_DEV_JOURNAL;

	journal->j_dev = dev_journal;
	journal->j_fs_dev = dev_fs;
	journal->j_inode = NULL;
	journal->j_blocksize = ctx->fs->blocksize;

	if (uuid_is_null(sb->s_journal_uuid)) {
		if (!sb->s_journal_inum) {
			retval = EXT2_ET_BAD_INODE_NUM;
			goto errout;
		}
		j_inode = e2fsck_allocate_memory(ctx, sizeof(*j_inode),
						 "journal inode");
		if (!j_inode) {
			retval = EXT2_ET_NO_MEMORY;
			goto errout;
		}

		j_inode->i_ctx = ctx;
		j_inode->i_ino = sb->s_journal_inum;

		if ((retval = ext2fs_read_inode(ctx->fs,
						sb->s_journal_inum,
						&j_inode->i_ext2))) {
		try_backup_journal:
			if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS ||
			    tried_backup_jnl)
				goto errout;
			memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode));
			memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks,
			       EXT2_N_BLOCKS*4);
			j_inode->i_ext2.i_size_high = sb->s_jnl_blocks[15];
			j_inode->i_ext2.i_size = sb->s_jnl_blocks[16];
			j_inode->i_ext2.i_links_count = 1;
			j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600;
			e2fsck_use_inode_shortcuts(ctx, 1);
			ctx->stashed_ino = j_inode->i_ino;
			ctx->stashed_inode = &j_inode->i_ext2;
			tried_backup_jnl++;
		}
		if (!j_inode->i_ext2.i_links_count ||
		    !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) {
			retval = EXT2_ET_NO_JOURNAL;
			goto try_backup_journal;
		}
		if (EXT2_I_SIZE(&j_inode->i_ext2) / journal->j_blocksize <
		    JFS_MIN_JOURNAL_BLOCKS) {
			retval = EXT2_ET_JOURNAL_TOO_SMALL;
			goto try_backup_journal;
		}
		pb.last_block = -1;
		retval = ext2fs_block_iterate3(ctx->fs, j_inode->i_ino,
					       BLOCK_FLAG_HOLE, 0,
					       process_journal_block, &pb);
		if ((pb.last_block + 1) * ctx->fs->blocksize <
		    (int) EXT2_I_SIZE(&j_inode->i_ext2)) {
			retval = EXT2_ET_JOURNAL_TOO_SMALL;
			goto try_backup_journal;
		}
		if (tried_backup_jnl && !(ctx->options & E2F_OPT_READONLY)) {
			retval = ext2fs_write_inode(ctx->fs, sb->s_journal_inum,
						    &j_inode->i_ext2);
			if (retval)
				goto errout;
		}

		journal->j_maxlen = EXT2_I_SIZE(&j_inode->i_ext2) /
			journal->j_blocksize;

#ifdef USE_INODE_IO
		retval = ext2fs_inode_io_intern2(ctx->fs, sb->s_journal_inum,
						 &j_inode->i_ext2,
						 &journal_name);
		if (retval)
			goto errout;

		io_ptr = inode_io_manager;
#else
		journal->j_inode = j_inode;
		ctx->journal_io = ctx->fs->io;
		if ((retval = (errcode_t) journal_bmap(journal, 0, &start)) != 0)
			goto errout;
#endif
	} else {
		ext_journal = 1;
		if (!ctx->journal_name) {
			char uuid[37];

			uuid_unparse(sb->s_journal_uuid, uuid);
			ctx->journal_name = blkid_get_devname(ctx->blkid,
							      "UUID", uuid);
			if (!ctx->journal_name)
				ctx->journal_name = blkid_devno_to_devname(sb->s_journal_dev);
		}
		journal_name = ctx->journal_name;

		if (!journal_name) {
			fix_problem(ctx, PR_0_CANT_FIND_JOURNAL, &pctx);
			retval = EXT2_ET_LOAD_EXT_JOURNAL;
			goto errout;
		}

		jfs_debug(1, "Using journal file %s\n", journal_name);
		io_ptr = unix_io_manager;
	}

#if 0
	test_io_backing_manager = io_ptr;
	io_ptr = test_io_manager;
#endif
#ifndef USE_INODE_IO
	if (ext_journal)
#endif
	{
		int flags = IO_FLAG_RW;
		if (!(ctx->mount_flags & EXT2_MF_ISROOT &&
		      ctx->mount_flags & EXT2_MF_READONLY))
			flags |= IO_FLAG_EXCLUSIVE;
		if ((ctx->mount_flags & EXT2_MF_READONLY) &&
		    (ctx->options & E2F_OPT_FORCE))
			flags &= ~IO_FLAG_EXCLUSIVE;


		retval = io_ptr->open(journal_name, flags,
				      &ctx->journal_io);
	}
	if (retval)
		goto errout;

	io_channel_set_blksize(ctx->journal_io, ctx->fs->blocksize);

	if (ext_journal) {
		blk64_t maxlen;

		start = ext2fs_journal_sb_start(ctx->fs->blocksize) - 1;
		bh = getblk(dev_journal, start, ctx->fs->blocksize);
		if (!bh) {
			retval = EXT2_ET_NO_MEMORY;
			goto errout;
		}
		ll_rw_block(READ, 1, &bh);
		if ((retval = bh->b_err) != 0) {
			brelse(bh);
			goto errout;
		}
		memcpy(&jsuper, start ? bh->b_data :  bh->b_data + SUPERBLOCK_OFFSET,
		       sizeof(jsuper));
#ifdef WORDS_BIGENDIAN
		if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
			ext2fs_swap_super(&jsuper);
#endif
		if (jsuper.s_magic != EXT2_SUPER_MAGIC ||
		    !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
			fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx);
			retval = EXT2_ET_LOAD_EXT_JOURNAL;
			brelse(bh);
			goto errout;
		}
		/* Make sure the journal UUID is correct */
		if (memcmp(jsuper.s_uuid, ctx->fs->super->s_journal_uuid,
			   sizeof(jsuper.s_uuid))) {
			fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx);
			retval = EXT2_ET_LOAD_EXT_JOURNAL;
			brelse(bh);
			goto errout;
		}

		/* Check the superblock checksum */
		if (jsuper.s_feature_ro_compat &
		    EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) {
			struct struct_ext2_filsys fsx;
			struct ext2_super_block	superx;
			void *p;

			p = start ? bh->b_data : bh->b_data + SUPERBLOCK_OFFSET;
			memcpy(&fsx, ctx->fs, sizeof(fsx));
			memcpy(&superx, ctx->fs->super, sizeof(superx));
			fsx.super = &superx;
			fsx.super->s_feature_ro_compat |=
					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM;
			if (!ext2fs_superblock_csum_verify(&fsx, p) &&
			    fix_problem(ctx, PR_0_EXT_JOURNAL_SUPER_CSUM_INVALID,
					&pctx)) {
				ext2fs_superblock_csum_set(&fsx, p);
				mark_buffer_dirty(bh);
			}
		}
		brelse(bh);

		maxlen = ext2fs_blocks_count(&jsuper);
		journal->j_maxlen = (maxlen < 1ULL << 32) ? maxlen : (1ULL << 32) - 1;
		start++;
	}

	if (!(bh = getblk(dev_journal, start, journal->j_blocksize))) {
		retval = EXT2_ET_NO_MEMORY;
		goto errout;
	}

	journal->j_sb_buffer = bh;
	journal->j_superblock = (journal_superblock_t *)bh->b_data;

#ifdef USE_INODE_IO
	if (j_inode)
		ext2fs_free_mem(&j_inode);
#endif

	*ret_journal = journal;
	e2fsck_use_inode_shortcuts(ctx, 0);
	return 0;

errout:
	e2fsck_use_inode_shortcuts(ctx, 0);
	if (dev_fs)
		ext2fs_free_mem(&dev_fs);
	if (j_inode)
		ext2fs_free_mem(&j_inode);
	if (journal)
		ext2fs_free_mem(&journal);
	return retval;
}
Ejemplo n.º 7
0
static errcode_t ext2fs_get_journal(ext2_filsys fs, journal_t **ret_journal)
{
	struct process_block_struct pb;
	struct ext2_super_block *sb = fs->super;
	struct ext2_super_block jsuper;
	struct buffer_head	*bh;
	struct inode		*j_inode = NULL;
	struct kdev_s		*dev_fs = NULL, *dev_journal;
	const char		*journal_name = 0;
	journal_t		*journal = NULL;
	errcode_t		retval = 0;
	io_manager		io_ptr = 0;
	unsigned long long	start = 0;
	int			ext_journal = 0;
	int			tried_backup_jnl = 0;

	retval = ext2fs_get_memzero(sizeof(journal_t), &journal);
	if (retval)
		return retval;

	retval = ext2fs_get_memzero(2 * sizeof(struct kdev_s), &dev_fs);
	if (retval)
		goto errout;
	dev_journal = dev_fs+1;

	dev_fs->k_fs = dev_journal->k_fs = fs;
	dev_fs->k_dev = K_DEV_FS;
	dev_journal->k_dev = K_DEV_JOURNAL;

	journal->j_dev = dev_journal;
	journal->j_fs_dev = dev_fs;
	journal->j_inode = NULL;
	journal->j_blocksize = fs->blocksize;

	if (uuid_is_null(sb->s_journal_uuid)) {
		if (!sb->s_journal_inum) {
			retval = EXT2_ET_BAD_INODE_NUM;
			goto errout;
		}
		retval = ext2fs_get_memzero(sizeof(*j_inode), &j_inode);
		if (retval)
			goto errout;

		j_inode->i_fs = fs;
		j_inode->i_ino = sb->s_journal_inum;

		retval = ext2fs_read_inode(fs, sb->s_journal_inum,
					   &j_inode->i_ext2);
		if (retval) {
try_backup_journal:
			if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS ||
			    tried_backup_jnl)
				goto errout;
			memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode));
			memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks,
			       EXT2_N_BLOCKS*4);
			j_inode->i_ext2.i_size_high = sb->s_jnl_blocks[15];
			j_inode->i_ext2.i_size = sb->s_jnl_blocks[16];
			j_inode->i_ext2.i_links_count = 1;
			j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600;
			tried_backup_jnl++;
		}
		if (!j_inode->i_ext2.i_links_count ||
		    !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) {
			retval = EXT2_ET_NO_JOURNAL;
			goto try_backup_journal;
		}
		if (EXT2_I_SIZE(&j_inode->i_ext2) / journal->j_blocksize <
		    JFS_MIN_JOURNAL_BLOCKS) {
			retval = EXT2_ET_JOURNAL_TOO_SMALL;
			goto try_backup_journal;
		}
		pb.last_block = -1;
		retval = ext2fs_block_iterate3(fs, j_inode->i_ino,
					       BLOCK_FLAG_HOLE, 0,
					       process_journal_block, &pb);
		if ((pb.last_block + 1) * fs->blocksize <
		    (int) EXT2_I_SIZE(&j_inode->i_ext2)) {
			retval = EXT2_ET_JOURNAL_TOO_SMALL;
			goto try_backup_journal;
		}
		if (tried_backup_jnl && (fs->flags & EXT2_FLAG_RW)) {
			retval = ext2fs_write_inode(fs, sb->s_journal_inum,
						    &j_inode->i_ext2);
			if (retval)
				goto errout;
		}

		journal->j_maxlen = EXT2_I_SIZE(&j_inode->i_ext2) /
			journal->j_blocksize;

#ifdef USE_INODE_IO
		retval = ext2fs_inode_io_intern2(fs, sb->s_journal_inum,
						 &j_inode->i_ext2,
						 &journal_name);
		if (retval)
			goto errout;

		io_ptr = inode_io_manager;
#else
		journal->j_inode = j_inode;
		fs->journal_io = fs->io;
		retval = (errcode_t)journal_bmap(journal, 0, &start);
		if (retval)
			goto errout;
#endif
	} else {
		ext_journal = 1;
		if (!fs->journal_name) {
			char uuid[37];
			blkid_cache blkid;

			blkid_get_cache(&blkid, NULL);
			uuid_unparse(sb->s_journal_uuid, uuid);
			fs->journal_name = blkid_get_devname(blkid,
							      "UUID", uuid);
			if (!fs->journal_name)
				fs->journal_name = blkid_devno_to_devname(sb->s_journal_dev);
			blkid_put_cache(blkid);
		}
		journal_name = fs->journal_name;

		if (!journal_name) {
			retval = EXT2_ET_LOAD_EXT_JOURNAL;
			goto errout;
		}

		jfs_debug(1, "Using journal file %s\n", journal_name);
		io_ptr = unix_io_manager;
	}

#if 0
	test_io_backing_manager = io_ptr;
	io_ptr = test_io_manager;
#endif
#ifndef USE_INODE_IO
	if (ext_journal)
#endif
	{
		retval = io_ptr->open(journal_name, fs->flags & EXT2_FLAG_RW,
				      &fs->journal_io);
	}
	if (retval)
		goto errout;

	io_channel_set_blksize(fs->journal_io, fs->blocksize);

	if (ext_journal) {
		blk64_t maxlen;

		start = ext2fs_journal_sb_start(fs->blocksize) - 1;
		bh = getblk(dev_journal, start, fs->blocksize);
		if (!bh) {
			retval = EXT2_ET_NO_MEMORY;
			goto errout;
		}
		ll_rw_block(READ, 1, &bh);
		retval = bh->b_err;
		if (retval) {
			brelse(bh);
			goto errout;
		}
		memcpy(&jsuper, start ? bh->b_data :
				bh->b_data + SUPERBLOCK_OFFSET,
		       sizeof(jsuper));
#ifdef WORDS_BIGENDIAN
		if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
			ext2fs_swap_super(&jsuper);
#endif
		if (jsuper.s_magic != EXT2_SUPER_MAGIC ||
		    !ext2fs_has_feature_journal_dev(&jsuper)) {
			retval = EXT2_ET_LOAD_EXT_JOURNAL;
			brelse(bh);
			goto errout;
		}
		/* Make sure the journal UUID is correct */
		if (memcmp(jsuper.s_uuid, fs->super->s_journal_uuid,
			   sizeof(jsuper.s_uuid))) {
			retval = EXT2_ET_LOAD_EXT_JOURNAL;
			brelse(bh);
			goto errout;
		}

		/* Check the superblock checksum */
		if (ext2fs_has_feature_metadata_csum(&jsuper)) {
			struct struct_ext2_filsys fsx;
			struct ext2_super_block	superx;
			void *p;

			p = start ? bh->b_data : bh->b_data + SUPERBLOCK_OFFSET;
			memcpy(&fsx, fs, sizeof(fsx));
			memcpy(&superx, fs->super, sizeof(superx));
			fsx.super = &superx;
			ext2fs_set_feature_metadata_csum(fsx.super);
			if (!ext2fs_superblock_csum_verify(&fsx, p)) {
				retval = EXT2_ET_LOAD_EXT_JOURNAL;
				brelse(bh);
				goto errout;
			}
		}
		brelse(bh);

		maxlen = ext2fs_blocks_count(&jsuper);
		journal->j_maxlen = (maxlen < 1ULL << 32) ? maxlen :
				    (1ULL << 32) - 1;
		start++;
	}

	bh = getblk(dev_journal, start, journal->j_blocksize);
	if (!bh) {
		retval = EXT2_ET_NO_MEMORY;
		goto errout;
	}

	journal->j_sb_buffer = bh;
	journal->j_superblock = (journal_superblock_t *)bh->b_data;

#ifdef USE_INODE_IO
	if (j_inode)
		ext2fs_free_mem(&j_inode);
#endif

	*ret_journal = journal;
	return 0;

errout:
	if (dev_fs)
		ext2fs_free_mem(&dev_fs);
	if (j_inode)
		ext2fs_free_mem(&j_inode);
	if (journal)
		ext2fs_free_mem(&journal);
	return retval;
}
Ejemplo n.º 8
0
static errcode_t journal_commit_trans(journal_transaction_t *trans)
{
	struct buffer_head *bh, *cbh = NULL;
	struct commit_header *commit;
#ifdef HAVE_SYS_TIME_H
	struct timeval tv;
#endif
	errcode_t err;

	JOURNAL_CHECK_TRANS_MAGIC(trans);

	if ((trans->flags & J_TRANS_COMMITTED) ||
	    !(trans->flags & J_TRANS_OPEN))
		return EXT2_ET_INVALID_ARGUMENT;

	bh = getblk(trans->journal->j_dev, 0, trans->journal->j_blocksize);
	if (bh == NULL)
		return ENOMEM;

	/* write the descriptor block header */
	commit = (struct commit_header *)bh->b_data;
	commit->h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER);
	commit->h_blocktype = ext2fs_cpu_to_be32(JFS_COMMIT_BLOCK);
	commit->h_sequence = ext2fs_cpu_to_be32(trans->tid);
	if (JFS_HAS_COMPAT_FEATURE(trans->journal,
				   JFS_FEATURE_COMPAT_CHECKSUM)) {
		__u32 csum_v1 = ~0;
		blk64_t cblk;

		cbh = getblk(trans->journal->j_dev, 0,
			     trans->journal->j_blocksize);
		if (cbh == NULL) {
			err = ENOMEM;
			goto error;
		}

		for (cblk = trans->start; cblk < trans->block; cblk++) {
			err = journal_bmap(trans->journal, cblk,
					   &cbh->b_blocknr);
			if (err)
				goto error;
			mark_buffer_uptodate(cbh, 0);
			ll_rw_block(READ, 1, &cbh);
			err = cbh->b_err;
			if (err)
				goto error;
			csum_v1 = ext2fs_crc32_be(csum_v1,
					(unsigned char const *)cbh->b_data,
					cbh->b_size);
		}

		commit->h_chksum_type = JFS_CRC32_CHKSUM;
		commit->h_chksum_size = JFS_CRC32_CHKSUM_SIZE;
		commit->h_chksum[0] = ext2fs_cpu_to_be32(csum_v1);
	} else {
		commit->h_chksum_type = 0;
		commit->h_chksum_size = 0;
		commit->h_chksum[0] = 0;
	}
#ifdef HAVE_SYS_TIME_H
	gettimeofday(&tv, NULL);
	commit->h_commit_sec = ext2fs_cpu_to_be32(tv.tv_sec);
	commit->h_commit_nsec = ext2fs_cpu_to_be32(tv.tv_usec * 1000);
#else
	commit->h_commit_sec = 0;
	commit->h_commit_nsec = 0;
#endif

	/* Write block */
	jbd2_commit_block_csum_set(trans->journal, bh);
	err = journal_bmap(trans->journal, trans->block, &bh->b_blocknr);
	if (err)
		goto error;

	dbg_printf("Writing commit block at %llu:%llu\n", trans->block,
		   bh->b_blocknr);
	mark_buffer_dirty(bh);
	ll_rw_block(WRITE, 1, &bh);
	err = bh->b_err;
	if (err)
		goto error;
	trans->flags |= J_TRANS_COMMITTED;
	trans->flags &= ~J_TRANS_OPEN;
	trans->block++;

	trans->fs->super->s_feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER;
	ext2fs_mark_super_dirty(trans->fs);
error:
	if (cbh)
		brelse(cbh);
	brelse(bh);
	return err;
}
Ejemplo n.º 9
0
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;
}
Ejemplo n.º 10
0
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_fs_dev->k_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;
}
Ejemplo n.º 11
0
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 sz, 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);

	if (JFS_HAS_INCOMPAT_FEATURE(trans->journal,
				     JFS_FEATURE_INCOMPAT_64BIT))
		sz = 8;
	else
		sz = 4;

	for (i = 0; i < revoke_len; i++) {
		/* Block full, write to journal */
		if (offset + sz > 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_fs_dev->k_fs->super)) {
			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]);
		else
			*((__u32 *)(&((char *)buf)[offset])) =
				ext2fs_cpu_to_be32(revoke_list[i]);
		offset += sz;
	}

	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;
}