Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 21 Mar 2015 08:58:07 +0900 (JST)
From:      Kohji Okuno <okuno.kohji@jp.panasonic.com>
To:        freebsd-arm@freebsd.org
Subject:   pmap-v6.c has a bug?
Message-ID:  <20150321.085807.1477684572929578361.okuno.kohji@jp.panasonic.com>

next in thread | raw e-mail | index | archive | help
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 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20150321.085807.1477684572929578361.okuno.kohji>