[PATCH v2 16/16] kcov: update kcov to use mmap_prepare

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



We can use the mmap insert pages functionality provided for use in
mmap_prepare to insert the kcov pages as required.

This does necessitate an allocation, but since it's in the mmap path this
doesn't seem egregious. The allocation/freeing of the pages array is
handled automatically by vma_desc_set_mixedmap_pages() and the mapping
logic.

Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@xxxxxxxxxx>
---
 kernel/kcov.c | 42 ++++++++++++++++++++++++++----------------
 1 file changed, 26 insertions(+), 16 deletions(-)

diff --git a/kernel/kcov.c b/kernel/kcov.c
index 1d85597057e1..2bcf403e5f6f 100644
--- a/kernel/kcov.c
+++ b/kernel/kcov.c
@@ -484,31 +484,41 @@ void kcov_task_exit(struct task_struct *t)
 	kcov_put(kcov);
 }
 
-static int kcov_mmap(struct file *filep, struct vm_area_struct *vma)
+static int kcov_mmap_error(int err)
+{
+	pr_warn_once("kcov: vm_insert_page() failed\n");
+	return err;
+}
+
+static int kcov_mmap_prepare(struct vm_area_desc *desc)
 {
 	int res = 0;
-	struct kcov *kcov = vma->vm_file->private_data;
-	unsigned long size, off;
-	struct page *page;
+	struct kcov *kcov = desc->file->private_data;
+	unsigned long size, nr_pages, i;
+	struct page **pages;
 	unsigned long flags;
 
 	spin_lock_irqsave(&kcov->lock, flags);
 	size = kcov->size * sizeof(unsigned long);
-	if (kcov->area == NULL || vma->vm_pgoff != 0 ||
-	    vma->vm_end - vma->vm_start != size) {
+	if (kcov->area == NULL || desc->pgoff != 0 ||
+	    vma_desc_size(desc) != size) {
 		res = -EINVAL;
 		goto exit;
 	}
 	spin_unlock_irqrestore(&kcov->lock, flags);
-	vm_flags_set(vma, VM_DONTEXPAND);
-	for (off = 0; off < size; off += PAGE_SIZE) {
-		page = vmalloc_to_page(kcov->area + off);
-		res = vm_insert_page(vma, vma->vm_start + off, page);
-		if (res) {
-			pr_warn_once("kcov: vm_insert_page() failed\n");
-			return res;
-		}
-	}
+
+	desc->vm_flags |= VM_DONTEXPAND;
+	nr_pages = size >> PAGE_SHIFT;
+
+	pages = mmap_action_mixedmap_pages(&desc->action, desc->start,
+					   nr_pages);
+	if (!pages)
+		return -ENOMEM;
+
+	for (i = 0; i < nr_pages; i++)
+		pages[i] = vmalloc_to_page(kcov->area + i * PAGE_SIZE);
+	desc->action.error_hook = kcov_mmap_error;
+
 	return 0;
 exit:
 	spin_unlock_irqrestore(&kcov->lock, flags);
@@ -761,7 +771,7 @@ static const struct file_operations kcov_fops = {
 	.open		= kcov_open,
 	.unlocked_ioctl	= kcov_ioctl,
 	.compat_ioctl	= kcov_ioctl,
-	.mmap		= kcov_mmap,
+	.mmap_prepare	= kcov_mmap_prepare,
 	.release        = kcov_close,
 };
 
-- 
2.51.0





[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux