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

Re: deadlock on ptrace



斉藤@densanと言います。

> 今後使われない(?) pmapを追いかけても仕方なさそうですし、
> 次の正式リリースを待つのも手でしょうか。

gdbを使っているとあまりによくhung-upするので、pmap を直してみました。

変更内容をpatch形式で示します。しかし、
patchを当てて下さいと言う意味では決してありません。
以前のsys/uvm/uvm_fault.cに加えた変更よりは、マトモだと思います。

変更の主旨ですが、kernel_mapを二重にlockする場合があり、
LK_SHAREDとLK_EXCLUSIVEの両方の場合があります。

pmap_alloc_pv()からuvm_km_zalloc(kernel_map, NBPG)が呼ばれ、
pmap_free_pv()からuvm_km_free(kernel_map, (vaddr_t)pvp, NBPG)呼ばれます。

trap.cの変更では、pmap_alloc_pv()の呼出元が、kernel_mapをlockする前に、
pmap_alloc_pv_before()の新しい関数を呼び出して、予め必要なページをallocします。

pmap_free_pv()では、kernel_mapのlock状態を見て、
uvm_km_free()を呼ばないようにしてます。
ここで飛ばしても問題は発生しないと読んだんですが。

--- pmap.c2	Tue Feb 19 17:11:08 2002
+++ pmap.c	Wed Feb 20 18:33:51 2002
@@ -98,6 +98,7 @@
 LIST_HEAD(pv_page_list, pv_page) pv_page_freelist;
 int pv_nfree;
 int pv_pcnt;
+void pmap_alloc_pv_before __P((void));
 static struct pv_entry *pmap_alloc_pv __P((void));
 static void pmap_free_pv __P((struct pv_entry *));
 void pmap_pinit __P((pmap_t));
@@ -738,8 +739,8 @@
 	bcopy((caddr_t)src, (caddr_t)dst, NBPG);
 }
 
-static struct pv_entry *
-pmap_alloc_pv()
+void
+pmap_alloc_pv_before()
 {
 	struct pv_page *pvp;
 	struct pv_entry *pv;
@@ -749,14 +750,23 @@
 		if (!(pvp = (struct pv_page *)uvm_km_zalloc(kernel_map, NBPG)))
 			panic("pmap_alloc_pv: uvm_km_zalloc() failed");
 		pv_pcnt++;
-		pvp->pvp_pgi.pgi_freelist = pv = &pvp->pvp_pv[1];
-		for (i = NPVPPG - 2; --i >= 0; pv++)
+		pvp->pvp_pgi.pgi_freelist = pv = &pvp->pvp_pv[0];
+		for (i = NPVPPG - 1; --i >= 0; pv++)
 			pv->pv_next = pv + 1;
 		pv->pv_next = 0;
-		pv_nfree += pvp->pvp_pgi.pgi_nfree = NPVPPG - 1;
+		pv_nfree += pvp->pvp_pgi.pgi_nfree = NPVPPG;
 		LIST_INSERT_HEAD(&pv_page_freelist, pvp, pvp_pgi.pgi_list);
-		pv = pvp->pvp_pv;
-	} else {
+	}
+}
+
+static struct pv_entry *
+pmap_alloc_pv()
+{
+	struct pv_page *pvp;
+	struct pv_entry *pv;
+	
+	pmap_alloc_pv_before();
+	{
 		pv_nfree--;
 		pvp = pv_page_freelist.lh_first;
 		if (--pvp->pvp_pgi.pgi_nfree <= 0)
@@ -778,11 +788,14 @@
 	case 1:
 		LIST_INSERT_HEAD(&pv_page_freelist, pvp, pvp_pgi.pgi_list);
 	default:
+	free:
 		pv->pv_next = pvp->pvp_pgi.pgi_freelist;
 		pvp->pvp_pgi.pgi_freelist = pv;
 		pv_nfree++;
 		break;
 	case NPVPPG:
+		if (kernel_map->lock.lk_sharecount || kernel_map->lock.lk_exclusivecount)
+			goto free;
 		pv_nfree -= NPVPPG - 1;
 		pv_pcnt--;
 		LIST_REMOVE(pvp, pvp_pgi.pgi_list);

--- trap.c2	Wed Feb 20 16:13:16 2002
+++ trap.c	Wed Feb 20 16:23:34 2002
@@ -63,6 +63,7 @@
 volatile int want_resched;
 
 static int fix_unaligned __P((struct proc *p, struct trapframe *frame));
+void pmap_alloc_pv_before __P((void));
 
 void
 trap(frame)
@@ -104,6 +105,8 @@
 				ftype = VM_PROT_READ | VM_PROT_WRITE;
 			else
 				ftype = VM_PROT_READ;
+			if (map == kernel_map)
+				pmap_alloc_pv_before();
 			if (uvm_fault(map, trunc_page(va), 0, ftype)
 			    == KERN_SUCCESS) {
 				/*