1. 程式人生 > >virtio的eventfd機制淺析

virtio的eventfd機制淺析

virtio是KVM環境下的I/O虛擬化的框架,目前已經使用到的虛擬化裝置包括block、net、scsi,本質是guest os與host os間的一種高效通訊機制。本文旨在對virtio通訊用到的eventfd進行分析。為了描述簡單,一般來說,稱guest側通知host側的行為為kick,host側通知guset側的行為為call。
參考資料:
1. virtio spec
2. Virtio 基本概念和裝置操作
3. note

1. 什麼是eventfd?

eventfd是隻存在於記憶體中的檔案,通過系統呼叫sys_eventfd可以建立新的檔案,它可以用於執行緒間、程序間的通訊,無論是核心態或使用者態。其實現機制並不複雜,參考核心原始碼樹的

fs/eventfd.c檔案,看資料結構struct eventfd_ctx的定義:

 struct eventfd_ctx {
         struct kref kref;
         wait_queue_head_t wqh;
         /*
          * Every time that a write(2) is performed on an eventfd, the
          * value of the __u64 being written is added to "count" and a
          * wakeup is
performed on "wqh". A read(2) will return the "count" * value to userspace, and will reset "count" to zero. The kernel * side eventfd_signal() also, adds to the "count" counter and * issue a wakeup. */ __u64 count; unsigned int flags; };

eventfd的訊號實際上就是上面的count

,write的時候對其++,read的時候則清零(並不絕對正確)。wait_queue_head wqh則是用來儲存監聽eventfd的睡眠程序,每當有程序來epoll、select且此時不存在有效的訊號(count <= 0),則sleep在wqh上。當某一程序對該eventfd進行write的時候,則會喚醒wqh上的睡眠程序。程式碼細節參考eventfd_read(), eventfd_write()

virtio用到的eventfd其實是kvm中的ioeventfd機制,是對eventfd的又一層封裝(eventfd + iodevice)。該機制不進一步細說,下面結合virtio的kick操作使用來分析,包括兩部分:
1. 如何設定:如何協商該eventfd?
2. 如何產生kick訊號:是誰來負責寫從而產生kick訊號?

2. 如何設定?

即qemu使用者態程序是如何和kvm.ko來協商使用哪一個eventfd來kick通訊。
這裡就要用到kvm的一個系統呼叫:ioctl(KVM_IOEVENTFD, struct kvm_ioeventfd),找一下qemu程式碼中執行該系統呼叫的路徑:

memory_region_transaction_commit() {
    address_space_update_ioeventfds() {
        address_space_add_del_ioeventfds() {
            MEMORY_LISTENER_CALL(eventfd_add, Reverse, &section,
            fd->match_data, fd->data, fd->e);
        }
    }
}

上面的eventfd_add有兩種可能的執行路徑:
1. mmio(Memory mapping I/O): kvm_mem_ioeventfd_add()
2. pio(Port I/O): kvm_io_ioeventfd_add()

通過程式碼靜態分析,上面的呼叫路徑其實只找到了一半,接下來使用gdb來檢視memory_region_transaction_commit()可能的執行路徑,結合vhost_blk(qemu使用者態新增的一項功能,跟qemu-virtio或dataplane在I/O鏈路上的層次類似)看一下設定eventfd的執行路徑:

#0  memory_region_transaction_commit () at /home/gavin4code/qemu-2-1-2/memory.c:799
#1  0x0000000000462475 in memory_region_add_eventfd (mr=0x1256068, addr=16, size=2, match_data=true, data=0, e=0x1253760)
    at /home/gavin4code/qemu-2-1-2/memory.c:1588
#2  0x00000000006d483e in virtio_pci_set_host_notifier_internal (proxy=0x1255820, n=0, assign=true, set_handler=false)
    at hw/virtio/virtio-pci.c:200
#3  0x00000000006d6361 in virtio_pci_set_host_notifier (d=0x1255820, n=0, assign=true) at hw/virtio/virtio-pci.c:884
#4  0x00000000004adb90 in vhost_dev_enable_notifiers (hdev=0x12e6b30, vdev=0x12561f8)
    at /home/gavin4code/qemu-2-1-2/hw/virtio/vhost.c:932
#5  0x00000000004764db in vhost_blk_start (vb=0x1256368) at /home/gavin4code/qemu-2-1-2/hw/block/vhost-blk.c:189
#6  0x00000000004740e5 in virtio_blk_handle_output (vdev=0x12561f8, vq=0x1253710)
    at /home/gavin4code/qemu-2-1-2/hw/block/virtio-blk.c:456
