# 帳票設計書 18-nfsstat - NFS統計レポート

## 概要

本ドキュメントは、FreeBSD の `nfsstat` コマンドが出力するNFS統計レポートの設計仕様を記述する。

### 本帳票の処理概要

nfsstat は、NFSクライアントおよびサーバーの統計情報をレポートするユーティリティである。カーネルのNFSサブシステムから統計データを取得し、RPC操作カウント、キャッシュ統計、サーバー統計などをフォーマットして出力する。

**業務上の目的・背景**：NFSファイルシステムの運用管理において、クライアント・サーバー間の通信状況、キャッシュ効率、I/Oパフォーマンスの把握のために使用される。NFSパフォーマンスの監視、ボトルネックの特定、容量計画などの課題を解決する。

**帳票の利用シーン**：NFSサーバー/クライアントのパフォーマンス監視、キャッシュヒット率の分析、RPC操作のカウント確認、I/Oスループットの継続的監視（インターバルモード）などの場面で利用される。

**主要な出力内容**：
1. クライアントRPC操作カウント（Getattr, Setattr, Lookup, Read, Write等）
2. クライアントRPC情報（タイムアウト、無効応答、リトライ等）
3. クライアントキャッシュ情報（属性キャッシュ、ルックアップキャッシュ、BIOキャッシュ等）
4. サーバーRPC操作カウント
5. サーバーWrite Gathering統計
6. サーバーキャッシュ統計
7. インターバルモードでのI/O統計（KB/t, tps, MB/s, ms, ql, %b）

**帳票の出力タイミング**：管理者がコマンドラインから `nfsstat` コマンドを実行した際に標準出力に出力される。-w オプションで定期的な更新出力も可能。

**帳票の利用者**：NFSサーバー/クライアント管理者、ストレージ管理者

## 帳票種別

集計表（NFS統計情報）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | コマンドラインインターフェース | N/A | `nfsstat` コマンド実行 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（標準出力）/ libxo構造化出力（JSON/XML対応） |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | N/A（標準出力） |
| 出力方法 | 標準出力（stdout） |
| 文字コード | ロケール依存 |

## 帳票レイアウト

### レイアウト概要

通常モードではクライアント/サーバーの統計を表形式で出力。インターバルモード（-w/-d）ではI/O統計を繰り返し表示する。

```
┌──────────────────────────────────────────────────────────────┐
│ Client Info:                                                   │
│ Rpc Counts:                                                    │
│       Getattr      Setattr       Lookup     Readlink           │
│          Read        Write       Create       Remove           │
│        xxxxx        xxxxx        xxxxx        xxxxx            │
│ Rpc Info:                                                      │
│      TimedOut      Invalid    X Replies      Retries           │
│      Requests                                                  │
│ Cache Info:                                                    │
│    Attr Hits  Attr Misses    Lkup Hits  Lkup Misses            │
│   BioR Hits  BioR Misses   BioW Hits  BioW Misses             │
├──────────────────────────────────────────────────────────────┤
│ Server Info:                                                   │
│ (同様の構造)                                                   │
│ Server Write Gathering:                                        │
│ Server Cache Stats:                                            │
└──────────────────────────────────────────────────────────────┘
```

