Ext3 文件系统错误 Journal has aborted

时间:2022-07-25 15:09:36

If your system abruptly loses power, or if a RAID card is beginning to fail, you might see an ominous message like this within your logs:

EXT3-fs error (device hda3) in start_transaction: Journal has aborted

Basically, the system is telling you that it’s detected a filesystem/journal mismatch, and it can’t utilize the journal any longer. When this situation pops up, the filesystem gets mounted read-only almost immediately. To fix the situation, you can remount the partition as ext2 (if it isn’t your active root partition), or you can commence the repair operations.

If you’re working with an active root partition, you will need to boot into some rescue media and perform. these operations there. If this error occurs with an additional partition besides the root partition, simply unmount the broken filesystem and proceed with these operations.

Remove the journal from the filesystem (effectively turning it into ext2):


# tune2fs -O ^has_journal /dev/hda3

Now, you will need to fsck it to correct any possible problems (throw in a -y flag to say yes to all repairs, -C for a progress bar):

# e2fsck /dev/hda3

Once that's finished, make a new journal which effectively makes the partition an ext3 filesystem again

# tune2fs -j /dev/hda3

You should be able to mount the partition as an ext3 partition at this time:

# mount -t ext3 /dev/hda3 /mnt/fixed

Be sure to check your dmesg output for any additional errors after you’re finished!

 

如:

EXT3-fs error (device sda6) in start_transaction: Journal has aborted
EXT3-fs error (device sda6) in start_transaction: Journal has aborted

明显是sda6分区文件系统损坏了,退出所有调用/dev/sda6分区的进程。可以通过以下命令查看:
fuser -vm /dev/sda6
也可通过 fuser -kvm /dev/sda6直接强制关闭调用此分区的进程

再umount /dev/sda6把分区卸载下来,要不强制修复会有问题。

 

可能错误点:挂载方式不对

Ext3 允许您从三种数据日志记录方式中选择一个: data=writeback 、 data=ordered 和 data=journal 。
要指定日志方式,可以向 /etc/fstab 的选项节添加适当的字符串(例如 data=journal ),也可以在调用 mount 时直接指定 -o data=journal 命令行选项。如果您愿意指定用于根文件系统的数据日志记录方法( data=ordered 是缺省值),则可以使用名为 rootflags 的特殊内核引导选项。因此,如果愿意将根文件系统置于完整数据日志记录方式下,则向内核引导选项添加 rootflags=data=journal 。

1 data=writeback 方式
处于 data=writeback 方式下,ext3 根本不执行任何形式的数据日志记录,提供给您的是和在 XFS、JFS 和 ReiserFS 文件系统中找到的类似的日志记录(仅元数据)。这会让最近修改的文件在出现意外的重新引导事件中被毁坏。如果不考虑这个缺点, data=writeback 方式在大多数情况下应该能够为您提供最佳的 ext3 性能。
2 data=ordered 方式
处于 data=ordered 方式下,ext3 只是正式记录元数据,而在逻辑上将元数据和数据块分组到称为事务的单个单元中。到了将新的元数据写到磁盘上的时候, 首先写的是相关的数据块。 data=ordered 方式有效地解决了在 data=writeback 方式 下和大多数其它日志记录文件系统中发现的毁坏问题,而这是在不需要完整数据日志记录的情况下做到的。一般说来, data=ordered ext3 文件系统执行的速度比 data=writeback 文件系统执行的速度稍微慢一些,但比对应的完整数据日志记录还是要快出许多。
将数据 附加到文件时, data=ordered 方式提供了 ext3 完整数据日志记录方式提供的所有完整性保证。不过,如果正在 覆盖某一部分文件,而此时系统崩溃,那么有可能所写的区将包含原始块和在其中散布了更新块的组合。这是因为 data=ordered 不提供首先覆盖哪一个数据块的保证,因此不能假设只是因为更新了被覆盖的块 x,也就更新了被覆盖的块 x-1。 data=ordered 让写操作顺序由硬盘的写高速缓存决定。一般说来,这个限制并不经常对人们具有负面影响,因为附加的文件一般比覆盖的文件更普遍。出于这个原因, data=ordered 方式是对完整数据日志记录的一个很好的更高性能的替代。
3 data=journal 方式
data=journal 方式提供了完整数据和元数据日志记录。所有新数据首先写入日志,然后再写入它的最终位置。在崩溃情况下,可以重放日志,使数据和元数据处于一致的状态。

 

 

后期:发现DOM卡固件需升级!

测试程序:

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>    /* printk() */
#include <linux/slab.h>        /* kmalloc() */
#include <linux/fs.h>        /* everything... */
#include <linux/errno.h>    /* error codes */
#include <linux/timer.h>
#include <linux/types.h>    /* size_t */
#include <linux/fcntl.h>    /* O_ACCMODE */
#include <linux/hdreg.h>    /* HDIO_GETGEO */
#include <linux/kdev_t.h>
#include <linux/vmalloc.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/buffer_head.h>    /* invalidate_bdev */
#include <linux/bio.h>
#include <linux/libata.h>

#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_sas.h>
#include <scsi/scsi_eh.h>
#include <linux/time.h>  /* for do_gettimeofday */

int host_no = 0;
module_param(host_no, int, S_IRUGO|S_IWUSR);
int reset_times = 100;
module_param(reset_times, int, S_IRUGO|S_IWUSR);
int reset_count = 0;
module_param(reset_count, int, S_IRUGO|S_IWUSR);

struct proc_dir_entry *proc_reset;
int reset_all_disk(char *page, char **start, off_t off, int count,
                          int *eof, void *data)
{

 int len = 0;
    struct Scsi_Host *shost;
    struct scsi_device *sdev;
    struct ata_port *aport;
 len += sprintf(page + len, "reset aport!");
    shost = scsi_host_lookup(host_no);
    shost_for_each_device(sdev, shost)
 {
        if(sdev && sdev->type == 0)
  {
                aport = ata_shost_to_port(shost);
    aport->ops->port_suspend(aport, aport->pm_mesg);
    msleep(1*HZ);
             aport->ops->port_resume(aport);   /* tell ACPI that we're resuming */

        }
    }
    return len;
}

static int __init reset_disk_init(void)
{
   
 struct proc_dir_entry *proc_reset_disk;
    proc_reset = proc_mkdir("reset", NULL);
 if (proc_reset == NULL) {
        printk("can't create reset proc dir");
        return -1;
    }
 proc_reset_disk = create_proc_entry("reset_disk", 0666, proc_reset);
    if (proc_reset_disk){
        proc_reset_disk->data = NULL;
        proc_reset_disk->read_proc = reset_all_disk;
    }
 
 return 0;
}
static void reset_disk_exit(void)
{
    remove_proc_entry("reset_disk", proc_reset);
 remove_proc_entry("reset", NULL);
}
MODULE_LICENSE("Dual BSD/GPL");
module_init(reset_disk_init);
module_exit(reset_disk_exit);