#7  0x00000000004a729e in virtio_queue_notify_vq (vq=0x1253710) at /home/gavin4code/qemu-2-1-2/hw/virtio/virtio.c:774
#8  0x00000000004a9196 in virtio_queue_host_notifier_read (n=0x1253760) at /home/gavin4code/qemu-2-1-2/hw/virtio/virtio.c:1265
#9  0x000000000073d23e in qemu_iohandler_poll (pollfds=0x119e4c0, ret=1) at iohandler.c:143
#10 0x000000000073ce41 in main_loop_wait (nonblocking=0) at main-loop.c:485
#11 0x000000000055524a in main_loop () at vl.c:2031
#12 0x000000000055c407 in main (argc=48, argv=0x7ffff99985c8, envp=0x7ffff9998750) at vl.c:4592

整體執行路徑還是很清晰的,vhost模組的vhost_dev_enable_notifiers()來告訴kvm需要用到的eventfd。

3. 如何產生kick訊號?

大體上來說,guest os覺得有必要通知host對virtqueue上的請求進行處理,就會執行vp_notify(),相當於執行一次port I/O(或者mmio),虛擬機器則會退出guest mode。這裡假設使用的是intel的vmx,當檢測到pio或者mmio會設定vmcs中的exit_reason,host核心態執行vmx_handle_eixt(),檢測exit_reason並執行相應的handler函式(kernel_io()),整體的執行路徑如下:

