return rv;
}
-static inline void *map_dirty_bitmap(XEN_GUEST_HANDLE_64(uint8) dirty_bitmap,
- unsigned long pages,
- struct page_info **page)
-{
- uint32_t pfec = PFEC_page_present | PFEC_write_access;
- unsigned long gfn;
- p2m_type_t p2mt;
-
- gfn = paging_gva_to_gfn(current,
- (unsigned long)(dirty_bitmap.p + (pages >> 3)),
- &pfec);
- if ( gfn == INVALID_GFN )
- return NULL;
-
- *page = get_page_from_gfn(current->domain, gfn, &p2mt, P2M_UNSHARE);
-
- if ( !p2m_is_ram(p2mt) )
- {
- put_page(*page);
- return NULL;
- }
- if ( p2m_is_paging(p2mt) )
- {
- put_page(*page);
- p2m_mem_paging_populate(current->domain, gfn);
- return NULL;
- }
- if ( p2m_is_shared(p2mt) || p2m_is_discard_write(p2mt) )
- {
- put_page(*page);
- return NULL;
- }
-
- return __map_domain_page(*page);
-}
-
-static inline void unmap_dirty_bitmap(void *addr, struct page_info *page)
-{
- if ( addr != NULL )
- {
- unmap_domain_page(addr);
- put_page(page);
- }
-}
-
/* Read a domain's log-dirty bitmap and stats. If the operation is a CLEAN,
* clear the bitmap and stats as well. */
mfn_t *l4 = NULL, *l3 = NULL, *l2 = NULL;
unsigned long *l1 = NULL;
int i4, i3, i2;
- uint8_t *dirty_bitmap;
- struct page_info *page;
- unsigned long index_mapped;
- again:
if ( !resuming )
{
domain_pause(d);
p2m_flush_hardware_cached_dirty(d);
}
- index_mapped = resuming ? d->arch.paging.preempt.log_dirty.done : 0;
- dirty_bitmap = map_dirty_bitmap(sc->dirty_bitmap, index_mapped, &page);
- if ( dirty_bitmap == NULL )
- {
- domain_unpause(d);
- return -EFAULT;
- }
-
paging_lock(d);
if ( !d->arch.paging.preempt.dom )
l4 = paging_map_log_dirty_bitmap(d);
i4 = d->arch.paging.preempt.log_dirty.i4;
i3 = d->arch.paging.preempt.log_dirty.i3;
- i2 = d->arch.paging.preempt.log_dirty.i2;
pages = d->arch.paging.preempt.log_dirty.done;
for ( ; (pages < sc->pages) && (i4 < LOGDIRTY_NODE_ENTRIES); i4++, i3 = 0 )
{
l3 = (l4 && mfn_valid(l4[i4])) ? map_domain_page(mfn_x(l4[i4])) : NULL;
- for ( ; (pages < sc->pages) && (i3 < LOGDIRTY_NODE_ENTRIES);
- i3++, i2 = 0 )
+ for ( ; (pages < sc->pages) && (i3 < LOGDIRTY_NODE_ENTRIES); i3++ )
{
l2 = ((l3 && mfn_valid(l3[i3])) ?
map_domain_page(mfn_x(l3[i3])) : NULL);
- for ( ; (pages < sc->pages) && (i2 < LOGDIRTY_NODE_ENTRIES); i2++ )
+ for ( i2 = 0;
+ (pages < sc->pages) && (i2 < LOGDIRTY_NODE_ENTRIES);
+ i2++ )
{
unsigned int bytes = PAGE_SIZE;
l1 = ((l2 && mfn_valid(l2[i2])) ?
bytes = (unsigned int)((sc->pages - pages + 7) >> 3);
if ( likely(peek) )
{
- if ( pages >> (3 + PAGE_SHIFT) !=
- index_mapped >> (3 + PAGE_SHIFT) )
+ if ( (l1 ? copy_to_guest_offset(sc->dirty_bitmap,
+ pages >> 3, (uint8_t *)l1,
+ bytes)
+ : clear_guest_offset(sc->dirty_bitmap,
+ pages >> 3, bytes)) != 0 )
{
- /* We need to map next page */
- d->arch.paging.preempt.log_dirty.i4 = i4;
- d->arch.paging.preempt.log_dirty.i3 = i3;
- d->arch.paging.preempt.log_dirty.i2 = i2;
- d->arch.paging.preempt.log_dirty.done = pages;
- d->arch.paging.preempt.dom = current->domain;
- d->arch.paging.preempt.op = sc->op;
- resuming = 1;
- paging_unlock(d);
- unmap_dirty_bitmap(dirty_bitmap, page);
- goto again;
+ rv = -EFAULT;
+ goto out;
}
- ASSERT(((pages >> 3) % PAGE_SIZE) + bytes <= PAGE_SIZE);
- if ( l1 )
- memcpy(dirty_bitmap + ((pages >> 3) % PAGE_SIZE), l1,
- bytes);
- else
- memset(dirty_bitmap + ((pages >> 3) % PAGE_SIZE), 0,
- bytes);
}
pages += bytes << 3;
if ( l1 )
{
d->arch.paging.preempt.log_dirty.i4 = i4;
d->arch.paging.preempt.log_dirty.i3 = i3 + 1;
- d->arch.paging.preempt.log_dirty.i2 = 0;
rv = -ERESTART;
break;
}
{
d->arch.paging.preempt.log_dirty.i4 = i4 + 1;
d->arch.paging.preempt.log_dirty.i3 = 0;
- d->arch.paging.preempt.log_dirty.i2 = 0;
rv = -ERESTART;
}
if ( rv )
if ( rv )
{
/* Never leave the domain paused on real errors. */
- unmap_dirty_bitmap(dirty_bitmap, page);
ASSERT(rv == -ERESTART);
return rv;
}
* paging modes (shadow or hap). Safe because the domain is paused. */
d->arch.paging.log_dirty.clean_dirty_bitmap(d);
}
- unmap_dirty_bitmap(dirty_bitmap, page);
domain_unpause(d);
return rv;
out:
d->arch.paging.preempt.dom = NULL;
paging_unlock(d);
- unmap_dirty_bitmap(dirty_bitmap, page);
domain_unpause(d);
if ( l1 )