使用 Linux AIO,能够做到 IOs 但也会将垃圾写入文件

Using Linux AIO, able to do IOs but writing garbage as well into the file

这可能看起来很愚蠢,但是,我使用的是 libaio(不是 posix aio),我可以向文件中写入一些内容,但我也会向文件中写入额外的内容。

我看了iocb的对齐要求和buffer字段的数据类型

这里是代码示例(仅使用相关部分,用于表示)

aio_context_t someContext;
struct iocb somecb;
struct io_event someevents[1];
struct iocb *somecbs[1];
somefd = open("/tmp/someFile", O_RDWR | O_CREAT);
char someBuffer[4096];

... // error checks 
someContext = 0; // this is necessary 
io_setup(32, &someContext ); // no error checks pasted here
strcpy(someBuffer, "hello stack overflow"); 


memset(&somecb, 0, sizeof(somecb));
somecb.aio_fildes = somefd ;
somecb.aio_lio_opcode = IOCB_CMD_PWRITE;
somecb.aio_buf = (uint64_t)someBuffer;
somecb.aio_offset = 0;
somecb.aio_nbytes = 100; // // // 
// I am avoiding the memeaign and sysconf get page part in sample paste
somecbs[0] = &somecb;  // address of the solid struct, avoiding heap
// avoiding error checks for this sample listing 
io_submit(someContext, 1, somecbs); 
// not checking for events count or errors 
io_getevents(someContext, 1, 1, someevents, NULL);

输出:

这段代码确实创建了文件,并写入了预期的字符串 你好堆栈溢出到文件 /tmp/someFile.

问题:

文件 /tmp/someFile 还包含在预期字符串之后,按顺序排列, @^@^@^@^@^@^@^@^@^ 和文件本身的一些部分(代码部分),可以说是垃圾。

我在一定程度上确定这是数据字段中的某个指针出错了,但无法破解。

我知道目前所有文件系统可能都不支持 aio 调用。我运行反对的那个确实支持。

编辑 - 如果您想要这次尝试的入门包,您可以从这里获得。

http://www.fsl.cs.sunysb.edu/~vass/linux-aio.txt

编辑 2:粗心大意,我在文件中设置了更多要写入的字节数,并且代码遵守了它。简而言之,要在 iocb.

的 bytes 字段中准确地写入一个 'hw' 需要不超过 2 个字节

这里发生了一些事情。首先,您提到的对齐要求是 512 字节或 4096 字节,具体取决于您的底层设备。尝试从 512 字节开始。适用于:

  1. 您在文件中写入的偏移量必须是 512 字节的倍数。它可以是 0、512、1024 等。您可以像这里一样在偏移量 0 处写入,但不能在偏移量 100 处写入。

  2. 写入文件的数据长度必须是 512 字节的倍数。同样,您可以写入 512 字节、1024 字节或 2048 字节,依此类推 - 512 的任意倍数。您不能像此处尝试的那样写入 100 字节。

  3. 包含您正在写入的数据的内存地址必须是 512 的倍数。(为了安全起见,我通常使用 4096。)在这里,您需要能够做 someBuffer % 512 并得到 0。(按照现在的代码,很可能不会。)

根据我的经验,未能满足上述任何要求实际上并不会返回错误!相反,它将使用正常的常规旧阻塞 I/O.

来完成 I/O 请求

未对齐 I/O: 如果您真的非常需要写入少量数据或以未对齐的偏移量写入,那么事情会变得更加棘手io_submit 界面。您需要进行对齐读取以覆盖您需要写入的数据范围,然后修改内存中的数据并将对齐区域写回磁盘。

例如,假设您要修改磁盘上的偏移量 768 到 1023。您需要将偏移量 512 处的 512 个字节读入缓冲区。然后,memcpy() 将 256 个字节写入该缓冲区的 256 个字节。最后,您在偏移量 512 处发出 512 字节缓冲区的写入。

未初始化的数据:正如其他人所指出的,您还没有完全初始化您正在写入的缓冲区。使用memset()初始化为零,避免写乱码。

分配对齐指针:为了满足数据缓冲区的指针要求,您需要使用posix_memalign()。例如,要分配 4096 字节且对齐限制为 512 字节:posix_memalign(&ptr, 512, 4096);

最后,考虑一下你是否需要这样做。即使在最好的情况下,io_submit仍然"blocks",尽管是第 10到 100 微秒级别。使用 preadpwrite 的正常阻塞 I/O 为您的应用程序提供了很多好处。而且,如果它变得繁重,您可以将其委托给另一个线程。如果您有一个对延迟敏感的应用程序,您无论如何都需要在另一个线程中执行 io_submit!