vmx_handle_eixt() {
    /* kvm_vmx_exit_handlers[exit_reason](vcpu); */
    handle_io() {
        kvm_emulate_pio() {
            kernel_io() {
                if (read) {
                    kvm_io_bus_read() {

                    }
                } else {
                    kvm_io_bus_write() {
                        ioeventfd_write();
                }
            }
        }
    }
}

最後會執行到ioeventfd_write(),這樣就產生了一次kick訊號。
如果該eventfd是由qemu側來監聽的,則會執行對應的qemu函式kvm_handle_io();如果是vhost來監聽的,則直接在vhost核心模組執行vhost->handle_kick()。

qemu kmv_handle_io()的呼叫棧如下所示:

Breakpoint 1, virtio_ioport_write (opaque=0x1606400, addr=18, val=0) at hw/virtio/virtio-pci.c:270
270   {
(gdb) t
[Current thread is 4 (Thread 0x414e7940 (LWP 29695))]
(gdb) bt
#0  virtio_ioport_write (opaque=0x1606400, addr=18, val=0) at hw/virtio/virtio-pci.c:270
#1  0x00000000006d4218 in virtio_pci_config_write (opaque=0x1606400, addr=18, val=0, size=1) at hw/virtio/virtio-pci.c:435
#2  0x000000000045c716 in memory_region_write_accessor (mr=0x1606c48, addr=18, value=0x414e6da8, size=1, shift=0, mask=255) at /home/gavin4code/qemu/memory.c:444
#3  0x000000000045c856 in access_with_adjusted_size (addr=18, value=0x414e6da8, size=1, access_size_min=1, access_size_max=4, access=0x45c689 <memory_region_write_accessor>, mr=0x1606c48)
    at /home/gavin4code/qemu/memory.c:481
#4  0x000000000045f84f in memory_region_dispatch_write (mr=0x1606c48, addr=18, data=0, size=1) at /home/gavin4code/qemu/memory.c:1138
#5  0x00000000004630be in io_mem_write (mr=0x1606c48, addr=18, val=0, size=1) at /home/gavin4code/qemu/memory.c:1976
#6  0x000000000040f030 in address_space_rw (as=0xd05d00 <address_space_io>, addr=49170, buf=0x7f4994f6b000 "", len=1, is_write=true) at /home/gavin4code/qemu/exec.c:2114
#7  0x0000000000458f62 in kvm_handle_io (port=49170, data=0x7f4994f6b000, direction=1, size=1, count=1) at /home/gavin4code/qemu/kvm-all.c:1674
#8  0x00000000004594c6 in kvm_cpu_exec (cpu=0x157ec50) at /home/gavin4code/qemu/kvm-all.c:1811
#9  0x0000000000440364 in qemu_kvm_cpu_thread_fn (arg=0x157ec50) at /home/gavin4code/qemu/cpus.c:930
#10 0x0000003705e0677d in start_thread () from /lib64/libpthread.so.0
#11 0x00000037056d49ad in clone () from /lib64/libc.so.6
#12 0x0000000000000000 in ?? ()

至此,整個virtio的evenfd機制分析結束。

相關推薦

Hibernate 緩存機制淺析

sa1. 為什麽要用 Hibernate 緩存? Hibernate是一個持久層框架,經常訪問物理數據庫。 為了降低應用程序對物理數據源訪問的頻次,從而提高應用程序的運行性能。 緩存內的數據是對物理數據源中的數據的復制,應用程序在運行時從緩存讀寫數據,在特定的時刻或事件會同步緩存和物理數據源的數據

Binder的工作機制淺析

實體類 聲明 工作 xmanager 失敗 pri src android 底層 在Android開發中,Binder主要用於Service中,包括AIDL和Messenger,其中Messenger的底層實現就是AIDL,所以我們這裏通過AIDL來分析一下Binder的工

java反射機制淺析

成員變量 java語言 運行時 淺析 表示 運行 如何 信息 動態獲取 Java反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為Java語言的反射

ASP.NET - 請求處理機制淺析

鏈接 span strong 優化 進行 沒有 可控 安全 進入 一些基本概念 1.進程( Process )//在一定的內存中承載應用程序,一個進程的錯誤可能造成其它進程的崩潰 2.應用程序域(AppDomain)//Net程序需要Clr進行托管以保障安全,App

Keepalived中Master和Backup主備切換機制淺析

keepalived priority weight BACKUP nginx 在keepalived的VRRP實例配置中會一般會設置Master和Backup來指定初始狀態,但是這並不意味著此節點一直就是Master角色。控制節點角色的是Keepalived配置文件中的“pr

MySQL鎖機制淺析

mysq 概率 共享 不可 不執行 date border ali 發的 MySQL使用了3種鎖機制 行級鎖,開銷大,加鎖慢,會出現死鎖,發生鎖沖突的概率最高,並發度也最高 表級鎖,開銷小,加鎖快,不會出現死鎖,發生鎖沖突的概率最低,並發度最低 頁級鎖,開銷和加鎖時間界於表

Spring中的反射機制淺析

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

oracle的resetlogs機制淺析

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Android Binder機制淺析

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Handler消息傳遞機制淺析

ria mes tail odi pro www. https www details http://www.runoob.com/w3cnote/android-tutorial-handler-message.html https://blog.csdn.net/lo

seajs原始碼分析-執行機制淺析(一)

前端技術發展簡直是日新月異,隨著angularjs,vuejs,reactjs等等這些框架的不斷興起,轉眼間jquery,seajs,Backbone這些框架已經成了清朝的框架了,再加上es6本身對於模組化的支援,也許,seajs模組化在將來的某天可能會徹底成為

Android截圖機制淺析

的除錯工具DDMS提供截圖功能,很多同步軟體例如豌豆莢也都提供截圖功能,經分析Android截圖原理大致如下: DDMS是通過adb呼叫裝置端的adbd(ADBdaemon)提供的framebufferservice進行截圖(原始碼在system/core/adb/framebuffer_service

H5 快取機制淺析,移動端 Web 載入效能優化

1 H5 快取機制介紹 H5,即 HTML5,是新一代的 HTML 標準,加入很多新的特性。離線儲存(也可稱為快取機制)是其中一個非常重要的特性。H5 引入的離線儲存,這意味著 web 應用可進行快取,並可在沒有因特網連線時進行訪問。 H5 應用程式快取為應用帶來三個優勢:

virtio的eventfd機制淺析

virtio是KVM環境下的I/O虛擬化的框架,目前已經使用到的虛擬化裝置包括block、net、scsi,本質是guest os與host os間的一種高效通訊機制。本文旨在對virtio通訊用到的eventfd進行分析。為了描述簡單,一般來說,稱guest側

H5 快取機制淺析 移動端 Web 載入效能優化

1 H5 快取機制介紹 H5,即 HTML5,是新一代的 HTML 標準,加入很多新的特性。離線儲存(也可稱為快取機制)是其中一個非常重要的特性。H5 引入的離線儲存,這意味著 web 應用可進行快取,並可在沒有因特網連線時進行訪問。 H5 應用程式快取為

Java的SPI機制淺析與簡單示例

一、SPI機制         這裡先說下SPI的一個概念,SPI英文為Service Provider Interface單從字面可以理解為Service提供者介面,正如從SPI的名字去理解SPI

Android 訊息處理機制淺析

Android是訊息驅動的,實現訊息驅動有幾個要素: 訊息的表示:Message 訊息佇列:MessageQueue 訊息迴圈,用於迴圈取出訊息進行處理:Looper 訊息處理,訊息迴圈從訊息佇列中取出訊息後要對訊息進行處理:Handler 平時我們最常使用的就是Messa

Android多網路機制淺析

Android從4.2版本開始,逐步支援了多網路功能。相關的api能夠讓開發者選擇想要的網路裝置訪問,並且各個裝置之間的切換和繫結也越來越方便。 判斷網路連通性機制 從Android4.2.2開始,引入了一個叫“captive portal” detection的機制,用

Windows 訊息機制淺析

1. Windows 的歷史中國人喜歡以史為鑑,而事實也確實是,如果你能知道一件事情的來龍去脈,往往可以更容易地理解事物為什麼會表現為當前這樣的現狀。所以,我的介紹性開場白通常會以一段歷史開始。不過,我不會以精確到年月日的那種方式詳細講述,而是選取幾個對我們的程式設計生涯有重

Android AIDL——實現機制淺析

1.基於前面寫的aidl使用,這段時間準備研究ActivityManager框架,對aidl進行了更深入的研究,因為android框架大量使用了程序通訊機制,所以,在研究android framework前認真研究一下AIDL的實現機制十分有必要的   2.前面講了aidl