Linux badblocks命令详解

badblocks 命令用于检查磁盘设备上的坏道(坏扇区)。它可以通过读写测试来识别磁盘中的不可靠扇区,并生成坏道列表,以便后续使用 e2fsckmke2fs 等工具将这些扇区标记为不可用。

重要警告

badblocks 的写入测试会破坏数据! 在使用 -w 选项前,请确保已备份所有重要数据,并且不要在已挂载的文件系统上运行写入测试。

语法格式

badblocks [选项] 设备 [结束块 [起始块]]
badblocks [选项] -o 输出文件 设备

设备可以是磁盘设备(如 /dev/sda)或分区(如 /dev/sda1)。

功能说明

  • 坏道检测:识别磁盘上的物理坏道和逻辑坏道
  • 多种测试模式:支持只读、非破坏性读写、破坏性读写等测试模式
  • 坏道列表:生成坏道列表文件,供其他工具使用
  • 块大小控制:支持自定义块大小进行测试
  • 进度显示:显示测试进度和已测试块的数量

常用选项

选项 说明
-v 详细模式,显示测试的详细信息
-s 显示测试进度
-o 文件 将坏道列表输出到指定文件
-n 非破坏性读写测试(默认模式)
-w 破坏性写入测试(会破坏数据
-c 数量 每次测试的块数(默认16)
-b 大小 块大小(字节),默认为1024
-i 文件 从文件中读取已知的坏道列表
-t 测试模式 指定测试模式(随机数模式)
-f 强制在已挂载的设备上运行(危险!)
-p 次数 重复扫描的次数,用于确认坏道
-h 显示帮助信息

测试模式说明

非破坏性测试 (-n)

安全模式 - 不会破坏现有数据

  • 读取每个块的数据并缓存
  • 写入测试模式数据
  • 重新读取验证
  • 恢复原始数据

适用场景:已包含数据的磁盘检查

破坏性测试 (-w)

危险模式 - 会完全破坏数据!

  • 向每个块写入特定模式
  • 读取验证写入的数据
  • 使用不同模式重复测试
  • 不恢复原始数据

适用场景:全新磁盘或已备份的磁盘

使用示例

示例1:只读模式检查(安全)

# 只读检查,不修改数据
sudo badblocks -v /dev/sdb

# 检查指定分区
sudo badblocks -vs /dev/sda1

# 检查并显示进度
sudo badblocks -sv /dev/sdb
Checking blocks 0 to 2097151
Checking for bad blocks (read-only test): done
Pass completed, 0 bad blocks found.

示例2:非破坏性读写测试

# 非破坏性读写测试(较慢但安全)
sudo badblocks -nsv /dev/sdb

# 指定输出文件
sudo badblocks -nsv -o badblocks.txt /dev/sdb

# 增加每次测试的块数以提高速度
sudo badblocks -nsv -c 128 /dev/sdb

示例3:破坏性写入测试(谨慎使用!)

警告:以下命令会完全擦除磁盘上的所有数据!仅在全新磁盘或已完全备份的磁盘上使用。
# 破坏性写入测试(4种模式)
sudo badblocks -wsv /dev/sdb

# 使用指定模式测试
sudo badblocks -wsv -t 0xaa /dev/sdb

# 多次重复测试以确认坏道
sudo badblocks -wsv -p 3 /dev/sdb

示例4:检查特定范围

# 检查从0到10000的块
sudo badblocks -sv /dev/sdb 10000

# 检查从1000到10000的块
sudo badblocks -sv /dev/sdb 10000 1000

# 检查最后1000个块(需要先知道总块数)
sudo fdisk -l /dev/sdb  # 查看总扇区数
# 假设总块数为N
sudo badblocks -sv /dev/sdb $((N-1)) $((N-1000))

示例5:使用已知坏道列表

# 从文件读取已知坏道列表
sudo badblocks -sv -i known_bad.txt /dev/sdb

# 结合检查,跳过已知坏道
sudo badblocks -nsv -i known_bad.txt -o new_bad.txt /dev/sdb

示例6:完整磁盘健康检查脚本

#!/bin/bash
# 磁盘健康检查脚本

DISK="/dev/sdb"
LOG_FILE="/var/log/disk_health.log"
REPORT_FILE="/var/log/disk_report_$(date +%Y%m%d).txt"

log_message() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

check_disk_info() {
    echo "=== 磁盘信息 ===" | tee -a "$REPORT_FILE"
    sudo fdisk -l "$DISK" | tee -a "$REPORT_FILE"
    echo "" | tee -a "$REPORT_FILE"

    echo "=== SMART信息 ===" | tee -a "$REPORT_FILE"
    if command -v smartctl &> /dev/null; then
        sudo smartctl -a "$DISK" | tee -a "$REPORT_FILE"
    else
        echo "smartctl未安装,跳过SMART检查" | tee -a "$REPORT_FILE"
    fi
    echo "" | tee -a "$REPORT_FILE"
}

run_badblocks_test() {
    local test_type=$1
    local output_file=$2

    log_message "开始 $test_type 测试"
    echo "=== $test_type 测试结果 ===" | tee -a "$REPORT_FILE"

    case $test_type in
        "readonly")
            sudo badblocks -sv "$DISK" 2>&1 | tee -a "$REPORT_FILE"
            ;;
        "nondestructive")
            sudo badblocks -nsv "$DISK" 2>&1 | tee -a "$REPORT_FILE"
            ;;
        *)
            log_message "未知测试类型: $test_type"
            return 1
            ;;
    esac

    log_message "$test_type 测试完成"
    echo "" | tee -a "$REPORT_FILE"
}

