vfio-iommu-type1和vfio_fops的关联

当在qemu中调用ioctl(container, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU)的时候会用到vfio_fops->vfio_fops_compat_ioctl->vfio_fops_unl_ioctl
static long vfio_fops_unl_ioctl(struct file *filep,
                unsigned int cmd, unsigned long arg)
{
    case VFIO_SET_IOMMU:
        ret = vfio_ioctl_set_iommu(container, arg);
        break;
}
继续调用vfio_ioctl_set_iommu->__vfio_container_attach_groups
static int __vfio_container_attach_groups(struct vfio_container *container,
                      struct vfio_iommu_driver *driver,
                      void *data)
{
    struct vfio_group *group;
    int ret = -ENODEV;

    list_for_each_entry(group, &container->group_list, container_next) {
        ret = driver->ops->attach_group(data, group->iommu_group);
        if (ret)
            goto unwind;
    }

    return ret;

}
针对vfio_iommu_type1.c 中的初始化函数
static int __init vfio_iommu_type1_init(void)
{
    return vfio_register_iommu_driver(&vfio_iommu_driver_ops_type1);
}
主要是注册一个vfio_iommu_driver_ops_type1。
static const struct vfio_iommu_driver_ops vfio_iommu_driver_ops_type1 = {
    .name        = "vfio-iommu-type1",
    .owner        = THIS_MODULE,
    .open        = vfio_iommu_type1_open,
    .release    = vfio_iommu_type1_release,
    .ioctl        = vfio_iommu_type1_ioctl,
    .attach_group    = vfio_iommu_type1_attach_group,
    .detach_group    = vfio_iommu_type1_detach_group,
};
因此在__vfio_container_attach_groups中的attach函数就对应vfio_iommu_type1_attach_group
static int vfio_iommu_type1_attach_group(void *iommu_data,
                     struct iommu_group *iommu_group)
{
    struct vfio_iommu *iommu = iommu_data;
    struct vfio_group *group, *g;
    struct vfio_domain *domain, *d;
    struct bus_type *bus = NULL;
    int ret;

    mutex_lock(&iommu->lock);
//遍历group_list看是否可以找到group第一次肯定找不到
    list_for_each_entry(d, &iommu->domain_list, next) {
        list_for_each_entry(g, &d->group_list, next) {
            if (g->iommu_group != iommu_group)
                continue;

            mutex_unlock(&iommu->lock);
            return -EINVAL;
        }
    }
//申请group和domian 对象
    group = kzalloc(sizeof(*group), GFP_KERNEL);
    domain = kzalloc(sizeof(*domain), GFP_KERNEL);
    if (!group || !domain) {
        ret = -ENOMEM;
        goto out_free;
    }
//让group->iommu_group指向iommu_group,这样下次在group_list 中就可以找到了
    group->iommu_group = iommu_group;

    /* Determine bus_type in order to allocate a domain */
    ret = iommu_group_for_each_dev(iommu_group, &bus, vfio_bus_type);
    if (ret)
        goto out_free;

    domain->domain = iommu_domain_alloc(bus);
    if (!domain->domain) {
        ret = -EIO;
        goto out_free;
    }

    if (iommu->nesting) {
        int attr = 1;

        ret = iommu_domain_set_attr(domain->domain, DOMAIN_ATTR_NESTING,
                        &attr);
        if (ret)
            goto out_domain;
    }

    ret = iommu_attach_group(domain->domain, iommu_group);
    if (ret)
        goto out_domain;
//将group 添加到dimain的group_list 中
    INIT_LIST_HEAD(&domain->group_list);
    list_add(&group->next, &domain->group_list);

    if (iommu_capable(bus, IOMMU_CAP_CACHE_COHERENCY))
        domain->prot |= IOMMU_CACHE;

    list_for_each_entry(d, &iommu->domain_list, next) {
        if (d->domain->ops == domain->domain->ops &&
            d->prot == domain->prot) {
            iommu_detach_group(domain->domain, iommu_group);
            if (!iommu_attach_group(d->domain, iommu_group)) {
                list_add(&group->next, &d->group_list);
                iommu_domain_free(domain->domain);
                kfree(domain);
                mutex_unlock(&iommu->lock);
                return 0;
            }

            ret = iommu_attach_group(domain->domain, iommu_group);
            if (ret)
                goto out_domain;
        }
    }

    vfio_test_domain_fgsp(domain);

    /* replay mappings on new domains */
    ret = vfio_iommu_replay(iommu, domain);
    if (ret)
        goto out_detach;
//将domian添加到vfio_iommu的domain_list 中
    list_add(&domain->next, &iommu->domain_list);

    mutex_unlock(&iommu->lock);

    return 0;

}
总结一个通过在qemu中调用VFIO_SET_IOMMU,让vfio-iommu-type1类型的iommu和vfio_fops 产生关联

你可能感兴趣的:(Linux,源码分析)