static int vduse_create_dev()

in vdpa_user/vduse_dev.c [1297:1369]


static int vduse_create_dev(struct vduse_dev_config *config,
			    void *config_buf, u64 api_version)
{
	int i, ret;
	struct vduse_dev *dev;

	ret = -EEXIST;
	if (vduse_find_dev(config->name))
		goto err;

	ret = -ENOMEM;
	dev = vduse_dev_create();
	if (!dev)
		goto err;

	dev->api_version = api_version;
	dev->device_features = config->features;
	dev->device_id = config->device_id;
	dev->vendor_id = config->vendor_id;
	dev->name = kstrdup(config->name, GFP_KERNEL);
	if (!dev->name)
		goto err_str;

	dev->domain = vduse_domain_create(VDUSE_IOVA_SIZE - 1,
					  VDUSE_BOUNCE_SIZE);
	if (!dev->domain)
		goto err_domain;

	dev->config = config_buf;
	dev->config_size = config->config_size;
	dev->vq_align = config->vq_align;
	dev->vq_num = config->vq_num;
	dev->vqs = kcalloc(dev->vq_num, sizeof(*dev->vqs), GFP_KERNEL);
	if (!dev->vqs)
		goto err_vqs;

	for (i = 0; i < dev->vq_num; i++) {
		dev->vqs[i].index = i;
		INIT_WORK(&dev->vqs[i].inject, vduse_vq_irq_inject);
		INIT_WORK(&dev->vqs[i].kick, vduse_vq_kick_work);
		spin_lock_init(&dev->vqs[i].kick_lock);
		spin_lock_init(&dev->vqs[i].irq_lock);
	}

	ret = idr_alloc(&vduse_idr, dev, 1, VDUSE_DEV_MAX, GFP_KERNEL);
	if (ret < 0)
		goto err_idr;

	dev->minor = ret;
	dev->msg_timeout = VDUSE_MSG_DEFAULT_TIMEOUT;
	dev->dev = device_create(vduse_class, NULL,
				 MKDEV(MAJOR(vduse_major), dev->minor),
				 dev, "%s", config->name);
	if (IS_ERR(dev->dev)) {
		ret = PTR_ERR(dev->dev);
		goto err_dev;
	}
	__module_get(THIS_MODULE);

	return 0;
err_dev:
	idr_remove(&vduse_idr, dev->minor);
err_idr:
	kfree(dev->vqs);
err_vqs:
	vduse_domain_destroy(dev->domain);
err_domain:
	kfree(dev->name);
err_str:
	vduse_dev_destroy(dev);
err:
	return ret;
}