解析したいのです/proc/net/tcp/
が、安全ですか?
/proc/
他のプロセス(またはOS自体)が同時にファイルを変更することを恐れずに、ファイルを開いて読み取る方法を教えてください。
sysctl
、これはどのように/proc/net/tcp/
ファイルを解析するのに役立ちますか?
解析したいのです/proc/net/tcp/
が、安全ですか?
/proc/
他のプロセス(またはOS自体)が同時にファイルを変更することを恐れずに、ファイルを開いて読み取る方法を教えてください。
sysctl
、これはどのように/proc/net/tcp/
ファイルを解析するのに役立ちますか?
回答:
一般的には違います。(したがって、ここでの答えのほとんどは間違っています。)必要なプロパティによっては、安全である可能性があります。ただし、内のファイルの一貫性について過度に想定すると、コードにバグが生じやすくなります/proc
。たとえば、それ/proc/mounts
が一貫したスナップショットであると想定したことから発生したこのバグを参照してください。
例えば:
/proc/uptime
誰かが別の回答で述べたように、完全にアトミックです-しかし、Linux 2.6.30以降、それは2年未満です。したがって、この小さくてささいなファイルでさえ、それまでは競合状態の影響を受け、ほとんどのエンタープライズカーネルに残っています。fs/proc/uptime.c
現在のソース、またはそれをアトミックにしたコミットを参照してください。2.6.30より前のカーネルでopen
はread
、少しファイルをファイルに入れることができます。その後、何度も戻ってくるread
と、最初に取得したものと一致しなくなります。(私はこれをデモンストレーションしました-楽しんでください)
/proc/mounts
単一のread
システムコール内でアトミックです。したがって、read
ファイル全体を一度に処理すると、システム上のマウントポイントの単一の一貫したスナップショットが得られます。ただし、複数のread
システムコールを使用する場合(ファイルが大きい場合)、通常のI / Oライブラリを使用し、この問題に特別な注意を払わないと、これが発生します。競合が発生します。状態。一貫性のあるスナップショットが得られないだけでなく、開始前に存在し、存在を停止しなかったマウントポイントが、表示されているものから失われる可能性があります。それが1 read()
に対してアトミックであることを確認するには、m_start()
中fs/namespace.c
を見て、マウントポイントのリストをガードするセマフォを取得m_stop()
します。read()
終わらせる。何が問題になるかを確認するには、昨年のバグ(上記でリンクしたものと同じ)を参照してください/proc/mounts
。
/proc/net/tcp
あなたが実際に求めているのは、それよりも一貫性が低いことです。それはですだけテーブルの各行内アトミック。これを確認するには、同じファイルlistening_get_next()
内net/ipv4/tcp_ipv4.c
とestablished_get_next()
そのすぐ下を見て、各エントリに対してロックが順番に取得するロックを確認します。行ごとの一貫性の欠如を示すのに便利な再現コードはありませんが、一貫性を保つためのロック(またはその他)はありません。考えてみると、これは理にかなっています。ネットワーキングはシステムの非常にビジーな部分であることが多いため、この診断ツールで一貫したビューを提示することは、オーバーヘッドに値しません。
続けて他の作品/proc/net/tcp
各行内の原子の中にバッファリングされseq_read()
、あなたが読むことができる、でfs/seq_file.c
。これにより、1 read()
つの行の一部になると、行全体のテキストがバッファーに保持され、次のread()
行が新しい行を開始する前にその行の残りを取得できるようになります。同じメカニズムが/proc/mounts
複数のread()
呼び出しを行った場合でも各行をアトミックに保つために使用されます。これは、/proc/uptime
新しいカーネルでアトミックを維持するために使用されるメカニズムでもあります。カーネルはメモリの使用に注意を払っているので、そのメカニズムはファイル全体をバッファリングしません。
ほとんどのファイルは同じ抽象化を使用しているため、のほとんどのファイルは/proc
と同じくらい一貫性があり/proc/net/tcp
、各行には、提供する情報の1つのエントリの一貫した画像がありますseq_file
。/proc/uptime
例が示すように、しかし、いくつかのファイルがまだ使用して、移行されていたseq_file
2009年として、最近、古いメカニズムを使用していて、そのレベルの原子性すら持っていないものはまだあると思います。これらの警告はめったに文書化されていません。特定のファイルについて、唯一の保証はソースを読み取ることです。
の場合は/proc/net/tcp
、それを読んで、恐れずに各行を解析できます。しかし、一度に複数の行から何らかの結論を導き出そうとすると、注意してください。他のプロセスとカーネルがあなたがそれを読んでいる間にそれを変更しており、おそらくバグを作成しています。
clock_gettime(2)
をCLOCK_MONOTONIC
(多分専門性があるが、私はここを知らないが、私は個人的にのみ起動の時以来でそれを見てきました)。Linuxの場合、オプションもありますsysinfo(2)
。
内のファイルが/proc
ユーザ空間での通常のファイルとして表示され、彼らは本当にファイルではなく、ユーザ空間から標準のファイル操作をサポートするエンティティ(ではありませんopen
、read
、close
)。これは、カーネルによって変更されているディスク上の通常のファイルを持っていることとはかなり異なることに注意してください。
カーネルが行うことは、内部の状態をsprintf
-like関数を使用して独自のメモリに出力することだけであり、read(2)
システムコールを発行するたびに、そのメモリがユーザー空間にコピーされます。
カーネルはこれらの呼び出しを通常のファイルの場合とはまったく異なる方法で処理します。つまり、読み取るデータのスナップショット全体がその時点で準備されている可能性があるopen(2)
一方で、カーネルは同時呼び出しが一貫してアトミックであることを確認します。私はそれをどこでも読んだことはありませんが、それ以外の場合は意味がありません。
私のアドバイスは、特定のUnixフレーバーでのprocファイルの実装を確認することです。これは実際には、標準によって管理されていない実装の問題(出力の形式と内容と同様)です。
最も単純な例はuptime
、Linux でのprocファイルの実装です。に提供されるコールバック関数でバッファ全体がどのように生成されるかに注意してくださいsingle_open
。
proc
ファイルはカーネルによって書き込み用に開かれた通常のファイルであると彼が思ったからです。
open()
は、多くのファイル、特に/proc/net/tcp
OPが関係しているについては間違っています。これらのセマンティクスを提供するコストを考えると、これは理にかなっています-これらのすべてのTCP接続を記録する内部データ構造をロックするなどの処理を行う必要があります。データをスキャンしてバッファにフォーマットするのに十分です。実際に起こることの詳細については私の答えを参照してください。
/ procは仮想ファイルシステムです。実際、カーネル内部の便利なビューを提供します。それを読むことは間違いなく安全です(それがここにある理由です)が、これらの仮想ファイルの内部は新しいバージョンのカーネルで進化する可能性があるため、長期的には危険です。
編集
Linuxカーネルdocのprocドキュメントで利用可能な詳細情報、1.4章ネットワーキング情報が時間とともにどのように進化するかについての情報を見つけることができません。私はそれがオープンで凍結されたと思ったが、明確な答えを得ることができない。
EDIT2
Sco docによると(linuxではありませんが、* nixのすべてのフレーバーがそのように動作すると確信しています)
プロセスの状態とその結果として/ procファイルの内容は瞬間的に変化する可能性がありますが、/ procファイルの単一のread(2)は、状態の「正しい」表現を返すことが保証されています。つまり、読み取りはプロセスの状態のアトミックスナップショット。このような保証は、実行中のプロセスの/ procファイルに適用される連続した読み取りには適用されません。さらに、as(address-space)ファイルに適用されるI / Oの原子性は特に保証されません。プロセスのアドレス空間の内容は、そのプロセスのLWPまたはシステム内の他のプロセスによって同時に変更される可能性があります。
proc
異なるカーネル間で同様の振る舞いをしているように扱うことを試みます(あるいは、それが存在すると仮定しても-Unixシステムでは必要ありません) )はあなたに傷ついた世界をもたらすでしょう。
/proc/net/tcp
、OPの主な関心事であるについては当てはまりません。むしろ、出力の個々の行のみがアトミックです。詳細については私の回答を参照してください。
Linuxカーネルのprocfs APIは、読み取りが一貫したデータを返すことを確認するためのインターフェースを提供します。のコメントを読んでください__proc_file_read
。大きなコメントブロックの項目1)は、このインターフェイスについて説明しています。
そうは言っても、返されたデータの整合性を確保するためにこのインターフェイスを正しく使用するかどうかは、特定のprocファイルの実装次第です。したがって、あなたの質問に答えるために:いいえ、カーネルは読み取り中のprocファイルの一貫性を保証しませんが、それらのファイルの実装に一貫性を提供する手段を提供します。
/proc
実際には一貫性を提供していません。詳細については私の回答を参照してください。
__proc_file_read()
非推奨ですseq_file
。長いブロックコメントのすぐ上に、やや苛立たしいコメント(Linusによる)を表示します。
現在、組み込みARMターゲットでドライバー開発を行っているので、Linux 2.6.27.8のソースが手元にあります。
linux-2.6.27.8-lpc32xx/net/ipv4/raw.c
たとえば、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
...
関数内でraw_sock_seq_show()
の階層の一部であるprocfsの機能を扱います。procfs読み取りは情報を更新するよりもはるかに一般的ではないため、テキストはファイルに対してread()
要求が行われるまで生成されません。これは/proc/net/tcp
合理的なメカニズムです。
一部のドライバー(mineなど)は、単一のでproc_read関数を実装しsprintf()
ます。コアドライバーの実装でさらに複雑になるのは、1回の読み取り中に中間のカーネルスペースバッファーに収まらない可能性がある非常に長い出力を処理することです。
64Kの読み取りバッファーを使用するプログラムでテストしましたが、proc_readがデータを返すために、システムでカーネルスペースバッファーが3072バイトになります。返されるテキストよりも多くのテキストを取得するには、前進ポインタを使用した複数の呼び出しが必要です。複数のI / Oが必要な場合に、返されるデータの整合性を保つための適切な方法がわかりません。確かにの各エントリ/proc/net/tcp
は自己矛盾がありません。横に並んだ線が異なる時間にスナップショットになる可能性があります。
ifstream
すると安全ではなくなりますが、使用read
すると安全になりますか?またはifstream
内部で使用しread
ますか?そして、あなたは何を提案しますか?
/proc/net/tcp
フォーマットされるかを説明するものであり、誰がそれを読み取るかとは完全に独立しています。
/proc/net/tcp
)異なる行は同じスナップショットからのものではありません。説明については、私の回答を参照してください。
未知のバグがない限り、/proc
破損したデータや古いデータと新しいデータの混合の読み取りにつながる競合状態はありません。この意味で、それは安全です。ただし、読み取ったデータの多くは、/proc
生成されてすぐに、さらには読み取り/処理に到達するまでに古くなっているという競合状態が依然として存在します。たとえば、プロセスはいつでも停止する可能性があり、新しいプロセスに同じpidを割り当てることができます。競合状態なしで使用できる唯一のプロセスIDは、自分の子プロセスです。ネットワーク情報(開いているポートなど)とのほとんどの情報についても同様/proc
です。のデータに依存することは悪い危険な習慣だと思います/proc
あなた自身のプロセスと潜在的にその子プロセスに関するデータを除いて、正確であること。もちろん、その他の情報を/proc
ユーザー/管理者に提供して、有益な情報やログ情報などを提供することも役立ちます。目的。
getpid()
)。それで、それは安全でなければなりません。
/proc
インタフェースが関係している、それらはすべて同じ弱点と強みを持っています。とにかく、OPはプロセスではなく、デバイスドライバー関連の情報について尋ねます。
N
が子プロセスのN
場合は、wait
-family関数を呼び出すまで、pid が同じ(おそらく終了した)プロセスを参照していることを確認できます。これにより、人種がなくなります。
/ 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()によってそれぞれ実装されます。