Source
x
// SPDX-License-Identifier: GPL-2.0 OR MIT
/******************************************************************************
* privcmd-buf.c
*
* Mmap of hypercall buffers.
*
* Copyright (c) 2018 Juergen Gross
*/
MODULE_LICENSE("GPL");
struct privcmd_buf_private {
struct mutex lock;
struct list_head list;
};
struct privcmd_buf_vma_private {
struct privcmd_buf_private *file_priv;
struct list_head list;
unsigned int users;
unsigned int n_pages;
struct page *pages[];
};
static int privcmd_buf_open(struct inode *ino, struct file *file)
{
struct privcmd_buf_private *file_priv;
file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
if (!file_priv)
return -ENOMEM;
mutex_init(&file_priv->lock);
INIT_LIST_HEAD(&file_priv->list);
file->private_data = file_priv;
return 0;
}
static void privcmd_buf_vmapriv_free(struct privcmd_buf_vma_private *vma_priv)
{
unsigned int i;
list_del(&vma_priv->list);
for (i = 0; i < vma_priv->n_pages; i++)
__free_page(vma_priv->pages[i]);
kfree(vma_priv);
}
static int privcmd_buf_release(struct inode *ino, struct file *file)
{
struct privcmd_buf_private *file_priv = file->private_data;
struct privcmd_buf_vma_private *vma_priv;
mutex_lock(&file_priv->lock);
while (!list_empty(&file_priv->list)) {
vma_priv = list_first_entry(&file_priv->list,
struct privcmd_buf_vma_private,
list);
privcmd_buf_vmapriv_free(vma_priv);
}
mutex_unlock(&file_priv->lock);
kfree(file_priv);
return 0;
}
static void privcmd_buf_vma_open(struct vm_area_struct *vma)
{
struct privcmd_buf_vma_private *vma_priv = vma->vm_private_data;
if (!vma_priv)
return;