mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-25 06:47:19 +00:00
[module] support in-memory kvmfr devices
Added an array option static_size_mb to the kvmfr module to create a list of in-memory kvmfr devices. These devices support dmabuf just like normal kvmfr devices. Additionally, they can be mmap'd, which allows them to be passed to qemu as ivshmem devices.
This commit is contained in:
parent
a450e0f8f5
commit
b447b78b17
152
module/kvmfr.c
152
module/kvmfr.c
@ -41,6 +41,11 @@ DEFINE_IDR(kvmfr_idr);
|
||||
#define KVMFR_DEV_NAME "kvmfr"
|
||||
#define KVMFR_MAX_DEVICES 10
|
||||
|
||||
static int static_size_mb[KVMFR_MAX_DEVICES];
|
||||
static int static_count;
|
||||
module_param_array(static_size_mb, int, &static_count, 0000);
|
||||
MODULE_PARM_DESC(static_size_mb, "List of static devices to create in MiB");
|
||||
|
||||
struct kvmfr_info
|
||||
{
|
||||
int major;
|
||||
@ -49,6 +54,12 @@ struct kvmfr_info
|
||||
|
||||
static struct kvmfr_info *kvmfr;
|
||||
|
||||
enum kvmfr_type
|
||||
{
|
||||
KVMFR_TYPE_PCI,
|
||||
KVMFR_TYPE_STATIC,
|
||||
};
|
||||
|
||||
struct kvmfr_dev
|
||||
{
|
||||
unsigned long size;
|
||||
@ -57,6 +68,7 @@ struct kvmfr_dev
|
||||
struct device * pDev;
|
||||
struct dev_pagemap pgmap;
|
||||
void * addr;
|
||||
enum kvmfr_type type;
|
||||
};
|
||||
|
||||
struct kvmfrbuf
|
||||
@ -142,14 +154,6 @@ static const struct dma_buf_ops kvmfrbuf_ops =
|
||||
.mmap = mmap_kvmfrbuf
|
||||
};
|
||||
|
||||
inline static unsigned long get_min_align(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_SPARSEMEM_VMEMMAP))
|
||||
return PAGES_PER_SUBSECTION;
|
||||
else
|
||||
return PAGES_PER_SECTION;
|
||||
}
|
||||
|
||||
static long kvmfr_dmabuf_create(struct kvmfr_dev * kdev, struct file * filp, unsigned long arg)
|
||||
{
|
||||
struct kvmfr_dmabuf_create create;
|
||||
@ -188,11 +192,25 @@ static long kvmfr_dmabuf_create(struct kvmfr_dev * kdev, struct file * filp, uns
|
||||
}
|
||||
|
||||
p = ((u8*)kdev->addr) + create.offset;
|
||||
for(i = 0; i < kbuf->pagecount; ++i)
|
||||
|
||||
switch (kdev->type)
|
||||
{
|
||||
case KVMFR_TYPE_PCI:
|
||||
for (i = 0; i < kbuf->pagecount; ++i)
|
||||
{
|
||||
kbuf->pages[i] = virt_to_page(p);
|
||||
p += PAGE_SIZE;
|
||||
}
|
||||
break;
|
||||
|
||||
case KVMFR_TYPE_STATIC:
|
||||
for (i = 0; i < kbuf->pagecount; ++i)
|
||||
{
|
||||
kbuf->pages[i] = vmalloc_to_page(p);
|
||||
p += PAGE_SIZE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
exp_kdev.ops = &kvmfrbuf_ops;
|
||||
exp_kdev.size = create.size;
|
||||
@ -241,10 +259,36 @@ static long device_ioctl(struct file * filp, unsigned int ioctl, unsigned long a
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int device_mmap(struct file * filp, struct vm_area_struct * vma)
|
||||
{
|
||||
struct kvmfr_dev * kdev;
|
||||
unsigned long size = vma->vm_end - vma->vm_start;
|
||||
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
|
||||
|
||||
kdev = (struct kvmfr_dev *)idr_find(&kvmfr_idr, iminor(filp->f_inode));
|
||||
if (!kdev)
|
||||
return -EINVAL;
|
||||
|
||||
if ((offset + size > kdev->size) || (offset + size < offset))
|
||||
return -EINVAL;
|
||||
|
||||
printk(KERN_INFO "mmap kvmfr%d: %lx-%lx with size %lu offset %lu\n",
|
||||
kdev->minor, vma->vm_start, vma->vm_end, size, offset);
|
||||
|
||||
switch (kdev->type)
|
||||
{
|
||||
case KVMFR_TYPE_STATIC:
|
||||
return remap_vmalloc_range(vma, kdev->addr, vma->vm_pgoff);
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
static struct file_operations fops =
|
||||
{
|
||||
.owner = THIS_MODULE,
|
||||
.unlocked_ioctl = device_ioctl
|
||||
.unlocked_ioctl = device_ioctl,
|
||||
.mmap = device_mmap,
|
||||
};
|
||||
|
||||
static int kvmfr_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
@ -262,6 +306,7 @@ static int kvmfr_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
goto out_disable;
|
||||
|
||||
kdev->size = pci_resource_len(dev, 2);
|
||||
kdev->type = KVMFR_TYPE_PCI;
|
||||
|
||||
mutex_lock(&minor_lock);
|
||||
kdev->minor = idr_alloc(&kvmfr_idr, kdev, 0, KVMFR_MAX_DEVICES, GFP_KERNEL);
|
||||
@ -351,6 +396,84 @@ static struct pci_driver kvmfr_pci_driver =
|
||||
.remove = kvmfr_pci_remove
|
||||
};
|
||||
|
||||
static int create_static_device_unlocked(int size_mb)
|
||||
{
|
||||
struct kvmfr_dev * kdev;
|
||||
int ret = -ENODEV;
|
||||
|
||||
kdev = kzalloc(sizeof(struct kvmfr_dev), GFP_KERNEL);
|
||||
if (!kdev)
|
||||
return -ENOMEM;
|
||||
|
||||
kdev->size = size_mb * 1024 * 1024;
|
||||
kdev->type = KVMFR_TYPE_STATIC;
|
||||
kdev->addr = vmalloc_user(kdev->size);
|
||||
if (!kdev->addr)
|
||||
{
|
||||
printk(KERN_ERR "kvmfr: failed to allocate memory for static device: %d MiB\n", size_mb);
|
||||
ret = -ENOMEM;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
kdev->minor = idr_alloc(&kvmfr_idr, kdev, 0, KVMFR_MAX_DEVICES, GFP_KERNEL);
|
||||
if (kdev->minor < 0)
|
||||
goto out_release;
|
||||
|
||||
kdev->devNo = MKDEV(kvmfr->major, kdev->minor);
|
||||
kdev->pDev = device_create(kvmfr->pClass, NULL, kdev->devNo, NULL, KVMFR_DEV_NAME "%d", kdev->minor);
|
||||
if (IS_ERR(kdev->pDev))
|
||||
goto out_unminor;
|
||||
|
||||
return 0;
|
||||
|
||||
out_unminor:
|
||||
idr_remove(&kvmfr_idr, kdev->minor);
|
||||
out_release:
|
||||
vfree(kdev->addr);
|
||||
out_free:
|
||||
kfree(kdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void free_static_device_unlocked(struct kvmfr_dev * kdev)
|
||||
{
|
||||
device_destroy(kvmfr->pClass, kdev->devNo);
|
||||
idr_remove(&kvmfr_idr, kdev->minor);
|
||||
vfree(kdev->addr);
|
||||
kfree(kdev);
|
||||
}
|
||||
|
||||
static void free_static_devices(void)
|
||||
{
|
||||
int id;
|
||||
struct kvmfr_dev * kdev;
|
||||
|
||||
mutex_lock(&minor_lock);
|
||||
idr_for_each_entry(&kvmfr_idr, kdev, id)
|
||||
free_static_device_unlocked(kdev);
|
||||
mutex_unlock(&minor_lock);
|
||||
}
|
||||
|
||||
static int create_static_devices(void)
|
||||
{
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&minor_lock);
|
||||
printk(KERN_INFO "kvmfr: creating %d static devices\n", static_count);
|
||||
for (i = 0; i < static_count; ++i)
|
||||
{
|
||||
ret = create_static_device_unlocked(static_size_mb[i]);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&minor_lock);
|
||||
|
||||
if (ret < 0)
|
||||
free_static_devices();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __init kvmfr_module_init(void)
|
||||
{
|
||||
int ret;
|
||||
@ -367,12 +490,18 @@ static int __init kvmfr_module_init(void)
|
||||
if (IS_ERR(kvmfr->pClass))
|
||||
goto out_unreg;
|
||||
|
||||
ret = pci_register_driver(&kvmfr_pci_driver);
|
||||
ret = create_static_devices();
|
||||
if (ret < 0)
|
||||
goto out_class_destroy;
|
||||
|
||||
ret = pci_register_driver(&kvmfr_pci_driver);
|
||||
if (ret < 0)
|
||||
goto out_free_static;
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_static:
|
||||
free_static_devices();
|
||||
out_class_destroy:
|
||||
class_destroy(kvmfr->pClass);
|
||||
out_unreg:
|
||||
@ -387,6 +516,7 @@ out_free:
|
||||
static void __exit kvmfr_module_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&kvmfr_pci_driver);
|
||||
free_static_devices();
|
||||
class_destroy(kvmfr->pClass);
|
||||
unregister_chrdev(kvmfr->major, KVMFR_DEV_NAME);
|
||||
kfree(kvmfr);
|
||||
|
Loading…
Reference in New Issue
Block a user