# 機能設計書 33-スワップ管理

## 概要

本ドキュメントは、FreeBSDにおけるスワップ領域の有効化・無効化・管理を行うswapon/swapoff/swapctlコマンドの機能設計書である。

### 本機能の処理概要

swapon/swapoff/swapctlは、スワップデバイスの有効化（追加）・無効化（削除）・一覧表示を行うコマンド群である。単一のバイナリで3つのコマンド名をサポートし、起動名に応じて動作モードが切り替わる。

**業務上の目的・背景**：物理メモリが不足した際にディスク上のスワップ領域を使用してシステムの安定性を維持する。スワップ領域の動的な追加・削除により、システムの稼働中にメモリリソースの調整が可能となる。

**機能の利用シーン**：システム起動時の/etc/fstabに基づくスワップ自動有効化、障害対応時のスワップ領域追加、メンテナンス時のスワップ領域無効化、スワップ使用状況の監視などで利用される。

**主要な処理内容**：
1. スワップデバイスの有効化（swapon()システムコール）
2. スワップデバイスの無効化（swapoff()システムコール）
3. スワップデバイス一覧・使用状況の表示（sysctl vm.swap_info）
4. /etc/fstab読み込みによる一括スワップ操作
5. GEOM ELI暗号化スワップデバイスの対応
6. md(4)デバイスベースのスワップ（vnodeバッキング）対応
7. TRIM（DIOCGDELETE）操作のサポート

**関連システム・外部連携**：カーネルスワップサブシステム、GEOM ELI暗号化、md(4)メモリディスク、/etc/fstab

**権限による制御**：swapon/swapoffシステムコールの実行にはroot権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 16 | ZFSブート設定画面 | 補助機能 | スワップパーティションサイズの設定 |

## 機能種別

システム管理（スワップ領域のCRUD操作 / 状態表示）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| -a | flag | No | /etc/fstab内の全スワップデバイスを操作 | - |
| -d | flag | No | swapctlモードでswapoffに切替 | swapctlモード時のみ |
| -E | flag | No | swapon前にTRIM実行 | swaponモード時のみ |
| -f | flag | No | 強制swapoff | swapoffモード時のみ |
| -l | flag | No | スワップデバイス一覧表示 | - |
| -s | flag | No | サマリー表示 | - |
| -L | flag | No | late属性デバイスの操作 | -a時 |
| -q | flag | No | 静粛モード | - |
| -g/-h/-k/-m | flag | No | 表示単位（GB/人間可読/KB/MB） | - |
| -F fstab | string | No | 代替fstabファイル | 有効なファイルパス |
| file | string | 条件付 | スワップデバイスパス | デバイスファイルが存在すること |

### 入力データソース

コマンドライン引数、/etc/fstab（-a時）、sysctl vm.swap_info（一覧表示時）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| デバイス一覧 | text | スワップデバイス名、サイズ、使用量 |
| サマリー | text | 全スワップ領域の合計・使用量 |
| 操作メッセージ | text | 追加/削除操作の結果 |

### 出力先

標準出力、プロセス終了コード

## 処理フロー

### 処理シーケンス

