Re: About pmap_mapdev() & pmap_unmapdev()

From: Konstantin Belousov <kostikbel_at_gmail.com>
Date: Sat, 4 Oct 2014 00:58:30 +0300
On Fri, Oct 03, 2014 at 05:25:33PM +0900, Kohji Okuno wrote:
> Hi,
> 
> At least in i386 && 9-stable, when we call pmap_mapdev() and
> pmap_unmapdev(), kernel_pmap.pm_stats.resident_count is decreased
> incorrectly.
> 
> pmap_mapdev_attr()->pmap_kenter_attr():
> In this path, kernel_pmap.pm_stats.resident_count is not increlmented.
> 
> pmap_unmapdev()->kmem_free(kernel_map)->vm_map_remove()->pmap_remove():
> But, in this path, kernel_pmap.pm_stats.resident_count is decreased in
> pmap_remove_pte().
> 
> While I called pmap_mapdev() and pmap_unmapdev() repeatedly and
> kernel_pmap.pm_stats.resident_count became `0', since pmap_remove()
> returned without removing ptes, I encountered various kernel panics.
I think you are right.

The problem seems to be fixed in HEAD and 10, since mapdev was switched
to use kva_alloc/kva_free.  I added stable_at_ to Cc:.

> 
> And, when I enabled INVARIANTS, I looked the following panic message.
> panic: vm_page_free_toq: freeing mapped page 0xXXXXXXXX.
Do you mean that this panic is related to missed pmap_remove() ?
I doubt it, since pmap_mapdev() does not establish managed mappings.

> 
> I think, I should change the following.
> What do you think about this?
> 
> 
> diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c
> index 2adc6f8..a0998e8 100644
> --- a/sys/i386/i386/pmap.c
> +++ b/sys/i386/i386/pmap.c
> _at__at_ -5061,6 +5061,7 _at__at_ pmap_mapdev_attr(vm_paddr_t pa, vm_size_t size, int mode)
>  {
>  	vm_offset_t va, offset;
>  	vm_size_t tmpsize;
> +	int kmem_allocated = 0;
>  
>  	offset = pa & PAGE_MASK;
>  	size = roundup(offset + size, PAGE_SIZE);
> _at__at_ -5068,13 +5069,18 _at__at_ pmap_mapdev_attr(vm_paddr_t pa, vm_size_t size, int mode)
>  
>  	if (pa < KERNLOAD && pa + size <= KERNLOAD)
>  		va = KERNBASE + pa;
> -	else
> +	else {
>  		va = kmem_alloc_nofault(kernel_map, size);
> +		kmem_allocated = 1;

You could just do
		PMAP_LOCK(kernel_pmap);
		kernel_pmap.pm_stats.resident_count += OFF_TO_IDX(size);
		PMAP_UNLOCK(kernel_pmap);
there.  And, the same fix is needed for amd64.

> +	}
>  	if (!va)
>  		panic("pmap_mapdev: Couldn't alloc kernel virtual memory");
>  
> -	for (tmpsize = 0; tmpsize < size; tmpsize += PAGE_SIZE)
> +	for (tmpsize = 0; tmpsize < size; tmpsize += PAGE_SIZE) {
>  		pmap_kenter_attr(va + tmpsize, pa + tmpsize, mode);
> +		if (kmem_allocated)
> +			kernel_pmap.pm_stats.resident_count++;
> +	}
>  	pmap_invalidate_range(kernel_pmap, va, va + tmpsize);
>  	pmap_invalidate_cache_range(va, va + size);
>  	return ((void *)(va + offset));
> _______________________________________________
> freebsd-current_at_freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-current
> To unsubscribe, send any mail to "freebsd-current-unsubscribe_at_freebsd.org"
Received on Fri Oct 03 2014 - 19:58:38 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:40:52 UTC