Skip to content
KaiGai Kohei edited this page Apr 14, 2016 · 4 revisions

設計メモ

PostgreSQLのshared_bufferの有無チェック -> BufTableLookup()で可能。BufferAlloc()を参照。共有ロック獲得用の関数もextensionから呼び出し可能。

Linuxのpage cacheの有無チェック -> find_get_page()で可能。do_generic_file_read()などが良いリファレンス。

NVMeドライバは /dev/nvme0n1p1 などのデバイスファイルを持ち、こいつに対して ioctl(2) を行う。 -> 対象のファイル自体ではない事に留意。

したがって、P2P DMAの対象ファイルとは別。 file descriptorをfget()関数に渡せばfile構造体をgetできる。最後にfputしてあげないとダメ。

対象ファイルから NVMe ドライバへのioctl()ハンドルを引く事はできる。 但し、実際には extra symbol を使って直接呼び出す。(余分なpage mappingを避けるため)

DMA_SSD2GPUの対象となるのは以下の3種類のソース

  • ユーザ空間のバッファ ** shared_buffer上の領域(all_visible=1)のケース ** MVCCチェックで"不可視"判定のものを塗りつぶしたデータ(all_visible=0) ** このどちらも Lock 済みのページに配置されている事が前提
  • Page Cache上のデータ(4KBアライン)
  • SSD上のブロック(Block-Sizeアライン)

最初の二つはHost RAM->GPU RAMのDMAなので、async_memcpy()の仕組みを使えば 行けるハズ。 NVMe-SSDのDMA機構を使うのは最後の一個だけ。

ファイルオフセット->セクタ番号への変換

VFSでI/Fが規定されているわけではない。 EXT4: ext4_get_block XFS: xfs_get_blocks のような関数コールが必要。これら関数はEXPORT_SYMBOL()されていないので、自前で関数ポインタをlookupしないとダメ。さらに、モジュールがunloadされたらシンボル:アドレスのペアをinvalidateする必要がある。 register_module_notifier()で登録可能。

DMなどが挟まっているケースでは、さらに物理ブロック位置を解決できるようにしないとダメ。 DBではRAIDほぼ必須なので、商用ライセンス版の独自機能にするか? RAIDの場合、同じファイルを複数のデバイスが構成する。->全てNVMeデバイスでないとダメというのは制約条件になるだろう。

TODO: ext4_get_block()で返されるblock_deviceは何を指すのか?たぶんDMデバイス。 物理的にNVMEなら何の問題もない。

メインメモリ->GPU RAMへのDMA

いったんホストメモリにマップされた後という前提。 dmaengineを使うasync_memcpyという実装があるので、これを使えないかどうか確認。 DMA元がshared_bufferの場合、get_user_pagesしないとダメなはず。(コピーは不要?) page cacheならそのまま使えてほしい。

雑多なメモ

NVMe区画上に作ったファイルの filp->f_inode->i_sb を手繰ってみると、nvmeデバイス (major=254)ではなく、blkext(major=259)として見えている。 おそらく、こいつがNVMeデバイスをブロックデバイスに見せている。 block/genhd.c にて定義されている。BLOCK_EXT_MAJOR == 259 なのでチェックは容易。

i_sb->bd_disk を参照した結果 major = 259 first_minor = 0 minors = 0 disk_name = nvme0n1 fops = nvme_fops

=> これを使って NVME デバイスのioctl()をコールできるはず。

Ext4/XFSともに、非常に小さなファイルに対して"inline"化がされているケースがある。 通常、PostgreSQLデータファイルではあり得ないので、ioctl()が入った時に、サポート 外として弾いてよい。XFSのinlineチェックは? ext4_has_inline_data()

POSIX File Lockでwrite(2)へのプロテクトできるか?

NVMeドライバの呼び出し方法

  • nvme_fops 経由で ioctl を呼び出す。 -> コマンドの余計なコピーが入る。互換性は保てる。ライブラリとの協調作業になりそう…。

  • upstream kernelの場合、EXPORT_SYMBOL_GPU()がちょろちょろ。 -> これを見るのが先決か

  • RHEL7/CentOS7の場合 EXPORT_SYMBOL()が無いので、シンボルの自己解決が必要。

nvme_ioctl NVME_IOCTL_SUBMIT_IO -> nvme_submit_io

nvme_submit_io nvme_map_user_pagesとnvme_setup_prpを呼び、nvme_submit_io_cmd()をコール。 nvme_submit_io_cmd()への流れは NVME-Donard と同じ。

nvme_submit_io_cmd()は非staticなのでシンボル解決可能。 GPU Memoryをiodへマップしたりする辺りは、ほとんど同じ。

async_memcpyの調査

raid5.c の利用ケースでは、async_memcpy()をコール後、戻り値の tx を init_async_submit() にセット、async_trigger_callback() を呼び出していた。 両方とも汎用の関数でEXPORT_SYMBOL()されている。

NVMe-SSD側がSyncなので、先にメモリコピー発動、次にSSD->GPUが正しいか。

DMデバイスの場合

そもそもRAID1なら同じブロックに同じ内容を書き込むわけだから、DMデバイスの下さえNVMe-SSDと確認できればOK?