diff options
author | Jennifer Herbert <jennifer.herbert@citrix.com> | 2015-01-05 10:07:46 -0500 |
---|---|---|
committer | David Vrabel <david.vrabel@citrix.com> | 2015-01-28 09:03:15 -0500 |
commit | 745282256c754ac5ed3dbe2fbef6471dc1373417 (patch) | |
tree | 9dbec8c554c05a2dde6dad9c040dba740486c077 | |
parent | 1401c00e59ea021c575f74612fe2dbba36d6a4ee (diff) |
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>
-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) | |||
309 | return err; | 309 | return err; |
310 | } | 310 | } |
311 | 311 | ||
312 | struct unmap_grant_pages_callback_data | ||
313 | { | ||
314 | struct completion completion; | ||
315 | int result; | ||
316 | }; | ||
317 | |||
318 | static void unmap_grant_callback(int result, | ||
319 | struct gntab_unmap_queue_data *data) | ||
320 | { | ||
321 | struct unmap_grant_pages_callback_data* d = data->data; | ||
322 | |||
323 | d->result = result; | ||
324 | complete(&d->completion); | ||
325 | } | ||
326 | |||
312 | static int __unmap_grant_pages(struct grant_map *map, int offset, int pages) | 327 | static int __unmap_grant_pages(struct grant_map *map, int offset, int pages) |
313 | { | 328 | { |
314 | int i, err = 0; | 329 | int i, err = 0; |
330 | struct gntab_unmap_queue_data unmap_data; | ||
331 | struct unmap_grant_pages_callback_data data; | ||
332 | |||
333 | init_completion(&data.completion); | ||
334 | unmap_data.data = &data; | ||
335 | unmap_data.done= &unmap_grant_callback; | ||
315 | 336 | ||
316 | if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) { | 337 | if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) { |
317 | int pgno = (map->notify.addr >> PAGE_SHIFT); | 338 | int pgno = (map->notify.addr >> PAGE_SHIFT); |
@@ -323,11 +344,16 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int pages) | |||
323 | } | 344 | } |
324 | } | 345 | } |
325 | 346 | ||
326 | err = gnttab_unmap_refs(map->unmap_ops + offset, | 347 | unmap_data.unmap_ops = map->unmap_ops + offset; |
327 | use_ptemod ? map->kunmap_ops + offset : NULL, map->pages + offset, | 348 | unmap_data.kunmap_ops = use_ptemod ? map->kunmap_ops + offset : NULL; |
328 | pages); | 349 | unmap_data.pages = map->pages + offset; |
329 | if (err) | 350 | unmap_data.count = pages; |
330 | return err; | 351 | |
352 | gnttab_unmap_refs_async(&unmap_data); | ||
353 | |||
354 | wait_for_completion(&data.completion); | ||
355 | if (data.result) | ||
356 | return data.result; | ||
331 | 357 | ||
332 | for (i = 0; i < pages; i++) { | 358 | for (i = 0; i < pages; i++) { |
333 | if (map->unmap_ops[offset+i].status) | 359 | if (map->unmap_ops[offset+i].status) |