balloon的概念来自下面的经典论文
Carl Waldspurger. in Proceedings of the 5th
Symposium on Operating Systems Design and Implementation, 2002
简而言之,balloon就是VMM打入guest的一个探子,通常以驱动方式存在,当guest空闲内存比较多时,通过吹气球inflat,让balloon申请若干内存,然后转给VMM。当guest load比较重,可以放气deflat,让VMM塞给balloon若干内存,然后balloon释放给guest。Linux 3.0已经包含了balloon for Xen的实现。
OVERVIEW
balloon的状态由描述,该结构在balloon_init函数中初始化。
struct {
//in xen/balloon.h
/*
We aim for 'current allocation' == 'target allocation'. */
unsigned
long current_pages;//guest当前实际mfn数目
unsigned
long ;//balloon期待guest拥有的mfn数目
/*
Number of pages in high- and low-memory balloons. guest中被剥夺mfn的页面*/
unsigned
long balloon_low;
unsigned
long balloon_high;
unsigned
long schedule_delay;
unsigned
long max_schedule_delay;
unsigned
long retry_count;
unsigned
long max_retry_count;
};
工作队列负责具体的操作,实际处理函数balloon_process根据target_pages值决定充气还是放气。外围代码通过调用balloon_set_new_target驱动balloon_worker。
static DECLARE_DELAYED_WORK(, );
balloon的外围代码在linux 3.0/drivers/xen/xen-balloon.c中,一个是xenstore的节点memory/target设置watch,另一个是在guest的sysfs文件系统创建子目录xen_memory,该子目录下有几个文件读/写balloon_stats的状态
核心操作inflat和deflat
主要代码中
increase_reservation对应放气,增加guest的内存。
decrease_reservation对应吹气,减少guest的内存。
/* List of ,
threaded through the mem_map array. ballooned_pages的页面都是有struct page结构,但是其对应的mfn已经被xen回收了
*/
static LIST_HEAD();
static enum bp_state
increase_reservation(unsigned long nr_pages)
{
int
rc;
unsigned
longpfn, i;
struct
page*page;
struct
xen_memory_reservation reservation = {
.address_bits
= 0,
.extent_order
= 0,
.domid= DOMID_SELF
};
/*下面的先取得若干page结构,然后通过超级调用populate_physmap让xen给这些page分配mfn,但是实际并不是如此,返回的mfn放在列表中,但是并没有和开始传递进去的各个page绑定起来,也就是前面传进去的参数只有reservation.nr_extents = nr_pages;才有作用,page传进去似乎是浪费(只有XENMEMF_populate_on_demand标记传进去page才有作用 fix me)。
*/
page
= balloon_first_page();
for
(i = 0; i < nr_pages; i++) {
if
(!page) {
nr_pages
= i;
break;
}
frame_list[i]
= page_to_pfn(page);
page
= balloon_next_page(page);
}
set_xen_guest_handle(reservation.extent_start,
);
rc
= HYPERVISOR_memory_op(,
&reservation);
//将部分page从ballooned pages摘除,和frame_list中取得的mfn绑定,包括P2M表,
//,最后guest使用
for
(i = 0; i < rc; i++) {
page
= balloon_retrieve(false);
pfn
= page_to_pfn(page);
set_phys_to_machine(pfn,
);//更新P2M表
/*
Link back into the page tables if not highmem. */
if
(xen_pv_domain() && !PageHighMem(page)) {
int
ret;
ret
= HYPERVISOR_update_va_mapping(//更新guest的页表
(unsigned
long)__va(pfn << PAGE_SHIFT),
mfn_pte(frame_list[i],
PAGE_KERNEL),
0);
}
/*
Relinquish the page back to the allocator. */
ClearPageReserved(page);
init_page_count(page);
;//释放给guest使用
}
balloon_stats.current_pages
+= rc;
return
BP_DONE;
}
static enum bp_state
decrease_reservation(unsigned long nr_pages, gfp_t gfp)
{
enum
bp_state state = BP_DONE;
unsigned
longpfn, i;
struct
page*page;
int
ret;
struct
xen_memory_reservation reservation = {
.address_bits
= 0,
.extent_order
= 0,
.domid= DOMID_SELF
};
for
(i = 0; i < nr_pages; i++) {
if
((page = alloc_page(gfp)) == NULL) {//向guest申请页面
nr_pages
= i;
state
= BP_EAGAIN;
break;
}
pfn
= page_to_pfn(page);
frame_list[i]
= pfn_to_mfn(pfn);//取得对应的mfn
scrub_page(page);
//为安全起见(可以挪到另一个guest使用),清0
if
(xen_pv_domain() && !PageHighMem(page)) {
ret
= HYPERVISOR_update_va_mapping(//将页表项清0
(unsigned
long)__va(pfn << PAGE_SHIFT),
__pte_ma(0),
0);
}
}
/*
Ensure that ballooned highmem pages don't have kmaps. */
kmap_flush_unused();
flush_tlb_all();
/*
No more mappings: invalidate P2M
and add to balloon. */
for
(i = 0; i < nr_pages; i++) {
pfn
= mfn_to_pfn(frame_list[i]);
__set_phys_to_machine(pfn,
INVALID_P2M_ENTRY);
balloon_append(pfn_to_page(pfn));//将page加入ballooned_pages链表
}
set_xen_guest_handle(reservation.extent_start,
frame_list);
reservation.nr_extents= nr_pages;
//将mfn转给Xen
ret
= HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
balloon_stats.current_pages
-= nr_pages;
return
state;
}
alloc_xenballooned_pages和free_xenballooned_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.
Xen的支持
见do_memory_op中的XENMEM_increase_reservation和XENMEM_decrease_reservation。increase_reservation是利用alloc_domheap_pages从Xen中获取物理页面,而decrease_reservation是调用guest_remove_page从guest回收页面。