### クライアントRPC操作部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | Getattr | GetAttr操作カウント | ext_nfsstats.rpccnt[NFSPROC_GETATTR] | "%13ju" | 13文字 |
| 2 | Setattr | SetAttr操作カウント | ext_nfsstats.rpccnt[NFSPROC_SETATTR] | "%13ju" | 13文字 |
| 3 | Lookup | Lookup操作カウント | ext_nfsstats.rpccnt[NFSPROC_LOOKUP] | "%13ju" | 13文字 |
| 4 | Readlink | Readlink操作カウント | ext_nfsstats.rpccnt[NFSPROC_READLINK] | "%13ju" | 13文字 |
| 5 | Read | Read操作カウント | ext_nfsstats.rpccnt[NFSPROC_READ] | "%13ju" | 13文字 |
| 6 | Write | Write操作カウント | ext_nfsstats.rpccnt[NFSPROC_WRITE] | "%13ju" | 13文字 |
| 7 | Create | Create操作カウント | ext_nfsstats.rpccnt[NFSPROC_CREATE] | "%13ju" | 13文字 |
| 8 | Remove | Remove操作カウント | ext_nfsstats.rpccnt[NFSPROC_REMOVE] | "%13ju" | 13文字 |
| 9 | Rename | Rename操作カウント | ext_nfsstats.rpccnt[NFSPROC_RENAME] | "%13ju" | 13文字 |
| 10 | Link | Link操作カウント | ext_nfsstats.rpccnt[NFSPROC_LINK] | "%13ju" | 13文字 |
| 11 | Symlink | Symlink操作カウント | ext_nfsstats.rpccnt[NFSPROC_SYMLINK] | "%13ju" | 13文字 |
| 12 | Mkdir | Mkdir操作カウント | ext_nfsstats.rpccnt[NFSPROC_MKDIR] | "%13ju" | 13文字 |
| 13 | Rmdir | Rmdir操作カウント | ext_nfsstats.rpccnt[NFSPROC_RMDIR] | "%13ju" | 13文字 |
| 14 | Readdir | Readdir操作カウント | ext_nfsstats.rpccnt[NFSPROC_READDIR] | "%13ju" | 13文字 |
| 15 | RdirPlus | ReaddirPlus操作カウント | ext_nfsstats.rpccnt[NFSPROC_READDIRPLUS] | "%13ju" | 13文字 |
| 16 | Access | Access操作カウント | ext_nfsstats.rpccnt[NFSPROC_ACCESS] | "%13ju" | 13文字 |
| 17 | Mknod | Mknod操作カウント | ext_nfsstats.rpccnt[NFSPROC_MKNOD] | "%13ju" | 13文字 |
| 18 | Fsstat | Fsstat操作カウント | ext_nfsstats.rpccnt[NFSPROC_FSSTAT] | "%13ju" | 13文字 |
| 19 | Fsinfo | Fsinfo操作カウント | ext_nfsstats.rpccnt[NFSPROC_FSINFO] | "%13ju" | 13文字 |
| 20 | PathConf | PathConf操作カウント | ext_nfsstats.rpccnt[NFSPROC_PATHCONF] | "%13ju" | 13文字 |
| 21 | Commit | Commit操作カウント | ext_nfsstats.rpccnt[NFSPROC_COMMIT] | "%13ju" | 13文字 |

### クライアントRPC情報部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | TimedOut | タイムアウト数 | ext_nfsstats.rpctimeouts | "%13ju" |
| 2 | Invalid | 無効応答数 | ext_nfsstats.rpcinvalid | "%13ju" |
| 3 | X Replies | 予期しない応答数 | ext_nfsstats.rpcunexpected | "%13ju" |
| 4 | Retries | リトライ数 | ext_nfsstats.rpcretries | "%13ju" |
| 5 | Requests | リクエスト数 | ext_nfsstats.rpcrequests | "%13ju" |

