Re: unmap_range() premature exit

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

 



On 05/08/2014 11:36 AM, Mario Smarduch wrote:
> On 05/08/2014 11:14 AM, Marc Zyngier wrote:
>> On Thu, May 08 2014 at  6:25:29 pm BST, Mario Smarduch <m.smarduch@xxxxxxxxxxx> wrote:
>>> On 05/08/2014 10:12 AM, Marc Zyngier wrote:
>>>> On Thu, May 08 2014 at  6:03:07 pm BST, Mario Smarduch <m.smarduch@xxxxxxxxxxx> wrote:
>>>>> It appears that for a memslot that crosses a PUD range unmap_range may
>>>>> return prematurely if lower pud is not mapping anything. 
>>>>>
>>>>> kvm_pud_addr_end(..) will return end and the loop will terminate possibly
>>>>> leaving unmapped ranges. 
>>>>>
>>>>> Am I missing something?
>>>>
>>>> With 3-level page tables (which is what we have with LPAE on ARMv7),
>>>> puds are the same thing as pgds (they are effectively collapsed). This
>>>> will change with the introduction of 4-level page tables on ARMv8.
>>>>
>>>> 	M.
>>>>
>>>
>>> But what if there is some memslot with range like
>>> 0xffff0000 - 0x1000f0000. The lower range has not paged anything
>>> in so its pud/pgd is none, but upper range has mappings.
>>> Then pud_none(...) will succeed for lower PUD range and
>>> kvm_pud_addr_end() will return 'end' and leave the upper mappings
>>> stranded.
>>
>> There is something I don't understand. The usual loop would be something
>> like (boilerplate code taken from the current KVM code base):
>>
>> <quote>
>> static void stage2_flush_puds(struct kvm *kvm, pgd_t *pgd,
>> 			      phys_addr_t addr, phys_addr_t end)
>> {
>> 	pud_t *pud;
>> 	phys_addr_t next;
>>
>> 	pud = pud_offset(pgd, addr);
>> 	do {
>> 		next = kvm_pud_addr_end(addr, end);
>> 		if (!pud_none(*pud)) {
>>                 	[...]
>> 		}
>> 	} while (pud++, addr = next, addr != end);
>> }
>>
>> static void stage2_flush_memslot(struct kvm *kvm,
>> 				 struct kvm_memory_slot *memslot)
>> {
>> 	phys_addr_t addr = memslot->base_gfn << PAGE_SHIFT;
>> 	phys_addr_t end = addr + PAGE_SIZE * memslot->npages;
>> 	phys_addr_t next;
>> 	pgd_t *pgd;
>>
>> 	pgd = kvm->arch.pgd + pgd_index(addr);
>> 	do {
>> 		next = kvm_pgd_addr_end(addr, end);
>> 		stage2_flush_puds(kvm, pgd, addr, next);
>> 	} while (pgd++, addr = next, addr != end);
>> }
>> </quote>
>>
>> If your memslot is across two pgd/pud, then kvm_pgd_addr_end will give
>> you the address of the next range you're interested in, and it will be
>> picked up at the next iteration.
>>
>> /me puzzled.
>>
>> 	M.
>>
Hi Marc,

I should have read you comments closer, I'm just basically repeating
what you're illustrating above.

- Mario

> 
> I think that with nopud, the kvm_pud_addr_end() should be inside a
> kvm_pgd_addr_end(....). Then kvm_pud_addr_end(...) can return end, which
> would be pgd end, but the way it is it's returning the 'end'.
> 
> while(addr < end) }
>   pgd = kvm->arch.pgd + pgd_index(addr);
>   pgd_end = kvm_pgd_addr_end(addr, end);
>   while(addr < pgd_end) {
>     pud = pud_offset(pgd,addr);
>     if(pud_none(*pud)) {
>        // this should be ok returning pgd end, but not the 'end'
>        addr = kvm_pud_addr_end(addr, pgd_end);
>        continue;
>     }
>     [....]
>   }
>   [ ....]
> }
> 
> - Mario
> _______________________________________________
> kvmarm mailing list
> kvmarm@xxxxxxxxxxxxxxxxxxxxx
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
> 

_______________________________________________
kvmarm mailing list
kvmarm@xxxxxxxxxxxxxxxxxxxxx
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm




[Index of Archives]     [Linux KVM]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux