# 通知設計書 1-DEV CREATE

## 概要

本ドキュメントは、FreeBSDカーネルのGEOMフレームワークにおいて、新しいGEOMデバイスが作成された際に発行されるdevctl通知「GEOM DEV CREATE」の設計を記述する。

### 本通知の処理概要

GEOMフレームワークがストレージデバイスプロバイダを検出し、対応するキャラクタデバイスノード（cdev）を作成した際に、devctlサブシステムを通じてユーザランドに通知を送信する処理である。

**業務上の目的・背景**：FreeBSDのGEOMフレームワークは、ディスクやパーティションなどのストレージデバイスを抽象化するサブシステムである。新しいディスクが接続された際やパーティションが認識された際に、devd(8)などのユーザランドデーモンがデバイスの出現を検知し、自動マウントや設定適用などの自動化処理を行うために本通知が必要となる。

**通知の送信タイミング**：GEOMのDEVクラスがプロバイダを「taste」（検出）し、make_dev_s()でcdevを作成した直後に送信される。エイリアスデバイスの作成時にも個別に送信される。

**通知の受信者**：devd(8)デーモンおよび/dev/devctlをモニタリングしているユーザランドプロセスが受信する。

**通知内容の概要**：作成されたcdevのデバイス名が「cdev=デバイス名」形式で通知される。

**期待されるアクション**：受信したデーモン（devd等）は、デバイスに応じた自動マウント、ファイルシステムチェック、デバイスノードの権限設定、dumpデバイスの初期化などを実行する。

## 通知種別

カーネル内devctl通知（/dev/devctl経由のユーザランド通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（devctlキューへのエンキュー） |
| 優先度 | 通常 |
| リトライ | なし（カーネル内通知のため） |

### 送信先決定ロジック

devctl_notify()により/dev/devctlデバイスのイベントキューに格納される。devd(8)など、/dev/devctlをopen/readしているプロセスがイベントを受信する。送信先の選択ロジックはなく、全リスナーにブロードキャストされる。

## 通知テンプレート

### devctl通知メッセージ

| 項目 | 内容 |
|-----|------|
| system | `GEOM` |
| subsystem | `DEV` |
| type | `CREATE` |
| data | `cdev=<デバイス名>` |

### 本文テンプレート

```
!system=GEOM subsystem=DEV type=CREATE cdev=<デバイス名>
```

### 添付ファイル

該当なし（カーネル内通知のため添付ファイルの概念はない）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| cdev | 作成されたデバイスのデバイス名 | gp->name（GEOMジオメトリ名）または gap->ga_alias（エイリアス名） | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| カーネル内部イベント | g_dev_taste()完了 | make_dev_s()が成功（error == 0） | GEOMプロバイダの検出時にcdevを作成し通知 |
| カーネル内部イベント | エイリアスデバイス作成 | make_dev_alias_p()が成功 | プロバイダのエイリアス名ごとに通知 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| make_dev_s()失敗 | cdev作成に失敗した場合、通知は発行されない |
| make_dev_alias_p()失敗 | エイリアス作成に失敗した場合、該当エイリアスの通知は発行されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[GEOMプロバイダ検出] --> B[g_dev_taste呼出]
    B --> C[g_new_geom / g_new_consumer]
    C --> D[g_attach]
    D -->|成功| E[make_dev_s でcdev作成]
    D -->|失敗| Z[終了・通知なし]
    E -->|成功| F[snprintf buf cdev=name]
    E -->|失敗| Z
    F --> G[devctl_notify GEOM DEV CREATE buf]
    G --> H{エイリアスあり?}
    H -->|あり| I[make_dev_alias_p でエイリアス作成]
    I -->|成功| J[devctl_notify GEOM DEV CREATE エイリアス名]
    J --> H
    I -->|失敗| H
    H -->|なし| K[終了]
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（カーネル内のデータ構造を使用）

### カーネル内データ構造

| データ構造 | 用途 | 備考 |
|-----------|------|------|
| struct g_provider | GEOMプロバイダ情報 | デバイス名、エイリアスリスト |
| struct g_geom | GEOMジオメトリ | プロバイダとコンシューマの管理 |
| struct g_dev_softc | DEVクラスのソフト状態 | cdevへの参照を保持 |

### 更新テーブル一覧

該当なし（永続ストレージへの書き込みはない）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| cdev作成失敗 | make_dev_s()がエラーを返した場合 | printfでエラーログを出力し、GEOMリソースを解放。通知は発行しない |
| エイリアス作成失敗 | make_dev_alias_p()がエラーを返した場合 | printfでエラーログを出力し、該当エイリアスをスキップ。次のエイリアスの処理を続行 |
| g_attach失敗 | コンシューマのアタッチに失敗した場合 | printfでエラーログを出力し、NULLを返す。通知は発行しない |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（カーネルイベントとして随時発行）

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

