diff options
author | Daniel De Graaf <dgdegra@tycho.nsa.gov> | 2011-02-09 15:12:00 -0500 |
---|---|---|
committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2011-02-14 14:16:21 -0500 |
commit | b57c18694ea1641b691fa05ed8af0ce339fa430b (patch) | |
tree | 3fb3b050ef993092db69463fa56507f03eb31cf8 /drivers/xen | |
parent | 84e4075d60fc8f1c0b937765620bc784dd0c3d39 (diff) |
xen-gntdev: Avoid unmapping ranges twice
In paravirtualized domains, mn_invl_page or mn_invl_range_start can
unmap a segment of a mapped region without unmapping all pages. When
the region is later released, the pages will be unmapped twice, leading
to an incorrect -EINVAL return.
Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/xen')
-rw-r--r-- | drivers/xen/gntdev.c | 33 |
1 files changed, 31 insertions, 2 deletions
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 4ca4262d3d1..4687cd557c9 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c | |||
@@ -282,7 +282,7 @@ static int map_grant_pages(struct grant_map *map) | |||
282 | return err; | 282 | return err; |
283 | } | 283 | } |
284 | 284 | ||
285 | static int unmap_grant_pages(struct grant_map *map, int offset, int pages) | 285 | static int __unmap_grant_pages(struct grant_map *map, int offset, int pages) |
286 | { | 286 | { |
287 | int i, err = 0; | 287 | int i, err = 0; |
288 | 288 | ||
@@ -301,7 +301,6 @@ static int unmap_grant_pages(struct grant_map *map, int offset, int pages) | |||
301 | } | 301 | } |
302 | } | 302 | } |
303 | 303 | ||
304 | pr_debug("map %d+%d [%d+%d]\n", map->index, map->count, offset, pages); | ||
305 | err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages + offset, pages); | 304 | err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages + offset, pages); |
306 | if (err) | 305 | if (err) |
307 | return err; | 306 | return err; |
@@ -314,6 +313,36 @@ static int unmap_grant_pages(struct grant_map *map, int offset, int pages) | |||
314 | return err; | 313 | return err; |
315 | } | 314 | } |
316 | 315 | ||
316 | static int unmap_grant_pages(struct grant_map *map, int offset, int pages) | ||
317 | { | ||
318 | int range, err = 0; | ||
319 | |||
320 | pr_debug("unmap %d+%d [%d+%d]\n", map->index, map->count, offset, pages); | ||
321 | |||
322 | /* It is possible the requested range will have a "hole" where we | ||
323 | * already unmapped some of the grants. Only unmap valid ranges. | ||
324 | */ | ||
325 | while (pages && !err) { | ||
326 | while (pages && !map->unmap_ops[offset].handle) { | ||
327 | offset++; | ||
328 | pages--; | ||
329 | } | ||
330 | range = 0; | ||
331 | while (range < pages) { | ||
332 | if (!map->unmap_ops[offset+range].handle) { | ||
333 | range--; | ||
334 | break; | ||
335 | } | ||
336 | range++; | ||
337 | } | ||
338 | err = __unmap_grant_pages(map, offset, range); | ||
339 | offset += range; | ||
340 | pages -= range; | ||
341 | } | ||
342 | |||
343 | return err; | ||
344 | } | ||
345 | |||
317 | /* ------------------------------------------------------------------ */ | 346 | /* ------------------------------------------------------------------ */ |
318 | 347 | ||
319 | static void gntdev_vma_close(struct vm_area_struct *vma) | 348 | static void gntdev_vma_close(struct vm_area_struct *vma) |