PCI热插拔

1在guest linux加载驱动模块:
    一般pci热插拔需要两个内核模块:  acpiphp.ko 和 pci_hotplug.ko  
pci_hotplug.ko  已经被编译进内核文件中,不需要再手动加载。(可以通过/boot/目录下的config 文件来判断是否已经编译进内核)
打开 /etc/modules 文件,在里面输入 acpiphp.即可在再次启动的时候加载 acpiphp 内核模块。


2使用QEMU monitor来热加载设备

QEMU monitor有一个命令pci_add,用来hotadd pci 设备。启动 qemu的时候加入参数    -monitor stdio.

QEMU 1.1.90 monitor - type 'help' for more information
(qemu) help pci_add
pci_add auto|[[<domain>:]<bus>:]<slot> nic|storage [[vlan=n][,macaddr=addr][,model=type]] [file=file][,if=type][,bus=nr]... -- hot-add PCI device

增加一个disk
hot-add个disk意味着 hot-add 个PCI设备,所以想正常工作需要在guest中加入PCI hotplug的支持。
下面的命令会在guest中加入一个scsi磁盘:

 * pci_add auto storage file=/home/sina/work/system/empty.img,if=scsi
也可依用if=virtio来替换 if=scsi,但是IDE不是hotpluggable
pci_add 前  

00:00.0 Host bridge: Intel Corporation 440FX - 82441FX PMC [Natoma] (rev 02)
00:01.0 ISA bridge: Intel Corporation 82371SB PIIX3 ISA [Natoma/Triton II]
00:01.1 IDE interface: Intel Corporation 82371SB PIIX3 IDE [Natoma/Triton II]
00:01.3 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 03)
00:02.0 VGA compatible controller: Cirrus Logic GD 5446
00:03.0 Ethernet controller: Intel Corporation 82540EM Gigabit Ethernet Controller (rev 03)

pci_add  empty.img 之后:

00:00.0 Host bridge: Intel Corporation 440FX - 82441FX PMC [Natoma] (rev 02)
00:01.0 ISA bridge: Intel Corporation 82371SB PIIX3 ISA [Natoma/Triton II]
00:01.1 IDE interface: Intel Corporation 82371SB PIIX3 IDE [Natoma/Triton II]
00:01.3 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 03)
00:02.0 VGA compatible controller: Cirrus Logic GD 5446
00:03.0 Ethernet controller: Intel Corporation 82540EM Gigabit Ethernet Controller (rev 03)
00:04.0 SCSI storage controller: LSI Logic / Symbios Logic 53c895a

在guest中通过 dmesg 可看到device已被加入。

[   93.533872] ACPI: PCI Interrupt Link [LNKD] enabled at IRQ 10
[   93.533951] sym53c8xx 0000:00:04.0: PCI INT A -> Link[LNKD] -> GSI 10 (level, high) -> IRQ 10
[   93.537031] sym0: <895a> rev 0x0 at pci 0000:00:04.0 irq 10
[   93.539563] sym0: No NVRAM, ID 7, Fast-40, LVD, parity checking
[   93.540029] sym0: SCSI BUS has been reset.
[   93.554166] scsi2 : sym-2.2.3
[   96.556817] sym0: unknown interrupt(s) ignored, ISTAT=0x5 DSTAT=0x80 SIST=0x0
[   96.556981] scsi 2:0:0:0: Direct-Access     QEMU     QEMU HARDDISK    1.1. PQ: 0 ANSI: 5
[   96.557004] scsi target2:0:0: tagged command queuing enabled, command queue depth 16.
[   96.557021] scsi target2:0:0: Beginning Domain Validation
[   96.559328] scsi target2:0:0: Domain Validation skipping write tests
[   96.559335] scsi target2:0:0: Ending Domain Validation
[   96.578176] sd 2:0:0:0: [sdb] 1048576 512-byte logical blocks: (536 MB/512 MiB)
[   96.578647] sd 2:0:0:0: [sdb] Write Protect is off
[   96.578651] sd 2:0:0:0: [sdb] Mode Sense: 63 00 00 08
[   96.579001] sd 2:0:0:0: [sdb] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[   96.583432] sd 2:0:0:0: Attached scsi generic sg2 type 0
[   96.585323] sdb: unknown partition table
[   96.586613] sd 2:0:0:0: [sdb] Attached SCSI disk

在虚拟机中验证是否已经将scsi硬盘插入:
$ls /dev/sd*
如果插入成功,那么/dev目录下将会出现新加入的硬盘。

增加NIC设备
pci_add auto nic model=e1000
可以用 model=rtl8139, model=virtio, or model=ne2k_pci 来替换model=e1000。
(qemu) pci_add auto nic  model=e1000                                                                                                
( 注意 测试时用户空间的程序应使用  qemu-kvm ,而不是qemu)

在monitor 中拔除pci设备:
(qemu)pci_del slot_num
其中slot_num为pci_add成功时所提示的slot号。


2、代码跟踪:
使用gdb对qemu的pci_add后执行的代码进行跟踪以便动态地分析QEMU的热插拔机制:
pci_device_hot_add 函数将会被调用,该函数首先获得pci_add的参数:

    PCIDevice *dev = NULL;
    const char *pci_addr = qdict_get_str(qdict, "pci_addr");
    const char *type = qdict_get_str(qdict, "type");
    const char *opts = qdict_get_try_str(qdict, "opts");
对于我们上面执行的pci_add命令,解析后:
pci_addr = “auto”
type = “storage”
opts = “if=scsi,file=empty.img”
pci_device_hot_add将会根据type进行选择去执行是执行 qemu_pci_hot_add_nic 还是qemu_pci_hot_add_storage,并将mon,pci_addr,opts传入,pci_device_hot_add函数的核心功能就完成了。

    if (strcmp(type, "nic") == 0) {
        dev = qemu_pci_hot_add_nic(mon, pci_addr, opts);
    } else if (strcmp(type, "storage") == 0) {
        dev = qemu_pci_hot_add_storage(mon, pci_addr, opts);
    } else {
        monitor_printf(mon, "invalid type: %s\n", type);
    }
进入 qemu_pci_hot_add_storage(mon,pci_addr,opts)  函数,该函数需要返回一个PCIDevice的指针。




原文链接:
http://www.linux-kvm.org/page/Hotadd_pci_devices















你可能感兴趣的:(PCI热插拔)