- /dev/devctlへのアクセスにはroot権限が必要（devd(8)はroot権限で動作）
- 通知に含まれるデバイス名はcdev名のみで、機密情報は含まれない
- デバイス名にスペースやダブルクォートが含まれる場合はprep_devname()で事前に拒否される

## 備考

- devctl_notify()の第4引数（data）はsnprintf()で「cdev=%s」形式にフォーマットされ、バッファサイズはSPECNAMELEN + 6（通常262バイト）
- GEOMのDEVクラスはDECLARE_GEOM_CLASS()マクロで登録される
- エイリアスデバイスはプロバイダに登録されたga_aliasリストに基づいて作成される

---

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

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

### 推奨読解順序

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

まず、GEOMフレームワークの基本データ構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | geom.h | `sys/geom/geom.h` | g_class, g_geom, g_provider, g_consumer構造体の定義 |
| 1-2 | geom_dev.c | `sys/geom/geom_dev.c` | g_dev_softc構造体（行60-70）：sc_dev, sc_aliasフィールド |

**読解のコツ**: GEOMはクラス→ジオメトリ→プロバイダ/コンシューマの階層構造を持つ。DEVクラスはプロバイダに対応するcdevを作成する。

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

GEOMのtasteメカニズムがデバイス作成の起点となる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | geom_dev.c | `sys/geom/geom_dev.c` | g_dev_taste()関数（行346-423）がエントリーポイント |

**主要処理フロー**:
1. **行359**: g_new_geom()で新しいジオメトリを作成
2. **行362**: g_new_consumer()で新しいコンシューマを作成
3. **行365**: g_attach()でプロバイダにアタッチ
4. **行384**: make_dev_s()でcdevを作成
5. **行404**: g_dev_attrchanged()でphyspathを設定
6. **行405-406**: snprintf()でbufを構築し、devctl_notify()でCREATE通知を発行
7. **行410-420**: エイリアスデバイスをループで作成し、各エイリアスにもCREATE通知を発行

#### Step 3: devctl通知メカニズムを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | devctl.h | `sys/sys/devctl.h` | devctl_notify()のプロトタイプ宣言（行17-18） |
| 3-2 | subr_bus.c | `sys/kern/subr_bus.c` | devctl_notify()の実装。イベントキューへのエンキュー処理 |

**主要処理フロー**:
- **devctl.h 行17-18**: devctl_notify(system, subsystem, type, data)の4引数インターフェース

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

```
g_dev_taste() [sys/geom/geom_dev.c:346]
    |
    +-- g_new_geom() [GEOMフレームワーク]
    +-- g_new_consumer() [GEOMフレームワーク]
    +-- g_attach() [GEOMフレームワーク]
    +-- make_dev_s() [sys/kern/kern_conf.c:839]
    |       +-- make_dev_sv() [sys/kern/kern_conf.c:772]
    |               +-- newdev() [sys/kern/kern_conf.c:564]
    |               +-- prep_devname() [sys/kern/kern_conf.c:708]
    |               +-- devfs_create() [devfs]
    |               +-- notify_create() [sys/kern/kern_conf.c:550]
    |                       +-- devctl_notify("DEVFS","CDEV","CREATE",...) [sys/kern/kern_conf.c:545]
    +-- g_dev_attrchanged("GEOM::physpath")
    +-- devctl_notify("GEOM","DEV","CREATE",...) [sys/geom/geom_dev.c:406]
    +-- [エイリアスループ]
            +-- make_dev_alias_p() [sys/kern/kern_conf.c:1016]
            +-- devctl_notify("GEOM","DEV","CREATE",...) [sys/geom/geom_dev.c:419]
```

### データフロー図

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

GEOMプロバイダ検出       --->  g_dev_taste()                --->  /dev/<デバイス名> (cdev作成)
(g_provider構造体)              |                                   |
                                +-- make_dev_s()                    +-- devctl_notify()
                                +-- snprintf("cdev=%s",name)              |
                                                                          v
                                                                  /dev/devctl (イベントキュー)
                                                                          |
                                                                          v
                                                                  devd(8) (ユーザランド)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| geom_dev.c | `sys/geom/geom_dev.c` | ソース | DEVクラスの実装。g_dev_taste()でCREATE通知を発行 |
| geom.h | `sys/geom/geom.h` | ヘッダ | GEOMフレームワークの主要データ構造定義 |
| devctl.h | `sys/sys/devctl.h` | ヘッダ | devctl_notify()のプロトタイプ |
| kern_conf.c | `sys/kern/kern_conf.c` | ソース | make_dev_s()実装およびDEVFS CDEV CREATE通知 |
| subr_bus.c | `sys/kern/subr_bus.c` | ソース | devctl_notify()の実装 |
