/proc/net/tcp/
を解析したいのですが、安全ですか?
他のプロセス(またはOS自体)が同時にファイルを変更することを恐れないで、どのようにして/proc/
からファイルを開いて読み取る必要がありますか?
/proc
のファイルはユーザースペースでは通常のファイルとして表示されますが、実際にはファイルではなく、ユーザースペースからの標準ファイル操作をサポートするエンティティです(open
、read
、close
)。 これは、カーネルによって変更されるディスク上に通常のファイルを置くこととはまったく異なることに注意してください。
カーネルはsprintf
に似た関数を使用して内部状態を自身のメモリに出力し、read(2)
システムコールを発行するたびにそのメモリがユーザー空間にコピーされます。
カーネルは通常のファイルとはまったく異なる方法でこれらの呼び出しを処理します。つまり、open(2)
の時点で、読み込むデータのスナップショット全体を準備することができます。同時呼び出しは、一貫してアトミックです。私はどこにも読んでいないが、それは本当にそうする意味がありません。
私のアドバイスは、あなたの特定のUnixの味でprocファイルの実装を見てみることです。これは本当に標準によって支配されていない実装の問題(出力のフォーマットと内容のように)です。
最も単純な例は、 uptime
Linuxではprocファイルの実装になります。バッファ全体がsingle_open
に供給されたコールバック関数で生成される方法に注意してください。
/ procの仮想ファイルシステムである:実際には、それだけで、カーネル内部の便利なビューを提供します。これらの仮想ファイルの内部には、カーネルの新しいバージョンで進化することとして、それは(それはここだ、なぜだと)それを読むために間違いなく安全ですが、それは長期的に危険なのです。
[〜#〜] edit [〜#〜]
Linux kernel docのprocドキュメンテーション の第1.4章ネットワーキングで詳細な情報を入手できます。私は、それがオープンに凍結したと思ったが、明確な答えを持つことはできません。
EDIT2
Sco doc (Linuxではなく、* nixのすべてのフレーバーがそのように動作することはかなり確信している)
プロセスの状態とは/ procファイルの結果、内容がある状態の ``正気「」の表現を、返すことが保証された瞬間、/ procファイルの単一の読み取り(2)にインスタントから変更できますが、読み取りは次のようになりますプロセスの状態のアトミックスナップショット。そのような保証は実行中のプロセスのために/ procファイルに適用される読み取りの連続にも適用されません。任意のI/OがAS(アドレス空間)ファイルに適用するために加えて、原子性は、具体的に保証されません。プロセスのアドレス空間の内容は、そのプロセスのLWPまたはシステム内の他のプロセスによって同時に変更される場合があります。
Linuxカーネルのprocfs APIは、読み取りが一貫したデータを返すようにするためのインターフェースを提供します。 __proc_file_read
のコメントを読んでください。大きなコメントブロック内の項目1)は、このインタフェースを説明しています。
そうは言っても、もちろんこのインターフェイスを正しく使用して、返されるデータの一貫性を確保するのは、特定のprocファイルの実装次第です。したがって、あなたの質問に答えるために:いいえ、カーネルは読み取り中にprocファイルの一貫性を保証しませんが、それらのファイルの実装に一貫性を提供する手段を提供します。
Linux 2.6.27.8のソースは、組み込みのARMターゲットで現在ドライバー開発を行っているので便利です。
たとえば、934行目の..._linux-2.6.27.8-lpc32xx/net/ipv4/raw.c
_ファイルには、
_ 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
...
_
procfs処理関数の階層の一部である関数raw_sock_seq_show()
内。テキストは、read()
リクエストが_/proc/net/tcp
_ファイルで作成されるまで生成されません。これは、procfs読み取りが確実に一般的ではないため、合理的なメカニズムです。情報を更新します。
一部のドライバー(私のものなど)は、単一のsprintf()
でproc_read関数を実装します。コアドライバーの実装における余分な複雑さは、単一の読み取り中に中間のカーネルスペースバッファーに収まらない可能性のある非常に長い出力を処理することです。
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()によって実装されます。 。