Whamcloud - gitweb
mke2fs: Add support for the undo I/O manager.
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Mon, 13 Aug 2007 10:26:26 +0000 (15:56 +0530)
committerTheodore Ts'o <tytso@mit.edu>
Sun, 27 Apr 2008 23:57:52 +0000 (19:57 -0400)
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 <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
misc/mke2fs.c
misc/mke2fs.conf.5.in

index 3812f86..ee608cd 100644 (file)
@@ -44,6 +44,7 @@ extern int optind;
 #endif
 #include <sys/ioctl.h>
 #include <sys/types.h>
+#include <libgen.h>
 
 #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,
index 6734bf3..06592f2 100644 (file)
@@ -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]