通过 pv 从 /dev/sdb 读取时内核崩溃

通过 pv 从 /dev/sdb 读取时内核崩溃

我有一个外置日立硬盘,它有烦人的“高级电源管理”功能,如果我一分钟不使用它,它就会让设备进入睡眠状态。使用“sudo hdparm -B 128”也无法关闭此功能。

例如,当我暂停视频稍事休息时,播放器无法正常工作并跳过半分钟,直到硬盘被唤醒。

为了欺骗硬盘,我编写了一个小的 shell 脚本,该脚本不断从设备读取数据,因此它永远不会进入休眠状态。它运行良好,但每次我使用此脚本一段时间后,都会出现内核恐慌。

这是我的 shell 脚本:

#!/bin/bash

if [[ "$(id -u)" != "0" ]]
then
  sudo -s <<EOF
  ionice -c3 pv -s 4000784052224 -q -L 1m '/dev/sdb' &> /dev/null
  while [ $?==0 ]
  do
    sleep 1
    ionice -c3 pv -s 4000784052224 -q -L 1m '/dev/sdb' &> /dev/null
  done
EOF
else
  ionice -c3 pv -s 4000784052224 -q -L 1m '/dev/sdb' &> /dev/null
  while [ $?==0 ]
  do
    sleep 1
    ionice -c3 pv -s 4000784052224 -q -L 1m '/dev/sdb' &> /dev/null
  done
fi

我正在使用 Linux Mint 17.1,内核版本为 3.16.0-031600-generic(该问题也出现在原始内核中)。

你知道为什么会发生这样的事吗?

答案1

我找到了内核崩溃的原因。显然,Linux 正在缓存这种无休止的数据传输,因此简单的解决方案是使用 nocache 关闭缓存。

因此,我现在的解决方案是以下文件:

/etc/udev/规则.d:

KERNEL=="sd*", SUBSYSTEMS=="usb", ATTRS{manufacturer}=="HGST", ATTRS{product}=="Touro Desk 3.0", ATTRS{serial}=="31001312300002100125", ACTION=="add", RUN+="/usr/local/bin/touro_read_loop"
ACTION=="remove",  ENV{ID_SERIAL=="HGST_Touro_Desk_3.0_31001312300002100125"}, RUN+="/usr/local/bin/touro_read_stop"

在 /usr/local/bin/touro_read_loop 中:

#!/bin/bash

if [ ! -e /tmp/.apm_pids ]
then
    setsid /usr/local/bin/touro_read_loop_main >/dev/null 2>&1 < /dev/null &
fi

在 /usr/local/bin/touro_read_loop_main:

#!/bin/bash

if [[ "$(id -u)" == "0" ]]
then
  while test -e '/dev/disk/by-id/usb-HGST_Touro_Desk_3.0_31001312300002100125-0:0'
    do
    setsid nice -n19 ionice -c3 nocache pv -s 4000784052224 -q -L 1m '/dev/disk/by-id/usb-HGST_Touro_Desk_3.0_31001312300002100125-0:0' >/dev/null 2>&1 < /dev/null &
    PV_ID=$(pgrep -nx pv)
    echo -ne "$$\n$PV_ID\n" > /tmp/.read_loop_pids

    while test -d "/proc/$PV_PID"
    do
      sleep 30
    done
  done
fi

在 /usr/local/bin/touro_read_stop 中:

#!/bin/bash

cat /tmp/.apm_pids | sudo xargs -i kill {}
sudo rm /tmp/.read_loop_pids

这样,每当我将硬盘插入笔记本电脑时,硬盘就始终处于活动状态,因此不再需要高级电源管理。

相关内容