を解析したいのです/proc/net/tcp/
が、安全ですか?
/proc/
他のプロセス (または OS 自体) が同時にファイルを変更することを恐れずに、ファイルを開いて読み取るにはどうすればよいですか?
一般的に、いいえ。(したがって、ここでの答えのほとんどは間違っています。)必要なプロパティによっては、安全かもしれません。しかし、.NET ファイルの一貫性について考えすぎると、コードにバグが発生しやすくなります/proc
。たとえば、一貫性のあるスナップショットであると想定して発生したこのバグを/proc/mounts
参照してください。
例えば:
/proc/uptime
誰かが別の回答で述べたように、完全にアトミックです-ただし、2年未満のLinux 2.6.30 以降のみです。そのため、この小さくて些細なファイルでさえ、それまでは競合状態の対象であり、ほとんどのエンタープライズ カーネルにはまだ残っています。fs/proc/uptime.c
現在のソース、またはそれをアトミックにしたコミットについては、を参照してください。2.6.30 より前のカーネルではopen
、ファイルの一部を取得できますが、read
後で何度も戻ってきた場合、read
得られる部分は最初の部分と矛盾します。(私はこれをデモンストレーションしたところです。楽しみのために自分で試してみてください。)
/proc/mounts
単一のread
システムコール内でアトミックです。したがって、read
ファイル全体を一度に取得すると、システム上のマウント ポイントの単一の一貫したスナップショットが得られます。ただし、複数のread
システム コールを使用する場合 (ファイルが大きい場合、通常の I/O ライブラリを使用し、この問題に特別な注意を払わないと、まさにこのようなことが起こります)、競合が発生する可能性があります。調子。一貫性のあるスナップショットを取得できないだけでなく、開始前に存在し、存在を停止したことのないマウント ポイントが表示されない可能性があります。それが 1 に対してアトミックであることを確認するにはread()
、m_start()
infs/namespace.c
を見て、マウントポイントのリストを保護するセマフォを取得することを確認しますm_stop()
。read()
終わらせる。何がうまくいかないかを確認するには、昨年のこのバグ(上記でリンクしたものと同じ) を参照してください/proc/mounts
。
/proc/net/tcp
、あなたが実際に求めているものは、それよりもさらに一貫性がありません。テーブルの各行内でのみアトミックです。これを確認するには、同じファイルのlistening_get_next()
innet/ipv4/tcp_ipv4.c
とestablished_get_next()
そのすぐ下を見て、各エントリで順番に実行されるロックを確認します。行から行への一貫性の欠如を示すのに便利な再現コードはありませんが、一貫性を保つロック (またはその他のもの) はありません。考えてみれば、これは理にかなっています。ネットワークは、システムの非常に忙しい部分であることが多いため、この診断ツールで一貫したビューを提示するオーバーヘッドは価値がありません。
/proc/net/tcp
各行内でアトミックを維持するもう 1 つの部分はseq_read()
、 で読み取ることができるのバッファリングですfs/seq_file.c
。これにより、read()
1 つの行を分割すると、行全体のテキストがバッファーに保持され、次のread()
行が新しい行を開始する前に残りの行を取得できるようになります。同じメカニズムを使用して、複数の呼び出し/proc/mounts
を行う場合でも各行をアトミックに保ちます。これは、新しいカーネルでアトミックを維持するために使用するメカニズムでもあります。カーネルはメモリの使用に慎重であるため、このメカニズムはファイル全体をバッファリングしません。read()
/proc/uptime
のほとんどのファイルは/proc
、少なくとも と同じくらい一貫性が/proc/net/tcp
あり、提供する情報が何であれ、各行は 1 つのエントリの一貫した図になります。これは、それらのほとんどが同じseq_file
抽象化を使用しているためです。ただし、/proc/uptime
例が示すように、一部のファイルは 2009 年まで使用するためにまだ移行されてseq_file
いました。古いメカニズムを使用していて、そのレベルの原子性すら持っていないものがまだあるに違いありません。これらの警告が文書化されることはめったにありません。特定のファイルについて、唯一の保証はソースを読み取ることです。
の場合/proc/net/tcp
、それを読んで各行を恐れることなく解析できます。しかし、一度に複数の行から何らかの結論を引き出そうとする場合は、注意してください。他のプロセスとカーネルは、それを読んでいる間にそれを変更しており、おそらくバグを作成しています.
の/proc
ファイルはユーザー空間では通常のファイルとして表示されますが、実際にはファイルではなく、ユーザー空間からの標準的なファイル操作をサポートするエンティティ ( open
、read
、close
) です。これは、カーネルによって変更されているディスク上の通常のファイルを持つこととはまったく異なることに注意してください。
カーネルが行うのは、-like 関数を使用して内部状態を独自のメモリに出力することだけであり、システム コールsprintf
を発行するたびに、そのメモリがユーザー空間にコピーされます。read(2)
カーネルはこれらの呼び出しを通常のファイルの場合とはまったく異なる方法で処理します。つまり、読み取るデータのスナップショット全体がその時点で準備できている可能性がありますがopen(2)
、カーネルは同時呼び出しが一貫してアトミックであることを確認します。私はそれをどこでも読んだことがありませんが、そうでなければ意味がありません。
私のアドバイスは、特定の Unix フレーバーでの proc ファイルの実装を調べることです。これは実際には (出力の形式や内容と同様に) 実装上の問題であり、標準によって管理されていません。
uptime
最も単純な例は、Linux での proc ファイルの実装です。に提供されたコールバック関数でバッファ全体がどのように生成されるかに注意してくださいsingle_open
。
/proc は仮想ファイル システムです。実際には、カーネルの内部構造を簡単に表示できます。それを読むことは間違いなく安全ですが (それがここにある理由です)、これらの仮想ファイルの内部がカーネルの新しいバージョンで進化する可能性があるため、長期的には危険です。
編集
詳細については、Linux kernel doc の proc ドキュメントの1.4 章 Networking を参照してください。開くとフリーズしたと思ったのですが、明確な答えがありません。
EDIT2
Sco docによると(Linuxではありませんが、* nixのすべてのフレーバーがそのように動作すると確信しています)
プロセスの状態とその結果として /proc ファイルの内容は瞬時に変化する可能性がありますが、/proc ファイルの単一の read(2) は状態の「正常な」表現を返すことが保証されています。プロセスの状態のアトミック スナップショット。そのような保証は、実行中のプロセスの /proc ファイルに適用される連続読み取りには適用されません。さらに、アトミック性は、as (アドレス空間) ファイルに適用される I/O に対して明確に保証されていません。プロセスのアドレス空間の内容は、そのプロセスの LWP またはシステム内の他のプロセスによって同時に変更される可能性があります。
Linux カーネルの procfs API は、読み取りが一貫したデータを返すことを確認するためのインターフェイスを提供します。のコメントを読んでください__proc_file_read
。大きなコメント ブロックの項目 1) は、このインターフェイスについて説明しています。
そうは言っても、返されるデータが一貫していることを確認するためにこのインターフェイスを正しく使用することは、もちろん特定の proc ファイルの実装次第です。したがって、あなたの質問に答えるには: いいえ、カーネルは読み取り中の proc ファイルの一貫性を保証しませんが、それらのファイルの実装が一貫性を提供する手段を提供します。
Linux 2.6.27.8 のソースが手元にあるのは、現在組み込み ARM ターゲットでドライバー開発を行っているからです。
ファイル ... linux-2.6.27.8-lpc32xx/net/ipv4/raw.c
at 行 934 には、たとえば
seq_printf(seq, "%4d: %08X:%04X %08X:%04X"
" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
i, src, srcp, dest, destp, sp->sk_state,
atomic_read(&sp->sk_wmem_alloc),
atomic_read(&sp->sk_rmem_alloc),
0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
出力する
[wally@zenetfedora ~]$ cat /proc/net/tcp
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 017AA8C0:0035 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 15160 1 f552de00 299
1: 00000000:C775 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 13237 1 f552ca00 299
...
関数を処理するprocfsraw_sock_seq_show()
の階層の一部である関数内。ファイルのリクエストが行われるまで、テキストは生成されません。procfsの読み取りは、情報の更新よりもはるかに一般的ではないため、妥当なメカニズムです。read()
/proc/net/tcp
一部のドライバー (私のものなど) は、単一の proc_read 関数を実装していsprintf()
ます。コア ドライバーの実装がさらに複雑になるのは、1 回の読み取りで中間のカーネル空間バッファーに収まらない可能性のある非常に長い出力を処理することです。
64K の読み取りバッファーを使用するプログラムでこれをテストしましたが、proc_read がデータを返すためにシステムで 3072 バイトのカーネル空間バッファーが発生します。それ以上のテキストを返すには、ポインタを進める複数の呼び出しが必要です。複数の i/o が必要な場合に、返されるデータの一貫性を保つ正しい方法がわかりません。確かに、各エントリ/proc/net/tcp
は自己一貫性があります。並んだ線が異なる時点でスナップショットされている可能性があります。
未知のバグを除けば、/proc
破損したデータや古いデータと新しいデータの混在を引き起こすような競合状態はありません。そういう意味では安心です。/proc
ただし、読み取ったデータの多くは、生成されるとすぐに古くなる可能性があり、さらに読み取り/処理するまでにはさらに古いという競合状態があります。たとえば、プロセスはいつでも終了する可能性があり、新しいプロセスに同じ pid を割り当てることができます。競合状態なしで使用できる唯一のプロセス ID は、自分の子プロセスです。同じことがネットワーク情報 (開いているポートなど) にも当てはまり、ほとんどの情報は/proc
. データに依存することは悪いことであり、危険な行為だと思います。/proc
自身のプロセスと、場合によってはその子プロセスに関するデータを除いて、正確であること。もちろん/proc
、情報提供/ロギングなどのために、ユーザー/管理者に他の情報を提示することは依然として有用な場合があります。目的。
/proc ファイルから読み取る場合、カーネルは、その proc ファイルの「読み取り」関数として事前に登録されている関数を呼び出しています。__proc_file_read
fs/proc/generic.c の関数を参照してください。
したがって、proc 読み取りの安全性は、読み取り要求を満たすためにカーネルが呼び出す関数と同じくらい安全です。その関数が触れてバッファに返すすべてのデータを適切にロックする場合、その関数を使用して読み取ることは完全に安全です。/proc/net/tcp への読み取り要求を満たすために使用されるような proc ファイルは、しばらく前から存在しており、綿密なレビューを受けているため、要求できるほど安全です。実際、多くの一般的な Linux ユーティリティは、proc ファイルシステムからの読み取りと、別の方法での出力のフォーマットに依存しています。(私の頭の上から、「ps」と「netstat」がこれを行うと思います)。
いつものように、私の言葉を鵜呑みにする必要はありません。ソースを見て、恐怖を和らげることができます。次の proc_net_tcp.txt のドキュメントは、/proc/net/tcp の「読み取り」関数がどこにあるのかを示しているため、その proc ファイルから読み取りを行うときに実行される実際のコードを見て、何もないことを自分で確認できます。ロックの危険。
このドキュメントでは、インターフェイス /proc/net/tcp および /proc/net/tcp6 について説明します。
これらのインターフェースは、tcp_diag を優先するため非推奨であることに注意してください。これらの /proc インターフェイスは、現在アクティブな TCP 接続に関する情報を提供し、それぞれ net/ipv4/tcp_ipv4.c の tcp4_seq_show() と net/ipv6/tcp_ipv6.c の tcp6_seq_show() によって実装されます。