x86/mm: fix up paging_mfn_is_dirty()
authorKeir Fraser <keir@xen.org>
Wed, 15 Dec 2010 12:12:15 +0000 (12:12 +0000)
committerKeir Fraser <keir@xen.org>
Wed, 15 Dec 2010 12:12:15 +0000 (12:12 +0000)
Add locking, and don't allocate the top-level page if it's not there.
Also gets rid of the default-to-1 case if there have been failed
allocations because the safer thing is actually to return 0 and avoid
modifying an un-dirtied page.

Signed-off-by: Tim Deegan <Tim.Deegan@citrix.com>
xen/arch/x86/mm/paging.c

index 61d2e5fd2bb9f33d7d3ea4dbb4b9db4d12207e19..f429d0b337ce54991fda405002506ed05fce68bb 100644 (file)
@@ -311,51 +311,45 @@ int paging_mfn_is_dirty(struct domain *d, mfn_t gmfn)
     unsigned long pfn;
     mfn_t mfn, *l4, *l3, *l2;
     unsigned long *l1;
-    int rv;
+    int rv = 0;
 
+    log_dirty_lock(d);
     ASSERT(paging_mode_log_dirty(d));
 
     /* We /really/ mean PFN here, even for non-translated guests. */
     pfn = get_gpfn_from_mfn(mfn_x(gmfn));
-    /* Page sharing not supported for shadow domains */
-    BUG_ON(SHARED_M2P(pfn));
-    if ( unlikely(!VALID_M2P(pfn)) )
-        return 0;
-    
-    if ( d->arch.paging.log_dirty.failed_allocs > 0 )
-        /* If we have any failed allocations our dirty log is bogus.
-         * Since we can't signal an error here, be conservative and
-         * report "dirty" in this case.  (The only current caller,
-         * _sh_propagate, leaves known-dirty pages writable, preventing
-         * subsequent dirty-logging faults from them.)
-         */
-        return 1;
+    /* Shared pages are always read-only; invalid pages can't be dirty. */
+    if ( unlikely(SHARED_M2P(pfn) || !VALID_M2P(pfn)) )
+        goto out;
 
-    l4 = paging_map_log_dirty_bitmap(d);
-    if ( !l4 ) 
-        return 0;
+    mfn = d->arch.paging.log_dirty.top;
+    if ( !mfn_valid(mfn) )
+        goto out;
 
+    l4 = map_domain_page(mfn_x(mfn));
     mfn = l4[L4_LOGDIRTY_IDX(pfn)];
     unmap_domain_page(l4);
     if ( !mfn_valid(mfn) )
-        return 0;
+        goto out;
 
     l3 = map_domain_page(mfn_x(mfn));
     mfn = l3[L3_LOGDIRTY_IDX(pfn)];
     unmap_domain_page(l3);
     if ( !mfn_valid(mfn) )
-        return 0;
+        goto out;
 
     l2 = map_domain_page(mfn_x(mfn));
     mfn = l2[L2_LOGDIRTY_IDX(pfn)];
     unmap_domain_page(l2);
     if ( !mfn_valid(mfn) )
-        return 0;
+        goto out;
 
     l1 = map_domain_page(mfn_x(mfn));
     rv = test_bit(L1_LOGDIRTY_IDX(pfn), l1);
     unmap_domain_page(l1);
 
+out:
+    log_dirty_unlock(d);
     return rv;
 }