c - 如何正确使用 posix_memalign

标签 c posix

我正在努力寻找如何正确使用 pread 和 pwrite。 在本例中,我尝试使用 pread 仅读取 256 个字节。 但是,无论何时我尝试读取少于 512 字节的 pread 都不会返回任何内容。 我相信这个问题必须与我分配给 posix_memalign 的 SECTOR 参数有关...

是否有一些我必须注意的明显信息?

#define BUF_SIZE 256
#define SECTOR 512
#define FILE_SIZE 1024 * 1024 * 1024 //1G


int main( int argc, char **argv ){

    int fd, nr;
    char fl_nm[]={"/dev/nvme0n1p1"};

    char* aligned_buf_w = NULL;
    char* aligned_buf_r = NULL;

    void* ad = NULL;
    if (posix_memalign(&ad, SECTOR, BUF_SIZE)) {
        perror("posix_memalign failed"); exit (EXIT_FAILURE);
    }

    aligned_buf_w = (char *)(ad);


    ad = NULL;
    if (posix_memalign(&ad, SECTOR, BUF_SIZE)) {
        perror("posix_memalign failed"); exit (EXIT_FAILURE);
    }
    aligned_buf_r = (char *)(ad);

    memset(aligned_buf_w, '*', BUF_SIZE * sizeof(char));

    printf("BEFORE READ BEGIN\n");
    printf("\t aligned_buf_w::%ld\n",strlen(aligned_buf_w));
    printf("\t aligned_buf_r::%ld\n",strlen(aligned_buf_r));
    printf("BEFORE READ END\n");


    fd = open(fl_nm, O_RDWR | O_DIRECT);
    pwrite(fd, aligned_buf_w, BUF_SIZE, 0);


    //write error checking
    if(nr == -1){
        perror("[error in write 2]\n");
    }


    nr = pread(fd, aligned_buf_r, BUF_SIZE, 0);
    //read error checking
    if(nr == -1){
        perror("[error in read 2]\n");
    }


    printf("AFTER READ BEGIN\n");
    printf("\taligned_buf_r::%ld \n",strlen(aligned_buf_r));
    printf("AFTER READ END\n");


    //error checking for close process
    if(close(fd) == -1){
        perror("[error in close]\n");
    }else{
        printf("[succeeded in close]\n");
    }


    return  0;
}

这是我读写512字节时的输出

BEFORE READ BEGIN
         aligned_buf_w::512
         aligned_buf_r::0
BEFORE READ END
AFTER READ BEGIN
        aligned_buf_r::512 
AFTER READ END
[succeeded in close]

这是我尝试读取 256 字节时的结果

BEFORE READ BEGIN
         aligned_buf_w::256
         aligned_buf_r::0
BEFORE READ END
[error in read 2]
: Invalid argument
AFTER READ BEGIN
        aligned_buf_r::0 
AFTER READ END
[succeeded in close]

最佳答案

在使用 O_DIRECT 时“内核将直接从/到作为参数传递的用户空间缓冲区指向的物理内存执行 DMA”- https://www.ukuug.org/events/linux2001/papers/html/AArcangeli-o_direct.html - 所以你必须遵守一些限制 - http://man7.org/linux/man-pages/man8/raw.8.html

All I/Os must be correctly aligned in memory and on disk: they must start at a sector offset on disk, they must be an exact number of sectors long, and the data buffer in virtual memory must also be aligned to a multiple of the sector size. The sector size is 512 bytes for most devices.

有了缓冲 IO,你就不用管它了。以下示例说明了在读取 HDD (/dev/sda9) 时:

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

#define SECTOR 512

int main( int argc, char **argv ){

int fd, nr, BUF_SIZE;
char fl_nm[]={"/dev/sda9"};
char* buf = NULL;

if (argc>1) {
    BUF_SIZE = atoi(argv[1]);

    // BUFFERED IO
    printf("Buffered IO -------\n");
    if ((buf = (char*)malloc(BUF_SIZE)) == NULL) perror("[malloc]");
    else {
        if ((fd = open(fl_nm, O_RDONLY)) == -1) perror("[open]");

        if((nr = pread(fd, buf, BUF_SIZE, 4096)) == -1) perror("[pread]");
        else
            printf("%i bytes read %.2x %.2x ...\n",nr,buf[0],buf[1]);

        free(buf);

        if(close(fd) == -1) perror("[close]");
    }

    // DIRECT IO
    printf("Direct IO ---------\n");
    if (posix_memalign((void *)&buf, SECTOR, BUF_SIZE)) {
        perror("posix_memalign failed");
    }
    else {
        if ((fd = open(fl_nm, O_RDONLY | O_DIRECT)) == -1) perror("[open]");

        /* buf size , buf alignment and offset has to observe hardware restrictions */
        if((nr = pread(fd, buf, BUF_SIZE, 4096)) == -1) perror("[pread]");
        else
            printf("%i bytes read %.2x %.2x ...\n",nr,buf[0],buf[1]);

        free(buf);

        if(close(fd) == -1) perror("[close]");
    }
}

return  0;
}

您可以验证以下行为:

$ sudo ./testodirect 512
Buffered IO -------
512 bytes read 01 04 ...
Direct IO ---------
512 bytes read 01 04 ...
$ sudo ./testodirect 4
Buffered IO -------
4 bytes read 01 04 ...
Direct IO ---------
[pread]: Invalid argument

顺便说一句,O_DIRECT 不是每个人都喜欢的 https://yarchive.net/comp/linux/o_direct.html

关于c - 如何正确使用 posix_memalign,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51993571/

相关文章:

c - 如何确定路径是否在目录内? (POSIX)

在 C 中将 time_t 转换为给定格式的字符串

c - 程序C计算奇数位总数

c - 为什么不应该在 linux 内核中将全局变量初始化为 0/NULL/false?

c - 从 `data.in` 读取并在 C 中写入 `data.out` 时出现问题

c - mprotect 后 malloc 导致段错误

c++ - 了解 posix 进程间信号量

c - fopen() 接受的参数格式是什么

c++ - Solaris 9 上的 printf + uint64?

c - 为什么 scanf 不允许更多输入?