タスクレットがある場合の割り込みハンドラーの登録
割り込みとタスクレットについては、EmBox社のブログの記事で明快に説明されているため、読者はすでにこの資料または類似の資料に精通していることが理解されます。
例として次の擬似コードを取り上げます。
struct my_struct { … struct tasklet_struct *tasklet; int irq; }; void tasklet_handler(…) { do_the_things_right(…); } irqreturn_t irq_handler(void *param) { struct my_struct *ms = param; … tasklet_schedule(&ms->tasklet); return IRQ_HANDLED; } int probe(…) { struct my_struct *ms; int err; ms = devm_kzalloc(…); … tasklet_init(&ms->tasklet, tasklet_handler, (unsigned long)ms); … err = devm_request_irq(ms->irq, irq_handler, …, ms); if (err) return err; return 0; } int remove(…) { struct my_struct *ms = …; … tasklet_kill(&ms->tasklet); }
気配りのある読者はすぐに次のように叫ぶだろう:「これが無限のサイクルにつながる競争条件だ!」そして彼は正しいだろう。
理由を見てみましょう。 タスクレットはソフト割り込み(softirq)のコンテキストで実行されるため、スケジューリング(
tasklet_schedule()
)とタスクの間に遅延が発生する可能性があります。 このとき、ユーザーが
rmmod my_module
、ドライバーをメモリーから削除するだけでよい場合があります。 もちろん、明示的に
tasklet_kill()
削除を呼び出します
tasklet_kill()
参照してください。ただし、割り込みハンドラはまだアクティブです。 devres APIを使用し、実行後にキューの順に削除することを計画しました
->remove()
!
治す方法は? はい、非常に簡単です、手を見てください:
int remove(…) { struct my_struct *ms = …; … devm_free_irq(ms->irq, ms); tasklet_kill(&ms->tasklet); }
オブジェクトの削除時にdevres APIを使用する場合、まさにそのまれなケースです。
キャラクターデバイスなどのドライバーを隠すものは何ですか?
ここで、次の擬似コードを検討してください。
int closecb(…) { struct my_struct *ms = …; do_something_on_close(ms, …); } struct file_ops fops = { .close = closecb, … }; int probe(…) { struct my_struct *ms; int err; ms = devm_kzalloc(…); … err = register_char_device(ms, "node_served_by_driver", &fops, …); if (err) return err; return 0; } int remove(…) { struct my_struct *ms = …; … }
次のシナリオを想像してください。
- ドライバがロードされ、デバイスに接続されていることを確認してください。
-
/dev/node_served_by_driver
を開き、デバイスが開いたままになるようにします。 - たとえば、次のコマンドを実行して、デバイスからドライバーを解放します。
echo our_device_name > /sys/bus/platform/drivers/our_driver_name/unbind
- 次に、デバイスを閉じます。
- カーネルの崩壊をお楽しみください。
なぜこれが起こっているのですか? はい。ステージ
->probe()
割り当てられたメモリ
->probe()
、デバイスが解放される
->probe()
解放されるためです。 そして、私たちはまだこのメモリを使用しています! この場合、デバイスドライバーは削除されず、削除できません。 デバイスを開いたプログラムによって保持され、明示的に閉じて削除されるまでメモリに残ります。
治療方法は? シンプル。 ドライバのファイル操作で
devm_kzalloc()
を使用して割り当てられたメモリを使用しないでください。オブジェクトの寿命を注意深く監視してください。 devres APIの作成者によると、 devプレフィックスはただそこにあるのではなく、リソースがユーザーからのイベントの処理ではなくハードウェアに直接関係していることを示すためです。
PS実際には、問題はより広く、将来のカーネルサミット2015での議論のために提起されています。
頑張ってデバッグしてください!