Linuxでファイルを使用するプロセスのPIDを取得する最も効率的な方法は何ですか

Linuxでファイルを使用するプロセスのPIDを取得する最も効率的な方法は何ですか

現在アクセス中のプロセスでそのファイルが開いていることを確認するために、要求に応じてクエリを実行するファイルがあるとします。すべてのPIDを繰り返すのは/proc/{PID}/fdリソース集約的なようです。同じことを行う他の方法はありますか?

答え1

これを実行できるツールは次のとおりです。fuser(出力PIDのみ)とlsof(多くのオプションと美しい出力)。

/proc/{PID}/fd のすべての PID を繰り返すのにリソースが多いようです。

とにかくこれがLinuxでは唯一の方法です。どのプロセスでファイルが開いているかを問い合わせるシステムコールはありません。しかし、直接これを実行しないでください。/proc/{PID}/fdこれは厳密に言えば、ファイルを開くだけであり、メモリマップされたファイル、ディレクトリを開くなどの他のケースはリストしないからです。

これは、ファイルを所有していてもルートで検索しない限り、他のユーザーとして実行されているプロセスがファイルを開くことができるかどうかわからないことを意味します。 (しかし、他のユーザーがファイルを見ることができず、ファイルが作成された後、またはシステムが再起動された後でもそのファイルを見ることができない場合、そのようなプロセスは存在しません。)

より一般的には、ユーザーが制御できないプロセスであり、これには、他の名前空間で実行されたり、追加の権限を持つプロセスなどの他の状況が含まれる場合があります。

答え2

使用lsof

たとえば、

[root@nagios01 objects]# lsof /var/lib/mysql/ib_logfile0 
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
mysqld  17699 mysql    9uW  REG    8,3  5242880 4850251 /var/lib/mysql/ib_logfile0

他の例:

merlin@uc-s4m75657:~/Experiments/test_ifxr$ lsof -a .
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
bash     8646 merlin  cwd    DIR  254,2     4096 421348 .
bash     9261 merlin  cwd    DIR  254,2     4096 421348 .
ssh     37456 merlin  cwd    DIR  254,2     4096 421348 .
bash    38639 merlin  cwd    DIR  254,2     4096 421348 .
lsof    38679 merlin  cwd    DIR  254,2     4096 421348 .
lsof    38680 merlin  cwd    DIR  254,2     4096 421348 .

ご覧のとおり、この場合、「現在のディレクトリ」(つまり、ポイントが指す場所)は6つのプロセスによって要求されます。

最後の例はまた、「PID」ではなく、同時に複数のPIDであってもよいことを示している。別の例は、複数のワーカープロセスから同時に読み取られることが多いPostgreSQLデータファイルです。

エディタでファイルを開くと、lsof出力には表示されません。たとえば、編集者はファイルをキャッシュし、開く/保存操作中にのみそのファイルに触れることができます。これはlsofに表示されます。

答え3

次の質問に対する私の意見に基づいて完全に終了していないプロセスを確認する必要がありますか?調査するテストコードを作成しました。

一部のスレッドが終了しました。別のスレッドを実行できるようにしながら、基本スレッドを終了させるプログラムのソースコード。

find_processes_using_file.clsofファイル名への参照を検索できるプログラムに似たソースコードです。コマンドラインオプションでは、次のことができます。

  1. 繰り返しPIDで検索/proc/<pid>/fd
  2. 繰り返しTIDで検索/proc/<pid>/task/<tid>/fd

テストハーネスの2つのインスタンスが起動しましたpartial_thread_exit。これにより、/dev/shm/IBV_MESSAGE_BW_IN_USE.first インスタンスと呼ばれる基本スレッドとは異なるスレッドが引き続き実行されます。

$ ./partial_thread_exit 
Blocker_Task tid 17995 running in pid 17994
Main thread in pid 17994 - press return to exit main thread only

別のスレッドが1つだけ実行されるように、2番目のインスタンスを残します。つまり、基本スレッドが終了しました。

