Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+70 -6
+67 -6
drivers/xen/balloon.c
··· 128 128 } 129 129 130 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 133 struct page *page; 134 134 135 135 if (list_empty(&ballooned_pages)) 136 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 142 list_del(&page->lru); 140 143 141 144 if (PageHighMem(page)) { ··· 236 233 return BP_EAGAIN; 237 234 238 235 for (i = 0; i < rc; i++) { 239 - page = balloon_retrieve(); 236 + page = balloon_retrieve(false); 240 237 BUG_ON(page == NULL); 241 238 242 239 pfn = page_to_pfn(page); ··· 266 263 return BP_DONE; 267 264 } 268 265 269 - static enum bp_state decrease_reservation(unsigned long nr_pages) 266 + static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp) 270 267 { 271 268 enum bp_state state = BP_DONE; 272 269 unsigned long pfn, i; ··· 282 279 nr_pages = ARRAY_SIZE(frame_list); 283 280 284 281 for (i = 0; i < nr_pages; i++) { 285 - if ((page = alloc_page(GFP_BALLOON)) == NULL) { 282 + if ((page = alloc_page(gfp)) == NULL) { 286 283 nr_pages = i; 287 284 state = BP_EAGAIN; 288 285 break; ··· 343 340 state = increase_reservation(credit); 344 341 345 342 if (credit < 0) 346 - state = decrease_reservation(-credit); 343 + state = decrease_reservation(-credit, GFP_BALLOON); 347 344 348 345 state = update_schedule(state); 349 346 ··· 368 365 schedule_delayed_work(&balloon_worker, 0); 369 366 } 370 367 EXPORT_SYMBOL_GPL(balloon_set_new_target); 368 + 369 + /** 370 + * alloc_xenballooned_pages - get pages that have been ballooned out 371 + * @nr_pages: Number of pages to get 372 + * @pages: pages returned 373 + * @return 0 on success, error otherwise 374 + */ 375 + int alloc_xenballooned_pages(int nr_pages, struct page** pages) 376 + { 377 + int pgno = 0; 378 + struct page* page; 379 + mutex_lock(&balloon_mutex); 380 + while (pgno < nr_pages) { 381 + page = balloon_retrieve(true); 382 + if (page) { 383 + pages[pgno++] = page; 384 + } else { 385 + enum bp_state st; 386 + st = decrease_reservation(nr_pages - pgno, GFP_HIGHUSER); 387 + if (st != BP_DONE) 388 + goto out_undo; 389 + } 390 + } 391 + mutex_unlock(&balloon_mutex); 392 + return 0; 393 + out_undo: 394 + while (pgno) 395 + balloon_append(pages[--pgno]); 396 + /* Free the memory back to the kernel soon */ 397 + schedule_delayed_work(&balloon_worker, 0); 398 + mutex_unlock(&balloon_mutex); 399 + return -ENOMEM; 400 + } 401 + EXPORT_SYMBOL(alloc_xenballooned_pages); 402 + 403 + /** 404 + * free_xenballooned_pages - return pages retrieved with get_ballooned_pages 405 + * @nr_pages: Number of pages 406 + * @pages: pages to return 407 + */ 408 + void free_xenballooned_pages(int nr_pages, struct page** pages) 409 + { 410 + int i; 411 + 412 + mutex_lock(&balloon_mutex); 413 + 414 + for (i = 0; i < nr_pages; i++) { 415 + if (pages[i]) 416 + balloon_append(pages[i]); 417 + } 418 + 419 + /* The balloon may be too large now. Shrink it if needed. */ 420 + if (current_target() != balloon_stats.current_pages) 421 + schedule_delayed_work(&balloon_worker, 0); 422 + 423 + mutex_unlock(&balloon_mutex); 424 + } 425 + EXPORT_SYMBOL(free_xenballooned_pages); 371 426 372 427 static int __init balloon_init(void) 373 428 {
+3
include/xen/balloon.h
··· 20 20 extern struct balloon_stats balloon_stats; 21 21 22 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);