main() {
    log_message "开始磁盘健康检查"

    # 检查磁盘是否已挂载
    if mount | grep -q "^$DISK"; then
        log_message "警告: $DISK 已挂载,建议卸载后再进行完整测试"
        echo "磁盘已挂载,仅进行只读检查" | tee -a "$REPORT_FILE"
        run_badblocks_test "readonly" "$REPORT_FILE"
    else
        log_message "$DISK 未挂载,进行非破坏性测试"
        run_badblocks_test "nondestructive" "$REPORT_FILE"
    fi

    check_disk_info

    log_message "磁盘健康检查完成"
    echo "检查报告保存至: $REPORT_FILE"
    echo "详细日志保存至: $LOG_FILE"
}

main "$@"

示例7:定期磁盘监控

#!/bin/bash
# 定期磁盘监控脚本

# 配置
DISKS=("/dev/sda" "/dev/sdb" "/dev/sdc")
LOG_DIR="/var/log/disk_monitor"
DAYS_TO_KEEP=30

# 创建日志目录
mkdir -p "$LOG_DIR"

# 清理旧日志
find "$LOG_DIR" -name "*.log" -mtime +$DAYS_TO_KEEP -delete

check_disk() {
    local disk=$1
    local log_file="$LOG_DIR/$(basename $disk)_$(date +%Y%m%d).log"

    echo "检查磁盘: $disk - $(date)" > "$log_file"
    echo "==========================" >> "$log_file"

    # 只读检查
    echo "执行只读坏道检查..." >> "$log_file"
    sudo badblocks -s "$disk" >> "$log_file" 2>&1
    result=$?

    if [ $result -eq 0 ]; then
        echo "检查完成: 未发现坏道" >> "$log_file"
    else
        echo "警告: 发现坏道或检查出错" >> "$log_file"
        # 发送警报
        echo "磁盘 $disk 发现问题,请查看日志: $log_file" | mail -s "磁盘警报" admin@example.com
    fi

    # 添加磁盘信息
    echo "" >> "$log_file"
    echo "磁盘信息:" >> "$log_file"
    sudo fdisk -l "$disk" >> "$log_file" 2>&1

    echo "$(date): 检查 $disk 完成" >> "$log_file"
}

# 主程序
for disk in "${DISKS[@]}"; do
    if [ -b "$disk" ]; then
        echo "正在检查 $disk ..."
        check_disk "$disk"
    else
        echo "跳过不存在的磁盘: $disk"
    fi
done

echo "所有磁盘检查完成"

示例8:与e2fsck结合使用

#!/bin/bash
# 使用badblocks和e2fsck修复文件系统

PARTITION="/dev/sdb1"
MOUNT_POINT="/mnt/data"
BADBLOCKS_FILE="/tmp/badblocks.txt"

echo "=== 文件系统坏道修复流程 ==="

