diff options
| -rw-r--r-- | drivers/xen/balloon.c | 73 | ||||
| -rw-r--r-- | include/xen/balloon.h | 3 |
2 files changed, 70 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; |
diff --git a/include/xen/balloon.h b/include/xen/balloon.h index f72e4794ec77..a2b22f01a51d 100644 --- a/include/xen/balloon.h +++ b/include/xen/balloon.h | |||
| @@ -20,3 +20,6 @@ struct balloon_stats { | |||
| 20 | extern struct balloon_stats balloon_stats; | 20 | extern struct balloon_stats balloon_stats; |
| 21 | 21 | ||
| 22 | void balloon_set_new_target(unsigned long target); | 22 | void balloon_set_new_target(unsigned long target); |
| 23 | |||
| 24 | int alloc_xenballooned_pages(int nr_pages, struct page** pages); | ||
| 25 | void free_xenballooned_pages(int nr_pages, struct page** pages); | ||
