diff options
author | Ken Sumrall <ksumrall@android.com> | 2011-06-22 16:50:24 -0700 |
---|---|---|
committer | Ken Sumrall <ksumrall@android.com> | 2011-06-22 18:24:24 -0700 |
commit | 97fc910ce0e05862888fd1d9e1938feba40f7539 (patch) | |
tree | 49bc594b662f2b44e6f2dc14db8d5bedc68e4c58 | |
parent | 671cd2188e2f224aaeac4955785199f228235719 (diff) | |
download | extras-97fc910ce0e05862888fd1d9e1938feba40f7539.tar.gz |
Fixes for ext4fixup.
Add check for filesystem that needs the journal run
Fix check for a cleanly unmounted filesystem.
Fix computation of new inode number
Fix check in two places for high bit being set on inode num
Only run sanity check pass if filesystem fixup state is unset
(i.e. not partway through the conversion)
Change-Id: Ib5521e7f3c04d32c02d9890644a99378e3a3659e
-rw-r--r-- | ext4_utils/ext4_utils.c | 2 | ||||
-rw-r--r-- | ext4_utils/ext4fixup.c | 40 |
2 files changed, 27 insertions, 15 deletions
diff --git a/ext4_utils/ext4_utils.c b/ext4_utils/ext4_utils.c index f4f04d90..5563acab 100644 --- a/ext4_utils/ext4_utils.c +++ b/ext4_utils/ext4_utils.c @@ -304,7 +304,7 @@ void ext4_parse_sb(struct ext4_super_block *sb) if (sb->s_magic != EXT4_SUPER_MAGIC) error("superblock magic incorrect"); - if (sb->s_state != EXT4_VALID_FS) + if ((sb->s_state & EXT4_VALID_FS) != EXT4_VALID_FS) error("filesystem state not valid"); info.block_size = 1024 << sb->s_log_block_size; diff --git a/ext4_utils/ext4fixup.c b/ext4_utils/ext4fixup.c index 052cac96..cb596371 100644 --- a/ext4_utils/ext4fixup.c +++ b/ext4_utils/ext4fixup.c @@ -56,19 +56,22 @@ #define STATE_UPDATING_INUMS 2 #define STATE_UPDATING_SB 3 +/* global flags */ static int verbose = 0; static int no_write = 0; + static int new_inodes_per_group = 0; + static int no_write_fixup_state = 0; static int compute_new_inum(unsigned int old_inum) { unsigned int group, offset; - group = old_inum / info.inodes_per_group; - offset = old_inum % info.inodes_per_group; + group = (old_inum - 1) / info.inodes_per_group; + offset = (old_inum -1) % info.inodes_per_group; - return (group * new_inodes_per_group) + offset; + return (group * new_inodes_per_group) + offset + 1; } /* Function to read the primary superblock */ @@ -194,6 +197,10 @@ static int read_ext(int fd) ext4_parse_sb(&sb); + if (info.feat_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) { + critical_error("Filesystem needs recovery first, mount and unmount to do that\n"); + } + /* Clear the low bit which is set while this tool is in progress. * If the tool crashes, it will still be set when we restart. * The low bit is set to make the filesystem unmountable while @@ -679,7 +686,7 @@ static int recurse_dir(int fd, struct ext4_inode *inode, char *dirbuf, int dirsi strncpy(name, dirp->name, dirp->name_len); name[dirp->name_len]='\0'; - /* Only recurse on pass 2 if the high bit is set. + /* Only recurse on pass UPDATE_INODE_NUMS if the high bit is set. * Otherwise, this inode entry has already been updated * and we'll do the wrong thing. Also don't recurse on . or .., * and certainly not on non-directories! @@ -691,7 +698,7 @@ static int recurse_dir(int fd, struct ext4_inode *inode, char *dirbuf, int dirsi is_dir = is_entry_dir(fd, dirp, mode); if ( is_dir && (strcmp(name, ".") && strcmp(name, "..")) && ((mode == SANITY_CHECK_PASS) || (mode == MARK_INODE_NUMS) || - ((mode == UPDATE_INODE_NUMS) && (dirp->inode | 0x80000000))) ) { + ((mode == UPDATE_INODE_NUMS) && (dirp->inode & 0x80000000))) ) { /* A directory! Recurse! */ read_inode(fd, dirp->inode & 0x7fffffff, &tmp_inode); @@ -731,7 +738,7 @@ static int recurse_dir(int fd, struct ext4_inode *inode, char *dirbuf, int dirsi if (mode == MARK_INODE_NUMS) { dirp->inode |= 0x80000000; } else if (mode == UPDATE_INODE_NUMS) { - if (dirp->inode | 0x80000000) { + if (dirp->inode & 0x80000000) { dirp->inode = compute_new_inum(dirp->inode & 0x7fffffff); } } @@ -820,15 +827,20 @@ int ext4fixup_internal(char *fsdev, int v_flag, int n_flag) * before we actually change anything, so we don't leave a filesystem in a * corrupted, unrecoverable state. Set no_write, make it quiet, and do a recurse * pass and a update_superblock pass. Set flags back to requested state when done. + * Only perform sanity check if the state is unset. If the state is _NOT_ unset, + * then the tool has already been run and interrupted, and it presumably ran and + * passed sanity checked before it got interrupted. It is _NOT_ safe to run sanity + * check if state is unset because it assumes inodes are to be computed using the + * old inodes/group, but some inode numbers may be updated to the new number. */ - verbose = 0; - no_write = 1; - recurse_dir(fd, &root_inode, dirbuf, dirsize, SANITY_CHECK_PASS); - update_superblocks_and_bg_desc(fd, STATE_UNSET); - verbose = v_flag; - no_write = n_flag; - if (get_fs_fixup_state(fd) == STATE_UNSET) { + verbose = 0; + no_write = 1; + recurse_dir(fd, &root_inode, dirbuf, dirsize, SANITY_CHECK_PASS); + update_superblocks_and_bg_desc(fd, STATE_UNSET); + verbose = v_flag; + no_write = n_flag; + set_fs_fixup_state(fd, STATE_MARKING_INUMS); } @@ -845,7 +857,7 @@ int ext4fixup_internal(char *fsdev, int v_flag, int n_flag) } if (get_fs_fixup_state(fd) == STATE_UPDATING_SB) { - /* set the new inodes/blockgruop number, + /* set the new inodes/blockgroup number, * and sets the state back to 0. */ if (!update_superblocks_and_bg_desc(fd, STATE_UPDATING_SB)) { |