### クライアントキャッシュ情報部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | Attr Hits | 属性キャッシュヒット | ext_nfsstats.attrcache_hits | "%13ju" |
| 2 | Attr Misses | 属性キャッシュミス | ext_nfsstats.attrcache_misses | "%13ju" |
| 3 | Lkup Hits | ルックアップキャッシュヒット | ext_nfsstats.lookupcache_hits | "%13ju" |
| 4 | Lkup Misses | ルックアップキャッシュミス | ext_nfsstats.lookupcache_misses | "%13ju" |
| 5 | BioR Hits | BIOリードキャッシュヒット | biocache_reads - read_bios | "%13ju" |
| 6 | BioR Misses | BIOリードキャッシュミス | ext_nfsstats.read_bios | "%13ju" |
| 7 | BioW Hits | BIOライトキャッシュヒット | biocache_writes - write_bios | "%13ju" |
| 8 | BioW Misses | BIOライトキャッシュミス | ext_nfsstats.write_bios | "%13ju" |
| 9 | BioRL Hits | BIO Readlinkキャッシュヒット | biocache_readlinks - readlink_bios | "%13ju" |
| 10 | BioRL Misses | BIO Readlinkキャッシュミス | ext_nfsstats.readlink_bios | "%13ju" |
| 11 | BioD Hits | BIO Readdirキャッシュヒット | biocache_readdirs - readdir_bios | "%13ju" |
| 12 | BioD Misses | BIO Readdirキャッシュミス | ext_nfsstats.readdir_bios | "%13ju" |
| 13 | DirE Hits | DirEOFキャッシュヒット | ext_nfsstats.direofcache_hits | "%13ju" |
| 14 | DirE Misses | DirEOFキャッシュミス | ext_nfsstats.direofcache_misses | "%13ju" |
| 15 | Accs Hits | Accessキャッシュヒット | ext_nfsstats.accesscache_hits | "%13ju" |
| 16 | Accs Misses | Accessキャッシュミス | ext_nfsstats.accesscache_misses | "%13ju" |

### インターバルモード（-d）出力部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | KB/t | 転送あたりKB | compute_new_stats() | "%5.2Lf" |
| 2 | tps | 秒あたり転送数 | compute_new_stats() | "%5.0Lf" |
| 3 | MB/s | 秒あたりMB | compute_new_stats() | "%7.2Lf" |
| 4 | ms | 転送あたりミリ秒 | compute_new_stats() | "%5.2Lf" |
| 5 | ql | キュー長 | srvstartcnt - srvdonecnt | "%3ju" |
| 6 | %b | ビジー率 | busytime / etime * 100 | "%3.0Lf" |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| NFS モジュールロード | nfscommonモジュールがロード済み | Yes（行228-229） |
| クライアント/サーバー選択 | -c（クライアント）-s（サーバー）で選択 | No（デフォルト: 両方） |

### ソート順

RPC操作名の固定順序で出力（ソートなし）

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| カーネルNFS統計 | 統計データ取得 | nfssvc(NFSSVC_GETSTATS) システムコール |
| NFSマウントオプション | -m オプション用 | nfssvc(NFSSVC_DUMPMNTOPTS) |

### テーブル別参照項目詳細

