diff options
author | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2011-03-15 10:23:57 -0400 |
---|---|---|
committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2011-03-16 10:05:35 -0400 |
commit | b6f3067985f12d514187059fb10fe3c877f87cb2 (patch) | |
tree | b41cf045fc3fa7b37186ea627fd87862ef8cf3ab /drivers/xen | |
parent | 803eb047a28d239809fff1f87274cdaa94e0d8ea (diff) |
xen-balloon: Add interface to retrieve ballooned pages
Pages that have been ballooned are useful for other Xen drivers doing
grant table actions, because these pages have valid struct page/PFNs but
have no valid MFN so are available for remapping.
Acked-by: Ian Campbell <ian.campbell@citrix.com>
Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
[v2: Deal with rebasing on top of modified balloon code]
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/xen')
-rw-r--r-- | drivers/xen/balloon.c | 73 |
1 files changed, 67 insertions, 6 deletions
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 7497041d0631..8c81cd24ed83 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c | |||
@@ -128,14 +128,17 @@ static void balloon_append(struct page *page) | |||
128 | } | 128 | } |
129 | 129 | ||
130 | /* balloon_retrieve: rescue a page from the balloon, if it is not empty. */ | 130 | /* balloon_retrieve: rescue a page from the balloon, if it is not empty. */ |
131 | static struct page *balloon_retrieve(void) | 131 | static struct page *balloon_retrieve(bool prefer_highmem) |
132 | { | 132 | { |
133 | struct page *page; | 133 | struct page *page; |
134 | 134 | ||
135 | if (list_empty(&ballooned_pages)) | 135 | if (list_empty(&ballooned_pages)) |
136 | return NULL; | 136 | return NULL; |
137 | 137 | ||
138 | page = list_entry(ballooned_pages.next, struct page, lru); | 138 | if (prefer_highmem) |
139 | page = list_entry(ballooned_pages.prev, struct page, lru); | ||
140 | else | ||
141 | page = list_entry(ballooned_pages.next, struct page, lru); | ||
139 | list_del(&page->lru); | 142 | list_del(&page->lru); |
140 | 143 | ||
141 | if (PageHighMem(page)) { | 144 | if (PageHighMem(page)) { |
@@ -233,7 +236,7 @@ static enum bp_state increase_reservation(unsigned long nr_pages) | |||
233 | return BP_EAGAIN; | 236 | return BP_EAGAIN; |
234 | 237 | ||
235 | for (i = 0; i < rc; i++) { | 238 | for (i = 0; i < rc; i++) { |
236 | page = balloon_retrieve(); | 239 | page = balloon_retrieve(false); |
237 | BUG_ON(page == NULL); | 240 | BUG_ON(page == NULL); |
238 | 241 | ||
239 | pfn = page_to_pfn(page); | 242 | pfn = page_to_pfn(page); |
@@ -263,7 +266,7 @@ static enum bp_state increase_reservation(unsigned long nr_pages) | |||
263 | return BP_DONE; | 266 | return BP_DONE; |
264 | } | 267 | } |
265 | 268 | ||
266 | static enum bp_state decrease_reservation(unsigned long nr_pages) | 269 | static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp) |
267 | { | 270 | { |
268 | enum bp_state state = BP_DONE; | 271 | enum bp_state state = BP_DONE; |
269 | unsigned long pfn, i; | 272 | unsigned long pfn, i; |
@@ -279,7 +282,7 @@ static enum bp_state decrease_reservation(unsigned long nr_pages) | |||
279 | nr_pages = ARRAY_SIZE(frame_list); | 282 | nr_pages = ARRAY_SIZE(frame_list); |
280 | 283 | ||
281 | for (i = 0; i < nr_pages; i++) { | 284 | for (i = 0; i < nr_pages; i++) { |
282 | if ((page = alloc_page(GFP_BALLOON)) == NULL) { | 285 | if ((page = alloc_page(gfp)) == NULL) { |
283 | nr_pages = i; | 286 | nr_pages = i; |
284 | state = BP_EAGAIN; | 287 | state = BP_EAGAIN; |
285 | break; | 288 | break; |
@@ -340,7 +343,7 @@ static void balloon_process(struct work_struct *work) | |||
340 | state = increase_reservation(credit); | 343 | state = increase_reservation(credit); |
341 | 344 | ||
342 | if (credit < 0) | 345 | if (credit < 0) |
343 | state = decrease_reservation(-credit); | 346 | state = decrease_reservation(-credit, GFP_BALLOON); |
344 | 347 | ||
345 | state = update_schedule(state); | 348 | state = update_schedule(state); |
346 | 349 | ||
@@ -366,6 +369,64 @@ void balloon_set_new_target(unsigned long target) | |||
366 | } | 369 | } |
367 | EXPORT_SYMBOL_GPL(balloon_set_new_target); | 370 | EXPORT_SYMBOL_GPL(balloon_set_new_target); |
368 | 371 | ||
372 | /** | ||
373 | * alloc_xenballooned_pages - get pages that have been ballooned out | ||
374 | * @nr_pages: Number of pages to get | ||
375 | * @pages: pages returned | ||
376 | * @return 0 on success, error otherwise | ||
377 | */ | ||
378 | int alloc_xenballooned_pages(int nr_pages, struct page** pages) | ||
379 | { | ||
380 | int pgno = 0; | ||
381 | struct page* page; | ||
382 | mutex_lock(&balloon_mutex); | ||
383 | while (pgno < nr_pages) { | ||
384 | page = balloon_retrieve(true); | ||
385 | if (page) { | ||
386 | pages[pgno++] = page; | ||
387 | } else { | ||
388 | enum bp_state st; | ||
389 | st = decrease_reservation(nr_pages - pgno, GFP_HIGHUSER); | ||
390 | if (st != BP_DONE) | ||
391 | goto out_undo; | ||
392 | } | ||
393 | } | ||
394 | mutex_unlock(&balloon_mutex); | ||
395 | return 0; | ||
396 | out_undo: | ||
397 | while (pgno) | ||
398 | balloon_append(pages[--pgno]); | ||
399 | /* Free the memory back to the kernel soon */ | ||
400 | schedule_delayed_work(&balloon_worker, 0); | ||
401 | mutex_unlock(&balloon_mutex); | ||
402 | return -ENOMEM; | ||
403 | } | ||
404 | EXPORT_SYMBOL(alloc_xenballooned_pages); | ||
405 | |||
406 | /** | ||
407 | * free_xenballooned_pages - return pages retrieved with get_ballooned_pages | ||
408 | * @nr_pages: Number of pages | ||
409 | * @pages: pages to return | ||
410 | */ | ||
411 | void free_xenballooned_pages(int nr_pages, struct page** pages) | ||
412 | { | ||
413 | int i; | ||
414 | |||
415 | mutex_lock(&balloon_mutex); | ||
416 | |||
417 | for (i = 0; i < nr_pages; i++) { | ||
418 | if (pages[i]) | ||
419 | balloon_append(pages[i]); | ||
420 | } | ||
421 | |||
422 | /* The balloon may be too large now. Shrink it if needed. */ | ||
423 | if (current_target() != balloon_stats.current_pages) | ||
424 | schedule_delayed_work(&balloon_worker, 0); | ||
425 | |||
426 | mutex_unlock(&balloon_mutex); | ||
427 | } | ||
428 | EXPORT_SYMBOL(free_xenballooned_pages); | ||
429 | |||
369 | static int __init balloon_init(void) | 430 | static int __init balloon_init(void) |
370 | { | 431 | { |
371 | unsigned long pfn, extra_pfn_end; | 432 | unsigned long pfn, extra_pfn_end; |