static long vduse_ioctl()

in vdpa_user/vduse_dev.c [1371:1440]


static long vduse_ioctl(struct file *file, unsigned int cmd,
			unsigned long arg)
{
	int ret;
	void __user *argp = (void __user *)arg;
	struct vduse_control *control = file->private_data;

	mutex_lock(&vduse_lock);
	switch (cmd) {
	case VDUSE_GET_API_VERSION:
		ret = put_user(control->api_version, (u64 __user *)argp);
		break;
	case VDUSE_SET_API_VERSION: {
		u64 api_version;

		ret = -EFAULT;
		if (get_user(api_version, (u64 __user *)argp))
			break;

		ret = -EINVAL;
		if (api_version > VDUSE_API_VERSION)
			break;

		ret = 0;
		control->api_version = api_version;
		break;
	}
	case VDUSE_CREATE_DEV: {
		struct vduse_dev_config config;
		unsigned long size = offsetof(struct vduse_dev_config, config);
		void *buf;

		ret = -EFAULT;
		if (copy_from_user(&config, argp, size))
			break;

		ret = -EINVAL;
		if (vduse_validate_config(&config) == false)
			break;

		buf = vmemdup_user(argp + size, config.config_size);
		if (IS_ERR(buf)) {
			ret = PTR_ERR(buf);
			break;
		}
		config.name[VDUSE_NAME_MAX - 1] = '\0';
		ret = vduse_create_dev(&config, buf, control->api_version);
		if (ret)
			kvfree(buf);
		break;
	}
	case VDUSE_DESTROY_DEV: {
		char name[VDUSE_NAME_MAX];

		ret = -EFAULT;
		if (copy_from_user(name, argp, VDUSE_NAME_MAX))
			break;

		name[VDUSE_NAME_MAX - 1] = '\0';
		ret = vduse_destroy_dev(name);
		break;
	}
	default:
		ret = -EINVAL;
		break;
	}
	mutex_unlock(&vduse_lock);

	return ret;
}