From owner-freebsd-arm@FreeBSD.ORG Sat Mar 21 00:10:29 2015 Return-Path: Delivered-To: freebsd-arm@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id A82BE6FE for ; Sat, 21 Mar 2015 00:10:29 +0000 (UTC) Received: from smtp.mei.co.jp (smtp.mei.co.jp [133.183.100.20]) by mx1.freebsd.org (Postfix) with ESMTP id 5F3AE17F for ; Sat, 21 Mar 2015 00:10:28 +0000 (UTC) Received: from mail-gw.jp.panasonic.com ([157.8.1.157]) by smtp.mei.co.jp (8.12.11.20060614/3.7W/kc-maile13) with ESMTP id t2KNw8Na004988 for ; Sat, 21 Mar 2015 08:58:08 +0900 (JST) Received: from epochmail.jp.panasonic.com ([157.8.1.130]) by mail.jp.panasonic.com (8.11.6p2/3.7W/kc-maili15) with ESMTP id t2KNw8B14789 for ; Sat, 21 Mar 2015 08:58:08 +0900 Received: by epochmail.jp.panasonic.com (8.12.11.20060308/3.7W/lomi11) id t2KNw8XL031748 for freebsd-arm@freebsd.org; Sat, 21 Mar 2015 08:58:08 +0900 Received: from localhost by lomi11.jp.panasonic.com (8.12.11.20060308/3.7W) with ESMTP id t2KNw8sO031736 for ; Sat, 21 Mar 2015 08:58:08 +0900 Date: Sat, 21 Mar 2015 08:58:07 +0900 (JST) Message-Id: <20150321.085807.1477684572929578361.okuno.kohji@jp.panasonic.com> To: freebsd-arm@freebsd.org Subject: pmap-v6.c has a bug? From: Kohji Okuno Organization: Panasonic Corporation X-Mailer: Mew version 6.6 on Emacs 24.4 / Mule 6.0 (HANACHIRUSATO) Mime-Version: 1.0 Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-BeenThere: freebsd-arm@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "Porting FreeBSD to ARM processors." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 21 Mar 2015 00:10:29 -0000 Hi All, We think that pmap_alloc_l2_bucket() in pmap-v6.c has a bug for a race-condition. Would you refer to the following "(***)" lines? When a context(called A) decides to allocate pte after A checks l2 and l2b->kva, A releases locks while A is allocating pte. In this timing, another context(called B) may free the same l2 from pmap_free_l2_bucket(). If this situation happens, l2b which is allocated by A will be lost since this l2b isn't able to trace from pmap. In this result, pmap_get_l2_bucket(pvchunk->pc_pmap, pventry->pv_va) will return NULL, then it will cause a kernel panic by NULL access. We saw this kind of panic in pmap_clearbits() and pmap_remove_all(). We add count-up l2_occupancy before unloking and count-down it after locking. We think that this change can prevent wrong release of l2. What do you think about this? Regards, Kohji Okuno 707 static struct l2_bucket * 708 pmap_alloc_l2_bucket(pmap_t pmap, vm_offset_t va) 709 { 710 struct l2_dtable *l2; 711 struct l2_bucket *l2b; 712 u_short l1idx; 713 714 l1idx = L1_IDX(va); 715 716 PMAP_ASSERT_LOCKED(pmap); 717 rw_assert(&pvh_global_lock, RA_WLOCKED); 718 if ((l2 = pmap->pm_l2[L2_IDX(l1idx)]) == NULL) { >> SNIP << 747 } 748 749 l2b = &l2->l2_bucket[L2_BUCKET(l1idx)]; 750 751 /* 752 * Fetch pointer to the L2 page table associated with the address. 753 */ 754 if (l2b->l2b_kva == NULL) { 755 pt_entry_t *ptep; 756 757 /* 758 * No L2 page table has been allocated. Chances are, this 759 * is because we just allocated the l2_dtable, above. 760 */ (***) l2->l2_occupancy++; /* prevent release of l2 */ 761 PMAP_UNLOCK(pmap); 762 rw_wunlock(&pvh_global_lock); 763 ptep = uma_zalloc(l2zone, M_NOWAIT); 764 rw_wlock(&pvh_global_lock); 765 PMAP_LOCK(pmap); (***) l2->l2_occupancy--; 766 if (l2b->l2b_kva != 0) { 767 /* We lost the race. */ 768 uma_zfree(l2zone, ptep); 769 return (l2b); 770 } 771 l2b->l2b_phys = vtophys(ptep); 772 if (ptep == NULL) { 773 /* 774 * Oops, no more L2 page tables available at this 775 * time. We may need to deallocate the l2_dtable 776 * if we allocated a new one above. 777 */ 778 if (l2->l2_occupancy == 0) { 779 pmap->pm_l2[L2_IDX(l1idx)] = NULL; 780 uma_zfree(l2table_zone, l2); 781 } 782 return (NULL); 783 } 784 785 l2->l2_occupancy++; 786 l2b->l2b_kva = ptep; 787 l2b->l2b_l1idx = l1idx; 788 } 789 790 return (l2b); 791 }