mirror of
https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git
synced 2025-01-22 16:33:37 +08:00
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 <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
This commit is contained in:
parent
c860850441
commit
b626b39a8c
210
misc/mke2fs.c
210
misc/mke2fs.c
@ -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,
|
||||
|
@ -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]
|
||||
|
Loading…
Reference in New Issue
Block a user