diff options
Diffstat (limited to 'virt/kvm/kvm_main.c')
-rw-r--r-- | virt/kvm/kvm_main.c | 129 |
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 | ||
2162 | static 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 | |||
2178 | static 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 | |||
2198 | void kvm_device_get(struct kvm_device *dev) | ||
2199 | { | ||
2200 | atomic_inc(&dev->users); | ||
2201 | } | ||
2202 | |||
2203 | void kvm_device_put(struct kvm_device *dev) | ||
2204 | { | ||
2205 | if (atomic_dec_and_test(&dev->users)) | ||
2206 | dev->ops->destroy(dev); | ||
2207 | } | ||
2208 | |||
2209 | static 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 | |||
2219 | static const struct file_operations kvm_device_fops = { | ||
2220 | .unlocked_ioctl = kvm_device_ioctl, | ||
2221 | .release = kvm_device_release, | ||
2222 | }; | ||
2223 | |||
2224 | struct 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 | |||
2232 | static 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 | |||
2162 | static long kvm_vm_ioctl(struct file *filp, | 2273 | static 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) |