diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-14 19:49:17 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-14 19:49:17 -0400 |
commit | 1dcf58d6e6e6eb7ec10e9abc56887b040205b06f (patch) | |
tree | c03e7a25ef13eea62f1547914a76e5c68f3f4c28 /mm/cma_debug.c | |
parent | 80dcc31fbe55932ac9204daee5f2ebc0c49b6da3 (diff) | |
parent | e4b0db72be2487bae0e3251c22f82c104f7c1cfd (diff) |
Merge branch 'akpm' (patches from Andrew)
Merge first patchbomb from Andrew Morton:
- arch/sh updates
- ocfs2 updates
- kernel/watchdog feature
- about half of mm/
* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (122 commits)
Documentation: update arch list in the 'memtest' entry
Kconfig: memtest: update number of test patterns up to 17
arm: add support for memtest
arm64: add support for memtest
memtest: use phys_addr_t for physical addresses
mm: move memtest under mm
mm, hugetlb: abort __get_user_pages if current has been oom killed
mm, mempool: do not allow atomic resizing
memcg: print cgroup information when system panics due to panic_on_oom
mm: numa: remove migrate_ratelimited
mm: fold arch_randomize_brk into ARCH_HAS_ELF_RANDOMIZE
mm: split ET_DYN ASLR from mmap ASLR
s390: redefine randomize_et_dyn for ELF_ET_DYN_BASE
mm: expose arch_mmap_rnd when available
s390: standardize mmap_rnd() usage
powerpc: standardize mmap_rnd() usage
mips: extract logic for mmap_rnd()
arm64: standardize mmap_rnd() usage
x86: standardize mmap_rnd() usage
arm: factor out mmap ASLR into mmap_rnd
...
Diffstat (limited to 'mm/cma_debug.c')
-rw-r--r-- | mm/cma_debug.c | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/mm/cma_debug.c b/mm/cma_debug.c new file mode 100644 index 000000000000..0b377536ccde --- /dev/null +++ b/mm/cma_debug.c | |||
@@ -0,0 +1,170 @@ | |||
1 | /* | ||
2 | * CMA DebugFS Interface | ||
3 | * | ||
4 | * Copyright (c) 2015 Sasha Levin <sasha.levin@oracle.com> | ||
5 | */ | ||
6 | |||
7 | |||
8 | #include <linux/debugfs.h> | ||
9 | #include <linux/cma.h> | ||
10 | #include <linux/list.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/mm_types.h> | ||
14 | |||
15 | #include "cma.h" | ||
16 | |||
17 | struct cma_mem { | ||
18 | struct hlist_node node; | ||
19 | struct page *p; | ||
20 | unsigned long n; | ||
21 | }; | ||
22 | |||
23 | static struct dentry *cma_debugfs_root; | ||
24 | |||
25 | static int cma_debugfs_get(void *data, u64 *val) | ||
26 | { | ||
27 | unsigned long *p = data; | ||
28 | |||
29 | *val = *p; | ||
30 | |||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | DEFINE_SIMPLE_ATTRIBUTE(cma_debugfs_fops, cma_debugfs_get, NULL, "%llu\n"); | ||
35 | |||
36 | static void cma_add_to_cma_mem_list(struct cma *cma, struct cma_mem *mem) | ||
37 | { | ||
38 | spin_lock(&cma->mem_head_lock); | ||
39 | hlist_add_head(&mem->node, &cma->mem_head); | ||
40 | spin_unlock(&cma->mem_head_lock); | ||
41 | } | ||
42 | |||
43 | static struct cma_mem *cma_get_entry_from_list(struct cma *cma) | ||
44 | { | ||
45 | struct cma_mem *mem = NULL; | ||
46 | |||
47 | spin_lock(&cma->mem_head_lock); | ||
48 | if (!hlist_empty(&cma->mem_head)) { | ||
49 | mem = hlist_entry(cma->mem_head.first, struct cma_mem, node); | ||
50 | hlist_del_init(&mem->node); | ||
51 | } | ||
52 | spin_unlock(&cma->mem_head_lock); | ||
53 | |||
54 | return mem; | ||
55 | } | ||
56 | |||
57 | static int cma_free_mem(struct cma *cma, int count) | ||
58 | { | ||
59 | struct cma_mem *mem = NULL; | ||
60 | |||
61 | while (count) { | ||
62 | mem = cma_get_entry_from_list(cma); | ||
63 | if (mem == NULL) | ||
64 | return 0; | ||
65 | |||
66 | if (mem->n <= count) { | ||
67 | cma_release(cma, mem->p, mem->n); | ||
68 | count -= mem->n; | ||
69 | kfree(mem); | ||
70 | } else if (cma->order_per_bit == 0) { | ||
71 | cma_release(cma, mem->p, count); | ||
72 | mem->p += count; | ||
73 | mem->n -= count; | ||
74 | count = 0; | ||
75 | cma_add_to_cma_mem_list(cma, mem); | ||
76 | } else { | ||
77 | pr_debug("cma: cannot release partial block when order_per_bit != 0\n"); | ||
78 | cma_add_to_cma_mem_list(cma, mem); | ||
79 | break; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | return 0; | ||
84 | |||
85 | } | ||
86 | |||
87 | static int cma_free_write(void *data, u64 val) | ||
88 | { | ||
89 | int pages = val; | ||
90 | struct cma *cma = data; | ||
91 | |||
92 | return cma_free_mem(cma, pages); | ||
93 | } | ||
94 | |||
95 | DEFINE_SIMPLE_ATTRIBUTE(cma_free_fops, NULL, cma_free_write, "%llu\n"); | ||
96 | |||
97 | static int cma_alloc_mem(struct cma *cma, int count) | ||
98 | { | ||
99 | struct cma_mem *mem; | ||
100 | struct page *p; | ||
101 | |||
102 | mem = kzalloc(sizeof(*mem), GFP_KERNEL); | ||
103 | if (!mem) | ||
104 | return -ENOMEM; | ||
105 | |||
106 | p = cma_alloc(cma, count, 0); | ||
107 | if (!p) { | ||
108 | kfree(mem); | ||
109 | return -ENOMEM; | ||
110 | } | ||
111 | |||
112 | mem->p = p; | ||
113 | mem->n = count; | ||
114 | |||
115 | cma_add_to_cma_mem_list(cma, mem); | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static int cma_alloc_write(void *data, u64 val) | ||
121 | { | ||
122 | int pages = val; | ||
123 | struct cma *cma = data; | ||
124 | |||
125 | return cma_alloc_mem(cma, pages); | ||
126 | } | ||
127 | |||
128 | DEFINE_SIMPLE_ATTRIBUTE(cma_alloc_fops, NULL, cma_alloc_write, "%llu\n"); | ||
129 | |||
130 | static void cma_debugfs_add_one(struct cma *cma, int idx) | ||
131 | { | ||
132 | struct dentry *tmp; | ||
133 | char name[16]; | ||
134 | int u32s; | ||
135 | |||
136 | sprintf(name, "cma-%d", idx); | ||
137 | |||
138 | tmp = debugfs_create_dir(name, cma_debugfs_root); | ||
139 | |||
140 | debugfs_create_file("alloc", S_IWUSR, cma_debugfs_root, cma, | ||
141 | &cma_alloc_fops); | ||
142 | |||
143 | debugfs_create_file("free", S_IWUSR, cma_debugfs_root, cma, | ||
144 | &cma_free_fops); | ||
145 | |||
146 | debugfs_create_file("base_pfn", S_IRUGO, tmp, | ||
147 | &cma->base_pfn, &cma_debugfs_fops); | ||
148 | debugfs_create_file("count", S_IRUGO, tmp, | ||
149 | &cma->count, &cma_debugfs_fops); | ||
150 | debugfs_create_file("order_per_bit", S_IRUGO, tmp, | ||
151 | &cma->order_per_bit, &cma_debugfs_fops); | ||
152 | |||
153 | u32s = DIV_ROUND_UP(cma_bitmap_maxno(cma), BITS_PER_BYTE * sizeof(u32)); | ||
154 | debugfs_create_u32_array("bitmap", S_IRUGO, tmp, (u32*)cma->bitmap, u32s); | ||
155 | } | ||
156 | |||
157 | static int __init cma_debugfs_init(void) | ||
158 | { | ||
159 | int i; | ||
160 | |||
161 | cma_debugfs_root = debugfs_create_dir("cma", NULL); | ||
162 | if (!cma_debugfs_root) | ||
163 | return -ENOMEM; | ||
164 | |||
165 | for (i = 0; i < cma_area_count; i++) | ||
166 | cma_debugfs_add_one(&cma_areas[i], i); | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | late_initcall(cma_debugfs_init); | ||