diff options
author | Jennifer Herbert <jennifer.herbert@citrix.com> | 2015-01-05 16:07:46 +0100 |
---|---|---|
committer | David Vrabel <david.vrabel@citrix.com> | 2015-01-28 15:03:15 +0100 |
commit | 745282256c754ac5ed3dbe2fbef6471dc1373417 (patch) | |
tree | 9dbec8c554c05a2dde6dad9c040dba740486c077 /drivers/xen/gntdev.c | |
parent | xen/gntdev: convert priv->lock to a mutex (diff) | |
download | linux-745282256c754ac5ed3dbe2fbef6471dc1373417.tar.xz linux-745282256c754ac5ed3dbe2fbef6471dc1373417.zip |
xen/gntdev: safely unmap grants in case they are still in use
Use gnttab_unmap_refs_async() to wait until the mapped pages are no
longer in use before unmapping them.
This allows userspace programs to safely use Direct I/O and AIO to a
network filesystem which may retain refs to pages in queued skbs after
the filesystem I/O has completed.
Signed-off-by: Jennifer Herbert <jennifer.herbert@citrix.com>
Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
Diffstat (limited to 'drivers/xen/gntdev.c')
-rw-r--r-- | drivers/xen/gntdev.c | 36 |
1 files changed, 31 insertions, 5 deletions
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 3c2534433b30..bccc54a80559 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -309,9 +309,30 @@ static int map_grant_pages(struct grant_map *map) return err; } +struct unmap_grant_pages_callback_data +{ + struct completion completion; + int result; +}; + +static void unmap_grant_callback(int result, + struct gntab_unmap_queue_data *data) +{ + struct unmap_grant_pages_callback_data* d = data->data; + + d->result = result; + complete(&d->completion); +} + static int __unmap_grant_pages(struct grant_map *map, int offset, int pages) { int i, err = 0; + struct gntab_unmap_queue_data unmap_data; + struct unmap_grant_pages_callback_data data; + + init_completion(&data.completion); + unmap_data.data = &data; + unmap_data.done= &unmap_grant_callback; if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) { int pgno = (map->notify.addr >> PAGE_SHIFT); @@ -323,11 +344,16 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int pages) } } - err = gnttab_unmap_refs(map->unmap_ops + offset, - use_ptemod ? map->kunmap_ops + offset : NULL, map->pages + offset, - pages); - if (err) - return err; + unmap_data.unmap_ops = map->unmap_ops + offset; + unmap_data.kunmap_ops = use_ptemod ? map->kunmap_ops + offset : NULL; + unmap_data.pages = map->pages + offset; + unmap_data.count = pages; + + gnttab_unmap_refs_async(&unmap_data); + + wait_for_completion(&data.completion); + if (data.result) + return data.result; for (i = 0; i < pages; i++) { if (map->unmap_ops[offset+i].status) |