のぴぴのメモ

自分用のLinuxとかの技術メモ

ダイレクトIOの実装

ファイルシステム上のファイルにキャッシュを解さずread/writeするためには、DirectIOで操作する必要がある。DirectIOを操作するには、

  1. ファイルをオープンする時に、O_DIRECTオプションを付与する
  2. read/writeで操作する際のバッファは、512KB(Linux kernel2.6以降)でアライメントする(したがって、バッファ意はposix_memalignで確保する。mallocや配列で確保するとread()/write()時に、EINVALエラーとなる)
  3. コンパイル時に"_GNU_SOURCE"オプションを付与する。

サンプルコードは以下の通り。

#include <unistd.h>
#include <fcntl.h>


#define BLOCKSIZE 512


int main(void)
{
        int  fdi, fdo;
        int  size = 100 * 1024 * 1024; /* 100MB */
        char *buf;

        /* allocate buffer memory */
        posix_memalign( (void **)&buf, BLOCKSIZE, size);

        /* open file */
        fdi = open("file_in", O_RDONLY                |O_DIRECT );
        fdo = open("file_out",O_WRONLY|O_CREAT|O_TRUNC|O_DIRECT,
                                S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP );

        /* copy "fdi" file to "fdo" file. */
        read(fdi, buf, size);
        write(fdo,buf, size);

}

コンパイルコマンド

$ gcc -D_GNU_SOURCE -o directio directio.c

テスト

$ dd if=/dev/zero of=file_in bs=1024 count=102400
102400+0 records in
102400+0 records out
104857600 bytes (105 MB) copied, 1.31783 s, 79.6 MB/s
$ ./directio

straceコマンドでシステムとレースしてみても

$ strace ./directio
   <中略>
open("file_in", O_RDONLY|O_DIRECT)      = 3
open("file_out", O_WRONLY|O_CREAT|O_TRUNC|O_DIRECT, 0660) = 4
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 104857600) = 104857600
write(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 104857600) = 104857600
exit_group(104857600)                   = ?
$