# 通知設計書 7-CDEVイベント

## 概要

本ドキュメントは、FreeBSDカーネルのDEVFS（デバイスファイルシステム）において、キャラクタデバイスの作成・破棄等のイベントが発生した際に発行されるdevctl通知「DEVFS CDEV <イベント名>」の設計を記述する。

### 本通知の処理概要

kern_conf.cのcdev管理機構において、キャラクタデバイス（cdev）が作成または破棄された際に、notify()関数を通じてdevctlサブシステムにユーザランド通知を送信する処理である。

**業務上の目的・背景**：DEVFSレイヤにおけるキャラクタデバイスの作成や破棄を、ユーザランドが検知するために本通知が必要となる。GEOMデバイス以外の一般的なキャラクタデバイス（/dev/tty*, /dev/pts/*等）の作成・破棄もこの通知で検知できる。devd(8)はDEVFSイベントに基づいてデバイスノードの権限設定やシンボリックリンクの管理を行う。

**通知の送信タイミング**：make_dev_sv()でデバイスが作成された際（notify_create）、およびdestroy_devl()やdelist_dev_locked()でデバイスが破棄された際（notify_destroy）に送信される。

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

**通知内容の概要**：イベントが発生したcdevのデバイス名が「cdev=デバイス名」形式で通知される。イベント種別はCREATEまたはDESTROYである。

**期待されるアクション**：受信したデーモンは、デバイス作成時にはデバイスノードの権限設定やシンボリックリンクの作成を、デバイス破棄時にはリソースのクリーンアップを実行する。

## 通知種別

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

## 送信仕様

### 基本情報

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

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

devctl_notify()により全リスナーにブロードキャストされる。

## 通知テンプレート

### devctl通知メッセージ

| 項目 | 内容 |
|-----|------|
| system | `DEVFS` |
| subsystem | `CDEV` |
| type | `CREATE` または `DESTROY` |
| data | `cdev=<デバイス名>` |

### 本文テンプレート

```
!system=DEVFS subsystem=CDEV type=CREATE cdev=<デバイス名>
!system=DEVFS subsystem=CDEV type=DESTROY cdev=<デバイス名>
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| cdev | イベントが発生したデバイスのデバイス名 | dev->si_name | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| カーネル内部イベント | make_dev_sv()完了 | デバイス作成成功時 | notify_create()経由でCREATE通知 |
| カーネル内部イベント | make_dev_alias_v()完了 | エイリアス作成成功時 | notify_create()経由でCREATE通知 |
| カーネル内部イベント | destroy_devl()実行 | CDP_UNREF_DTRフラグが未設定の場合 | notify_destroy()経由でDESTROY通知 |
| カーネル内部イベント | delist_dev_locked()実行 | デバイスのdelistと同時 | notify_destroy()経由でDESTROY通知 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| cold != 0 | システムブート初期段階ではnotify()がreturnし通知は発行されない |
| CDP_UNREF_DTR設定済み | destroy_devl()でCDP_UNREF_DTRフラグが既に設定されている場合、notify_destroy()は呼ばれない |
| M_NOWAIT && malloc失敗 | MAKEDEV_NOWAITフラグ使用時にメモリ確保に失敗した場合 |

## 処理フロー

### 送信フロー（CREATE）

```mermaid
flowchart TD
    A[make_dev_sv / make_dev_alias_v] --> B[デバイス作成成功]
    B --> C[notify_create呼出]
    C --> D[notify関数呼出]
    D --> E{cold != 0 ?}
    E -->|Yes| F[return 通知なし]
    E -->|No| G[malloc でdataバッファ確保]
    G --> H{malloc成功?}
    H -->|No| F
    H -->|Yes| I[cdev=si_name でdata構築]
    I --> J[devctl_notify DEVFS CDEV CREATE data]
    J --> K[free data]
    K --> L[終了]
```

### 送信フロー（DESTROY）

```mermaid
flowchart TD
    A[destroy_devl / delist_dev_locked] --> B[notify_destroy呼出]
    B --> C[notify関数呼出]
    C --> D[devctl_notify DEVFS CDEV DESTROY data]
    D --> E[終了]
```

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

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

| データ構造 | 用途 | 備考 |
|-----------|------|------|
| struct cdev | キャラクタデバイス | si_nameからデバイス名を取得 |
| struct cdev_priv | cdevの内部情報 | cdp_flagsのCDP_UNREF_DTRフラグを参照 |

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| メモリ確保失敗 | malloc()がNULLを返した場合 | 通知をスキップしてreturn |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

制限なし

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

- /dev/devctlへのアクセスにはroot権限が必要
- 通知に含まれるのはデバイス名のみ

## 備考

- notify()関数内でデータバッファをmallocし、devctl_notify()呼出後にfreeする
- MAKEDEV_NOWAITフラグ使用時はM_NOWAITでmalloc、それ以外はM_WAITOKでmalloc
- coldフラグがtrueの場合（システムブート初期段階）は通知を発行しない
- notify_destroy()はMAKEDEV_WAITOKで呼ばれるため、メモリ確保失敗は通常発生しない
- GEOMデバイスの場合、本通知（DEVFS CDEV CREATE/DESTROY）に加えてGEOM DEV CREATE/DESTROYも別途発行される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | conf.h | `sys/sys/conf.h` | struct cdevの定義：si_nameフィールド |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | kern_conf.c | `sys/kern/kern_conf.c` | notify()関数（行529-547）：通知の共通処理 |
| 2-2 | kern_conf.c | `sys/kern/kern_conf.c` | notify_create()関数（行549-554）：CREATE通知のラッパー |
| 2-3 | kern_conf.c | `sys/kern/kern_conf.c` | notify_destroy()関数（行556-561）：DESTROY通知のラッパー |

**主要処理フロー**:
1. **行536**: cold判定で早期return
2. **行538**: mflagsをMAKEDEV_NOWAITフラグに基づいて決定
3. **行539**: namelen = strlen(dev->si_name)
4. **行540**: data = malloc(namelen + sizeof(prefix), M_TEMP, mflags)
5. **行543-544**: memcpyで"cdev="プレフィクスとsi_nameを結合
6. **行545**: devctl_notify("DEVFS", "CDEV", ev, data)
7. **行546**: free(data, M_TEMP)

#### Step 3: 呼び出し元を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | kern_conf.c | `sys/kern/kern_conf.c` | make_dev_sv()関数（行832）：notify_create呼出 |
| 3-2 | kern_conf.c | `sys/kern/kern_conf.c` | make_dev_alias_v()関数（行993）：notify_create呼出 |
| 3-3 | kern_conf.c | `sys/kern/kern_conf.c` | destroy_devl()関数（行1159）：notify_destroy呼出 |
| 3-4 | kern_conf.c | `sys/kern/kern_conf.c` | delist_dev_locked()関数（行1212）：notify_destroy呼出 |

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

```
[CREATE]
make_dev_sv() [sys/kern/kern_conf.c:772]
    +-- notify_create(dev, flags) [行832]
            +-- notify(dev, "CREATE", flags) [行553]
                    +-- devctl_notify("DEVFS", "CDEV", "CREATE", data) [行545]

make_dev_alias_v() [sys/kern/kern_conf.c:958]
    +-- notify_create(dev, flags) [行993]

[DESTROY]
destroy_devl() [sys/kern/kern_conf.c:1090]
    +-- notify_destroy(dev) [行1159]
            +-- notify(dev, "DESTROY", MAKEDEV_WAITOK) [行560]
                    +-- devctl_notify("DEVFS", "CDEV", "DESTROY", data) [行545]

delist_dev_locked() [sys/kern/kern_conf.c:1196]
    +-- notify_destroy(dev) [行1212]
```

### データフロー図

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

cdev作成/破棄            --->  notify_create/notify_destroy  --->  notify()
                                                                      |
                                                                      +-- malloc(data)
                                                                      +-- memcpy("cdev=" + si_name)
                                                                      +-- devctl_notify()
                                                                      +-- free(data)
                                                                          |
                                                                          v
                                                                  /dev/devctl
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| kern_conf.c | `sys/kern/kern_conf.c` | ソース | notify(), notify_create(), notify_destroy()の実装 |
| conf.h | `sys/sys/conf.h` | ヘッダ | struct cdevの定義 |
| devctl.h | `sys/sys/devctl.h` | ヘッダ | devctl_notify()のプロトタイプ |
| subr_bus.c | `sys/kern/subr_bus.c` | ソース | devctl_notify()の実装 |
