vfio 从group->device_list 中查找device,并通过匿名node和fd建立关系

在qemu中hw/vfio/common.c的vfio_get_device
int vfio_get_device(VFIOGroup *group, const char *name,
                    VFIODevice *vbasedev, Error **errp)
{
    struct vfio_device_info dev_info = { .argsz = sizeof(dev_info) };
    int ret, fd;

    fd = ioctl(group->fd, VFIO_GROUP_GET_DEVICE_FD, name);
    if (fd < 0) {
        error_setg_errno(errp, errno, "error getting device from group %d",
                         group->groupid);
        error_append_hint(errp,
                      "Verify all devices in group %d are bound to vfio-<bus> "
                      "or pci-stub and not already in use\n", group->groupid);
        return fd;
    }
 
}
来获得device,从vfio_get_device 也可以看出VFIO_GROUP_GET_DEVICE_FD 这个ioctl是在group中实现,而在kernel中group的ioctl如下:
static long vfio_group_fops_unl_ioctl(struct file *filep,
                      unsigned int cmd, unsigned long arg)
{
    struct vfio_group *group = filep->private_data;
    long ret = -ENOTTY;

    switch (cmd) {
    case VFIO_GROUP_GET_DEVICE_FD:
    {
        char *buf;

        buf = strndup_user((const char __user *)arg, PAGE_SIZE);
        if (IS_ERR(buf))
            return PTR_ERR(buf);

        ret = vfio_group_get_device_fd(group, buf);
        kfree(buf);
        break;
    }

}
通过strndup_user 将用户空间的name copy到buf中,这个buf中就是一个字符串,代表具体的device.
static int vfio_group_get_device_fd(struct vfio_group *group, char *buf)
{
    struct vfio_device *device;
    struct file *filep;
    int ret;

    if (0 == atomic_read(&group->container_users) ||
        !group->container->iommu_driver || !vfio_group_viable(group))
        return -EINVAL;

    if (group->noiommu && !capable(CAP_SYS_RAWIO))
        return -EPERM;
//通过遍历group->device_list 来找vfio_device,匹配的规则是(!strcmp(dev_name(it->dev), buf)) 即名字相等.
    device = vfio_device_get_from_name(group, buf);
    if (!device)
        return -ENODEV;
//调用device的open函数
    ret = device->ops->open(device->device_data);
    if (ret) {
        vfio_device_put(device);
        return ret;
    }

    /*
     * We can't use anon_inode_getfd() because we need to modify
     * the f_mode flags directly to allow more than just ioctls
     */
//找到没有使用的fd
    ret = get_unused_fd_flags(O_CLOEXEC);
    if (ret < 0) {
        device->ops->release(device->device_data);
        vfio_device_put(device);
        return ret;
    }
//使用匿名node将device和vfio_device_fops 想关联
    filep = anon_inode_getfile("[vfio-device]", &vfio_device_fops,
                   device, O_RDWR);
    if (IS_ERR(filep)) {
        put_unused_fd(ret);
        ret = PTR_ERR(filep);
        device->ops->release(device->device_data);
        vfio_device_put(device);
        return ret;
    }

    /*
     * TODO: add an anon_inode interface to do this.
     * Appears to be missing by lack of need rather than
     * explicitly prevented.  Now there's need.
     */
    filep->f_mode |= (FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);

    atomic_inc(&group->container_users);
//将fd和通过匿名node返回的filep关联.
    fd_install(ret, filep);

    if (group->noiommu)
        dev_warn(device->dev, "vfio-noiommu device opened by user "
             "(%s:%d)\n", current->comm, task_pid_nr(current));

    return ret;
}
其中vfio_device_get_from_name的实现如下:可以看到是从group->device_list 中遍历查找device,匹配的规则就是name相等就行,所有的device都是挂在group->device_list 这个list中。

static struct vfio_device *vfio_device_get_from_name(struct vfio_group *group,
                             char *buf)
{
    struct vfio_device *it, *device = NULL;

    mutex_lock(&group->device_lock);
    list_for_each_entry(it, &group->device_list, group_next) {
        if (!strcmp(dev_name(it->dev), buf)) {
            device = it;
            vfio_device_get(device);
            break;
        }
    }
    mutex_unlock(&group->device_lock);

    return device;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值