#### nfsstatsv1構造体

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| rpccnt[] | クライアントRPC操作カウント | nfssvc() | NFSPROCインデックス |
| rpctimeouts | RPCタイムアウト数 | nfssvc() | |
| rpcinvalid | 無効RPC数 | nfssvc() | |
| rpcunexpected | 予期しない応答数 | nfssvc() | |
| rpcretries | RPCリトライ数 | nfssvc() | |
| rpcrequests | RPCリクエスト数 | nfssvc() | |
| attrcache_hits/misses | 属性キャッシュ統計 | nfssvc() | |
| lookupcache_hits/misses | ルックアップキャッシュ統計 | nfssvc() | |
| biocache_reads/read_bios | BIOリードキャッシュ統計 | nfssvc() | |
| biocache_writes/write_bios | BIOライトキャッシュ統計 | nfssvc() | |
| srvrpccnt[] | サーバーRPC操作カウント | nfssvc() | NFSV4OPインデックス |
| srvcache_inproghits | サーバーキャッシュInProgress | nfssvc() | |
| srvcache_nonidemdonehits | サーバーキャッシュNon-Idem | nfssvc() | |
| srvcache_misses | サーバーキャッシュミス | nfssvc() | |
| srvbytes[] | サーバーI/Oバイト数 | nfssvc() | インターバルモード用 |
| srvops[] | サーバーI/O操作数 | nfssvc() | インターバルモード用 |
| srvduration[] | サーバーI/O時間 | nfssvc() | bintime型 |
| busytime | サーバービジー時間 | nfssvc() | bintime型 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| BioR Hits | biocache_reads - read_bios | N/A | 行357-358 |
| BioW Hits | biocache_writes - write_bios | N/A | 行360-361 |
| MB/s | total_bytes / (1024*1024) / etime | 小数2位 | 行576-586 |
| KB/t | total_bytes / 1024 / total_operations | 小数2位 | 行591-596 |
| tps | total_operations / etime | 整数 | 行597-602 |
| ms/transfer | srvduration / total_operations * 1000 | 小数2位 | 行604-609 |
| queue_len | srvstartcnt - srvdonecnt | N/A | 行611 |
| busy_pct | busytime_delta / etime * 100 | 整数 | 行579-585 |
| キャッシュヒット率 (sperc1) | hits * 100 / (hits + misses) | 整数% | 行516-528 |
| キャッシュヒット率 (sperc2) | (ttl - misses) * 100 / ttl | 整数% | 行530-543 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[nfsstatコマンド実行] --> B[xo_parse_args/オプション解析]
    B --> C{nfscommonモジュールチェック}
    C -->|未ロード| Z[エラー終了]
    C -->|ロード済| D{インターバルモード?}
    D -->|Yes| E[exp_sidewaysintpr]
    D -->|No| F{拡張出力モード?}
    F -->|Yes| G[exp_intpr NFSv4.1/4.2統計]
    F -->|No| H[intpr 標準統計出力]
    E --> I[ループ: nfssvc統計取得]
    I --> J[printhdr ヘッダー出力]
    J --> K[compute_new_stats 計算]
    K --> L[統計行出力]
    L --> M[sleep interval]
    M --> I
    G --> N[xo_emit出力]
    H --> N
    N --> O[xo_finish]
    O --> P[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| NFSモジュール未ロード | modfind("nfscommon") < 0 | "NFS client/server not loaded" | xo_err(1, ...) |
| 統計取得失敗 | nfssvc()戻り値 < 0 | "Can't get stats" | xo_err(1, ...) |
| -e/-E排他エラー | 両オプション同時指定 | "-e and -E are mutually exclusive" | xo_err(1, ...) |
| -m権限エラー | EPERM | "Only privileged users can use the -m option" | xo_errx(1, ...) |
| xo_finish失敗 | 出力完了エラー | "stdout" | xo_err(1, ...) |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 固定サイズ（nfsstatsv1構造体1つ） |
| 目標出力時間 | 即時（システムコール1回） |
| 同時出力数上限 | 制限なし |

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

- nfssvc()システムコールによるカーネル統計読み取りのため、適切な権限が必要
- -m オプション（マウントオプション表示）は特権ユーザーのみ使用可能
- -z オプションで統計をゼロクリア可能なため、運用上の注意が必要

## 備考

- libxo対応: JSON/XML/テキスト形式での構造化出力をサポート（行87, 144, 235-240）
- NFSSTAT_XO_VERSION = "1"（行127）
- -E オプションでNFSv4.1/4.2の拡張操作統計を表示（exp_intpr関数、行618-1093）
- -e オプションでNFSv4の拡張操作統計を表示（NFSv4.2なし）
- -d オプションでdevstat互換のI/O統計を表示（Read/Write/Commit別）
- -W オプションでワイドモード（ms/transfer列やCommit列を追加表示）
- -z オプションで統計取得後にゼロクリア
- -q オプションでタイトル抑制
- -M/-N オプションは非推奨（無視される）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | nfsport.h | `fs/nfs/nfsport.h` | nfsstatsv1構造体の定義（rpccnt[], srvrpccnt[], srvbytes[], srvops[], srvduration[], busytime等） |
| 1-2 | nfsproto.h | `fs/nfs/nfsproto.h` | NFSPROC_* / NFSV4OP_* 定数定義 |
| 1-3 | nfsstat.c | `usr.bin/nfsstat/nfsstat.c` | STAT_TYPE_READ/WRITE/COMMIT定義（行110-113）、statstruct配列（行119-123） |

**読解のコツ**: nfsstatsv1はNFSSTATS_V1バージョンの統計構造体で、rpccnt[]はクライアント操作、srvrpccnt[]はサーバー操作のカウンタである。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | nfsstat.c | `usr.bin/nfsstat/nfsstat.c` | main()（行129-246）：オプション解析、モード分岐 |

**主要処理フロー**:
1. **行144-148**: xo_parse_args()でlibxoオプション処理、xo_set_version()
2. **行150-219**: getopt("cdEesWM:mN:w:zq")によるオプション解析
3. **行228-229**: modfind("nfscommon")でNFSモジュールの存在確認
4. **行231-241**: インターバルモード/通常モードの分岐

#### Step 3: 通常モード出力を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | nfsstat.c | `usr.bin/nfsstat/nfsstat.c` | intpr()（行251-473）：クライアント/サーバー統計出力 |
| 3-2 | nfsstat.c | `usr.bin/nfsstat/nfsstat.c` | exp_intpr()（行618-1093）：NFSv4.1/4.2拡張統計出力 |

**主要処理フロー（intpr）**:
- **行256-265**: nfssvc(NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT)で統計取得
- **行266-386**: クライアント統計出力（operations、rpcs、cache）
- **行387-472**: サーバー統計出力（operations、write gathering、cache）

#### Step 4: インターバルモードを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | nfsstat.c | `usr.bin/nfsstat/nfsstat.c` | exp_sidewaysintpr()（行1121-1258）：定期更新統計出力 |
| 4-2 | nfsstat.c | `usr.bin/nfsstat/nfsstat.c` | compute_new_stats()（行553-612）：I/O統計計算 |
| 4-3 | nfsstat.c | `usr.bin/nfsstat/nfsstat.c` | compute_totals()（行1095-1112）：合計統計計算 |

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

```
main() [nfsstat.c:129]
    |
    +-- xo_parse_args() [libxoオプション処理]
    +-- xo_set_version() [バージョン設定]
    +-- getopt() [オプション解析]
    +-- modfind("nfscommon") [NFSモジュール確認]
    |
    +-- [通常モード]
    |   +-- intpr() [nfsstat.c:251]
    |   |   +-- nfssvc(NFSSVC_GETSTATS) [統計取得]
    |   |   +-- xo_emit() [libxo出力: クライアント統計]
    |   |   +-- xo_emit() [libxo出力: サーバー統計]
    |   +-- exp_intpr() [nfsstat.c:618]
    |       +-- nfssvc(NFSSVC_GETSTATS) [統計取得]
    |       +-- xo_emit() [NFSv4/4.1/4.2統計出力]
    |
    +-- [インターバルモード]
        +-- exp_sidewaysintpr() [nfsstat.c:1121]
            +-- nfssvc() [統計取得]
            +-- compute_totals() [nfsstat.c:1095]
            +-- printhdr() [nfsstat.c:475]
            +-- compute_new_stats() [nfsstat.c:553]
            +-- printf() [I/O統計出力]
            +-- sleep(interval) [待機]
```

### データフロー図

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

カーネルNFS統計 ──────> nfssvc() ────────────> xo_emit()  ──> stdout
(nfsstatsv1構造体)     [システムコール]       [libxo出力]     (テキスト/
                                                              JSON/XML)

[インターバルモード]
カーネルNFS統計 ──────> nfssvc() ──> compute_new_stats() ──> printf()
(nfsstatsv1構造体)     [差分取得]    [MB/s, KB/t, tps計算]   (テキスト)
                            |
                      compute_totals()
                      [全操作合計]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| nfsstat.c | `usr.bin/nfsstat/nfsstat.c` | ソース | メインプログラム（1259行） |
| nfsport.h | `fs/nfs/nfsport.h` | ヘッダ | nfsstatsv1構造体定義 |
| nfsproto.h | `fs/nfs/nfsproto.h` | ヘッダ | NFS操作定数定義 |
| nfssvc.h | `nfs/nfssvc.h` | ヘッダ | nfssvc()フラグ定義 |
| Makefile | `usr.bin/nfsstat/Makefile` | ビルド | ビルド設定（libxo依存） |
