if ( rc )
return rc;
+ /* Need to take care of the reference obtained in gnttab_map_frame(). */
+ page = mfn_to_page(mfn);
t = p2m_ram_rw;
break;
/* Map at new location. */
rc = guest_physmap_add_entry(d, gfn, mfn, 0, t);
- /* If we fail to add the mapping, we need to drop the reference we
- * took earlier on foreign pages */
- if ( rc && space == XENMAPSPACE_gmfn_foreign )
+ /*
+ * For XENMAPSPACE_gmfn_foreign if we failed to add the mapping, we need
+ * to drop the reference we took earlier. In all other cases we need to
+ * drop any reference we took earlier (perhaps indirectly).
+ */
+ if ( space == XENMAPSPACE_gmfn_foreign ? rc : page != NULL )
{
ASSERT(page != NULL);
put_page(page);
rc = gnttab_map_frame(d, idx, gpfn, &mfn);
if ( rc )
return rc;
+ /* Need to take care of the reference obtained in gnttab_map_frame(). */
+ page = mfn_to_page(mfn);
break;
case XENMAPSPACE_gmfn:
}
if ( !rc )
- gnttab_set_frame_gfn(gt, status, idx, gfn);
+ {
+ /*
+ * Make sure gnttab_unpopulate_status_frames() won't (successfully)
+ * free the page until our caller has completed its operation.
+ */
+ if ( get_page(mfn_to_page(*mfn), d) )
+ gnttab_set_frame_gfn(gt, status, idx, gfn);
+ else
+ rc = -EBUSY;
+ }
grant_write_unlock(gt);