* [PATCH v3 1/3] mm: cma: debugfs interface
2015-01-28 2:22 [PATCH v3 0/3] mm: cma: debugfs access to CMA Sasha Levin
@ 2015-01-28 2:22 ` Sasha Levin
2015-01-28 2:22 ` [PATCH v3 2/3] mm: cma: allocation trigger Sasha Levin
2015-01-28 2:22 ` [PATCH v3 3/3] mm: cma: release trigger Sasha Levin
2 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2015-01-28 2:22 UTC (permalink / raw)
To: linux-kernel; +Cc: iamjoonsoo.kim, m.szyprowski, akpm, lauraa, Sasha Levin
Implement a simple debugfs interface to expose information about CMA areas
in the system.
Useful for testing/sanity checks for CMA since it was impossible to previously
retrieve this information in userspace.
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
---
mm/Kconfig | 6 ++++++
mm/Makefile | 1 +
mm/cma.c | 19 ++++--------------
mm/cma.h | 20 +++++++++++++++++++
mm/cma_debug.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 92 insertions(+), 15 deletions(-)
create mode 100644 mm/cma.h
create mode 100644 mm/cma_debug.c
diff --git a/mm/Kconfig b/mm/Kconfig
index a03131b..390214d 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -517,6 +517,12 @@ config CMA_DEBUG
processing calls such as dma_alloc_from_contiguous().
This option does not affect warning and error messages.
+config CMA_DEBUGFS
+ bool "CMA debugfs interface"
+ depends on CMA && DEBUG_FS
+ help
+ Turns on the DebugFS interface for CMA.
+
config CMA_AREAS
int "Maximum count of the CMA areas"
depends on CMA
diff --git a/mm/Makefile b/mm/Makefile
index 3c1caa2..51052ba 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -76,3 +76,4 @@ obj-$(CONFIG_GENERIC_EARLY_IOREMAP) += early_ioremap.o
obj-$(CONFIG_CMA) += cma.o
obj-$(CONFIG_MEMORY_BALLOON) += balloon_compaction.o
obj-$(CONFIG_PAGE_EXTENSION) += page_ext.o
+obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o
diff --git a/mm/cma.c b/mm/cma.c
index 75016fd..e093b53 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -35,16 +35,10 @@
#include <linux/highmem.h>
#include <linux/io.h>
-struct cma {
- unsigned long base_pfn;
- unsigned long count;
- unsigned long *bitmap;
- unsigned int order_per_bit; /* Order of pages represented by one bit */
- struct mutex lock;
-};
-
-static struct cma cma_areas[MAX_CMA_AREAS];
-static unsigned cma_area_count;
+#include "cma.h"
+
+struct cma cma_areas[MAX_CMA_AREAS];
+unsigned cma_area_count;
static DEFINE_MUTEX(cma_mutex);
phys_addr_t cma_get_base(struct cma *cma)
@@ -75,11 +69,6 @@ static unsigned long cma_bitmap_aligned_offset(struct cma *cma, int align_order)
(cma->base_pfn >> cma->order_per_bit);
}
-static unsigned long cma_bitmap_maxno(struct cma *cma)
-{
- return cma->count >> cma->order_per_bit;
-}
-
static unsigned long cma_bitmap_pages_to_bits(struct cma *cma,
unsigned long pages)
{
diff --git a/mm/cma.h b/mm/cma.h
new file mode 100644
index 0000000..4141887
--- /dev/null
+++ b/mm/cma.h
@@ -0,0 +1,20 @@
+#ifndef __MM_CMA_H__
+#define __MM_CMA_H__
+
+struct cma {
+ unsigned long base_pfn;
+ unsigned long count;
+ unsigned long *bitmap;
+ unsigned int order_per_bit; /* Order of pages represented by one bit */
+ struct mutex lock;
+};
+
+extern struct cma cma_areas[MAX_CMA_AREAS];
+extern unsigned cma_area_count;
+
+static unsigned long cma_bitmap_maxno(struct cma *cma)
+{
+ return cma->count >> cma->order_per_bit;
+}
+
+#endif
diff --git a/mm/cma_debug.c b/mm/cma_debug.c
new file mode 100644
index 0000000..3a25413
--- /dev/null
+++ b/mm/cma_debug.c
@@ -0,0 +1,61 @@
+/*
+ * CMA DebugFS Interface
+ *
+ * Copyright (c) 2015 Sasha Levin <sasha.levin@oracle.com>
+ */
+
+
+#include <linux/debugfs.h>
+#include <linux/cma.h>
+
+#include "cma.h"
+
+static struct dentry *cma_debugfs_root;
+
+static int cma_debugfs_get(void *data, u64 *val)
+{
+ unsigned long *p = data;
+
+ *val = *p;
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(cma_debugfs_fops, cma_debugfs_get, NULL, "%llu\n");
+
+static void cma_debugfs_add_one(struct cma *cma, int idx)
+{
+ struct dentry *tmp;
+ char name[16];
+ int u32s;
+
+ sprintf(name, "cma-%d", idx);
+
+ tmp = debugfs_create_dir(name, cma_debugfs_root);
+
+ debugfs_create_file("base_pfn", S_IRUGO, tmp,
+ &cma->base_pfn, &cma_debugfs_fops);
+ debugfs_create_file("count", S_IRUGO, tmp,
+ &cma->count, &cma_debugfs_fops);
+ debugfs_create_file("order_per_bit", S_IRUGO, tmp,
+ &cma->order_per_bit, &cma_debugfs_fops);
+
+ u32s = DIV_ROUND_UP(cma_bitmap_maxno(cma), BITS_PER_BYTE * sizeof(u32));
+ debugfs_create_u32_array("bitmap", S_IRUGO, tmp, (u32*)cma->bitmap, u32s);
+}
+
+static int __init cma_debugfs_init(void)
+{
+ int i;
+
+ cma_debugfs_root = debugfs_create_dir("cma", NULL);
+ if (!cma_debugfs_root)
+ return -ENOMEM;
+
+ for (i = 0; i < cma_area_count; i++)
+ cma_debugfs_add_one(&cma_areas[i], i);
+
+ return 0;
+}
+late_initcall(cma_debugfs_init);
+
--
1.7.10.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v3 2/3] mm: cma: allocation trigger
2015-01-28 2:22 [PATCH v3 0/3] mm: cma: debugfs access to CMA Sasha Levin
2015-01-28 2:22 ` [PATCH v3 1/3] mm: cma: debugfs interface Sasha Levin
@ 2015-01-28 2:22 ` Sasha Levin
2015-01-28 2:22 ` [PATCH v3 3/3] mm: cma: release trigger Sasha Levin
2 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2015-01-28 2:22 UTC (permalink / raw)
To: linux-kernel; +Cc: iamjoonsoo.kim, m.szyprowski, akpm, lauraa, Sasha Levin
Provides a userspace interface to trigger a CMA allocation.
Usage:
echo [pages] > alloc
This would provide testing/fuzzing access to the CMA allocation paths.
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
---
mm/cma.c | 6 ++++++
mm/cma.h | 4 ++++
mm/cma_debug.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 64 insertions(+), 2 deletions(-)
diff --git a/mm/cma.c b/mm/cma.c
index e093b53..e0a9cc2 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -121,6 +121,12 @@ static int __init cma_activate_area(struct cma *cma)
} while (--i);
mutex_init(&cma->lock);
+
+#ifdef CONFIG_CMA_DEBUGFS
+ INIT_HLIST_HEAD(&cma->mem_head);
+ spin_init(&cma->mem_head_lock);
+#endif
+
return 0;
err:
diff --git a/mm/cma.h b/mm/cma.h
index 4141887..1132d73 100644
--- a/mm/cma.h
+++ b/mm/cma.h
@@ -7,6 +7,10 @@ struct cma {
unsigned long *bitmap;
unsigned int order_per_bit; /* Order of pages represented by one bit */
struct mutex lock;
+#ifdef CONFIG_CMA_DEBUGFS
+ struct hlist_head mem_head;
+ spinlock_t mem_head_lock;
+#endif
};
extern struct cma cma_areas[MAX_CMA_AREAS];
diff --git a/mm/cma_debug.c b/mm/cma_debug.c
index 3a25413..5bd6863 100644
--- a/mm/cma_debug.c
+++ b/mm/cma_debug.c
@@ -7,9 +7,18 @@
#include <linux/debugfs.h>
#include <linux/cma.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
#include "cma.h"
+struct cma_mem {
+ struct hlist_node node;
+ struct page *p;
+ unsigned long n;
+};
+
static struct dentry *cma_debugfs_root;
static int cma_debugfs_get(void *data, u64 *val)
@@ -23,8 +32,48 @@ static int cma_debugfs_get(void *data, u64 *val)
DEFINE_SIMPLE_ATTRIBUTE(cma_debugfs_fops, cma_debugfs_get, NULL, "%llu\n");
-static void cma_debugfs_add_one(struct cma *cma, int idx)
+static void cma_add_to_cma_mem_list(struct cma *cma, struct cma_mem *mem)
+{
+ spin_lock(&cma->mem_head_lock);
+ hlist_add_head(&mem->node, &cma->mem_head);
+ spin_unlock(&cma->mem_head_lock);
+}
+
+static int cma_alloc_mem(struct cma *cma, int count)
+{
+ struct cma_mem *mem;
+ struct page *p;
+
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem)
+ return -ENOMEM;
+
+ p = cma_alloc(cma, count, 0);
+ if (!p) {
+ kfree(mem);
+ return -ENOMEM;
+ }
+
+ mem->p = p;
+ mem->n = count;
+
+ cma_add_to_cma_mem_list(cma, mem);
+
+ return 0;
+}
+
+static int cma_alloc_write(void *data, u64 val)
{
+ int pages = val;
+ struct cma *cma = data;
+
+ return cma_alloc_mem(cma, pages);
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(cma_alloc_fops, NULL, cma_alloc_write, "%llu\n");
+
+static void cma_debugfs_add_one(struct cma *cma, int idx)
+{
struct dentry *tmp;
char name[16];
int u32s;
@@ -33,12 +82,15 @@ static void cma_debugfs_add_one(struct cma *cma, int idx)
tmp = debugfs_create_dir(name, cma_debugfs_root);
+ debugfs_create_file("alloc", S_IWUSR, cma_debugfs_root, cma,
+ &cma_alloc_fops);
+
debugfs_create_file("base_pfn", S_IRUGO, tmp,
&cma->base_pfn, &cma_debugfs_fops);
debugfs_create_file("count", S_IRUGO, tmp,
&cma->count, &cma_debugfs_fops);
debugfs_create_file("order_per_bit", S_IRUGO, tmp,
- &cma->order_per_bit, &cma_debugfs_fops);
+ &cma->order_per_bit, &cma_debugfs_fops);
u32s = DIV_ROUND_UP(cma_bitmap_maxno(cma), BITS_PER_BYTE * sizeof(u32));
debugfs_create_u32_array("bitmap", S_IRUGO, tmp, (u32*)cma->bitmap, u32s);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v3 3/3] mm: cma: release trigger
2015-01-28 2:22 [PATCH v3 0/3] mm: cma: debugfs access to CMA Sasha Levin
2015-01-28 2:22 ` [PATCH v3 1/3] mm: cma: debugfs interface Sasha Levin
2015-01-28 2:22 ` [PATCH v3 2/3] mm: cma: allocation trigger Sasha Levin
@ 2015-01-28 2:22 ` Sasha Levin
2015-01-29 7:51 ` Joonsoo Kim
2 siblings, 1 reply; 6+ messages in thread
From: Sasha Levin @ 2015-01-28 2:22 UTC (permalink / raw)
To: linux-kernel; +Cc: iamjoonsoo.kim, m.szyprowski, akpm, lauraa, Sasha Levin
Provides a userspace interface to trigger a CMA release.
Usage:
echo [pages] > free
This would provide testing/fuzzing access to the CMA release paths.
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
---
mm/cma_debug.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/mm/cma_debug.c b/mm/cma_debug.c
index 5bd6863..c29f029 100644
--- a/mm/cma_debug.c
+++ b/mm/cma_debug.c
@@ -39,6 +39,59 @@ static void cma_add_to_cma_mem_list(struct cma *cma, struct cma_mem *mem)
spin_unlock(&cma->mem_head_lock);
}
+static struct cma_mem *cma_get_entry_from_list(struct cma *cma)
+{
+ struct cma_mem *mem = NULL;
+
+ spin_lock(&cma->mem_head_lock);
+ if (!hlist_empty(&cma->mem_head)) {
+ mem = hlist_entry(cma->mem_head.first, struct cma_mem, node);
+ hlist_del_init(&mem->node);
+ }
+ spin_unlock(&cma->mem_head_lock);
+
+ return mem;
+}
+
+static int cma_free_mem(struct cma *cma, int count)
+{
+ struct cma_mem *mem = NULL;
+
+ while (count) {
+ mem = cma_get_entry_from_list(cma);
+ if (mem == NULL)
+ return 0;
+
+ if (mem->n <= count) {
+ cma_release(cma, mem->p, mem->n);
+ count -= mem->n;
+ kfree(mem);
+ } else if (cma->order_per_bit == 0) {
+ cma_release(cma, mem->p, count);
+ mem->p += count;
+ mem->n -= count;
+ count = 0;
+ cma_add_to_cma_mem_list(cma, mem);
+ } else {
+ cma_add_to_cma_mem_list(cma, mem);
+ break;
+ }
+ }
+
+ return 0;
+
+}
+
+static int cma_free_write(void *data, u64 val)
+{
+ int pages = val;
+ struct cma *cma = data;
+
+ return cma_free_mem(cma, pages);
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(cma_free_fops, NULL, cma_free_write, "%llu\n");
+
static int cma_alloc_mem(struct cma *cma, int count)
{
struct cma_mem *mem;
@@ -85,6 +138,9 @@ static void cma_debugfs_add_one(struct cma *cma, int idx)
debugfs_create_file("alloc", S_IWUSR, cma_debugfs_root, cma,
&cma_alloc_fops);
+ debugfs_create_file("free", S_IWUSR, cma_debugfs_root, cma,
+ &cma_free_fops);
+
debugfs_create_file("base_pfn", S_IRUGO, tmp,
&cma->base_pfn, &cma_debugfs_fops);
debugfs_create_file("count", S_IRUGO, tmp,
--
1.7.10.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v3 3/3] mm: cma: release trigger
2015-01-28 2:22 ` [PATCH v3 3/3] mm: cma: release trigger Sasha Levin
@ 2015-01-29 7:51 ` Joonsoo Kim
2015-01-29 13:04 ` Sasha Levin
0 siblings, 1 reply; 6+ messages in thread
From: Joonsoo Kim @ 2015-01-29 7:51 UTC (permalink / raw)
To: Sasha Levin; +Cc: linux-kernel, m.szyprowski, akpm, lauraa
On Tue, Jan 27, 2015 at 09:22:57PM -0500, Sasha Levin wrote:
> Provides a userspace interface to trigger a CMA release.
>
> Usage:
>
> echo [pages] > free
>
> This would provide testing/fuzzing access to the CMA release paths.
>
> Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
> ---
> mm/cma_debug.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 56 insertions(+)
>
> diff --git a/mm/cma_debug.c b/mm/cma_debug.c
> index 5bd6863..c29f029 100644
> --- a/mm/cma_debug.c
> +++ b/mm/cma_debug.c
> @@ -39,6 +39,59 @@ static void cma_add_to_cma_mem_list(struct cma *cma, struct cma_mem *mem)
> spin_unlock(&cma->mem_head_lock);
> }
>
> +static struct cma_mem *cma_get_entry_from_list(struct cma *cma)
> +{
> + struct cma_mem *mem = NULL;
> +
> + spin_lock(&cma->mem_head_lock);
> + if (!hlist_empty(&cma->mem_head)) {
> + mem = hlist_entry(cma->mem_head.first, struct cma_mem, node);
> + hlist_del_init(&mem->node);
> + }
> + spin_unlock(&cma->mem_head_lock);
> +
> + return mem;
> +}
> +
> +static int cma_free_mem(struct cma *cma, int count)
> +{
> + struct cma_mem *mem = NULL;
> +
> + while (count) {
> + mem = cma_get_entry_from_list(cma);
> + if (mem == NULL)
> + return 0;
> +
> + if (mem->n <= count) {
> + cma_release(cma, mem->p, mem->n);
> + count -= mem->n;
> + kfree(mem);
> + } else if (cma->order_per_bit == 0) {
> + cma_release(cma, mem->p, count);
> + mem->p += count;
> + mem->n -= count;
> + count = 0;
> + cma_add_to_cma_mem_list(cma, mem);
> + } else {
> + cma_add_to_cma_mem_list(cma, mem);
> + break;
> + }
> + }
Hmm... I'm not sure we need to deal with "mem->m < count" case.
It is not suitable for any cma_alloc/release usecase.
And, I'd like to insert some error log to last case rather than
silently ignoring the request.
Thanks.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v3 3/3] mm: cma: release trigger
2015-01-29 7:51 ` Joonsoo Kim
@ 2015-01-29 13:04 ` Sasha Levin
0 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2015-01-29 13:04 UTC (permalink / raw)
To: Joonsoo Kim; +Cc: linux-kernel, m.szyprowski, akpm, lauraa
On 01/29/2015 02:51 AM, Joonsoo Kim wrote:
> On Tue, Jan 27, 2015 at 09:22:57PM -0500, Sasha Levin wrote:
>> > +static int cma_free_mem(struct cma *cma, int count)
>> > +{
>> > + struct cma_mem *mem = NULL;
>> > +
>> > + while (count) {
>> > + mem = cma_get_entry_from_list(cma);
>> > + if (mem == NULL)
>> > + return 0;
>> > +
>> > + if (mem->n <= count) {
>> > + cma_release(cma, mem->p, mem->n);
>> > + count -= mem->n;
>> > + kfree(mem);
>> > + } else if (cma->order_per_bit == 0) {
>> > + cma_release(cma, mem->p, count);
>> > + mem->p += count;
>> > + mem->n -= count;
>> > + count = 0;
>> > + cma_add_to_cma_mem_list(cma, mem);
>> > + } else {
>> > + cma_add_to_cma_mem_list(cma, mem);
>> > + break;
>> > + }
>> > + }
> Hmm... I'm not sure we need to deal with "mem->m < count" case.
> It is not suitable for any cma_alloc/release usecase.
Maybe not, but the code in mm/cma.c supports that right now. If that
ever changes we can make appropriate changes here.
> And, I'd like to insert some error log to last case rather than
> silently ignoring the request.
I can add that.
Thanks,
Sasha
^ permalink raw reply [flat|nested] 6+ messages in thread