Linuxの不揮発メモリ対応について

#(2019/6/12追記)
今なおこの記事を参照してくれる方がいらっしゃるのですが、現在は以下のスライドのほうが情報が新しいです。
本記事は残しておきますが、新しい情報はこちらをご参照ください。
https://www.slideshare.net/ygotokernel/nvdimmlinux-137104084

#はじめに
[Linux Advent Calendar](http://qiita.com/advent-calendar/2016/linux)の24日目の記事として不揮発メモリの状況について記載したいと思います。今回はkernelのソースの中とかのあまり技術的に深いところは突っ込まず、概略レベルです。（深いところはまだまだ勉強中の身です）。間違いなどがあればご指摘いただけると幸いです。

#不揮発メモリとは
　これまでPCやサーバなどで主記憶装置といえば、電源を停止させたり再起動させるとデータがクリアされる揮発性のRAMが使われて来ました。この主記憶としてのメモリが不揮発、即ち電源を落としたり再起動させたりした時にもデータが残るようになると考えれば、まあ間違いではないです。
　不揮発メモリといえばNAND FlashがSSDなどで使われて普及していますが、[Intel 3D Xpoint](http://www.intel.co.jp/content/www/jp/ja/architecture-and-technology/non-volatile-memory.html)が次世代の不揮発メモリとして期待されています。また、CPUからはDIMM Slotぐらいの近いところに配置されるため、SATAやPCIeなどのプロトコルによる制限も受けないことから、性能面でも期待されています。

## 名称
　主記憶装置としての不揮発メモリについては、一般的にnon volatile memory, persistent memoryといった言葉が使われてきました。が、最近ではNVDIMMという名前が浸透しつつあるようで、後述のIntelの仕様書やLinux Kernelのディレクトリ名もNVDIMMという言葉が使われるようになってきました。このため、本記事でも以後はNVDIMMと記載します。

#NVDIMMの扱いの難しさ
##あれ？意外と不便…
　これまで電源が落ちたり、再起動したりすると0クリアされていたメモリですが、これが不揮発になると便利なことがいっぱいありそうな予感がしますよね。例えば、「データが残っているのでシステムやプロセスの再起動の速度が速くなりそう」とか。
　しかし、これまで揮発性だったメモリが不揮発になるということは、意外と扱いが難しいことがわかっています。例えば、以下のような問題が考えられます。

- 突然の電源断  
データの書き込み途中に、突然電源が落ちた時はどうしましょうか？ソフトウェアがどこまでデータを書いたのかを再起動後に認識して、その次はどこから書けばよいのかを探す方法が無ければなりません。また、厄介なことにCPUキャッシュは揮発性のままですから、キャッシュからNVDIMMに押し出されたところまでしかデータの保証ができません。
- データ破壊  
バグやハード故障など何らかの問題により、NVDIMM中のデータが壊れることも考えられます。データが壊れたことを検出するためのチェックサムや、壊れた時に復旧するための仕組みなどが必要となってきます。
- 互換性  
NVDIMMの中をどのように使うかについては互換性が無ければいけません。ソフトをアップデートしたらメモリ中のデータのサイズや構造体の中身が変わってしまうようでは、不揮発性のメリットを生かすことができません。

　このようにNVDIMMには色々な課題があるため、このままでは従来のソフトウェアがNVDIMMをそのまま使うことはできません。そこで、直近ではNVDIMMをストレージデバイスとして見せて、その上にファイルシステムを構築するというのが現在の流れです。「なーんだ、つまんない」と思うかもしれませんが、ストレージに様々なデータを保存してきたファイルシステムの過去の技術の蓄積というのはやはり馬鹿にできません。

##速度を生かすには
　一方で、NVDIMMをファイルシステムとして使うのでは、性能的には無駄が大きいことがわかっています。これは当然で、これまでOSというのはHDDのようにストレージが遅いということを前提に設計されてきたのに対して、NVDIMMの性能はそれをはるかに上回るからです。NVDIMMの素子の性能はDRAMと比べてやや遅い[^nvdimm_speed]といった程度であり、HDDと比べたら桁違いに早くなる見込みです。このような場合、パッと思いつくだけでも、今までファイルのキャッシュすなわちpage cacheをRAMに一度乗せてからNVDIMMに保存するというのは、無駄に思えてきます。

### Moneta/Moneta-D
　このようにストレージがものすごく速くなった場合、どういう対策が必要かという研究がされています。カリフォルニア大学の[Moneta](https://cseweb.ucsd.edu/~swanson/papers/Micro2010Moneta.pdf)、そして[Moneta-D](http://cseweb.ucsd.edu/~swanson/papers/Asplos2012MonetaD.pdf)の論文が有名なようです。
　この論文では、高速なデバイスのポテンシャルを引き出すために、IOスケジューラの処理の削除や、デバイスの割り込み処理を止めてCPUがspin（すなわちpolling)する処理に変更、user空間driverの実装などの様々な施策を行っています。詳細は論文に譲りますが、NVDIMMのためには今のOSの設計を大きく変える必要がありそうだということは伝わってきます。

[^nvdimm_speed]: NVDIMMの種類によって、実際の速度は変わるでしょう。普段はDRAMを使って電源が切れるとモジュール内部のバッテリーを使ってNVDIMMに保存するNVDIMM-Nと、NVDIMMのみで構成するNVDIMM-Fでは性能に差が出るはずです。

#現在の方向性
ここまで述べてきた問題に対応するため、NVDIMMには以下のように複数のインタフェースが考えられています。短期的には前述のようにストレージとして見せてファイルシステムを構築するのが主な使い方です。長期的にはメモリとしてのインタフェースを提供して、NVDIMMのポテンシャルをフルに生かせるアプリの登場を期待しているようです。

- block device/ファイルシステム
  NVDIMMをそのままブロックデバイスとして提供する方法です。それをraw deviceとして利用したり、ファイルシステムを構築して利用したりすることができます。従来のソフトでもそのままNVDIMMを使うことができます。 ただし、kernel側に無駄な処理があるので、NVDIMMの本来の性能を引き出すには至らないでしょう。

- DAX(Direct Access Mode)
  NVDIMMの領域管理まではファイルシステムのインタフェースで行いますが、アプリに割り与えた領域の内部は不揮発メモリとしてバイト単位で利用することができます。page cacheなどの処理がスキップされるので、速度は通常のファイルシステムでアクセスする方法よりも早くなります。
　従来のソフトをそのまま使うことはできません。与えられた領域の内部について、互換性やデータ破壊時の対応などのNVDIMMの諸問題はアプリ側の責任だからです。
　また、ファイルシステム側がDAX対応している必要があります。この記事を執筆した時点では、ext4とxfsのみがDAXに対応しています。

- メモリインタフェース(？)
　将来は、NVDIMMをkernelレイヤをスキップして、直接アプリレベルで操作するということも考えられているようです。ただし、現在のところ具体的な仕様や実装などはなく、実現度は不明です。実現すればDPDKやSPDKのようなものになるのかもしれません。

- 管理コマンド
 不揮発メモリの領域などを管理するためのインタフェースも考えられており、管理コマンドがこれを使用します。

以下の図は[Intelが公開している仕様](http://pmem.io/documents/NVDIMM_Namespace_Spec.pdf)の抜粋です。左から、管理コマンド、ブロックデバイス・ファイルシステムとしての使い方、DAX、そしてメモリインタフェースの説明になっています。

![nvdimm_interface.jpg](https://qiita-image-store.s3.amazonaws.com/0/101351/b23da40f-f68f-6a7d-de52-d6e408879cd9.jpeg)

#関連仕様
　上記を踏まえて、NVDIMMのための仕様が策定されています。重要なのはメモリとしてCPUから直接アクセスする方法と、ストレージとしてブロック単位でアクセスする方法の2つが提示されていることです。
　これも[Intelが公開している仕様](http://pmem.io/documents/NVDIMM_Namespace_Spec.pdf)の抜粋ですが、SPA(System Phisical Address)として、CPUから直接NVDIMMにアクセスする方法と、Block Window経由でNVDIMMのDPA(Dimm Phisical Address)にアクセスするストレージとしてのアクセス方法が提示されています。

![nvdimm_namespace.jpg](https://qiita-image-store.s3.amazonaws.com/0/101351/e228cc96-36cd-94ae-47fc-6649e284c8bd.jpeg)

　なお、Intelが主導して規格を出しているのは、LinuxとWindows間でもNVDIMMの仕様について互換性を保つ必要があるためだと考えています。

では、これを踏まえて各仕様を簡単に紹介しましょう。

## namespace
　NVDIMMには、名前を付けて領域を管理するようになります。それが[namespace](http://pmem.io/documents/NVDIMM_Namespace_Spec.pdf)です。上記の図からも、Persistent Memory NamesapceとBlock Namespaceの2種類のnamespaceを定義できることがわかります。
　また、この仕様の最初の部分はNVDIMMの仕様の概略を知るのにちょうど良いテキストとなっていて、ここまで引用した図もこのから抜粋したものです。初めて勉強するときはこの仕様から読み始めるのが良さそうです。

##ACPI
  今の[ACPIの仕様](http://www.uefi.org/sites/default/files/resources/ACPI_6_1.pdf)にはNVDIMMの仕様が追加されています。

- NFIT  
  NVDIMMのためのテーブルとして、ACPIの仕様にNFITが追加されました。NVDIMMのSPAの領域がどこにあるのかや、Block Windowでアクセスする際のコントロール領域の情報などが定義されています。
- \_DSM  
\_DSMメソッドは本来はDevice Specific Methodとして、様々なデバイスのためのメソッドですが、NVDIMMのための機能も新たに提案されています。
namespaceの設定やNVDIMMのヘルスデータの確認など、NVDIMMを管理するための機能などが定義されています。ただし、現在は標準化された仕様はなく、[Intel](http://pmem.io/documents/NVDIMM_DSM_Interface_Example-V1.3.pdf), [HP](https://github.com/HewlettPackard/hpe-nvm/blob/master/Documentation/NFIT_DSM_DDR4_NDVIMM-N_v88s.pdf), [MicroSoft](https://msdn.microsoft.com/en-us/library/windows/hardware/mt604741(v=vs.85).aspx)がExampleとしてそれぞれ別々に定義している状態です。

##Block Window
　[NVDIMM Block Window Driver Writer’s Guide](http://pmem.io/documents/NVDIMM_DriverWritersGuide-July-2016.pdf)には、NVDIMMをストレージとしてアクセスするためのBlock Windowインタフェースについて詳細に規定されています。

##BTT
　今までのHDDなどのデバイスはデータ保証の単位がブロックサイズであり、ファイルシステムなどのコンポーネントもそれを前提に実装されています。しかし、NVDIMMはそれがバイト単位になりますから、そのままブロックデバイスとして使うと突然の電源断などの時に問題が生じます。このため、block単位でデータ保証するための仕組みが設けられています。
　仕様自体は先ほどのnamespaceの仕様書内に書かれています。

#Windowsは？
　Linuxの状況の前に、ちょっと寄り道になりますがWindows Server 2016についてです。以下の通り、動画で案内を出していますが、これが参考になるからです。
　やはり、通常のストレージとして使う方法とDAXのインタフェースを提供しています。

- [Using Non-volatile Memory (NVDIMM-N) as Block Storage in Windows Server 2016](https://www.youtube.com/watch?v=GoIPOSPL5Ww)
- [Using Non-volatile Memory (NVDIMM-N) as Byte-Addressable Storage in Windows Server 2016](https://www.youtube.com/watch?v=c9OdZKEHhyw)

興味深いのはデモの性能の数値です。通常のファイルシステムの使い方でも__NVMeのSSDの10倍以上__、DAXなら__NVMeのSSDの70倍以上__という性能が出ているようです。宣伝動画なので眉に唾をつける必要があるかもしれませんが、それでも興味深いデータです。

#Linuxの対応について
　では、Linuxの状況です。Upstreamでは基本的なドライバなどは開発が済んでいて、現在はDAXのための機能開発の真っ最中です。

##NVDIMMのページ
主な情報は、https://nvdimm.wiki.kernel.org/ や http://pmem.io に記載されています。まずは、ここにアクセスするとよいでしょう。

##エミュレータ
bootオプションでmemmap=xx!yyGと記載することで、既存のDRAMを使ってNVDIMMのエミュレーションを行うことができます。このため、今不揮発メモリを持っていない人でもNVDIMMがどのようになるか、試すことができます。ただし、機能を有効化するためにはkernelのconfigとコンパイルが必要です。使い方については https://nvdimm.wiki.kernel.org/ に記載されています。また、xxとyyにどのような値を設定すればよいかについては[ここ](https://nvdimm.wiki.kernel.org/how_to_choose_the_correct_memmap_kernel_parameter_for_pmem_on_your_system)を参照するとよいでしょう。

##kernel/driver
kernel/driverについては[Linux-nvdimm](https://lists.01.org/mailman/listinfo/linux-nvdimm)のメーリングリストで、実装について議論しています。
kernelソースのNVDIMM関連のソースは以下になります。

- NVDIMMの主なドライバはdrivers/nvdimmの配下に作られています。
- ACPIのドライバはdrivers/acpi/nfitに作られています。
- ファイルシステムのDAX対応のため、共通部分はfs/dax.cに記載されています。
- ext4とxfsにもdax対応のための修正がなされています。

NVDIMMの開発ツリーは以下が使われているようで、上のほうが開発用のツリーとして使われているようです。
https://git.kernel.org/cgit/linux/kernel/git/djbw/nvdimm.git/
https://git.kernel.org/cgit/linux/kernel/git/nvdimm/nvdimm.git/

##管理コマンド
　管理コマンドとして[ndctl](https://github.com/pmem/ndctl)コマンドが開発されています。

##ライブラリ
　DAXの上で使うライブラリとして[nvml](http://pmem.io/nvml/)が作らています。nvmlのソースも[github](https://github.com/pmem/nvml/)で管理されています。（実は筆者もまだ試していません）

#まとめ
　NVDIMMとLinuxについてざっくりとまとめてみました。NVDIMMが一般に普及するのはまだ先でしょうが、エミュレータもあるので色々と試してみるのは悪くないでしょう。
　本格的に使うにはもう少し安定度などの熟成が必要かもしれませんが、それも徐々に解消されてくるでしょう。また、将来的にはNVDIMMのためにこれまでのkernelの作りが大きく変わってくることもあるかもしれません。

　ではでは。

#おまけ
　Fujitsu Advent Calendarのほうも、[1枚目](http://qiita.com/advent-calendar/2016/fujitsu)、[2枚目](http://qiita.com/advent-calendar/2016/fujitsu_ext)ともによろしくお願いします。