From b626b39a8c87dfb6d973b4ad7eca1eefa659d3d6 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Mon, 13 Aug 2007 15:56:26 +0530 Subject: [PATCH] mke2fs: Add support for the undo I/O manager. When running mke2fs, if a file system is detected on the device, we use Undo I/O manager as the io manager. This helps in reverting the changes made to the filesystem in case we wrongly selected the device. Signed-off-by: Aneesh Kumar K.V Signed-off-by: "Theodore Ts'o" --- misc/mke2fs.c | 210 ++++++++++++++++++++++++++++++++------------------ misc/mke2fs.conf.5.in | 16 ++++ 2 files changed, 149 insertions(+), 77 deletions(-) diff --git a/misc/mke2fs.c b/misc/mke2fs.c index 3812f86..ee608cd 100644 --- a/misc/mke2fs.c +++ b/misc/mke2fs.c @@ -44,6 +44,7 @@ extern int optind; #endif #include #include +#include #include "ext2fs/ext2_fs.h" #include "et/com_err.h" @@ -87,6 +88,7 @@ char *volume_label; char *mount_dir; char *journal_device; int sync_kludge; /* Set using the MKE2FS_SYNC env. option */ +char **fs_types; profile_t profile; @@ -339,68 +341,6 @@ static void progress_close(struct progress_struct *progress) fputs(_("done \n"), stdout); } - -/* - * Helper function which zeros out _num_ blocks starting at _blk_. In - * case of an error, the details of the error is returned via _ret_blk_ - * and _ret_count_ if they are non-NULL pointers. Returns 0 on - * success, and an error code on an error. - * - * As a special case, if the first argument is NULL, then it will - * attempt to free the static zeroizing buffer. (This is to keep - * programs that check for memory leaks happy.) - */ -static errcode_t zero_blocks(ext2_filsys fs, blk_t blk, int num, - struct progress_struct *progress, - blk_t *ret_blk, int *ret_count) -{ - int j, count, next_update, next_update_incr; - static char *buf; - errcode_t retval; - - /* If fs is null, clean up the static buffer and return */ - if (!fs) { - if (buf) { - free(buf); - buf = 0; - } - return 0; - } - /* Allocate the zeroizing buffer if necessary */ - if (!buf) { - buf = malloc(fs->blocksize * STRIDE_LENGTH); - if (!buf) { - com_err("malloc", ENOMEM, - _("while allocating zeroizing buffer")); - exit(1); - } - memset(buf, 0, fs->blocksize * STRIDE_LENGTH); - } - /* OK, do the write loop */ - next_update = 0; - next_update_incr = num / 100; - if (next_update_incr < 1) - next_update_incr = 1; - for (j=0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) { - count = num - j; - if (count > STRIDE_LENGTH) - count = STRIDE_LENGTH; - retval = io_channel_write_blk(fs->io, blk, count, buf); - if (retval) { - if (ret_count) - *ret_count = count; - if (ret_blk) - *ret_blk = blk; - return retval; - } - if (progress && j > next_update) { - next_update += num / 100; - progress_update(progress, blk); - } - } - return 0; -} - static void write_inode_tables(ext2_filsys fs, int lazy_flag) { errcode_t retval; @@ -433,7 +373,7 @@ static void write_inode_tables(ext2_filsys fs, int lazy_flag) fs->group_desc[i].bg_flags |= EXT2_BG_INODE_ZEROED; ext2fs_group_desc_csum_set(fs, i); } - retval = zero_blocks(fs, blk, num, 0, &blk, &num); + retval = ext2fs_zero_blocks(fs, blk, num, &blk, &num); if (retval) { fprintf(stderr, _("\nCould not write %d " "blocks in inode table starting at %u: %s\n"), @@ -447,7 +387,7 @@ static void write_inode_tables(ext2_filsys fs, int lazy_flag) sync(); } } - zero_blocks(0, 0, 0, 0, 0, 0); + ext2fs_zero_blocks(0, 0, 0, 0, 0); progress_close(&progress); } @@ -596,8 +536,8 @@ static void create_journal_dev(ext2_filsys fs) struct progress_struct progress; errcode_t retval; char *buf; - blk_t blk; - int count; + blk_t blk, err_blk; + int c, count, err_count; retval = ext2fs_create_journal_superblock(fs, fs->super->s_blocks_count, 0, &buf); @@ -612,15 +552,26 @@ static void create_journal_dev(ext2_filsys fs) progress_init(&progress, _("Zeroing journal device: "), fs->super->s_blocks_count); - retval = zero_blocks(fs, 0, fs->super->s_blocks_count, - &progress, &blk, &count); - if (retval) { - com_err("create_journal_dev", retval, - _("while zeroing journal device (block %u, count %d)"), - blk, count); - exit(1); + blk = 0; + count = fs->super->s_blocks_count; + while (count > 0) { + if (count > 1024) + c = 1024; + else + c = count; + retval = ext2fs_zero_blocks(fs, blk, c, &err_blk, &err_count); + if (retval) { + com_err("create_journal_dev", retval, + _("while zeroing journal device " + "(block %u, count %d)"), + err_blk, err_count); + exit(1); + } + blk += c; + count -= c; + progress_update(&progress, blk); } - zero_blocks(0, 0, 0, 0, 0, 0); + ext2fs_zero_blocks(0, 0, 0, 0, 0); retval = io_channel_write_blk(fs->io, fs->super->s_first_data_block+1, @@ -1109,7 +1060,6 @@ static void PRS(int argc, char *argv[]) char * extended_opts = 0; const char * fs_type = 0; const char * usage_types = 0; - char **fs_types; blk_t dev_size; #ifdef __linux__ struct utsname ut; @@ -1709,6 +1659,102 @@ static void PRS(int argc, char *argv[]) fs_param.s_blocks_count); } +static int should_do_undo(const char *name) +{ + errcode_t retval; + io_channel channel; + __u16 s_magic; + struct ext2_super_block super; + io_manager manager = unix_io_manager; + int csum_flag, force_undo; + + csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(&fs_param, + EXT4_FEATURE_RO_COMPAT_GDT_CSUM); + force_undo = get_int_from_profile(fs_types, "force_undo", 0); + if (!force_undo && (!csum_flag || !lazy_itable_init)) + return 0; + + retval = manager->open(name, IO_FLAG_EXCLUSIVE, &channel); + if (retval) { + /* + * We don't handle error cases instead we + * declare that the file system doesn't exist + * and let the rest of mke2fs take care of + * error + */ + retval = 0; + goto open_err_out; + } + + io_channel_set_blksize(channel, SUPERBLOCK_OFFSET); + retval = io_channel_read_blk(channel, 1, -SUPERBLOCK_SIZE, &super); + if (retval) { + retval = 0; + goto err_out; + } + +#if defined(WORDS_BIGENDIAN) + s_magic = ext2fs_swab16(super.s_magic); +#else + s_magic = super.s_magic; +#endif + + if (s_magic == EXT2_SUPER_MAGIC) + retval = 1; + +err_out: + io_channel_close(channel); + +open_err_out: + + return retval; +} + +static int mke2fs_setup_tdb(const char *name, io_manager *io_ptr) +{ + errcode_t retval = 0; + char *tdb_dir, tdb_file[PATH_MAX]; + char *device_name, *tmp_name; + + /* + * Configuration via a conf file would be + * nice + */ + tdb_dir = getenv("E2FSPROGS_UNDO_DIR"); + if (!tdb_dir) + profile_get_string(profile, "defaults", + "undo_dir", 0, "/var/lib/e2fsprogs", + &tdb_dir); + + if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) || + access(tdb_dir, W_OK)) + return 0; + + tmp_name = strdup(name); + device_name = basename(tmp_name); + sprintf(tdb_file, "%s/mke2fs-%s.e2undo", tdb_dir, device_name); + + if (!access(tdb_file, F_OK)) { + if (unlink(tdb_file) < 0) { + retval = errno; + com_err(program_name, retval, + _("while trying to delete %s"), + tdb_file); + return retval; + } + } + + set_undo_io_backing_manager(*io_ptr); + *io_ptr = undo_io_manager; + set_undo_io_backup_file(tdb_file); + printf(_("Overwriting existing filesystem; this can be undone " + "using the command:\n" + " e2undo %s %s\n\n"), tdb_file, name); +err_out: + free(tmp_name); + return retval; +} + int main (int argc, char *argv[]) { errcode_t retval = 0; @@ -1718,6 +1764,7 @@ int main (int argc, char *argv[]) unsigned int i; int val; io_manager io_ptr; + char tdb_string[40]; #ifdef ENABLE_NLS setlocale(LC_MESSAGES, ""); @@ -1734,6 +1781,12 @@ int main (int argc, char *argv[]) io_ptr = unix_io_manager; #endif + if (should_do_undo(device_name)) { + retval = mke2fs_setup_tdb(device_name, &io_ptr); + if (retval) + exit(1); + } + /* * Initialize the superblock.... */ @@ -1743,6 +1796,9 @@ int main (int argc, char *argv[]) com_err(device_name, retval, _("while setting up superblock")); exit(1); } + sprintf(tdb_string, "tdb_data_size=%d", fs->blocksize <= 4096 ? + 32768 : fs->blocksize * 8); + io_channel_set_options(fs->io, tdb_string); if (fs_param.s_flags & EXT2_FLAGS_TEST_FILESYS) fs->super->s_flags |= EXT2_FLAGS_TEST_FILESYS; @@ -1857,8 +1913,8 @@ int main (int argc, char *argv[]) if (start > rsv) start -= rsv; if (start > 0) - retval = zero_blocks(fs, start, blocks - start, - NULL, &ret_blk, NULL); + retval = ext2fs_zero_blocks(fs, start, blocks - start, + &ret_blk, NULL); if (retval) { com_err(program_name, retval, diff --git a/misc/mke2fs.conf.5.in b/misc/mke2fs.conf.5.in index 6734bf3..06592f2 100644 --- a/misc/mke2fs.conf.5.in +++ b/misc/mke2fs.conf.5.in @@ -107,6 +107,13 @@ command-line option to .BR mke2fs (8). .TP +.I force_undo +This relation, if set to a boolean value of true, forces +.B mke2fs +to always try to create an undo file, even if the undo file might be +huge and it might extend the time to create the filesystem image +because the inode table isn't being initialized lazily. +.TP .I fs_type This relation specifies the default filesystem type if the user does not specify it via the @@ -140,6 +147,15 @@ This relation specifies the default inode size if the user does not specify one on the command line, and the filesystem-type specific section of the configuration file does not specify a default inode size. +.TP +.I undo_dir +This relation specifies the directory where the undo file should be +stored. It can be overriden via the +.B E2FSPROGS_UNDO_DIR +environemnt variable. If the directory location is set to the value +.IR none , +.B mke2fs +will not create an undo file. .SH THE [fs_types] STANZA Each tag in the .I [fs_types] -- 1.8.3.1