cregit-Linux how code gets into the kernel

Release 4.18 drivers/xen/privcmd-buf.c

Directory: drivers/xen
// SPDX-License-Identifier: GPL-2.0 OR MIT

/******************************************************************************
 * privcmd-buf.c
 *
 * Mmap of hypercall buffers.
 *
 * Copyright (c) 2018 Juergen Gross
 */


#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
#include <linux/slab.h>

#include "privcmd.h"

MODULE_LICENSE("GPL");


static unsigned int limit = 64;
module_param(limit, uint, 0644);
MODULE_PARM_DESC(limit, "Maximum number of pages that may be allocated by "
			"the privcmd-buf device per open file");


struct privcmd_buf_private {
	
struct mutex lock;
	
struct list_head list;
	
unsigned int allocated;
};


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; }

Contributors

PersonTokensPropCommitsCommitProp
Juergen Gross68100.00%1100.00%
Total68100.00%1100.00%


static void privcmd_buf_vmapriv_free(struct privcmd_buf_vma_private *vma_priv) { unsigned int i; vma_priv->file_priv->allocated -= vma_priv->n_pages; list_del(&vma_priv->list); for (i = 0; i < vma_priv->n_pages; i++) if (vma_priv->pages[i]) __free_page(vma_priv->pages[i]); kfree(vma_priv); }

Contributors

PersonTokensPropCommitsCommitProp
Juergen Gross72100.00%1100.00%
Total72100.00%1100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Juergen Gross87100.00%1100.00%
Total87100.00%1100.00%


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; mutex_lock(&vma_priv->file_priv->lock); vma_priv->users++; mutex_unlock(&vma_priv->file_priv->lock); }

Contributors

PersonTokensPropCommitsCommitProp
Juergen Gross51100.00%1100.00%
Total51100.00%1100.00%


static void privcmd_buf_vma_close(struct vm_area_struct *vma) { struct privcmd_buf_vma_private *vma_priv = vma->vm_private_data; struct privcmd_buf_private *file_priv; if (!vma_priv) return; file_priv = vma_priv->file_priv; mutex_lock(&file_priv->lock); vma_priv->users--; if (!vma_priv->users) privcmd_buf_vmapriv_free(vma_priv); mutex_unlock(&file_priv->lock); }

Contributors

PersonTokensPropCommitsCommitProp
Juergen Gross70100.00%1100.00%
Total70100.00%1100.00%


static vm_fault_t privcmd_buf_vma_fault(struct vm_fault *vmf) { pr_debug("fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n", vmf->vma, vmf->vma->vm_start, vmf->vma->vm_end, vmf->pgoff, (void *)vmf->address); return VM_FAULT_SIGBUS; }

Contributors

PersonTokensPropCommitsCommitProp
Juergen Gross47100.00%1100.00%
Total47100.00%1100.00%

static const struct vm_operations_struct privcmd_buf_vm_ops = { .open = privcmd_buf_vma_open, .close = privcmd_buf_vma_close, .fault = privcmd_buf_vma_fault, };
static int privcmd_buf_mmap(struct file *file, struct vm_area_struct *vma) { struct privcmd_buf_private *file_priv = file->private_data; struct privcmd_buf_vma_private *vma_priv; unsigned long count = vma_pages(vma); unsigned int i; int ret = 0; if (!(vma->vm_flags & VM_SHARED) || count > limit || file_priv->allocated + count > limit) return -EINVAL; vma_priv = kzalloc(sizeof(*vma_priv) + count * sizeof(void *), GFP_KERNEL); if (!vma_priv) return -ENOMEM; vma_priv->n_pages = count; count = 0; for (i = 0; i < vma_priv->n_pages; i++) { vma_priv->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); if (!vma_priv->pages[i]) break; count++; } mutex_lock(&file_priv->lock); file_priv->allocated += count; vma_priv->file_priv = file_priv; vma_priv->users = 1; vma->vm_flags |= VM_IO | VM_DONTEXPAND; vma->vm_ops = &privcmd_buf_vm_ops; vma->vm_private_data = vma_priv; list_add(&vma_priv->list, &file_priv->list); if (vma_priv->n_pages != count) ret = -ENOMEM; else for (i = 0; i < vma_priv->n_pages; i++) { ret = vm_insert_page(vma, vma->vm_start + i * PAGE_SIZE, vma_priv->pages[i]); if (ret) break; } if (ret) privcmd_buf_vmapriv_free(vma_priv); mutex_unlock(&file_priv->lock); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Juergen Gross298100.00%1100.00%
Total298100.00%1100.00%

const struct file_operations xen_privcmdbuf_fops = { .owner = THIS_MODULE, .open = privcmd_buf_open, .release = privcmd_buf_release, .mmap = privcmd_buf_mmap, }; EXPORT_SYMBOL_GPL(xen_privcmdbuf_fops); struct miscdevice xen_privcmdbuf_dev = { .minor = MISC_DYNAMIC_MINOR, .name = "xen/hypercall", .fops = &xen_privcmdbuf_fops, };

Overall Contributors

PersonTokensPropCommitsCommitProp
Juergen Gross874100.00%1100.00%
Total874100.00%1100.00%
Directory: drivers/xen
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.