# 1. 卸载分区(如果已挂载)
echo "1. 卸载分区..."
if mount | grep -q "$PARTITION"; then
    sudo umount "$PARTITION"
    echo "  分区已卸载"
else
    echo "  分区未挂载"
fi

# 2. 运行坏道检查
echo -e "\n2. 运行坏道检查..."
sudo badblocks -nsv -o "$BADBLOCKS_FILE" "$PARTITION"

# 3. 检查是否有坏道
if [ -s "$BADBLOCKS_FILE" ]; then
    echo "  发现坏道,数量: $(wc -l < "$BADBLOCKS_FILE")"

    # 4. 使用e2fsck标记坏道
    echo -e "\n3. 标记坏道..."
    sudo e2fsck -l "$BADBLOCKS_FILE" "$PARTITION"

    # 5. 强制检查文件系统
    echo -e "\n4. 强制检查文件系统..."
    sudo e2fsck -f -v "$PARTITION"
else
    echo "  未发现坏道"
fi

# 6. 重新挂载
echo -e "\n5. 重新挂载..."
sudo mount "$PARTITION" "$MOUNT_POINT"

echo -e "\n修复流程完成"
if [ -f "$BADBLOCKS_FILE" ]; then
    echo "坏道列表保存于: $BADBLOCKS_FILE"
fi

与其他工具结合使用

e2fsck - 标记坏道

将badblocks的输出提供给e2fsck,在文件系统中标记坏道:

# 生成坏道列表
sudo badblocks -o badblocks.txt /dev/sdb1

# 使用e2fsck标记坏道
sudo e2fsck -l badblocks.txt /dev/sdb1
mke2fs - 创建文件系统时排除坏道

创建文件系统时直接排除已知坏道:

# 先检查坏道
sudo badblocks -o badblocks.txt /dev/sdb

# 创建文件系统时排除坏道
sudo mke2fs -l badblocks.txt /dev/sdb1

注意事项

  • 数据安全:使用 -w 选项会永久删除磁盘上的所有数据
  • 挂载状态:避免在已挂载的文件系统上运行写入测试
  • 测试时间:完整测试大容量磁盘可能需要很长时间(数小时甚至数天)
  • 性能影响:运行badblocks时磁盘性能会严重下降
  • SSD限制:SSD的坏道检测与HDD不同,频繁写入测试可能缩短SSD寿命
  • 系统稳定性:测试期间避免断电或强制重启
  • 备份:运行任何磁盘检查前都应备份重要数据
  • 硬件问题:如果发现大量坏道,可能是磁盘即将损坏的征兆

常见问题和解决方案

优化建议:

  1. 增加每次测试的块数:
    sudo badblocks -c 1024 /dev/sdb
  2. 只测试特定区域(如怀疑有问题的区域)
  3. 使用只读模式(-v 而不加 -n-w
  4. 在系统负载较低时运行
  5. 考虑使用更快的测试方法(但可能不够全面)

中断方法:

  1. Ctrl + C 发送SIGINT信号
  2. 如果无响应,按 Ctrl + Z 挂起进程,然后终止:
    # 找到进程ID
    jobs -l
    
    # 或使用ps查找
    ps aux | grep badblocks
    
    # 终止进程
    kill -9 进程ID
  3. 注意:破坏性测试中断后,磁盘数据已部分破坏,不可恢复

处理步骤:

  1. 备份数据:立即备份磁盘上的所有重要数据
  2. 验证坏道:重新运行测试确认坏道:
    sudo badblocks -sv -i badblocks.txt /dev/sdb
  3. 标记坏道:使用文件系统工具标记坏道:
    # 对于ext2/3/4文件系统
    sudo e2fsck -l badblocks.txt /dev/sdb1
  4. 监控变化:定期检查坏道是否增加
  5. 考虑更换:如果坏道数量持续增加,考虑更换磁盘

相关命令

  • fsck - 检查并修复Linux文件系统
  • e2fsck - 检查ext2/ext3/ext4文件系统
  • smartctl - SMART磁盘监控工具
  • hdparm - 硬盘参数设置和测试
  • dd - 磁盘数据复制和转换
  • fdisk - 磁盘分区工具
  • lsblk - 列出块设备信息