EXT3分区表崩溃的解决方法
分区表崩溃,主要是超级块或组块崩溃了。以下红色为修改的部分,主要在错误的时候进行修复分区表,可能还是想的不是周到,需要多次测试。这里只是分区崩溃后的处理方法,最好是可以找到造成分区崩溃的真正原因,以此来避免分区的崩溃。
struct super_block * ext3_read_super (struct super_block * sb, void * data,
int silent)
{
struct buffer_head * bh;
struct ext3_super_block *es = 0;
struct ext3_sb_info *sbi = EXT3_SB(sb);
unsigned long sb_block = 1;
unsigned long logic_sb_block = 1;
unsigned long offset = 0;
unsigned long journal_inum = 0;
kdev_t dev = sb->s_dev;
int blocksize;
int hblock;
int db_count;
int i,j;
int needs_recovery;
struct buffer_head * bh2;
struct buffer_head *bh3; //add mwp
struct buffer_head *temp;
int loop = 0;
#ifdef CONFIG_JBD_DEBUG
ext3_ro_after = 0;
#endif
/*
* See what the current blocksize for the device is, and
* use that as the blocksize. Otherwise (or if the blocksize
* is smaller than the default) use the default.
* This is important for devices that have a hardware
* sectorsize that is larger than the default.
*/
blocksize = EXT3_MIN_BLOCK_SIZE;
hblock = get_hardsect_size(dev);
if (blocksize < hblock)
blocksize = hblock;
//printk("in ext3_read_super/n");
sbi->s_mount_opt = 0;
sbi->s_resuid = EXT3_DEF_RESUID;
sbi->s_resgid = EXT3_DEF_RESGID;
if (!parse_options ((char *) data, &sb_block, sbi, &journal_inum, 0)) {
sb->s_dev = 0;
goto out_fail;
}
//printk("after parse_options/n");
sb->s_blocksize = blocksize;
set_blocksize (dev, blocksize);
//sb->s_flags |= MS_SYNCHRONOUS; //add mwp
/*
* The ext3 superblock will not be buffer aligned for other than 1kB
* block sizes. We need to calculate the offset from buffer start.
*/
if (blocksize != EXT3_MIN_BLOCK_SIZE) {
logic_sb_block = (sb_block * EXT3_MIN_BLOCK_SIZE) / blocksize;
offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize;
}
//printk("super logic block is %d/n,block size is %d,offset is %d",logic_sb_block,sb->s_blocksize,
// offset);
BEGIN:
if (!(bh = sb_bread(sb, logic_sb_block))) {
printk (KERN_ERR "EXT3-fs: unable to read superblock/n");
goto out_fail;
}
/*
* Note: s_es must be initialized as soon as possible because
* some ext3 macro-instructions depend on its value
*/
if(loop >=2)
goto failed_mount;
loop ++;
es = (struct ext3_super_block *) (((char *)bh->b_data) + offset);
sbi->s_es = es;
sb->s_magic = le16_to_cpu(es->s_magic);
if (sb->s_magic != EXT3_SUPER_MAGIC) {
if (!silent)
printk(KERN_ERR
"VFS: Can't find ext3 filesystem on dev %s.current sb->s_magic is %x/n",
bdevname(dev),sb->s_magic);
//
//if(sb->s_magic == 0)
{
printk("your filesystem have error/n");
if (!(bh2 = sb_bread(sb, 32768*4))) {
printk (KERN_ERR "EXT3-fs: unable to read superblock/n");
goto out_fail;
}
es = (struct ext3_super_block *) (((char *)bh2->b_data) + offset);
sbi->s_es = es;
sb->s_magic = le16_to_cpu(es->s_magic);
if (sb->s_magic != EXT3_SUPER_MAGIC) {
printk("find magic error/n");
// {
brelse(bh2);
goto failed_mount;
if (!(bh3 = sb_bread(sb, 32768 *4+1))) {
printk (KERN_ERR "EXT3-fs: unable to read superblock/n");
goto out_fail;
}
/*printk("in read block 32769/n");
for(i=0;i<blocksize/16;i++)
{
for(j=0;j<16;j++)
{
printk("%x-",*(((char *)bh3->b_data) + offset+i*16+j));
}
printk("/n");
}*/
es = (struct ext3_super_block *) (((char *)bh3->b_data) + offset);
sbi->s_es = es;
sb->s_magic = le16_to_cpu(es->s_magic);
if (sb->s_magic != EXT3_SUPER_MAGIC) {
printk("find maigic in 32769 block error/n");
brelse(bh3);
goto failed_mount;
}
else
{
printk("find magic in 32769 block correct/n");
}
// }
}
else
{
printk("find correct magic in 32768*4/n");
//备份新的超级块
//brelse(bh);
for(i=0;i<blocksize;i++)
{
*((char *)bh->b_data + offset +i)= *((char *)bh2->b_data + offset+i);
}
/*printk("after copy/n");
for(i=0;i<blocksize/16;i++)
{
for(j=0;j<16;j++)
{
printk("%x-",*(((char *)bh->b_data) + offset+i*16+j));
}
printk("/n");
}*/
//让其脏
mark_buffer_dirty(bh);
brelse(bh2);
set_bit(BH_Sync, &bh->b_state);
ll_rw_block(WRITE, 1, &bh);
wait_on_buffer(bh);
//fsync_dev(sb->s_dev); //add mwp
if (buffer_uptodate(bh))
{
//return bh;
brelse(bh);
goto BEGIN;
}
else
goto failed_mount;
}
}
goto failed_mount;
}
if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV &&
(EXT3_HAS_COMPAT_FEATURE(sb, ~0U) ||
EXT3_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
EXT3_HAS_INCOMPAT_FEATURE(sb, ~0U)))
printk(KERN_WARNING
"EXT3-fs warning: feature flags set on rev 0 fs, "
"running e2fsck is recommended/n");
/*
* Check feature flags regardless of the revision level, since we
* previously didn't change the revision level when setting the flags,
* so there is a chance incompat flags are set on a rev 0 filesystem.
*/
if ((i = EXT3_HAS_INCOMPAT_FEATURE(sb, ~EXT3_FEATURE_INCOMPAT_SUPP))) {
printk(KERN_ERR "EXT3-fs: %s: couldn't mount because of "
"unsupported optional features (%x)./n",
bdevname(dev), i);
goto failed_mount;
}
if (!(sb->s_flags & MS_RDONLY) &&
(i = EXT3_HAS_RO_COMPAT_FEATURE(sb, ~EXT3_FEATURE_RO_COMPAT_SUPP))){
printk(KERN_ERR "EXT3-fs: %s: couldn't mount RDWR because of "
"unsupported optional features (%x)./n",
bdevname(dev), i);
goto failed_mount;
}
sb->s_blocksize_bits = le32_to_cpu(es->s_log_block_size) + 10;
sb->s_blocksize = 1 << sb->s_blocksize_bits;
printk("after process sb->s_flags/n");
if (sb->s_blocksize < EXT3_MIN_BLOCK_SIZE ||
sb->s_blocksize > EXT3_MAX_BLOCK_SIZE) {
printk(KERN_ERR
"EXT3-fs: Unsupported filesystem blocksize %d on %s./n",
blocksize, bdevname(dev));
goto failed_mount;
}
sb->s_maxbytes = ext3_max_size(sb->s_blocksize_bits);
// printk("after get sb->s_maxbytes/n");
if (sb->s_blocksize != blocksize) {
blocksize = sb->s_blocksize;
/*
* Make sure the blocksize for the filesystem is larger
* than the hardware sectorsize for the machine.
*/
if (sb->s_blocksize < hblock) {
printk(KERN_ERR "EXT3-fs: blocksize %d too small for "
"device blocksize %d./n", blocksize, hblock);
goto failed_mount;
}
brelse (bh);
set_blocksize (dev, sb->s_blocksize);
logic_sb_block = (sb_block * EXT3_MIN_BLOCK_SIZE) / blocksize;
offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize;
bh = sb_bread(sb, logic_sb_block);
if (!bh) {
printk(KERN_ERR
"EXT3-fs: Can't read superblock on 2nd try./n");
return NULL;
}
es = (struct ext3_super_block *)(((char *)bh->b_data) + offset);
sbi->s_es = es;
if (es->s_magic != le16_to_cpu(EXT3_SUPER_MAGIC)) {
printk (KERN_ERR
"EXT3-fs: Magic mismatch, very weird !/n");
goto failed_mount;
}
}
if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV) {
sbi->s_inode_size = EXT3_GOOD_OLD_INODE_SIZE;
sbi->s_first_ino = EXT3_GOOD_OLD_FIRST_INO;
} else {
sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
if (sbi->s_inode_size != EXT3_GOOD_OLD_INODE_SIZE) {
printk (KERN_ERR
"EXT3-fs: unsupported inode size: %d/n",
sbi->s_inode_size);
goto failed_mount;
}
}
sbi->s_frag_size = EXT3_MIN_FRAG_SIZE <<
le32_to_cpu(es->s_log_frag_size);
if (blocksize != sbi->s_frag_size) {
printk(KERN_ERR
"EXT3-fs: fragsize %lu != blocksize %u (unsupported)/n",
sbi->s_frag_size, blocksize);
goto failed_mount;
}
sbi->s_frags_per_block = 1;
sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group);
sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group);
sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group);
sbi->s_inodes_per_block = blocksize / EXT3_INODE_SIZE(sb);
sbi->s_itb_per_group = sbi->s_inodes_per_group /sbi->s_inodes_per_block;
sbi->s_desc_per_block = blocksize / sizeof(struct ext3_group_desc);
sbi->s_sbh = bh;
if (sbi->s_resuid == EXT3_DEF_RESUID)
sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
if (sbi->s_resgid == EXT3_DEF_RESGID)
sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
sbi->s_mount_state = le16_to_cpu(es->s_state);
sbi->s_addr_per_block_bits = log2(EXT3_ADDR_PER_BLOCK(sb));
sbi->s_desc_per_block_bits = log2(EXT3_DESC_PER_BLOCK(sb));
if (sbi->s_blocks_per_group > blocksize * 8) {
printk (KERN_ERR
"EXT3-fs: #blocks per group too big: %lu/n",
sbi->s_blocks_per_group);
goto failed_mount;
}
if (sbi->s_frags_per_group > blocksize * 8) {
printk (KERN_ERR
"EXT3-fs: #fragments per group too big: %lu/n",
sbi->s_frags_per_group);
goto failed_mount;
}
if (sbi->s_inodes_per_group > blocksize * 8) {
printk (KERN_ERR
"EXT3-fs: #inodes per group too big: %lu/n",
sbi->s_inodes_per_group);
goto failed_mount;
}
sbi->s_groups_count = (le32_to_cpu(es->s_blocks_count) -
le32_to_cpu(es->s_first_data_block) +
EXT3_BLOCKS_PER_GROUP(sb) - 1) /
EXT3_BLOCKS_PER_GROUP(sb);
db_count = (sbi->s_groups_count + EXT3_DESC_PER_BLOCK(sb) - 1) /
EXT3_DESC_PER_BLOCK(sb);
sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *),
GFP_KERNEL);
if (sbi->s_group_desc == NULL) {
printk (KERN_ERR "EXT3-fs: not enough memory/n");
goto failed_mount;
}
for (i = 0; i < db_count; i++) {
sbi->s_group_desc[i] = sb_bread(sb, logic_sb_block + i + 1);
if (!sbi->s_group_desc[i]) {
printk (KERN_ERR "EXT3-fs: "
"can't read group descriptor %d/n", i);
db_count = i;
goto failed_mount2;
}
}
//检查组描述符
if (!ext3_check_descriptors (sb)) {
printk (KERN_ERR "EXT3-fs: group descriptors corrupted !/n");
//释放内存
for(i = 0 ;i< db_count; i++)
{
brelse (sbi->s_group_desc[i] );
}
for (i = 0; i < db_count; i++) {
sbi->s_group_desc[i] = sb_bread(sb, logic_sb_block + i + 1);
if (!sbi->s_group_desc[i]) {
printk (KERN_ERR "EXT3-fs: "
"can't read group descriptor %d/n", i);
db_count = i;
goto failed_mount2;
}
temp = sb_bread(sb, 32768 + i + 1);
//拷贝数据
for(j=0;j<sb->s_blocksize;j++)
{
*((char *)(sbi->s_group_desc[i])->b_data +j)= *((char *)temp->b_data +j);
}
mark_buffer_dirty(sbi->s_group_desc[i]);
brelse(temp);
set_bit(BH_Sync, &sbi->s_group_desc[i]->b_state);
ll_rw_block(WRITE, 1, &sbi->s_group_desc[i]);
wait_on_buffer(sbi->s_group_desc[i]);
if (buffer_uptodate(sbi->s_group_desc[i]))
{
printk("flush buffer sbi->s_group_desc[%d] error /n",i);
}
}
//继续进行判断
if (!ext3_check_descriptors (sb)) {
goto failed_mount2;
}
}
for (i = 0; i < EXT3_MAX_GROUP_LOADED; i++) {
sbi->s_inode_bitmap_number[i] = 0;
sbi->s_inode_bitmap[i] = NULL;
sbi->s_block_bitmap_number[i] = 0;
sbi->s_block_bitmap[i] = NULL;
}
sbi->s_loaded_inode_bitmaps = 0;
sbi->s_loaded_block_bitmaps = 0;
sbi->s_gdb_count = db_count;
get_random_bytes(&sbi->s_next_generation, sizeof(u32));
/*
* set up enough so that it can read an inode
*/
sb->s_op = &ext3_sops;
sb->dq_op = &ext3_qops;
INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
sb->s_root = 0;
needs_recovery = (es->s_last_orphan != 0 ||
EXT3_HAS_INCOMPAT_FEATURE(sb,
EXT3_FEATURE_INCOMPAT_RECOVER));
/*
* The first inode we look at is the journal inode. Don't try
* root first: it may be modified in the journal!
*/
if (!test_opt(sb, NOLOAD) &&
EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
if (ext3_load_journal(sb, es))
goto failed_mount2;
} else if (journal_inum) {
if (ext3_create_journal(sb, es, journal_inum))
goto failed_mount2;
} else {
if (!silent)
printk (KERN_ERR
"ext3: No journal on filesystem on %s/n",
bdevname(dev));
goto failed_mount2;
}
/* We have now updated the journal if required, so we can
* validate the data journaling mode. */
switch (test_opt(sb, DATA_FLAGS)) {
case 0:
/* No mode set, assume a default based on the journal
capabilities: ORDERED_DATA if the journal can
cope, else JOURNAL_DATA */
if (journal_check_available_features
(sbi->s_journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE))
set_opt(sbi->s_mount_opt, ORDERED_DATA);
else
set_opt(sbi->s_mount_opt, JOURNAL_DATA);
break;
case EXT3_MOUNT_ORDERED_DATA:
case EXT3_MOUNT_WRITEBACK_DATA:
if (!journal_check_available_features
(sbi->s_journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)) {
printk(KERN_ERR "EXT3-fs: Journal does not support "
"requested data journaling mode/n");
goto failed_mount3;
}
default:
break;
}
/*
* The journal_load will have done any necessary log recovery,
* so we can safely mount the rest of the filesystem now.
*/
sb->s_root = d_alloc_root(iget(sb, EXT3_ROOT_INO));
if (!sb->s_root || !S_ISDIR(sb->s_root->d_inode->i_mode) ||
!sb->s_root->d_inode->i_blocks || !sb->s_root->d_inode->i_size) {
if (sb->s_root) {
dput(sb->s_root);
sb->s_root = NULL;
printk(KERN_ERR
"EXT3-fs: corrupt root inode, run e2fsck/n");
} else
printk(KERN_ERR "EXT3-fs: get root inode failed/n");
goto failed_mount3;
}
ext3_setup_super (sb, es, sb->s_flags & MS_RDONLY);
/*
* akpm: core read_super() calls in here with the superblock locked.
* That deadlocks, because orphan cleanup needs to lock the superblock
* in numerous places. Here we just pop the lock - it's relatively
* harmless, because we are now ready to accept write_super() requests,
* and aviro says that's the only reason for hanging onto the
* superblock lock.
*/
EXT3_SB(sb)->s_mount_state |= EXT3_ORPHAN_FS;
unlock_super(sb); /* akpm: sigh */
ext3_orphan_cleanup(sb, es);
lock_super(sb);
EXT3_SB(sb)->s_mount_state &= ~EXT3_ORPHAN_FS;
if (needs_recovery)
printk (KERN_INFO "EXT3-fs: recovery complete./n");
ext3_mark_recovery_complete(sb, es);
printk (KERN_INFO "EXT3-fs: mounted filesystem with %s data mode./n",
test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA ? "journal":
test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered":
"writeback");
return sb;
failed_mount3:
journal_destroy(sbi->s_journal);
failed_mount2:
for (i = 0; i < db_count; i++)
brelse(sbi->s_group_desc[i]);
kfree(sbi->s_group_desc);
failed_mount:
ext3_blkdev_remove(sbi);
brelse(bh);
out_fail:
return NULL;
}