使用O_DIRECT打开的文件,如何使用seek()和read()函数?

3

我正在尝试从文件中seekread,我的目标是所有读操作直接来自磁盘。为了实现这一点,我使用O_DIRECT选项打开文件,使用lseek()函数定位到所需的偏移量,并尝试从磁盘中read()一个块。然而在从磁盘中读取时遇到了错误:

#define _GNU_SOURCE
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>

int main(int argc, char *argv[])
{
        int disk_fd_read;
        off_t disk_off;
        int ret;

        int next_block;

        disk_fd_read = open(argv[1], O_RDONLY | O_DIRECT);
        if (disk_fd_read < 0) {
                printf("disk open error: %s\n", strerror(errno));
                exit(1);
        }

        disk_off = 100;

        disk_off = lseek(disk_fd_read, disk_off, SEEK_SET);
        if (disk_off != 100 || disk_off < 0) {
                printf("Error: could not seek %s\n", strerror(errno));
                exit (1);
        }
        printf("disk offset = %ld\n", disk_off);
        ret = read(disk_fd_read, &next_block, sizeof(uint64_t));
        /* 
        pread does not work either...
        ret = pread(disk_fd_read, &next_block, sizeof(uint64_t), disk_off);
        */
        if( ret == -1) {
                printf("error reading from device %s\n",strerror(errno));
                exit(1);
        }
        close(disk_fd_read);
}

/* RUN:
dd if=/dev/zero of=1Mfile bs=1M count=1
./a.out 1Mfile
disk offset = 100
error reading from device Invalid argument
*/

当我在打开文件时去掉O_DIRECT选项,错误消失了。从read手册中可以看到:
    EINVAL fd  is attached to an object which is unsuitable for reading; or the file was 
opened with the O_DIRECT flag, and either the address specified in buf, the value specified 
in count, or the current file offset is not suitably aligned.

这是否意味着lseek不支持O_DIRECT?我们如何从不同的磁盘偏移量进行寻址并直接从磁盘读取?


在没有检查argc以确保用户实际输入了命令行参数的情况下,永远不要超出argv [0]的范围访问。 - user3629249
1个回答

3
“适当对齐”是关键。您需要确保偏移量与4k(页面大小)对齐。此外,大小必须是4k的倍数。

谢谢,跟进一下:我将磁盘偏移改为4k,我在char缓冲区中读取了4k字节(这使得count指定的值和当前文件偏移量对齐到pagesize)。我仍然遇到错误,我认为这是因为我不知道如何将buf中的地址对齐到4k?我目前使用char buf [4096]并将数据读入缓冲区。 - Shehbaz Jaffer
1
这个帖子帮助我使用了页面对齐的内存地址。现在代码可以正常工作了。谢谢! - Shehbaz Jaffer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接