```
1. プログラム名からモード判定（swapon/swapoff/swapctl）
   └─ argv[0]の末尾文字列で判定
2. getoptでオプション解析
3. モードに応じた処理分岐
   ├─ SWAPON/SWAPOFF:
   │   ├─ -a時: /etc/fstab走査、各swエントリに対してswap_on_off()
   │   └─ 個別: 指定デバイスに対してswap_on_off()
   └─ SWAPCTL:
       └─ -l/-s: swaplist()でvm.swap_info sysctl取得
4. swap_on_off()内でデバイスタイプ判定
   ├─ md(4)デバイス → swap_on_off_md()
   ├─ .eli暗号化 → swap_on_off_geli()
   └─ 通常デバイス → swap_on_off_sfile()
5. swapon()/swapoff()システムコール実行
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{プログラム名判定}
    B -->|swapon| C[which_prog=SWAPON]
    B -->|swapoff| D[which_prog=SWAPOFF]
    B -->|swapctl| E[which_prog=SWAPCTL]
    C --> F[getopt解析]
    D --> F
    E --> F
    F --> G{-a フラグ?}
    G -->|Yes| H[/etc/fstab走査]
    G -->|No| I{-l or -s?}
    I -->|Yes| J[swaplist表示]
    I -->|No| K[swap_on_off 個別]
    H --> L[swap_on_off ループ]
    L --> M{デバイスタイプ}
    K --> M
    M -->|md| N[swap_on_off_md]
    M -->|.eli| O[swap_on_off_geli]
    M -->|通常| P[swap_on_off_sfile]
    N --> Q[swapon/swapoff syscall]
    O --> Q
    P --> Q
    Q --> R[終了]
    J --> R
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-33-01 | プログラム名によるモード切替 | argv[0]に"swapon"/"swapoff"が含まれるかで初期モードを決定 | 起動時 |
| BR-33-02 | fstab noautoスキップ | fstabエントリにnoautoオプションがある場合はスキップ | -a時 |
| BR-33-03 | late属性制御 | lateオプションのあるデバイスは-Lフラグ指定時のみ操作 | -a時 |
| BR-33-04 | trimonceサポート | fstabにtrimonceオプションがある場合、swapon前にTRIM実行 | swapon -a時 |
| BR-33-05 | GEOM ELI自動設定 | .eli接尾辞のデバイスはgeli onetimeで暗号化デバイスを自動作成 | swapon時 |

### 計算ロジック

スワップ使用量表示: ページ数 * ページサイズでバイト単位に変換後、指定単位（K/M/G/H）で表示

## データベース操作仕様

該当なし

### 操作別データベース影響一覧

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| EBUSY | デバイス使用中 | 既にスワップとして使用中のデバイスをswapon | 既存の使用状況を確認 |
| EINVAL | パラメータ無効 | NSWAPDEV制限到達（swapon時）、無効なデバイス（swapoff時） | デバイス構成を確認 |
| - | 警告 | geli引数の不正（sectorsize, keylen等） | fstabのオプション確認 |

### リトライ仕様

明示的なリトライ機構はない。

## トランザクション仕様

swapon/swapoffシステムコールはアトミック。md+geliの組み合わせ時、mdconfig→geli→swaponの順で実行され、途中失敗時のロールバックはswapoff時にmdconfig detachまで実行される。

## パフォーマンス要件

TRIMオプション（-E/trimonce）は初回スワップ有効化時にSSDのTRIMコマンドを発行し、スワップ領域のI/O性能を改善する。

## セキュリティ考慮事項

- swapon/swapoffはroot権限が必要
- GEOM ELI暗号化スワップにより、スワップデータのディスク上での暗号化が可能
- geliのonetimeモードはランダムキーを使用し、再起動後にデータ復元不可

## 備考

swapctlはswapon/swapoffの統合インタフェースであり、-aでswapon、-dでswapoff、-l/-sで一覧/サマリー表示となる。

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | swap_pager.h | `sys/vm/swap_pager.h` | xswdev構造体（スワップデバイス情報）、XSWDEV_VERSION |
| 1-2 | swapon.c | `sbin/swapon/swapon.c` | orig_prog/which_prog列挙型（SWAPON/SWAPOFF/SWAPCTL） |

**読解のコツ**: swapon.cは単一バイナリで3つのコマンド動作をサポートするため、which_prog変数の状態遷移を追跡することが重要。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | swapon.c | `sbin/swapon/swapon.c` | main()関数のモード判定とgetoptループ |

**主要処理フロー**:
1. **71-223行目**: main() - プログラム名判定(82-88行目)、getoptループ(92-164行目)、fstab走査(172-200行目)
2. **225-254行目**: swap_on_off() - デバイスタイプ判定とディスパッチ
3. **745-774行目**: swap_on_off_sfile() - swapon/swapoffシステムコール実行
4. **809-892行目**: swaplist() - vm.swap_info sysctlによる一覧表示

#### Step 3: GEOM ELI暗号化スワップを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | swapon.c | `sbin/swapon/swapon.c` | swap_on_off_geli()およびswap_on_geli_args() |

**主要処理フロー**:
- **271-373行目**: swap_on_geli_args() - fstabマウントオプションからgeliコマンド引数を構築
- **375-414行目**: swap_on_off_geli() - geli onetimeコマンド実行後、swap_on_off_sfile()呼び出し

#### Step 4: md(4)デバイスベースのスワップを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | swapon.c | `sbin/swapon/swapon.c` | swap_on_off_md() |

**主要処理フロー**:
- **416-627行目**: swap_on_off_md() - mdconfig attach/detachとswapon/swapoffの組み合わせ処理

### プログラム呼び出し階層図

```
main() [swapon.c:71]
    |
    +-- プログラム名判定 [82-88行目]
    +-- getopt解析 [92-164行目]
    |
    +-- [SWAPON/SWAPOFF モード]
    |   +-- getfsent() [173行目] (/etc/fstab走査, -a時)
    |   +-- swap_on_off() [225行目]
    |       |
    |       +-- swap_on_off_md() [416行目] (mdデバイス)
    |       |   +-- run_cmd(mdconfig ...) [473-531行目]
    |       |   +-- swap_on_off_geli() or swap_on_off_sfile()
    |       |
    |       +-- swap_on_off_geli() [375行目] (.eliデバイス)
    |       |   +-- swap_on_geli_args() [271行目]
    |       |   +-- run_cmd(geli onetime ...) [399行目]
    |       |   +-- swap_on_off_sfile()
    |       |
    |       +-- swap_on_off_sfile() [745行目] (通常デバイス)
    |           +-- swapon_trim() [704行目] (-E時)
    |           |   +-- ioctl(DIOCGDELETE)
    |           |   +-- swapon()
    |           +-- swapon() / swapoff()
    |
    +-- [SWAPCTL モード]
        +-- swaplist() [809行目]
            +-- sysctl(vm.swap_info)
```

### データフロー図

```
[入力]                    [処理]                          [出力]

コマンドライン引数 ──> モード判定 + getopt解析
/etc/fstab ──────> getfsent() fstab走査
                         |
                    swap_on_off() デバイスタイプ判定
                         |
                    +----+----+
                    |    |    |
                   md  geli  通常
                    |    |    |
                    +----+----+
                         |
                    swapon()/swapoff() syscall ──> カーネルスワップサブシステム
                         |
sysctl vm.swap_info ──> swaplist() ──> 標準出力（デバイス一覧/サマリー）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| swapon.c | `sbin/swapon/swapon.c` | ソース | swapon/swapoff/swapctlメイン処理 |
| swapon.8 | `sbin/swapon/swapon.8` | manページ | swaponマニュアル |
| swap_pager.h | `sys/vm/swap_pager.h` | ヘッダ | スワップページャインタフェース |
| mdioctl.h | `sys/sys/mdioctl.h` | ヘッダ | md(4) ioctl定義 |
| fstab | `/etc/fstab` | 設定 | ファイルシステムテーブル |
