[Linux] Translating Process ID between Namespaces

原文はこちら。
https://blogs.oracle.com/linux/translating-process-id-between-namespaces

pid(プロセスID)を異なる名前空間の間で変換する課題に関する、Oracle Linuxのカーネル開発者であるNagarathnam Muthusamyによる寄稿です。これはLinuxカーネルの名前空間サポートには現在ない機能ですが、CDBを使ってOracle Databaseのマルチテナント利用を実現するために重要な機能です。
Oracle Database 12c Feature: Multitenant Database
http://www.oracle.com/technetwork/articles/database/multitenant-part1-pdbs-2193987.html
LinuxカーネルのプロセスID(PID)名前空間機能は、プロセス・グループ間で分離を提供する効果的な方法で、さまざまなコンテナの実装で利用されてきました。プロセス間の強力な分離が求められていますが、システム内の他のプロセスの活動やリソースの利用状況を監視したいプロセスが常に存在します。PID名前空間の各々には独自のPIDシーケンスがあり、プロセスIDと独自のPID名前空間との間で相互変換するために、階層の先頭からプロセスを監視するためのプロセスが必要です。Linuxカーネルには、結果PIDを返すさまざまなAPIセットがありますが、これらのAPIはいずれもPID変換に使用できます。以下でその方法をご紹介します。

SCM_CREDENTIALS:

送信側は、SCM_CREDENTIALSメッセージを送受信して、自身の名前空間のPIDをターゲットの名前空間のPIDに変換できます。この方法の欠点は、PID変換に対するソケット通信チャネルが必要で、その管理オーバーヘッドが増える点です。このメソッドは、ルートでない、もしくはCAP_SYS_ADMINを持たない限り、送信側が他のプロセスのPIDを変換できません。
unix - sockets for local interprocess communication
http://man7.org/linux/man-pages/man7/unix.7.html

/proc/<pid>/status file

/proc/<pid>/statusファイルは、異なる名前空間のプロセスに関連付けられたPIDを見つける方法を提供します。親名前空間からの、親名前空間から子名前空間へのPID変換は、所望のレベルで所望のPIDを見つけるために、親名前空間内のすべてのstatusファイルを検索する必要があります。
proc - process information pseudo-filesystem
http://man7.org/linux/man-pages/man5/proc.5.html
Patchwork [resend,v10,1/2] /proc/PID/status: show all sets of pid according to nslogin
https://patchwork.kernel.org/patch/5861791/

shmctl(..,IPC_STAT,..), msgctl(..,IPC_STAT,..)

共有メモリのIPC_STATが提供する構造体shmid_dsには、以下の2要素が含まれています。
pid_t           shm_cpid;    /* PID of creator */
pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
メッセージキューのIPC_STATが提供する構造体struct msqid_dsには、 以下の2要素が含まれています。
pid_t           msg_lspid;    /* PID of last msgsnd(2) */
pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
これらの要素のPIDは、呼び出し元のPID名前空間に変換されます。名前空間にかかわらず、プロセス共有リソースの利用状況を監視するために監視側がこれらのPIDを利用できますが、共有メモリやメッセージキューを作成せずに、これらのAPIを汎用的なPID変換のために利用することはできません。
shmctl - System V shared memory control
http://man7.org/linux/man-pages/man2/shmctl.2.html
msgctl - System V message control operations
http://man7.org/linux/man-pages/man2/msgctl.2.html

semctl(..,GETPID,..)

semctlのGETPIDコマンドは、セマフォに対して最後の操作を実行したプロセスのPIDを提供します。shmctlおよびmsgctlと同様に、これはセマフォのユーザを監視する優れた方法ですが、セマフォを作成しないで汎用PID変換に使用することはできません。shmctlとsemctlはアップストリームのLinuxカーネル4.17で修正されました。この機能は、旧リリースでは使用できない可能性がありますが、Oracle UEKに取り込まれる予定です。
semctl - System V semaphore control operations
http://man7.org/linux/man-pages/man2/semctl.2.html

fcntl(..,F_GETLK,..)

fcntlのF_GETLKコマンドは、ファイルロック保持中のプロセスに関する情報を提供します。この情報は、呼び出し元の名前空間に変換されます。異なるPID名前空間を通じた変換を必要とするプロセスは、ロック可能な共通の場所にダミーファイルを作成できます。fcntlを使ったファイルロック所有者に関する問い合わせは、呼び出し元の名前空間の下で観測されるプロセスの変換後のPIDを返します。確かにファイルはどのIPCメカニズムよりも軽量ですが、PID変換のためだけにシステム内のすべてのプロセスのファイル作成とクリーンアップという、追加のオーバーヘッドが必要です。

Is there any cleaner way?

通常、監視プロセスやシステム内の他のプロセスでPID変換が必要な場合、前述の方法のいずれかを使用してこの問題を回避できます。上記のオプションのいずれもあなたのユースケースを満足しない場合ですが、その状況はあなただけではありません。

私はKonstantinと協力して、translate_pidという新しいシステムコールを使いPID変換機能を提供する古いパッチを復活させました。この議論は以下のURLで追いかけることができます。このリンクには、APIの以前のバージョンへのポインタもあります。
[PATCH RFC v5] pidns: introduce syscall translate_pid
https://lkml.org/lkml/2018/4/4/677
このAPIは以下の関数シグネチャを伴って動き始めました。
pid_t getvpid(pid_t pid, pid_t source, pid_t target)
ここで強調されている大きな問題は、名前空間を識別するためのPIDの使用でした。PIDを使うすべてのAPIは、PIDの再利用に関わる競合状態の影響を受けやすいのですが、Linuxカーネルには、それらのインタフェースが設計されたときにリソースを識別する優れた方法がなかったために、多くの既存のPIDベースのインタフェースしか持っていませんでした。この提案は次のAPIにつながります。
pid_t translate_pid(pid_t pid, int source, int target);
ここで、sourceとtargetは、ソースとターゲットの名前空間の/proc/<pid>/ns/pidファイルを指すファイル記述子です。このAPIの大きな問題は、すべてのPID変換のためにファイルの開閉に関する追加ステップです。このAPIは、PID変換を必要とするが、/proc/<pid>/ns/pidファイルを開く権限を持たないユースケースでも利用できません。

このブログを書いている時点で議論中のAPIは、以下のように両方の世界の最善を取り込もうとしています。
pid_t translate_pid(pid_t pid, int source_type, int source, int target_type, int target);
ここで、以下のように *type 引数を使って、ソースとターゲットを解釈する方法を変更します。
TRANSLATE_PID_CURRENT_PIDNS //現在のPID名前空間、引数を使わない
TRANSLATE_PID_TASK_PIDNS //task pid-ns、引数はtask pid
TRANSLATE_PID_FD_PIDNS //pidns fd、引数はファイル記述子
APIが完成すると、他の既存のメソッドの問題を回避しない、PIDを変換するためのよりクリーンなメソッドが用意されることでしょう。

0 件のコメント:

コメントを投稿