$ ./partial_thread_exit 
Blocker_Task tid 13435 running in pid 13434
Main thread in pid 13434 - press return to exit main thread only

Main thread exiting...

PIDで検索を実行すると、通常のユーザーまたはrootとして実行しているかにかかわらず、メインスレッドで実行されているプロセスのみを見つけることができます。

$ time ./find_processes_using_file /dev/shm/IBV_MESSAGE_BW_IN_USE
/proc/17994/fd/3 -> /dev/shm/IBV_MESSAGE_BW_IN_USE

num_filenames_compared=2532 num_eacces_errors=260

real    0m0.019s
user    0m0.003s
sys 0m0.015s
$ time sudo ./find_processes_using_file /dev/shm/IBV_MESSAGE_BW_IN_USE
/proc/17994/fd/3 -> /dev/shm/IBV_MESSAGE_BW_IN_USE

num_filenames_compared=3435 num_eacces_errors=0

real    0m0.044s
user    0m0.011s
sys 0m0.031s

また、このオプションを使用してTIDで検索を実行すると、通常-tのユーザーまたはrootとして実行しているかにかかわらず、メインスレッドを持つプロセスとメインスレッドが終了したプロセスを見つけることができます。

$ time ./find_processes_using_file -t /dev/shm/IBV_MESSAGE_BW_IN_USE
/proc/13434/task/13435/fd/3 -> /dev/shm/IBV_MESSAGE_BW_IN_USE
/proc/17994/task/17994/fd/3 -> /dev/shm/IBV_MESSAGE_BW_IN_USE

num_filenames_compared=68327 num_eacces_errors=317

real    0m0.254s
user    0m0.036s
sys 0m0.217s
$ time sudo ./find_processes_using_file -t /dev/shm/IBV_MESSAGE_BW_IN_USE
/proc/13434/task/13435/fd/3 -> /dev/shm/IBV_MESSAGE_BW_IN_USE
/proc/17994/task/17994/fd/3 -> /dev/shm/IBV_MESSAGE_BW_IN_USE

num_filenames_compared=69500 num_eacces_errors=0

real    0m0.280s
user    0m0.048s
sys 0m0.228s

予想通り、TIDで検索するのは、以下のようにPIDで検索するよりも遅くなります。

  1. より多くのリアルタイムレポートtime
  2. 報告されるより大きな値は、num_filenames_comparedPID / TIDと一致する必要がある開いているファイルの数です。

明らかに、2つの間の絶対的な違いは、システムで実行されているTID / PIDの総数に依存します。

num_eacces_errors通常のユーザーとして実行すると、PID / TIDのディレクトリを開く試みが失敗し、表示された場合、値は0ではありません。つまり、特定のプロセスでどのファイルを開いたかを確認する権限は何度もありませんか?fdEACCES

答え4

カーネルには直接的な方法がないことを考慮すると、非常に原始的な方法があります。各ファイルが保存されているファイルシステムでは、pidになる可能性があるプロセス参照と参照カウントを作成する必要があります。これにはstruct inodeを変更することも含まれます。ただし、これには、参照とカウントをそれぞれ入力および削除する開始システム呼び出しと終了システム呼び出しを変更することが含まれます。構造体inodeは、現在の最後のアクセスや最後の変更タイムスタンプなどのタイムスタンプを維持し、この目的のために同じタイムスタンプを追跡できます。 fstatなどのシステムコールは、後でこのプロセス参照を返すように変更できます。これには、ファイルシステムやカーネルシステムコールを変更する必要があるなど、いくつかの欠点があります。ターゲットによって(組み込みデバイスの場合)、これが可能な場合があります。パブリックコールとシャットダウンコールによる参照の変更には同期が必要になる可能性があります。まれなケースを除いて、これは絶対に不可能です。これには、このパッチのカーネルアップグレードも含まれます。あまりにも多くのプロセスがファイルにアクセスし、参照リストが大きくなるなど、考慮する必要があるいくつかの要因があります。これはアプリケーション固有の問題です。

関連情報