gpt4 book ai didi

c++ - 从启动时保留的内存写入时,内核 AIO (libaio) 写入请求失败

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:52:40 25 4
gpt4 key购买 nike

我是 linux aio (libaio) 的新手,希望这里有更多经验的人可以帮助我。

我的系统执行从 PCI 设备到系统 RAM 的高速 DMA。然后我想使用 libaio 直接从 DMA 地址空间将数据写入磁盘。目前,通过使用“memmap”内核启动命令,在启动时保留用于 DMA 的内存。

在我的应用程序中,内存使用 mmap 映射到虚拟用户空间地址指针,我相信我应该能够将其作为缓冲区传递给 io_prep_pwrite() 调用。但是,当我这样做时,写入似乎没有成功。当使用 io_getevents 获取请求时,“res”字段的错误代码为 -22,打印为“Bad Address”。

但是,如果我从先前映射的内存位置执行 memcpy 到我的应用程序分配的新缓冲区,然后在对 io_prep_pwrite 的调用中使用指向此本地缓冲区的指针,则请求工作正常并且数据写入磁盘.问题是执行 memcpy 会造成我需要将数据流式传输到磁盘的速度瓶颈,而且我无法跟上 DMA 速率。

我不明白为什么我必须先复制内存才能使写请求生效。我创建了一个最小示例来说明下面的问题。 bufBaseLoc 是映射地址,localBuffer 是数据复制到的地址。我不想执行以下行:

memcpy(localBuffer, bufBaseLoc, WRITE_SIZE);

...或者根本没有 localBuffer。在“准备 IOCB”部分,我想使用:

io_prep_pwrite(iocb, fid, bufBaseLoc, WRITE_SIZE, 0);

...但是它不起作用。但是本地缓冲区(只是一个拷贝)确实有效。

有人知道为什么吗?任何帮助将不胜感激。

谢谢,

#include <cstdio>
#include <string>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <libaio.h>

#define WRITE_SIZE 0x80000 //4MB buffer
#define DMA_BASE_ADDRESS 0x780000000 //Physical address of memory reserved at boot

//Reaping callback
void writeCallback(io_context_t ctx, struct iocb *iocb, long res, long res2)
{
//Res is number of bytes written by the request. It should match the requested IO size. If negative it is an error code
if(res != (long)iocb->u.c.nbytes)
{
fprintf(stderr, "WRITE_ERROR: %s\n", strerror(-res));
}
else
{
fprintf(stderr, "Success\n");
}
}

int main()
{
//Initialize Kernel AIO
io_context_t ctx = 0;
io_queue_init(256, &ctx);

//Open /dev/mem and map physical address to userspace
int fdmem = open("/dev/mem", O_RDWR);
void *bufBaseLoc = mmap(NULL, WRITE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fdmem, DMA_BASE_ADDRESS);

//Set memory here for test (normally done be DMA)
memset(bufBaseLoc, 1, WRITE_SIZE);

//Initialize Local Memory Buffer (DON’T WANT TO HAVE TO DO THIS)
uint8_t* localBuffer;
posix_memalign((void**)&localBuffer, 4096, WRITE_SIZE);
memset(localBuffer, 1, WRITE_SIZE);

//Open/Allocate file on disk
std::string filename = "tmpData.dat";
int fid = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_DIRECT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
posix_fallocate(fid, 0, WRITE_SIZE);

//Copy from DMA buffer to local process buffer (THIS IS THE COPY I WANT TO AVOID)
memcpy(localBuffer, bufBaseLoc, WRITE_SIZE);

//Prepare IOCB
struct iocb *iocbs[1];
struct iocb *iocb = (struct iocb*) malloc(sizeof (struct iocb));
io_prep_pwrite(iocb, fid, localBuffer, WRITE_SIZE, 0); //<--THIS WORKS (but is not what I want to do)
//io_prep_pwrite(iocb, fid, bufBaseLoc, WRITE_SIZE, 0); //<--THIS DOES NOT WORK (but is what I want to do)
io_set_callback(iocb, writeCallback);
iocbs[0] = iocb;

//Send Request
int res = io_submit(ctx, 1, iocbs);
if (res !=1)
{
fprintf(stderr, "IO_SUBMIT_ERROR: %s\n", strerror(-res));
}

//Reap Request
struct io_event events[1];
size_t ret = io_getevents(ctx, 1, 1, events, 0);
if (ret==1)
{
io_callback_t cb=(io_callback_t)events[0].data;
struct iocb *iocb_e = events[0].obj;
cb(ctx, iocb_e, events[0].res, events[0].res2);
}

}

最佳答案

可能是您的原始缓冲区未对齐。

libAIO 写入磁盘的任何缓冲区都需要对齐(我认为大约为 4K)。当您分配您的临时缓冲区时,您使用 posix_memalign,它将分配它正确对齐,这意味着写入将成功。如果您的原始保留缓冲区未对齐,则可能会导致您出现问题。

如果您可以尝试使用对齐的分配分配初始缓冲区,则可以解决问题。

关于c++ - 从启动时保留的内存写入时,内核 AIO (libaio) 写入请求失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29707058/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com