参考资料

【openstack相关】

http://specs.openstack.org/openstack/nova-specs/specs/juno/implemented/enabled-qemu-memballoon-stats.html

http://lists.openstack.org/pipermail/openstack-dev/2015-January/054652.html

http://stackalytics.com/report/blueprint/nova/enabled-qemu-memballoon-stats

https://github.com/openstack/nova-specs/blob/master/specs/juno/implemented/enabled-qemu-memballoon-stats.rst

https://openstack.nimeyo.com/902/openstack-dev-libvirt-memory-ballooning-nova

【虚拟化相关】

http://smilejay.com/2012/11/use-ballooning-in-kvm/

http://libvirt.org/formatdomain.html#elementsMemoryAllocation

http://www.espenbraastad.no/post/memory-ballooning/

virsh相关命令

virsh domstats —balloon

visrh dommemstat

http://www.openstack.cn/?p=4540

http://niusmallnan.com/_build/html/_templates/openstack/libvirt_memory_usage.html

http://blog.csdn.net/tpiperatgod/article/details/46377555

注:这个命令获取的是guest内部的内存信息

使用virsh dommemstat通过balloon获取guest内存使用情况的函数update_balloon_stats,

他只是获取了SWAPIN,SWAPOUT,major pagefault,min pagefault,free内存,total内存统计,其中我们最关心的是free内存统计就是NR_FREE_PAGES,对我们指导意义不大,linux都是尽最大的努力的使用内存,其中很多是cache占用了,而NR_FREE_PAGES中不包括cache,这样我们以为虚拟机中的内存不多,其实可能比较多,其实我们比较关注的是memavailable对应的内存大小

MemAvailable: 20751532 kB

centos7内核搞了一个算法来评估memavailable,可以参考meminfo_proc_show函数实现

virsh setmem

【automatic ballooning】

http://www.linux-kvm.org/page/Projects/auto-ballooning

https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg571627.html

https://www.mail-archive.com/qemu-devel@nongnu.org/msg211168.html

【代码分析】

1. 前端代码

后端调整balloon size时是通过virtio config changed中断通知virtio-ballon设备,在virtio-balloon的config-change handle中会通worker读取virtio-pci的config空间,找到相应的size设置,然后决定做fill还是leak,最后把balloon的结果size写到config空间中

static void virtballoon_changed(struct virtio_device *vdev)

{

struct virtio_balloon *vb = vdev->priv;

wake_up(&vb->config_change);

}

static int balloon(void *_vballoon)

{

struct virtio_balloon *vb = _vballoon;

set_freezable();

while (!kthread_should_stop()) {

s64 diff;

try_to_freeze();

wait_event_interruptible(vb->config_change,

  1. (diff = towards_target(vb)) != 0
  2. || vb->need_stats_update
  3. || kthread_should_stop()
  4. || freezing(current));

if (vb->need_stats_update)

stats_handle_request(vb);

if (diff > 0)

fill_balloon(vb, diff);

else if (diff < 0)

leak_balloon(vb, -diff);

update_balloon_size(vb);

}

return 0;

}

static void stats_request(struct virtqueue *vq)

{

struct virtio_balloon *vb = vq->vdev->priv;

vb->need_stats_update = 1;

wake_up(&vb->config_change);

}

这个是后端通知前端更新stats的处理函数。

2. 后端代码

从qemu的balloon_stats_set_poll_interval函数来看,它会设置一个stats_timer,

s->stats_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, balloon_stats_poll_cb, s);

每隔stats_poll_interval时间就会virtio_notify前端virtio-balloon设备update stats,前端最终会调用注册的callback stats_request,stats_request会设置need_stats_update,然后wakeup balloon内核线程,该内核线程回去更新stats。

并且后端还提供了一个qmp info balloon,该qmp最终会去读balloon stats