パスはファイルのように見えるが、操作の意味は大きく異なる。tmpfs はアプリケーションデータを保存し、procfs は状態を生成し、sysfs への書き込みはデバイスを制御する可能性がある。これらのインターフェースを読む際は、まず責任範囲、寿命、リソースの境界を確認する。
| 説明すべき現象 | 参照箇所 |
| 読み取ったテキストは整合性のあるスナップショットか? | 第 1~2 節:分類と seq_file |
| なぜ sysfs 属性をエディタで保存できないのか? | 第 3~4 節:制御とトレーシングインターフェース |
| 一時ファイルがスワップに触れるのはなぜか? | 第 5 節:tmpfs と memfd |
| デバイスノード、初期ルート、実際のマウントの違いは? | 第 6~7 節:起動と位置特定 |
1. 責任範囲で分類する
| ファイルシステム | 一般的な責任 | 重要な境界 |
| procfs | プロセスとシステム情報、一部制御インターフェース | PID namespace、権限、マウントオプションの影響を受ける |
| sysfs | デバイスモデルおよびカーネルオブジェクト属性 | 属性インターフェースは ABI に準拠する必要があり、内部構造を無制限にエクスポートするものではない |
| debugfs | 開発・デバッグ用インターフェース | 安定したユーザー ABI を保証しない場合が多く、完全に無効化されている可能性もある |
| tracefs | トレース設定とデータ | ファイルによってスナップショット、ブロッキングストリーム、消費型レコードなど異なる |
| tmpfs | 一時ファイル、共有メモリ関連ストレージ | メモリを占有し、設定に応じてスワップ可能。容量と inode 制限がある |
| ramfs | 単純なメモリファイルストレージ | 通常のファイルのように書き戻して解放できず、tmpfs のようなサイズ上限もない |
| devtmpfs | カーネルデバイスノード | ノードが存在しても、デバイスが現在利用可能である、またはアクセス権があることを保証しない |
/proc/filesystems 内の nodev は「すべての擬似ファイルシステム」に対する正確なラベルではない。NFS などのブロックデバイスをマウントソースとしないファイルシステムも nodev としてリストされる場合がある。また、これはマウントオプションの nodev とは等価ではない。nodev オプションは、デバイス特殊ファイルをデバイスとして使用することを制限するものである。
2. procfs:テキスト出力の背後にはオブジェクトの寿命がある
/proc/<pid>/status、maps、fd はそれぞれタスクの状態、仮想メモリマップ、ファイルディスクリプタに関連する。これらのオブジェクトは読み取り中に変化したり、終了したりする可能性がある。PID は再利用されるため、同じ数値パスを複数回読み取っても、必ずしも同じ長寿命のオブジェクトを操作しているわけではない。安定したプロセス参照が必要な場合は、ディレクトリ名を恒久的な ID として扱うのではなく、pidfd などのインターフェースを理解する必要がある。
/proc/self はアクセスするユーザーに応じて解決される。コンテナが認識するプロセスの集合は、proc マウントに関連付けられた PID namespace に依存する。権限や hidepid なども可視性に影響を与える。すべての /proc システム統計が自動的にコンテナ固有の統計になるわけではない。/proc/<pid>/mem は厳格なアクセスチェックの対象であり、ptrace 権限を回避する代替チャネルとして一般化できるものではない。procfs ドキュメント を参照。
seq_file は出力の整理を管理するが、システムを凍結はしない
seq_file はセグメント化された出力、バッファリング、シーク位置の管理を行い、反復可能なオブジェクトからテキストを生成するのに適している。start/next/stop/show などのコールバックは、依然として対応するオブジェクトの同期と参照ルールに従う必要がある。バッファ不足や seek の場合、再走査が発生する可能性があるため、show には再現不可能なビジネスロジックの副作用を含めるべきではない。
単一の cat コマンドでも、複数の read 呼び出しで構成されることがある。出力の複数のフィールドが同じ整合性のあるスナップショットから来ているかどうかは、実装に依存し、「seq_file を使用している」という事実だけでグローバルな原子性の観測を推論することはできない。ユーザーランドでの解析では、キーによる識別を行い、新しいフィールドの追加を許容すべきであり、行番号が永遠に特定のものを指すと依存すべきではない。seq_file インターフェース を参照。
以下は、seq_file を再利用して定数のみを出力する独立したカーネルモジュールの例である。これは登録、失敗時の戻り値、および削除のペアリングを示しており、可変なドライバオブジェクトは読み取らない。
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
static struct proc_dir_entry *entry;
static int kb_show(struct seq_file *seq, void *unused)
{
seq_puts(seq, "format_version 1\n");
seq_puts(seq, "example_value 42\n");
return 0;
}
static int __init kb_init(void)
{
entry = proc_create_single("kb_seq_example", 0444, NULL, kb_show);
return entry ? 0 : -ENOMEM;
}
static void __exit kb_exit(void)
{
proc_remove(entry);
}
module_init(kb_init);
module_exit(kb_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Constant seq_file teaching example");
対応する Kbuild の動作は obj-m += kb_seq_example.o である。教学用のチェックでは、オブジェクトファイルのみをコンパイルすればよく、モジュールのロードは必要ない。定数を動的オブジェクトに変更した場合でも、削除時の並行コールバック、バックグラウンドタスク、およびプライベートデータの寿命を依然として処理しなければならない。このフレームワークをコピーしただけでは、それらの参照関係が自動的に解決されるわけではない。
3. sysfs と kernfs:オブジェクト属性は通常の編集可能なファイルではない
sysfs は、カーネルオブジェクトをディレクトリ、属性、リンクとして提示する。/sys/devices はデバイスの階層を表し、bus/class などのビューはリンクによって整理されることが多い。1つの kobject は通常ディレクトリに対応し、属性がファイルに対応する。各 kobject が直接1つの属性ファイルに等しいとは言えない。
| 操作 | 属性インターフェースの実際の動作 |
| show | 現在の値を生成する |
| store | 入力を検証し、対応する変更を実行する |
| 成功を返す | インターフェースの処理結果を報告するが、任意のデバイス操作が完全に終了したことを必ずしも意味しない |
テキスト属性は通常、簡潔で明確な値を使用する。バイナリ属性には独自の契約がある。サイズ、シーク、および繰り返し読み取りも、インターフェースに従って解釈する必要がある。sysfs の設計 を参照。
kernfs は、sysfs、cgroupfs などにツリーとファイル操作の基盤を提供し、6.x よりも以前から存在する。ノードの削除と実行中の操作の調整も行わなければならないため、「RCU 付きのディレクトリツリー」としてのみ理解してはならない。そのリンク機能は主にシンボリックリンクであり、通常のディスクファイルシステムのような任意のハードリンクセマンティクスを持つと一般化してはならない。フレームワークが提供する同期は、ドライバのプライベート状態の保護に代わるものではない。
ユーザーランドで制御属性に書き込む際は、ドキュメントで規定された入力形式全体を使用し、エディタの一時ファイルと rename を使った保存モードを用いてはならない。属性の安定性と単位を理解するには、ファイル名から推測するのではなく、Documentation/ABI/ 内の対応するエントリを優先して参照すべきである。
4. debugfs と tracefs:観測にもオーバーヘッドと状態変化がある
debugfs は開発者がデータをエクスポートするのに便利だが、インターフェースはバージョンや設定に応じて変化する可能性がある。本番環境でのトラブルシューティングでは、権限と手順に従って使用できる。「不安定な ABI」だからといって、本番環境で絶対に読み取れないわけではない。debugfs ノードを作成するドライバは、ユーザーがオープンした参照を保持している場合のデバイス削除やデータ解放も考慮する必要がある。
tracefs はトレース機能のために独立したマウントを提供する。trace と trace_pipe の読み取り方法は異なる。後者は新しいイベントを待機してデータを消費できるため、cat がすぐに終了しない場合がある。イベントスイッチ、バッファサイズ、または tracing_on を変更すると、システムのトレース状態が変更される。特定のノードを公開するかどうかは、設定、マウント、および権限によって制限される。debugfs および ftrace ドキュメント を参照。
5. tmpfs:一時とは、スペースを占有しないこと、またはディスクに触れないことを意味しない
tmpfs は shmem メカニズムを使用してユーザーデータを保存する。通常のファイルシステムのデータブロックバックエンドはないが、スワップが許可された設定ではコンテンツをスワップアウトできる。したがって、「データは RAM のみにあり、ディスクに現れない」というのは一般的な保証ではない。アンマウントまたは再起動後、スワップに書き込まれていたり fsync が呼び出されたりしていたとしても、永続ファイルシステムのように回復することを期待してはならない。
4つの数量:クォータ、論理長、残留およびスワップアウト
| 数量 | 意味 |
| size=、nr_inodes= | 容量と inode 数の上限。すべてのメモリを予約するものではない |
| ファイルの論理サイズ | スパース拡張後、非常に大きくなる可能性があるが、すべてのコンテンツページを割り当てるわけではない |
| 割り当て済みページと残留量 | どのくらいの内容が割り当てられ、現在 RAM にあるか |
| スワップアウト量 | コンテンツの一部はスワップバックアップによって引き受ける可能性がある |
マウントクォータ、cgroup、およびシステム負荷が複合的に作用するため、マウントにまだ余裕があっても、メモリ割り当てが必ずしも成功するわけではない。tmpfs ドキュメント を参照。
/dev/shm には POSIX 共有メモリオブジェクトを保持するために tmpfs がマウントされることが多い。/run には実行状態が保存されることが多く、/tmp は tmpfs である場合もあればディスクディレクトリである場合もあり、実際の mountinfo を確認する必要がある。System V 共有メモリ、匿名共有マップなども関連する shmem メカニズムを使用するが、すべてが /dev/shm 内の可視な名前に対応するわけではない。
以下では、まずファイルの長さを変更し、その後数ページのみを書き込む。ページをスワップアウトした後、論理長、割り当て量、RAM、およびスワップを照合する。RAM を解放しても、ファイルの割り当て済みコンテンツの帳簿は同時に消去されない。
図を準備しています
ファイルは8ページあるのに、なぜ8ページのRAMを占有しないのか?スパース長、ファイルシステム割り当てクォータ、RAM残留、スワップバックアップは、4つの異なる帳簿である。スワップアウトは残留を減らすものの、tmpfs のコンテンツ割り当てクォータを解放しない。
{"id":"tmpfs-four-quantities","title":"ファイルは8ページあるのに、なぜ8ページのRAMを占有しないのか?","summary":"スパース長、ファイルシステム割り当てクォータ、RAM残留、スワップバックアップは、4つの異なる帳簿である。スワップアウトは残留を減らすものの、tmpfs のコンテンツ割り当てクォータを解放しない。","height":1000,"html":"<h2 data-i18n=\"heading\"></h2><p class=\"intro\" data-i18n=\"intro\"></p><div class=\"control\"><label for=\"length\" data-i18n=\"length\"></label><output for=\"length\" id=\"length-value\"></output><input id=\"length\" type=\"range\" min=\"0\" max=\"8\" value=\"8\" step=\"1\"></div><p class=\"caption\" data-i18n=\"pages\"></p><div class=\"choices\"><button data-page=\"0\">0<span id=\"p0\"></span></button><button data-page=\"1\">1<span id=\"p1\"></span></button><button data-page=\"2\">2<span id=\"p2\"></span></button><button data-page=\"3\">3<span id=\"p3\"></span></button><button data-page=\"4\">4<span id=\"p4\"></span></button><button data-page=\"5\">5<span id=\"p5\"></span></button><button data-page=\"6\">6<span id=\"p6\"></span></button><button data-page=\"7\">7<span id=\"p7\"></span></button></div><div class=\"actions\"><button id=\"write\" data-i18n=\"write\"></button><button id=\"read\" data-i18n=\"read\"></button><button id=\"swap\" data-i18n=\"swap\"></button></div><div class=\"metrics\"><div><span data-i18n=\"logical\"></span><strong id=\"logical\"></strong></div><div><span data-i18n=\"allocated\"></span><strong id=\"allocated\"></strong></div><div><span data-i18n=\"resident\"></span><strong id=\"resident\"></strong></div><div><span data-i18n=\"swapped\"></span><strong id=\"swapped\"></strong></div></div><div class=\"band\"><i id=\"ram-band\"></i><i class=\"second\" id=\"swap-band\"></i></div><div class=\"copy\"><p id=\"explanation\" role=\"status\"></p><p class=\"reserve\" aria-hidden=\"true\" data-i18n=\"note\"></p><p class=\"reserve\" aria-hidden=\"true\" data-i18n=\"full\"></p></div><div class=\"actions\"><button id=\"reset\" data-i18n=\"reset\"></button></div><details class=\"scope\"><summary data-i18n=\"scopeLabel\"></summary><p data-i18n=\"scope\"></p></details>","css":".intro{margin:8px 0 18px;color:var(--muted);font-size:14px}.caption,.hint{font-size:12px;color:var(--muted);margin-top:12px}.control{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 12px;align-items:center;margin:14px 0;font-size:13px}.control label{font-size:13px}.control output{color:var(--accent);min-width:5em;text-align:right;font-variant-numeric:tabular-nums}.control input{grid-column:1/-1;width:100%;margin:0}.presets{display:flex;gap:4px;align-items:stretch}.presets button{flex:1 1 0;min-width:0;overflow-wrap:anywhere;font-size:13px}.actions{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}.actions button{flex:1;min-width:0;font-size:13px;min-height:42px}.copy{display:grid;font-size:14px;margin:16px 0}.copy>*{grid-area:1/1;margin:0}.reserve{visibility:hidden}.scope{margin-top:14px;color:var(--muted);font-size:12px}.scope summary{padding:8px 0;cursor:pointer}.scope p{margin-top:10px}.two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.card{border:1px solid var(--rule);border-radius:9px;padding:14px;min-width:0}.card header{font-size:14px;font-weight:600;margin-bottom:10px}.card button{font-size:12px;width:100%;min-width:0}.card small{display:block;font-size:12px;color:var(--muted)}.card code{font-size:12px;overflow-wrap:anywhere}.metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.metrics>div{border-left:2px solid var(--accent);padding-left:10px;min-width:0}.metrics span{display:block;min-height:3.2em;color:var(--muted);font-size:12px}.metrics strong{font-size:23px;display:block;font-weight:500;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.formula{border-top:1px solid var(--rule);padding-top:12px;margin-top:14px;font-size:13px;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.value{font:500 20px var(--viz-font-ui)}.legend{display:flex;flex-wrap:wrap;gap:6px 14px;font-size:12px;color:var(--muted);margin:12px 0}.legend span:before{content:'';display:inline-block;width:8px;height:8px;border-radius:2px;background:var(--accent);margin-right:6px}.legend .second:before{background:var(--second)}.check{display:flex;align-items:center;gap:8px;font-size:13px;margin:12px 0}.check input{width:16px;height:16px;flex-shrink:0;accent-color:var(--accent)}select,input[type=text],input[type=number]{background:var(--paper);color:var(--ink);font:inherit;font-size:13px;padding:10px;border:1px solid var(--rule);border-radius:7px;max-width:100%;min-width:0}select{width:100%;min-height:42px}.band{height:20px;display:flex;background:var(--surface);border-radius:4px;overflow:hidden}.band i{height:100%;display:block;background:var(--accent);transition:width .25s}.band i.second{background:var(--second)}button:disabled{cursor:default}.status{font-size:13px;min-height:4.8em}.mono{font-family:var(--viz-font-mono);font-variant-numeric:tabular-nums}.muted{color:var(--muted)}\n@media(max-width:480px){.two{gap:8px}.card{padding:12px 9px}.actions button,.presets button{font-size:12px}.metrics strong{font-size:20px}.metrics{gap:8px}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important;animation:none!important}}\n.track-row{margin:16px 0}.track-row>span{display:block;font-size:12px;color:var(--muted);margin-bottom:7px}.track{display:flex;gap:5px;min-width:0}.cell{flex:1;min-width:0;min-height:48px;border:1px solid var(--rule);border-radius:5px;background:var(--surface);display:flex;align-items:center;justify-content:center;text-align:center;padding:5px 3px;font-size:12px;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.cell.on{background:var(--accent-soft);border-color:var(--accent)}.cell.gold{background:var(--second-soft);border-color:var(--second)}.cell.empty{border-style:dashed;color:var(--muted)}.cell.error{border-color:var(--second);text-decoration:line-through}.choices{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin:14px 0}.choices button{min-width:0;padding:10px 4px;font-size:12px;overflow-wrap:anywhere}.choices button[aria-current=true]{border-color:var(--accent);background:var(--accent-soft)}.relation{display:grid;grid-template-columns:minmax(0,1fr) 28px minmax(0,1fr);align-items:center;gap:6px;margin:12px 0}.relation .cell{min-height:72px}.relation>i{text-align:center;font-style:normal;color:var(--accent)}.readout{font-size:13px;white-space:pre-line;min-height:6.4em;overflow-wrap:anywhere}.plot{position:relative;border-left:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:8px 0;margin:18px 0}.plot-row{height:28px;position:relative;margin:4px 0;background:var(--surface)}.plot-row i{position:absolute;inset-block:5px;background:var(--accent);min-width:2px;transition:width .2s,left .2s}.plot-row b{position:relative;padding:4px 6px;font:11px/28px var(--viz-font-ui);background:var(--paper);border-radius:3px}.axis{display:flex;justify-content:space-between;font-size:11px;color:var(--muted)}\n\n.choices button{min-height:7.5em}.choices span{display:block;font-size:11px;min-height:4.8em;margin-top:5px}.choices button.outside{opacity:.5}.choices button.swapped{border-style:dashed;border-color:var(--second)}","js":"const $=s=>document.querySelector(s);const set=(id,v)=>$('#'+id).textContent=v;const t=k=>viz.t(k);function cells(id,values){$('#'+id).replaceChildren(...values.map(v=>{const e=document.createElement('div');e.className='cell '+(v.cls||'');e.textContent=v.text;e.title=v.title||v.text;return e;}));}function pressed(mode){document.querySelectorAll('[data-mode]').forEach(e=>e.setAttribute('aria-pressed',String(e.dataset.mode===mode)));}let chosen=0,pages=Array(8).fill(null),length=8,message='note';function draw(){const allocated=pages.filter(Boolean).length,ram=pages.filter(x=>x==='ram').length,swap=allocated-ram;set('length-value',length+' P');for(let i=0;i<8;i++){const e=document.querySelector('[data-page=\"'+i+'\"]');e.setAttribute('aria-current',String(i===chosen));e.classList.toggle('outside',i>=length);e.classList.toggle('swapped',pages[i]==='swap');set('p'+i,t(i>=length?'outside':pages[i]==='swap'?'swapState':pages[i]??'hole'));}set('logical',length*4);set('allocated',allocated+' / 4');set('resident',ram);set('swapped',swap);$('#ram-band').style.width=ram/4*100+'%';$('#swap-band').style.width=swap/4*100+'%';$('#read').disabled=$('#write').disabled=chosen>=length;$('#swap').disabled=chosen>=length||pages[chosen]!=='ram';set('explanation',t(message));}$('#length').oninput=()=>{length=+$('#length').value;for(let i=length;i<8;i++)pages[i]=null;message='note';draw();};document.querySelectorAll('[data-page]').forEach(e=>e.onclick=()=>{chosen=+e.dataset.page;draw();});$('#write').onclick=()=>{if(pages[chosen]===null&&pages.filter(Boolean).length>=4)message='full';else{pages[chosen]='ram';message='note';}draw();};$('#read').onclick=()=>{if(pages[chosen]==='swap')pages[chosen]='ram';message='note';draw();};$('#swap').onclick=()=>{pages[chosen]='swap';message='note';draw();};$('#reset').onclick=()=>{pages=Array(8).fill(null);length=8;$('#length').value=8;message='note';draw();};draw();","audio":false,"strings":{"allocated":"割り当てクォータ / 4ページ","full":"4ページのクォータが満杯であり、この空洞に新しいコンテンツを割り当てられない。まずファイルの長さを短縮して割り当て済みページを解放する。スワップアウトはこのクォータを空にできない。","heading":"ファイルは8ページあるのに、なぜ8ページのRAMを占有しないのか?","hole":"空洞","intro":"ページの選択位置をクリックし、書き込み、読み取り、またはスワップアウトを行う。論理長を変更する。割り当て量と残留量がなぜ一緒に変化しないか観察する。","length":"論理長 / ページ","logical":"論理長 / KiB","note":"ファイルを短縮すると末尾のコンテンツが削除される。再延長すると空洞のみが回復する。スワップアウトはコンテンツと割り当てクォータを保持し、スワップアウトされたページを読み取ると、それは RAM に戻る。","outside":"ファイル末尾の外側","pages":"ページの位置とコンテンツ状態","ram":"残留","read":"選択したページを読み取る","reset":"リセット","resident":"RAM残留 / ページ","scope":"8ページのアドレス範囲、最大4ページの割り当て、ページあたり4 KiB。未書き込みの空洞は0を読み出し、モデルは永続コンテンツの割り当てをカウントしない。実際の読み取りでも一時的なメモリオーバーヘッドが発生する可能性がある。スワップが許可され、容量が十分であれば、inode/cgroup のクォータとメタデータを省略する。シミュレーションのみで、実際の負荷メモリを要求しない。","scopeLabel":"モデル範囲と規約","swap":"選択したページをスワップアウト","swapState":"スワップアウト","swapped":"スワップアウト / ページ","write":"選択したページに書き込む"}}
memfd:fd によって管理されるメモリファイル
通常の memfd_create() は、匿名のメモリファイルを提供し、mmap や fd の渡しが可能であり、seals を使用して後続の変更を制限できる。MFD_HUGETLB は異なるバックアップモードに属しており、通常の shmem パスと混同してはならない。seals はオブジェクトレベルの制約であり、単に現在の fd を読み取り専用に書き換えるものではない。既に書き込み可能な共有マップが存在する場合などは、特定の seal の追加に影響を与える可能性がある。
import errno
import fcntl
import os
fd = os.memfd_create("kb-memfd", os.MFD_CLOEXEC | os.MFD_ALLOW_SEALING)
try:
assert os.write(fd, b"hello") == 5
seals = (fcntl.F_SEAL_WRITE | fcntl.F_SEAL_GROW |
fcntl.F_SEAL_SHRINK | fcntl.F_SEAL_SEAL)
fcntl.fcntl(fd, fcntl.F_ADD_SEALS, seals)
assert fcntl.fcntl(fd, fcntl.F_GET_SEALS) & seals == seals
assert os.pread(fd, 5, 0) == b"hello"
try:
os.pwrite(fd, b"X", 0)
except OSError as error:
assert error.errno == errno.EPERM
else:
raise AssertionError("sealed file unexpectedly writable")
print("memfd コンテンツは読み取り可能、seal により書き換えが阻止される:通過")
finally:
os.close(fd)
この例ではファイルシステムをマウントせず、恒久的なパスも作成しない。また、永続化や秘密データがスワップアウトされないという保証も示していない。インターフェースの詳細は memfd_create(2) を参照。
6. ramfs、rootfs、initramfs、および devtmpfs
| 名称 | 起動またはストレージにおける役割 |
| ramfs | メモリファイルストレージ。通常の書き戻しバックエンドおよび tmpfs 式の容量制限がない |
| rootfs | 起動に必要な特殊なルートマウント。設定に応じて ramfs または tmpfs を使用する |
| initramfs | 初期ルートに解凍されるアーカイブコンテンツおよび起動環境 |
ramfs への継続的な書き込みはシステムメモリを消費する可能性がある。initramfs は、ramfs/tmpfs と並列のディスクファイルシステムフォーマットではない。rootfs と initramfs を参照。
デバイスノード:ノードの作成とハードウェアの起動は別々に考える
devtmpfs は、カーネルデバイスモデルによって基本的なデバイスノードが管理される。udev などのユーザーランド機能は、イベントに基づいて権限、名前付けリンク、およびその他のルールを適用する。ノードの基本的な作成は udev のみに帰属させることはできず、すべての起動パスでカーネルが /dev を自動的にマウントするとも限らない。カーネル設定と initramfs のユーザーランドがマウントプロセスに影響を与える。
デバイスノードは、タイプやデバイス番号などのメタデータであり、オープンすると対応するドライバに入る。ノードを削除してもハードウェアが停止するわけではなく、ノードを再作成してもドライバが存在することが保証されるわけではない。nodev マウント制限、権限、およびデバイスアクセス制御は、認可判断に参加し続ける。
7. 観測を必要な範囲に限定する
| 問題 | 優先して確認すべき箇所 |
/tmp が実際にメモリ上にあるかどうか | findmnt -T /tmp および実際のマウントオプション |
| tmpfs が一杯だがシステムにまだメモリがある | マウント容量、inode クォータ、論理/実際の使用量 |
/proc/<pid> で予期したタスクが表示されない | PID namespace、プロセスの寿命、権限、および hidepid |
| sysfs 属性が存在しない | デバイスインスタンス、ドライババインディング、カーネル設定、および ABI ドキュメント |
| tracefs の読み取りが終了しない | ブロッキング/消費型ストリームを読み取っていないか、イベントがまだ生成されていないか |
findmnt、df -t tmpfs、および定点での属性読み取りは、通常、最初の事実構築に十分である。/sys/devices の全体を再帰的に走査するのは高価であり、混乱を招く。動的インターフェースに対しては、拡張子が通常のファイルに似ているからといって、バッチ読み書きしてはならない。ソースコードは fs/proc/、fs/sysfs/、fs/kernfs/、mm/shmem.c、および drivers/base/devtmpfs.c を沿って段階的に特定できる。