X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lib%2Fext2fs%2Fmkjournal.c;h=838d751c01396a337ff260ade37424159ed25bae;hb=d182831a15dfa4d36979be10fdfd4ec06bdd65b9;hp=3cae874be07af2b7811ce0c671f859f133975eab;hpb=674c0cc4cb137c6362cb1ae71b6db5cbccbad83a;p=tools%2Fe2fsprogs.git diff --git a/lib/ext2fs/mkjournal.c b/lib/ext2fs/mkjournal.c index 3cae874..838d751 100644 --- a/lib/ext2fs/mkjournal.c +++ b/lib/ext2fs/mkjournal.c @@ -2,13 +2,14 @@ * mkjournal.c --- make a journal for a filesystem * * Copyright (C) 2000 Theodore Ts'o. - * + * * %Begin-Header% - * This file may be redistributed under the terms of the GNU Public - * License. + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. * %End-Header% */ +#include "config.h" #include #include #if HAVE_UNISTD_H @@ -42,13 +43,13 @@ * returns it as an allocated block. */ errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, - __u32 size, int flags, + __u32 num_blocks, int flags, char **ret_jsb) { errcode_t retval; journal_superblock_t *jsb; - if (size < 1024) + if (num_blocks < 1024) return EXT2_ET_JOURNAL_TOO_SMALL; if ((retval = ext2fs_get_mem(fs->blocksize, &jsb))) @@ -62,7 +63,7 @@ errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, else jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2); jsb->s_blocksize = htonl(fs->blocksize); - jsb->s_maxlen = htonl(size); + jsb->s_maxlen = htonl(num_blocks); jsb->s_nr_users = htonl(1); jsb->s_first = htonl(1); jsb->s_sequence = htonl(1); @@ -90,20 +91,21 @@ errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, * filesystems. */ static errcode_t write_journal_file(ext2_filsys fs, char *filename, - blk_t size, int flags) + blk_t num_blocks, int flags) { errcode_t retval; char *buf = 0; int fd, ret_size; blk_t i; - if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf))) + if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags, + &buf))) return retval; /* Open the device or journal file */ if ((fd = open(filename, O_WRONLY)) < 0) { retval = errno; - goto errout; + goto errfree; } /* Write the superblock out */ @@ -117,7 +119,10 @@ static errcode_t write_journal_file(ext2_filsys fs, char *filename, goto errout; memset(buf, 0, fs->blocksize); - for (i = 1; i < size; i++) { + if (flags & EXT2_MKJOURNAL_LAZYINIT) + goto success; + + for (i = 1; i < num_blocks; i++) { ret_size = write(fd, buf, fs->blocksize); if (ret_size < 0) { retval = errno; @@ -126,10 +131,12 @@ static errcode_t write_journal_file(ext2_filsys fs, char *filename, if (ret_size != (int) fs->blocksize) goto errout; } - close(fd); +success: retval = 0; errout: + close(fd); +errfree: ext2fs_free_mem(&buf); return retval; } @@ -145,8 +152,8 @@ errout: * programs that check for memory leaks happy.) */ #define STRIDE_LENGTH 8 -errcode_t ext2fs_zero_blocks(ext2_filsys fs, blk_t blk, int num, - blk_t *ret_blk, int *ret_count) +errcode_t ext2fs_zero_blocks2(ext2_filsys fs, blk64_t blk, int num, + blk64_t *ret_blk, int *ret_count) { int j, count; static char *buf; @@ -179,7 +186,7 @@ errcode_t ext2fs_zero_blocks(ext2_filsys fs, blk_t blk, int num, if (count > STRIDE_LENGTH) count = STRIDE_LENGTH; } - retval = io_channel_write_blk(fs->io, blk, count, buf); + retval = io_channel_write_blk64(fs->io, blk, count, buf); if (retval) { if (ret_count) *ret_count = count; @@ -192,56 +199,75 @@ errcode_t ext2fs_zero_blocks(ext2_filsys fs, blk_t blk, int num, return 0; } +errcode_t ext2fs_zero_blocks(ext2_filsys fs, blk_t blk, int num, + blk_t *ret_blk, int *ret_count) +{ + blk64_t ret_blk2; + errcode_t retval; + + retval = ext2fs_zero_blocks2(fs, blk, num, &ret_blk2, ret_count); + if (retval) + *ret_blk = (blk_t) ret_blk2; + return retval; +} + /* * Helper function for creating the journal using direct I/O routines */ struct mkjournal_struct { int num_blocks; int newblocks; - blk_t blk_to_zero; + blk64_t goal; + blk64_t blk_to_zero; int zero_count; + int flags; char *buf; errcode_t err; }; static int mkjournal_proc(ext2_filsys fs, - blk_t *blocknr, - e2_blkcnt_t blockcnt, - blk_t ref_block EXT2FS_ATTR((unused)), - int ref_offset EXT2FS_ATTR((unused)), - void *priv_data) + blk64_t *blocknr, + e2_blkcnt_t blockcnt, + blk64_t ref_block EXT2FS_ATTR((unused)), + int ref_offset EXT2FS_ATTR((unused)), + void *priv_data) { struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data; - blk_t new_blk; - static blk_t last_blk = 0; + blk64_t new_blk; errcode_t retval; - + if (*blocknr) { - last_blk = *blocknr; + es->goal = *blocknr; return 0; } - retval = ext2fs_new_block(fs, last_blk, 0, &new_blk); - if (retval) { - es->err = retval; - return BLOCK_ABORT; + if (blockcnt && + (EXT2FS_B2C(fs, es->goal) == EXT2FS_B2C(fs, es->goal+1))) + new_blk = es->goal+1; + else { + es->goal &= ~EXT2FS_CLUSTER_MASK(fs); + retval = ext2fs_new_block2(fs, es->goal, 0, &new_blk); + if (retval) { + es->err = retval; + return BLOCK_ABORT; + } + es->newblocks++; } if (blockcnt >= 0) es->num_blocks--; - es->newblocks++; retval = 0; if (blockcnt <= 0) - retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf); - else { + retval = io_channel_write_blk64(fs->io, new_blk, 1, es->buf); + else if (!(es->flags & EXT2_MKJOURNAL_LAZYINIT)) { if (es->zero_count) { if ((es->blk_to_zero + es->zero_count == new_blk) && (es->zero_count < 1024)) es->zero_count++; else { - retval = ext2fs_zero_blocks(fs, - es->blk_to_zero, - es->zero_count, - 0, 0); + retval = ext2fs_zero_blocks2(fs, + es->blk_to_zero, + es->zero_count, + 0, 0); es->zero_count = 0; } } @@ -258,31 +284,33 @@ static int mkjournal_proc(ext2_filsys fs, es->err = retval; return BLOCK_ABORT; } - *blocknr = new_blk; - last_blk = new_blk; - ext2fs_block_alloc_stats(fs, new_blk, +1); + *blocknr = es->goal = new_blk; + ext2fs_block_alloc_stats2(fs, new_blk, +1); if (es->num_blocks == 0) return (BLOCK_CHANGED | BLOCK_ABORT); else return BLOCK_CHANGED; - + } /* * This function creates a journal using direct I/O routines. */ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, - blk_t size, int flags) + blk_t num_blocks, int flags) { char *buf; + dgrp_t group, start, end, i, log_flex; errcode_t retval; struct ext2_inode inode; + unsigned long long inode_size; struct mkjournal_struct es; - if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf))) + if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags, + &buf))) return retval; - + if ((retval = ext2fs_read_bitmaps(fs))) return retval; @@ -292,20 +320,55 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, if (inode.i_blocks > 0) return EEXIST; - es.num_blocks = size; + es.num_blocks = num_blocks; es.newblocks = 0; es.buf = buf; es.err = 0; + es.flags = flags; es.zero_count = 0; - retval = ext2fs_block_iterate2(fs, journal_ino, BLOCK_FLAG_APPEND, + if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) { + inode.i_flags |= EXT4_EXTENTS_FL; + if ((retval = ext2fs_write_inode(fs, journal_ino, &inode))) + return retval; + } + + /* + * Set the initial goal block to be roughly at the middle of + * the filesystem. Pick a group that has the largest number + * of free blocks. + */ + group = ext2fs_group_of_blk2(fs, (ext2fs_blocks_count(fs->super) - + fs->super->s_first_data_block) / 2); + log_flex = 1 << fs->super->s_log_groups_per_flex; + if (fs->super->s_log_groups_per_flex && (group > log_flex)) { + group = group & ~(log_flex - 1); + while ((group < fs->group_desc_count) && + ext2fs_bg_free_blocks_count(fs, group) == 0) + group++; + if (group == fs->group_desc_count) + group = 0; + start = group; + } else + start = (group > 0) ? group-1 : group; + end = ((group+1) < fs->group_desc_count) ? group+1 : group; + group = start; + for (i=start+1; i <= end; i++) + if (ext2fs_bg_free_blocks_count(fs, i) > + ext2fs_bg_free_blocks_count(fs, group)) + group = i; + + es.goal = (fs->super->s_blocks_per_group * group) + + fs->super->s_first_data_block; + + retval = ext2fs_block_iterate3(fs, journal_ino, BLOCK_FLAG_APPEND, 0, mkjournal_proc, &es); if (es.err) { retval = es.err; goto errout; } if (es.zero_count) { - retval = ext2fs_zero_blocks(fs, es.blk_to_zero, + retval = ext2fs_zero_blocks2(fs, es.blk_to_zero, es.zero_count, 0, 0); if (retval) goto errout; @@ -314,22 +377,29 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) goto errout; - inode.i_size += fs->blocksize * size; + inode_size = (unsigned long long)fs->blocksize * num_blocks; + inode.i_size = inode_size & 0xFFFFFFFF; + inode.i_size_high = (inode_size >> 32) & 0xFFFFFFFF; + if (inode.i_size_high) + fs->super->s_feature_ro_compat |= + EXT2_FEATURE_RO_COMPAT_LARGE_FILE; ext2fs_iblk_add_blocks(fs, &inode, es.newblocks); inode.i_mtime = inode.i_ctime = fs->now ? fs->now : time(0); inode.i_links_count = 1; inode.i_mode = LINUX_S_IFREG | 0600; - if ((retval = ext2fs_write_inode(fs, journal_ino, &inode))) + if ((retval = ext2fs_write_new_inode(fs, journal_ino, &inode))) goto errout; retval = 0; memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4); + fs->super->s_jnl_blocks[15] = inode.i_size_high; fs->super->s_jnl_blocks[16] = inode.i_size; fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS; ext2fs_mark_super_dirty(fs); errout: + ext2fs_zero_blocks2(0, 0, 0, 0, 0); ext2fs_free_mem(&buf); return retval; } @@ -339,17 +409,17 @@ errout: * in the filesystem. For very small filesystems, it is not reasonable to * have a journal that fills more than half of the filesystem. */ -int ext2fs_default_journal_size(__u64 blocks) +int ext2fs_default_journal_size(__u64 num_blocks) { - if (blocks < 2048) + if (num_blocks < 2048) return -1; - if (blocks < 32768) + if (num_blocks < 32768) return (1024); - if (blocks < 256*1024) + if (num_blocks < 256*1024) return (4096); - if (blocks < 512*1024) + if (num_blocks < 512*1024) return (8192); - if (blocks < 1024*1024) + if (num_blocks < 1024*1024) return (16384); return 32768; } @@ -369,7 +439,7 @@ errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev) /* Make sure the device exists and is a block device */ if (stat(journal_dev->device_name, &st) < 0) return errno; - + if (!S_ISBLK(st.st_mode)) return EXT2_ET_JOURNAL_NOT_BLOCK; /* Must be a block device */ @@ -377,7 +447,8 @@ errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev) start = 1; if (journal_dev->blocksize == 1024) start++; - if ((retval = io_channel_read_blk(journal_dev->io, start, -1024, buf))) + if ((retval = io_channel_read_blk64(journal_dev->io, start, -1024, + buf))) return retval; jsb = (journal_superblock_t *) buf; @@ -402,9 +473,9 @@ errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev) } /* Writeback the journal superblock */ - if ((retval = io_channel_write_blk(journal_dev->io, start, -1024, buf))) + if ((retval = io_channel_write_blk64(journal_dev->io, start, -1024, buf))) return retval; - + fs->super->s_journal_inum = 0; fs->super->s_journal_dev = st.st_rdev; memcpy(fs->super->s_journal_uuid, jsb->s_uuid, @@ -419,7 +490,7 @@ errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev) * POSIX routines if the filesystem is mounted, or using direct I/O * functions if it is not. */ -errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags) +errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks, int flags) { errcode_t retval; ext2_ino_t journal_ino; @@ -436,7 +507,7 @@ errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags) strcat(jfile, "/.journal"); /* - * If .../.journal already exists, make sure any + * If .../.journal already exists, make sure any * immutable or append-only flags are cleared. */ #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP) @@ -456,25 +527,44 @@ errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags) if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0) return errno; - if ((retval = write_journal_file(fs, jfile, size, flags))) + /* Note that we can't do lazy journal initialization for mounted + * filesystems, since the zero writing is also allocating the + * journal blocks. We could use fallocate, but not all kernels + * support that, and creating a journal on a mounted ext2 + * filesystems is extremely rare these days... Ignore it. */ + flags &= ~EXT2_MKJOURNAL_LAZYINIT; + + if ((retval = write_journal_file(fs, jfile, num_blocks, flags))) goto errout; - + /* Get inode number of the journal file */ - if (fstat(fd, &st) < 0) + if (fstat(fd, &st) < 0) { + retval = errno; goto errout; + } #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP) retval = fchflags (fd, UF_NODUMP|UF_IMMUTABLE); #else #if HAVE_EXT2_IOCTLS - f = EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL; + if (ioctl(fd, EXT2_IOC_GETFLAGS, &f) < 0) { + retval = errno; + goto errout; + } + f |= EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL; retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f); #endif #endif - if (retval) + if (retval) { + retval = errno; goto errout; - - close(fd); + } + + if (close(fd) < 0) { + retval = errno; + fd = -1; + goto errout; + } journal_ino = st.st_ino; } else { if ((mount_flags & EXT2_MF_BUSY) && @@ -484,10 +574,10 @@ errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags) } journal_ino = EXT2_JOURNAL_INO; if ((retval = write_journal_inode(fs, journal_ino, - size, flags))) + num_blocks, flags))) return retval; } - + fs->super->s_journal_inum = journal_ino; fs->super->s_journal_dev = 0; memset(fs->super->s_journal_uuid, 0, @@ -507,14 +597,14 @@ main(int argc, char **argv) { errcode_t retval; char *device_name; - ext2_filsys fs; + ext2_filsys fs; if (argc < 2) { fprintf(stderr, "Usage: %s filesystem\n", argv[0]); exit(1); } device_name = argv[1]; - + retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0, unix_io_manager, &fs); if (retval) { @@ -534,6 +624,6 @@ main(int argc, char **argv) } ext2fs_close(fs); exit(0); - + } #endif