【问题标题】:Using Linux AIO, able to do IOs but writing garbage as well into the file使用 Linux AIO,能够进行 IO,但也会将垃圾写入文件
【发布时间】:2018-01-25 21:20:28
【问题描述】:

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

我了解了iocb的缓冲区字段的对齐要求和数据类型。

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

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(而非 posix)将“hello world”准确且仅写入文件?

我知道目前并非所有文件系统都支持 aio 调用。我正在与之对抗的人确实支持。

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

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

编辑 2:粗心,我在文件中设置了更多的字节数,并且代码正在兑现它。简而言之,要在 iocb 的字节字段中写入 'hw' ,需要不超过 2 个字节。

【问题讨论】:

  • 你想要的字符串的长度是 100 字节,还是可能更短?
  • /tmp/someFile的文件大小终于是100了吧?
  • @Hasturkun 更短。
  • 请注意,您设置为在 somecb.aio_nbytes = 100; 中写入 100 个字节,我认为这是您的最终文件大小。您可能会写超出缓冲区的初始化部分。您可能希望在编写时使用实际的字符串长度。
  • 1) somecb.aio_buf = (uint64_t)someBuffer; :我看不出这里需要演员表。 2) struct iocb *somecbs[1]; 你不需要这个。 3)你假设零/空填充缓冲区。

标签: c linux pointers io aio


【解决方案1】:

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

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

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

  3. 包含您正在写入的数据的内存地址必须是 512 的倍数。(为了安全起见,我通常使用 4096。)在这里,您需要能够做到 @987654321 @ 并得到 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 仍然“阻塞”,尽管在 10 到 100 微秒级别。使用preadpwrite 的普通阻塞I/O 为您的应用程序提供了很多好处。而且,如果它变得繁重,您可以将其降级到另一个线程。如果您有一个对延迟敏感的应用程序,则无论如何您都需要在另一个线程中执行 io_submit!

【讨论】:

  • >根据我的经验,不满足上述任何要求实际上不会给你一个错误!我如何确切地证明它? strace 够用吗?
  • 是的,使用strace -T。这将为您提供每个系统调用所花费的时间。如果您对 io_submit 的调用花费的时间超过 50 微秒,则可能是使用了缓冲 I/O。如果我的回答对你有帮助,请采纳。谢谢!
猜你喜欢
  • 1970-01-01
  • 2022-08-18
  • 1970-01-01
  • 1970-01-01
  • 2017-10-02
  • 2012-04-18
  • 1970-01-01
  • 2015-06-14
  • 1970-01-01
相关资源
最近更新 更多