オンデマンドにswap スペースを確保して利用する(固定サイズのswap 領域を事前に用意して使用しない方法)

# 概要 
現代ではPC に十分なメモリが搭載されるのが当たり前となり、swap 領域の必然性が無くなってくる傾向にあります。
また仮にswap 領域を取るにしてもswap 専用の固定サイズのパーティションを作る方式を採用した場合、使われるかもわからない(むしろ使われないようにするほうが望ましい)ものに対して、メモリと同等前後の領域をHDD やSSD に割り当てるのはディスク容量の有効活用の点において嬉しいことではありません。
ここでは`swapspace` を使い、ディスク領域を効率よく使いながら、swap 領域が必要な時のみ必要な量だけオンデマンドにswap ファイルを作成してswap 領域を利用することができる環境の作成を行ってみます。

# 留意事項 
色々と検証した結果、swap ファイルを作成する場所は任意ですが、`ext4` でフォーマットされている必要があります。`xfs` ではだめでした。
また、今回はArch Linux を使いますが他のディストリビューションでも`swapspace` を使うことで同様のことが実現できるので、試してみてください。

- Tookmund/Swapspace
    - https://github.com/Tookmund/Swapspace

# swapspace モジュールのインストール 
Arcu Linux では`swapspace` はAUR で提供されているのでそちらからインストールします。


```console:AURからswapspaceのインストール
# git clone https://aur.archlinux.org/swapspace.git
# cd swapspace
# makepkg -sri
```


インストール後はswapspace デーモンを起動して完了です。

```console:swapspaceデーモンの起動
# systemctl restart swapspace
# systemctl enable swapspace
```


デフォルトではswap 領域が必要になれば`/var/lib/swapspace` ディレクトリ配下に1, 2, 3, ... とファイルが作成されていきます。

# swapspace 設定 
`/etc/swapspace.conf` ファイルを編集することで細かな設定を調整することができます。
基本的にデフォルト値で問題ないようになっているので、特に理由が無い限りは設定変更しなくて問題ありません。


* パラメータ一覧
<table><tbody>
    <th> 変数</th>
    <th> 説明</th>
    <th> 初期値</th>
  <tr>
    <td> swappath</td>
    <td> swap ファイルが作成される場所。</td>
    <td> /var/lib/swapspace</td>
  </tr>
  <tr>
    <td> lower_freelimit</td>
    <td> メモリの残り領域がこのパーセンテージを下回った場合にswap 領域を作成する。例えばメモリ1000MB ある環境でこの値を20 に設定すると空きメモリ領域が200 MB を下回るとswap 領域が作成されます。</td>
    <td> 20</td>
  </tr>
  <tr>
    <td> upper_freelimit</td>
    <td> メモリの残り領域がこのパーセンテージを上回った場合、swap 領域を開放しようとします。例えばメモリ1000MB ある環境でこの値を60 に設定すると空きメモリ領域が600 MB を上回るとswap 領域が解放されます。</td>
    <td> 60</td>
  </tr>
  <tr>
    <td> freetarget</td>
    <td> swap 領域を追加する時のswap 領域の空き領域の目安のパーセンテージ。swap の残り領域がこのパーセンテージを下回った場合にswap 領域を追加します。lower_freelimit とupper_freelimit の間の値に設定する必要があります。</td>
    <td> 30</td>
  </tr>
  <tr>
    <td> min_swapsize</td>
    <td> swap ファイル1 つあたりのサイズの下限値。</td>
    <td> 4m</td>
  </tr>
  <tr>
    <td> max_swapsize</td>
    <td> swap ファイル1 つあたりのサイズの上限値。</td>
    <td> 2t</td>
  </tr>
  <tr>
    <td> cooldown</td>
    <td> ディスクスペースが無くなった時に発生するswap ファイル割当の一時停止時間。もしくはswap ファイルが作成されてから解除されるまでの冷却時間。値は大雑把な秒単位で指定します。不要なswap ファイルはできるだけ早く削除してほしい場合はこの値を小さくします。</td>
    <td> 600</td>
  </tr>
</tbody></table>

# 領域のテスト 
下記のプログラムを実行してswap ファイルをテストしてみましょう。


```c:memeater.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char** argv) {
    int max = -1;
    int mb = 0;
    char* buffer;

    if(argc > 1)
        max = atoi(argv[1]);

    while((buffer=malloc(1024*1024)) != NULL && mb != max) {
        memset(buffer, 0, 1024*1024);
        mb++;
        printf("Allocated %d MB\n", mb);
        sleep(1);
    }
    return 0;
}
```


ファイルを作成したらコンパイルして実行します。


```console:コンパイル
# gcc filename.c -o memeater
```


プログラムを実行します。


```console
# ./memeater
-> free コマンドの結果、/var/lib/swapspace ディレクトリ配下を確認してswap されることを確認してください
```


# xfs ファイルシステム上で動作しない件について 
swap ファイルの作成場所がxfs ファイルシステム上では失敗する件ですが、xfs ファイルシステム上ではfallocate で作成したファイルをswap ファイルとして利用できない問題と関連しているようです。
以下のコマンドを実行するとext4 ファイルシステム上では成功しますが、xfs ファイルシステム上では失敗します。


```console:fallocateで作成したファイルに対してswapon
# fallocate -l $((1024 * 1024 * 1024 * 4)) /swapfile
# chmod 600 /swapfile
# mkswap /swapfile
# swapon /swapfile
swapon: /swapfile: swapon failed: Invalid argument
```


上記コマンドでは4G のファイルを作成するコマンドですが、fallocate では事前予約する形でFILE IO を発生させないで4G の未初期化領域として4G を確保し、ファイルの内容をすべて0 埋めするような形式とは異なります。
これがxfs 上でswap ファイルを作成する上で何か問題となっているようです。
xfs では、現段階ではしっかりとファイルの中身を何かしらのデータで埋めてあげたうえでswap ファイルとして使用しないといけないようです。


```console:ddで作成したファイルに対してswapon
# dd if=/dev/zero of=/swapfile bs=1G count=4
# chmod 600 /swapfile
# mkswap /swapfile
# swapon /swapfile
```


# 参考 
- swapspace(AUR)
    - https://aur.archlinux.org/packages/swapspace/

- How to test swap partition
    - https://unix.stackexchange.com/questions/1367/how-to-test-swap-partition

- swapon fails with fallocate on xfs #5
    - https://github.com/sous-chefs/swap/issues/5