aboutsummaryrefslogtreecommitdiffstats
path: root/virt/kvm/kvm_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'virt/kvm/kvm_main.c')
-rw-r--r--virt/kvm/kvm_main.c129
1 files changed, 129 insertions, 0 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index f9492f3847d6..5f0d78c2537b 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2159,6 +2159,117 @@ out:
2159} 2159}
2160#endif 2160#endif
2161 2161
2162static int kvm_device_ioctl_attr(struct kvm_device *dev,
2163 int (*accessor)(struct kvm_device *dev,
2164 struct kvm_device_attr *attr),
2165 unsigned long arg)
2166{
2167 struct kvm_device_attr attr;
2168
2169 if (!accessor)
2170 return -EPERM;
2171
2172 if (copy_from_user(&attr, (void __user *)arg, sizeof(attr)))
2173 return -EFAULT;
2174
2175 return accessor(dev, &attr);
2176}
2177
2178static long kvm_device_ioctl(struct file *filp, unsigned int ioctl,
2179 unsigned long arg)
2180{
2181 struct kvm_device *dev = filp->private_data;
2182
2183 switch (ioctl) {
2184 case KVM_SET_DEVICE_ATTR:
2185 return kvm_device_ioctl_attr(dev, dev->ops->set_attr, arg);
2186 case KVM_GET_DEVICE_ATTR:
2187 return kvm_device_ioctl_attr(dev, dev->ops->get_attr, arg);
2188 case KVM_HAS_DEVICE_ATTR:
2189 return kvm_device_ioctl_attr(dev, dev->ops->has_attr, arg);
2190 default:
2191 if (dev->ops->ioctl)
2192 return dev->ops->ioctl(dev, ioctl, arg);
2193
2194 return -ENOTTY;
2195 }
2196}
2197
2198void kvm_device_get(struct kvm_device *dev)
2199{
2200 atomic_inc(&dev->users);
2201}
2202
2203void kvm_device_put(struct kvm_device *dev)
2204{
2205 if (atomic_dec_and_test(&dev->users))
2206 dev->ops->destroy(dev);
2207}
2208
2209static int kvm_device_release(struct inode *inode, struct file *filp)
2210{
2211 struct kvm_device *dev = filp->private_data;
2212 struct kvm *kvm = dev->kvm;
2213
2214 kvm_device_put(dev);
2215 kvm_put_kvm(kvm);
2216 return 0;
2217}
2218
2219static const struct file_operations kvm_device_fops = {
2220 .unlocked_ioctl = kvm_device_ioctl,
2221 .release = kvm_device_release,
2222};
2223
2224struct kvm_device *kvm_device_from_filp(struct file *filp)
2225{
2226 if (filp->f_op != &kvm_device_fops)
2227 return NULL;
2228
2229 return filp->private_data;
2230}
2231
2232static int kvm_ioctl_create_device(struct kvm *kvm,
2233 struct kvm_create_device *cd)
2234{
2235 struct kvm_device_ops *ops = NULL;
2236 struct kvm_device *dev;
2237 bool test = cd->flags & KVM_CREATE_DEVICE_TEST;
2238 int ret;
2239
2240 switch (cd->type) {
2241 default:
2242 return -ENODEV;
2243 }
2244
2245 if (test)
2246 return 0;
2247
2248 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
2249 if (!dev)
2250 return -ENOMEM;
2251
2252 dev->ops = ops;
2253 dev->kvm = kvm;
2254 atomic_set(&dev->users, 1);
2255
2256 ret = ops->create(dev, cd->type);
2257 if (ret < 0) {
2258 kfree(dev);
2259 return ret;
2260 }
2261
2262 ret = anon_inode_getfd(ops->name, &kvm_device_fops, dev, O_RDWR);
2263 if (ret < 0) {
2264 ops->destroy(dev);
2265 return ret;
2266 }
2267
2268 kvm_get_kvm(kvm);
2269 cd->fd = ret;
2270 return 0;
2271}
2272
2162static long kvm_vm_ioctl(struct file *filp, 2273static long kvm_vm_ioctl(struct file *filp,
2163 unsigned int ioctl, unsigned long arg) 2274 unsigned int ioctl, unsigned long arg)
2164{ 2275{
@@ -2304,6 +2415,24 @@ static long kvm_vm_ioctl(struct file *filp,
2304 break; 2415 break;
2305 } 2416 }
2306#endif /* CONFIG_HAVE_KVM_IRQ_ROUTING */ 2417#endif /* CONFIG_HAVE_KVM_IRQ_ROUTING */
2418 case KVM_CREATE_DEVICE: {
2419 struct kvm_create_device cd;
2420
2421 r = -EFAULT;
2422 if (copy_from_user(&cd, argp, sizeof(cd)))
2423 goto out;
2424
2425 r = kvm_ioctl_create_device(kvm, &cd);
2426 if (r)
2427 goto out;
2428
2429 r = -EFAULT;
2430 if (copy_to_user(argp, &cd, sizeof(cd)))
2431 goto out;
2432
2433 r = 0;
2434 break;
2435 }
2307 default: 2436 default:
2308 r = kvm_arch_vm_ioctl(filp, ioctl, arg); 2437 r = kvm_arch_vm_ioctl(filp, ioctl, arg);
2309 if (r == -ENOTTY) 2438 if (r == -ENOTTY)