我试图从有故障的外部SSD读取数据,以创建用于数据恢复的映像。驱动器是一个Apacer Panther SSD,通过Ubuntu上的ICY BOX SATA到USB连接器连接到USB端口。
执行下面的MWE,read
挂起在某个地址。地址在连续运行之间基本上是稳定的,但它可以变化(例如,不同的日子)。块大小为1时,read
挂起在某个扇区的第一个字节上。结果是程序冻结,没有信号中断读取,ctrl-c只是打印“^C”到终端,但不杀死程序,报警的处理程序永远不会被调用。
关闭终端并在新的终端上重新运行程序,没有read
完成(它挂起在第一次迭代上)。只有断开并重新连接SSD,我才能再次从磁盘读取。但是,如果我在read
被阻止时断开驱动器,程序将继续。
修改并运行程序,使用stdin作为文件描述符,SIGINT和SIGALRM中断read
。
所以问题是:a)为什么read
无限期阻塞,因为根据man page,它被信号中断?B)有什么办法可以解决这个问题吗?
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/select.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
void sig_handler(int signum){
printf("Alarm handler\n");
}
int main(int argc, char *argv[]) {
// Register ALARM signal handler to prevent read() from blocking indefinitely
struct sigaction alarm_int_handler = {.sa_handler=sig_handler};
sigaction(SIGALRM, &alarm_int_handler, 0);
char* disk_name = "/dev/sdb";
const int block_size = 512;
int offset = 0;
char block[block_size];
// Open disk to read as binary file via file descriptor
int fd = open(disk_name, O_RDONLY | O_NONBLOCK);
if (fd == -1){
perror(disk_name);
exit(0);
}
int i;
int position = offset;
for (i=0; i<100000; i++){
// Reset alarm to 1 sec (to interrupt blocked read)
alarm(1);
// Seek to current position
int seek_pos = lseek(fd, position, SEEK_SET);
if (seek_pos == -1){
perror("Seek");
}
printf("Reading... ");
fflush(stdout);
int len = read(fd, block, block_size);
printf("Read %d chars at %d\n", len, position);
if (len == -1){
if (errno != EINTR){
perror("Read");
}
else {
printf("Read aborted due to interrupt\n");
// TODO: handle it
}
}
position += len;
}
close(fd);
printf("Position %d (%d)\n", position, i * block_size);
printf("Done\n");
return 0;
}
终端上的输出如下所示
.
.
.
Reading... Read 1 chars at 29642749
Reading... Read 1 chars at 29642750
Reading... Read 1 chars at 29642751
Reading...
2条答案
按热度按时间kkbh8khc1#
这听起来像是你的SSD可能有缺陷(无法响应请求,例如:它的固件在试图从闪存中的损坏数据恢复时挂起)或者内核驱动程序有错误。
至于为什么这个过程对信号没有React:有一个进程状态称为"uninterruptible sleep"(在
top
和htop
中缩写为状态D
)。当进程的控制流在内核内部时(即,在系统调用(如read
)期间,例如等待来自磁盘或网络的数据(NFS挂载在网络中断期间因此而臭名昭著)。如果您的SSD没有回复数据请求,那么进程将无限期地等待数据,因为内核不会第二次请求SSD。或者可能是这样,SSD总是拒绝回答,或者甚至可能在尝试几个小时后超时.谁知道呢kq0g1dla2#
这可能是一个内核驱动程序的bug。
你试过非阻塞读取吗?常规文件不能被轮询,但是描述符仍然可以被设置为非阻塞的