[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[netbsd,08859] lockmgr() で panic



清原です
# 昨日送信したメールが、設定の関係ではねられたようですので、再送
# しています。2 通受信した場合は無視して下さい。
# こっちは微妙に文章を捕捉しています。


NetBSD の IEEE1394 に不満を感じて、FreeBSD の firewire のドライバを
移植できないかと思っていろいろやってみてるのですが、わからないこと
が出てきたので、ご存知でしたらお教え下さい。

FreeBSD の fwohci(4) や firewire(4) は動くようになったっぽいのですが、
IEEE1394 の HDD を刺すと panic するという現象が出ます。調べてみると
(FreeBSD の)firewire の fwdma.c 内 fwdma_malloc() で DMA 用のメモリ
を確保していたので、そこを bus_dmamem_{alloc,map},bus_dmamap_{create,
load} に置き換えてみたのですが、bus_dmamem_map() から呼ばれる先にある
lockmgr() 内で panic していました。

  メモリ確保部の変更前 (FreeBSD)
	bus_dma_tag_create()
	bus_dmamem_alloc()
	bus_dmamap_load()

  変更後
	bus_dmamem_alloc()
	bus_dmamem_map()
	bus_dmamap_create()
	bus_dmamap_load()


# KASSERT() が無効になっているので lockmgr() まで呼ばれますが、有効
# になっている場合は uvm_map.c の uvm_map() で落ちるはずです。

kern_lock.c ---
int
#if defined(LOCKDEBUG)
_lockmgr(__volatile struct lock *lkp, u_int flags,
    struct simplelock *interlkp, const char *file, int line)
#else
lockmgr(__volatile struct lock *lkp, u_int flags,
    struct simplelock *interlkp)
#endif
{
        int error;
        pid_t pid;
        lwpid_t lid;
        int extflags;
        cpuid_t cpu_id;
        struct lwp *l = curlwp;

 略

        if (extflags & LK_SPIN) {
                pid = LK_KERNPROC;
                lid = 0;
        } else {
                if (l == NULL) {
                        if (!doing_shutdown) {
                                panic("lockmgr: no context");   <--- ここで
                        } else {
 
---

uvm_map.c ---
int
uvm_map(struct vm_map *map, vaddr_t *startp /* IN/OUT */, vsize_t size,
    struct uvm_object *uobj, voff_t uoffset, vsize_t align, uvm_flag_t flags)
{
  略

        KASSERT(doing_shutdown || curlwp != NULL ||	<---有効ならここで
            (map->flags & VM_MAP_INTRSAFE));

---



curlwp が NULL になっている理由は、callout_reset() で呼ばれた関数の中から
bus_dmamem_map() を呼び出しているからなのです。
その上、bus_dmamem_map() で確保するメモリは kernel_map (uvm_map の最初の
引数)のメモリで、これは VM_MAP_INTRSAFE ではないと思っています。

curlwp が「何者」で何時 NULL になるのか、まだ理解できていないのですが、
「現在実行中のプロセスに関する情報」へのポインタであると聞いたので、試し
に次のようなプログラムを複数実行して CPU 使用率が 100% の状態にしてから
HDD を刺してみると panic しませんでした。

負荷をかけるプログラム ---
int
main(int argc, char *argv[])
{
	while (1);
}
---


つまり callout_reset() の処理中だと、CPU が IDLE 状態 (curlwp が NULL) に
なっていることがあるので、ここでは bus_dmamem_map() が使えないようだという
ことがわかってきました。


そこでお伺いしたいのですが、このような場合の解決策はどのようになるのでし
ょうか?

	1. bus_dmamem_{alloc,map}() を使わずに malloc() で確保したメモリ
	   を代用する
	   -> kernel の空間は常に物理メモリ上にあるという前提で。

	2. callout 内で bus_dmamem_map() を実行しないで、kthread を作成
	   してそっちでやる
	   -> kthread からだと curlwp がどこかを指しているであろうから。

	3. その他の方法 ?


宜しくお願い致します。

# この後の CAM -> scsipi(4) への対応がきつそうな気が…
--
kiyohara