无限期地读取外部SSD上的块

问题描述 投票:0回答:2

我正在尝试从有故障的外部 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...
c linux posix
2个回答
0
投票

这可能是内核驱动程序错误。

您尝试过非阻塞读取吗?常规文件无法轮询,但描述符仍然可以设为非阻塞


0
投票

听起来您的 SSD 可能有缺陷(无法响应请求,例如,在尝试从闪存中的损坏数据中恢复时其固件挂起)或内核驱动程序有错误。

至于进程为什么不响应信号:有一种进程状态叫做“不间断睡眠”(在

D
top
中缩写为状态
htop
)。当进程的控制流位于内核代码内部时,例如等待来自磁盘或网络的数据(NFS 挂载在网络中断期间因此而臭名昭著),进程就会进入此状态。如果您的 SSD 没有回复数据请求,则该进程将无限期地等待数据,因为内核不会第二次询问 SSD。

© www.soinside.com 2019 - 2024. All rights reserved.