printkデッドロックとは、Linuxカーネルのprintk
関数を呼び出してログを印刷するときに、システム内の複数のスレッドが互いにリソースを解放するのを待ち、続行できない状況を指します。 printkデッドロックは、システムアプリケーションおよびサービスの動作に悪影響を及ぼし、カーネルのダウンタイムを引き起こす。 したがって、システムの安定性と信頼性を確保するには、最も早い機会にprintkデッドロックを防止および解決することが重要です。 このトピックでは、printkデッドロックが原因でAlibaba Cloud Linuxでダウンタイムの問題が発生する理由と、問題を解決する方法について説明します。
問題の説明
Alibaba Cloud Linuxオペレーティングシステムのカーネルでダウンタイムの問題が発生した場合、vmcoreファイルを分析すると、次のような症状が現れます。
ダウンタイムの問題が発生すると、vmcoreという名前のダンプファイルが生成されます。 vmcoreファイル内のカーネルログを表示し、"Call Trace:" で始まるコールトレース情報を取得して原因を分析し、問題のトラブルシューティングを行うことができます。
dmesgコマンドの実行後に表示されるカーネルログには、スケジューリングとwork_queueに関連する
警告
ログが含まれています。特定のプロセスのコールトレース情報には、次の特性があります。
最後に呼び出された関数は、
_raw_spin_lock
、queued_spin_lock_slowpath
、raw_spin_rq_lock_netsted
関数などのスピンロックを取得することを目的としています。システムは、
printk
関数、console_unlock
関数、およびスピンロックを順番に取得する前述の関数を呼び出します。
原因
この問題は、Linuxコミュニティのprintkメカニズムが使用されているときに発生するデッドロックによって発生します。 printkデッドロックは発生する可能性は低いですが、Alibaba Cloud Linux 3のカーネルバージョン5.10.134-16.3
で発生する可能性があります。
なぜprintkデッドロックが発生するのですか?
カーネルがwork_queueまたはrunqueue (rq) のスピンロックを保持した後にprintk関数を呼び出してカーネルログを印刷する場合、printkは基盤となるDirect Rendering Manager (DRM) ドライバを呼び出してwork_queueまたはrqを再度ロックしようとします。 その結果、システムのダウンタイム問題を引き起こすprintkデッドロックが発生します。
説明DRMドライバがオブジェクトをロックしようとする方法については、drm/fb-helper: Add fb_deferred_io supportパッチを参照してください。
スケジューリングとwork_queueに関連する
警告
ログが表示されるのはなぜですか。カーネルがwork_queueまたはrqのスピンロックを保持し、printk関数を呼び出してログを印刷すると、printkはスケジューリングとwork_queueに関する警告メッセージをカーネルログに印刷します。 このため、demesgコマンドの出力には、スケジューリングとwork_queueの警告ログが含まれています。
Alibaba Cloud Linux 3のカーネルバージョン
5.10.134-16.3
がprintkデッドロックの確率が高いのはなぜですか。スケジューリングとwork_queueの
警告
ログは、いくつかのシナリオでのみ出力されます。 Alibaba Cloud Linux 3のカーネルバージョン5.10.134-16.3
では、Linuxコミュニティからバックポートされる非同期スロットル解除機能に回帰欠陥があります。 この欠陥により、警告
ログが印刷される可能性が高まり、Alibaba Cloud Linux 3でprinttkデッドロックが発生する可能性が高くなります。
影響を受けるバージョン
printkデッドロックは、LinuxコミュニティによってリリースされたLinux 4.10のdrm/fb-helper: Add fb_deferred_io support patchで発生する既知の問題です。
問題は、Alibaba Cloud Linuxのカーネルバージョン
4.19
および5.10
に存在します。Alibaba Cloud Linux 3のカーネルバージョン
5.10.134-16.3
では、この問題の可能性が高くなります。
解決策
次のコマンドを実行してログレベルを変更し、printk関数が警告
ログをシリアルポートに印刷しないようにします。
ジャーナルシステムがシリアルポートでログをキャプチャするが、dmesgコマンドを実行して印刷されたカーネルログはキャプチャしない場合は、ログレベルを変更する際に注意してください。
ログレベルを変更すると、シリアルポートの
警告
ログが失われますが、dmesgコマンドを使用して出力されるカーネルログの警告
ログには影響しません。
sysctl -w kernel.printk="<console_loglevel> <default_message_loglevel> <minimum_console_loglevel> <default_console_loglevel>"> /etc/sysctl.conf
kernel.printk
パラメーターの有効値:
console_loglevel
: ログレベルを指定します。 printk関数は、指定されたログレベルよりも高いログレベルを持つログをシリアルポートに出力します。default_message_loglevel
: デフォルトのログレベルを指定します。 ログレベルが指定されていない場合、デフォルトレベルのログを印刷するためにprintk関数が呼び出されます。minimum_console_loglevel
:console_loglevel
パラメーターの最小値を指定します。default_console_loglevel
:console_loglevel
パラメーターのデフォルト値を指定します。
Linuxは、カーネルログの8つのログレベルを定義します。 より低いログレベルは、より高い優先度を示す。 警告
ログがシリアルポートに出力されないようにするには、console_loglevel
パラメーターを4以下の値に設定することを推奨します。 サンプルコマンド:
sysctl -w kernel.printk="4 4 1 7" >> /etc/sysctl.conf
次のログレベルを使用できます。
#define LOGLEVEL_EMERG 0 /* system is unusable */
#define LOGLEVEL_ALERT 1 /* action must be taken immediately */
#define LOGLEVEL_CRIT 2 /* critical conditions */
#define LOGLEVEL_ERR 3 /* error conditions */
#define LOGLEVEL_WARNING 4 /* warning conditions */
#define LOGLEVEL_NOTICE 5 /* normal but significant condition */
#define LOGLEVEL_INFO 6 /* informational */
#define LOGLEVEL_DEBUG 7 /* debug-level messages */