Blame view

mm/cma_debug.c 4.45 KB
28b24c1fc   Sasha Levin   mm: cma: debugfs ...
1
2
3
4
5
6
7
8
9
  /*
   * CMA DebugFS Interface
   *
   * Copyright (c) 2015 Sasha Levin <sasha.levin@oracle.com>
   */
  
  
  #include <linux/debugfs.h>
  #include <linux/cma.h>
26b02a1f9   Sasha Levin   mm: cma: allocati...
10
11
12
  #include <linux/list.h>
  #include <linux/kernel.h>
  #include <linux/slab.h>
8325330b0   Sasha Levin   mm: cma: release ...
13
  #include <linux/mm_types.h>
28b24c1fc   Sasha Levin   mm: cma: debugfs ...
14
15
  
  #include "cma.h"
26b02a1f9   Sasha Levin   mm: cma: allocati...
16
17
18
19
20
  struct cma_mem {
  	struct hlist_node node;
  	struct page *p;
  	unsigned long n;
  };
28b24c1fc   Sasha Levin   mm: cma: debugfs ...
21
22
23
24
25
26
27
28
29
30
  static struct dentry *cma_debugfs_root;
  
  static int cma_debugfs_get(void *data, u64 *val)
  {
  	unsigned long *p = data;
  
  	*val = *p;
  
  	return 0;
  }
28b24c1fc   Sasha Levin   mm: cma: debugfs ...
31
32
  DEFINE_SIMPLE_ATTRIBUTE(cma_debugfs_fops, cma_debugfs_get, NULL, "%llu
  ");
2e32b9476   Dmitry Safonov   mm: cma: add func...
33
34
35
36
37
38
39
  static int cma_used_get(void *data, u64 *val)
  {
  	struct cma *cma = data;
  	unsigned long used;
  
  	mutex_lock(&cma->lock);
  	/* pages counter is smaller than sizeof(int) */
d56e84b40   Joonsoo Kim   mm/cma_debug: cor...
40
  	used = bitmap_weight(cma->bitmap, (int)cma_bitmap_maxno(cma));
2e32b9476   Dmitry Safonov   mm: cma: add func...
41
42
43
44
45
  	mutex_unlock(&cma->lock);
  	*val = (u64)used << cma->order_per_bit;
  
  	return 0;
  }
2e32b9476   Dmitry Safonov   mm: cma: add func...
46
47
48
49
50
51
52
53
  DEFINE_SIMPLE_ATTRIBUTE(cma_used_fops, cma_used_get, NULL, "%llu
  ");
  
  static int cma_maxchunk_get(void *data, u64 *val)
  {
  	struct cma *cma = data;
  	unsigned long maxchunk = 0;
  	unsigned long start, end = 0;
d56e84b40   Joonsoo Kim   mm/cma_debug: cor...
54
  	unsigned long bitmap_maxno = cma_bitmap_maxno(cma);
2e32b9476   Dmitry Safonov   mm: cma: add func...
55
56
57
  
  	mutex_lock(&cma->lock);
  	for (;;) {
d56e84b40   Joonsoo Kim   mm/cma_debug: cor...
58
  		start = find_next_zero_bit(cma->bitmap, bitmap_maxno, end);
2e32b9476   Dmitry Safonov   mm: cma: add func...
59
60
  		if (start >= cma->count)
  			break;
d56e84b40   Joonsoo Kim   mm/cma_debug: cor...
61
  		end = find_next_bit(cma->bitmap, bitmap_maxno, start);
2e32b9476   Dmitry Safonov   mm: cma: add func...
62
63
64
65
66
67
68
  		maxchunk = max(end - start, maxchunk);
  	}
  	mutex_unlock(&cma->lock);
  	*val = (u64)maxchunk << cma->order_per_bit;
  
  	return 0;
  }
2e32b9476   Dmitry Safonov   mm: cma: add func...
69
70
  DEFINE_SIMPLE_ATTRIBUTE(cma_maxchunk_fops, cma_maxchunk_get, NULL, "%llu
  ");
26b02a1f9   Sasha Levin   mm: cma: allocati...
71
72
73
74
75
76
  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);
  }
8325330b0   Sasha Levin   mm: cma: release ...
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
  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 {
  			pr_debug("cma: cannot release partial block when order_per_bit != 0
  ");
  			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);
  }
8325330b0   Sasha Levin   mm: cma: release ...
129
130
  DEFINE_SIMPLE_ATTRIBUTE(cma_free_fops, NULL, cma_free_write, "%llu
  ");
26b02a1f9   Sasha Levin   mm: cma: allocati...
131
132
133
134
135
136
137
138
  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;
875abdb6d   Andrew Morton   mm-cma-allocation...
139
  	p = cma_alloc(cma, count, 0);
26b02a1f9   Sasha Levin   mm: cma: allocati...
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
  	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);
  }
26b02a1f9   Sasha Levin   mm: cma: allocati...
160
161
  DEFINE_SIMPLE_ATTRIBUTE(cma_alloc_fops, NULL, cma_alloc_write, "%llu
  ");
28b24c1fc   Sasha Levin   mm: cma: debugfs ...
162
163
164
165
166
167
168
169
170
  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);
2292c0b1c   Joonsoo Kim   mm/cma_debug: fix...
171
  	debugfs_create_file("alloc", S_IWUSR, tmp, cma,
26b02a1f9   Sasha Levin   mm: cma: allocati...
172
  				&cma_alloc_fops);
2292c0b1c   Joonsoo Kim   mm/cma_debug: fix...
173
  	debugfs_create_file("free", S_IWUSR, tmp, cma,
8325330b0   Sasha Levin   mm: cma: release ...
174
  				&cma_free_fops);
28b24c1fc   Sasha Levin   mm: cma: debugfs ...
175
176
177
178
179
  	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,
26b02a1f9   Sasha Levin   mm: cma: allocati...
180
  				&cma->order_per_bit, &cma_debugfs_fops);
2e32b9476   Dmitry Safonov   mm: cma: add func...
181
182
  	debugfs_create_file("used", S_IRUGO, tmp, cma, &cma_used_fops);
  	debugfs_create_file("maxchunk", S_IRUGO, tmp, cma, &cma_maxchunk_fops);
28b24c1fc   Sasha Levin   mm: cma: debugfs ...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
  
  	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);