int16_t status;
/* Shared state beteen *_unmap and *_unmap_complete */
- u16 flags;
+ u16 done;
unsigned long frame;
struct domain *rd;
grant_ref_t ref;
refcnt++;
}
- if ( gnttab_host_mapping_get_page_type(op, ld, rd) )
+ if ( gnttab_host_mapping_get_page_type(op->flags & GNTMAP_readonly,
+ ld, rd) )
{
if ( (owner == dom_cow) ||
!get_page_type(pg, PGT_writable_page) )
struct active_grant_entry *act;
s16 rc = 0;
struct grant_mapping *map;
+ unsigned int flags;
bool put_handle = false;
ld = current->domain;
grant_read_lock(rgt);
+ if ( rgt->gt_version == 0 )
+ {
+ /*
+ * This ought to be impossible, as such a mapping should not have
+ * been established (see the nr_grant_entries(rgt) bounds check in
+ * __gnttab_map_grant_ref()). Doing this check only in
+ * __gnttab_unmap_common_complete() - as it used to be done - would,
+ * however, be too late.
+ */
+ rc = GNTST_bad_gntref;
+ flags = 0;
+ goto unlock_out;
+ }
+
op->rd = rd;
op->ref = map->ref;
{
gdprintk(XENLOG_WARNING, "Unstable handle %#x\n", op->handle);
rc = GNTST_bad_handle;
+ flags = 0;
goto unlock_out;
}
* hold anyway; see docs/misc/grant-tables.txt's "Locking" section.
*/
- op->flags = read_atomic(&map->flags);
+ flags = read_atomic(&map->flags);
smp_rmb();
- if ( unlikely(!op->flags) || unlikely(map->domid != dom) ||
+ if ( unlikely(!flags) || unlikely(map->domid != dom) ||
unlikely(map->ref != op->ref) )
{
gdprintk(XENLOG_WARNING, "Unstable handle %u\n", op->handle);
op->frame = act->frame;
- if ( op->dev_bus_addr )
- {
- if ( unlikely(op->dev_bus_addr != pfn_to_paddr(act->frame)) )
- PIN_FAIL(act_release_out, GNTST_general_error,
- "Bus address doesn't match gntref (%"PRIx64" != %"PRIpaddr")\n",
- op->dev_bus_addr, pfn_to_paddr(act->frame));
-
- map->flags &= ~GNTMAP_device_map;
- }
+ if ( op->dev_bus_addr &&
+ unlikely(op->dev_bus_addr != pfn_to_paddr(act->frame)) )
+ PIN_FAIL(act_release_out, GNTST_general_error,
+ "Bus address doesn't match gntref (%"PRIx64" != %"PRIpaddr")\n",
+ op->dev_bus_addr, pfn_to_paddr(act->frame));
- if ( (op->host_addr != 0) && (op->flags & GNTMAP_host_map) )
+ if ( op->host_addr && (flags & GNTMAP_host_map) )
{
if ( (rc = replace_grant_host_mapping(op->host_addr,
op->frame, op->new_addr,
- op->flags)) < 0 )
+ flags)) < 0 )
goto act_release_out;
map->flags &= ~GNTMAP_host_map;
+ op->done |= GNTMAP_host_map | (flags & GNTMAP_readonly);
+ }
+
+ if ( op->dev_bus_addr && (flags & GNTMAP_device_map) )
+ {
+ map->flags &= ~GNTMAP_device_map;
+ op->done |= GNTMAP_device_map | (flags & GNTMAP_readonly);
}
if ( !(map->flags & (GNTMAP_device_map|GNTMAP_host_map)) )
}
/* If just unmapped a writable mapping, mark as dirtied */
- if ( rc == GNTST_okay && !(op->flags & GNTMAP_readonly) )
+ if ( rc == GNTST_okay && !(flags & GNTMAP_readonly) )
gnttab_mark_dirty(rd, op->frame);
op->status = rc;
struct page_info *pg;
uint16_t *status;
- if ( rd == NULL )
+ if ( !op->done )
{
- /*
- * Suggests that __gntab_unmap_common failed in
- * rcu_lock_domain_by_id() or earlier, and so we have nothing
- * to complete
- */
+ /* __gntab_unmap_common() didn't do anything - nothing to complete. */
return;
}
rgt = rd->grant_table;
grant_read_lock(rgt);
- if ( rgt->gt_version == 0 )
- goto unlock_out;
act = active_entry_acquire(rgt, op->ref);
sha = shared_entry_header(rgt, op->ref);
else
status = &status_entry(rgt, op->ref);
- if ( op->dev_bus_addr &&
- unlikely(op->dev_bus_addr != pfn_to_paddr(act->frame)) )
- {
- /*
- * Suggests that __gntab_unmap_common failed early and so
- * nothing further to do
- */
- goto act_release_out;
- }
-
pg = mfn_to_page(op->frame);
- if ( op->dev_bus_addr && (op->flags & GNTMAP_device_map) )
+ if ( op->done & GNTMAP_device_map )
{
if ( !is_iomem_page(act->frame) )
{
- if ( op->flags & GNTMAP_readonly )
+ if ( op->done & GNTMAP_readonly )
put_page(pg);
else
put_page_and_type(pg);
}
ASSERT(act->pin & (GNTPIN_devw_mask | GNTPIN_devr_mask));
- if ( op->flags & GNTMAP_readonly )
+ if ( op->done & GNTMAP_readonly )
act->pin -= GNTPIN_devr_inc;
else
act->pin -= GNTPIN_devw_inc;
}
- if ( (op->host_addr != 0) && (op->flags & GNTMAP_host_map) )
+ if ( op->done & GNTMAP_host_map )
{
- if ( op->status != 0 )
- {
- /*
- * Suggests that __gntab_unmap_common failed in
- * replace_grant_host_mapping() or IOMMU handling, so nothing
- * further to do (short of re-establishing the mapping in the
- * latter case).
- */
- goto act_release_out;
- }
-
if ( !is_iomem_page(op->frame) )
{
- if ( gnttab_host_mapping_get_page_type(op, ld, rd) )
+ if ( gnttab_host_mapping_get_page_type(op->done & GNTMAP_readonly,
+ ld, rd) )
put_page_type(pg);
put_page(pg);
}
ASSERT(act->pin & (GNTPIN_hstw_mask | GNTPIN_hstr_mask));
- if ( op->flags & GNTMAP_readonly )
+ if ( op->done & GNTMAP_readonly )
act->pin -= GNTPIN_hstr_inc;
else
act->pin -= GNTPIN_hstw_inc;
}
if ( ((act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0) &&
- !(op->flags & GNTMAP_readonly) )
+ !(op->done & GNTMAP_readonly) )
gnttab_clear_flag(_GTF_writing, status);
if ( act->pin == 0 )
gnttab_clear_flag(_GTF_reading, status);
- act_release_out:
active_entry_release(act);
- unlock_out:
grant_read_unlock(rgt);
rcu_unlock_domain(rd);
common->handle = op->handle;
/* Intialise these in case common contains old state */
+ common->done = 0;
common->new_addr = 0;
common->rd = NULL;
common->frame = 0;
common->handle = op->handle;
/* Intialise these in case common contains old state */
+ common->done = 0;
common->dev_bus_addr = 0;
common->rd = NULL;
common->frame = 0;
if ( gnttab_release_host_mappings(d) &&
!is_iomem_page(act->frame) )
{
- if ( gnttab_host_mapping_get_page_type(map, d, rd) )
+ if ( gnttab_host_mapping_get_page_type((map->flags &
+ GNTMAP_readonly),
+ d, rd) )
put_page_type(pg);
put_page(pg);
}