C语言 在外部SSD上无限期读取数据块

tjvv9vkg  于 2023-10-16  发布在  其他
关注(0)|答案(2)|浏览(117)

我试图从有故障的外部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...
kkbh8khc

kkbh8khc1#

这听起来像是你的SSD可能有缺陷(无法响应请求,例如:它的固件在试图从闪存中的损坏数据恢复时挂起)或者内核驱动程序有错误。
至于为什么这个过程对信号没有React:有一个进程状态称为"uninterruptible sleep"(在tophtop中缩写为状态D)。当进程的控制流在内核内部时(即,在系统调用(如read)期间,例如等待来自磁盘或网络的数据(NFS挂载在网络中断期间因此而臭名昭著)。如果您的SSD没有回复数据请求,那么进程将无限期地等待数据,因为内核不会第二次请求SSD。或者可能是这样,SSD总是拒绝回答,或者甚至可能在尝试几个小时后超时.谁知道呢

kq0g1dla

kq0g1dla2#

这可能是一个内核驱动程序的bug。
你试过非阻塞读取吗?常规文件不能被轮询,但是描述符仍然可以被设置为非阻塞的

相关问题