~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/mm/cma_debug.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * CMA DebugFS Interface
  4  *
  5  * Copyright (c) 2015 Sasha Levin <sasha.levin@oracle.com>
  6  */
  7 
  8 
  9 #include <linux/debugfs.h>
 10 #include <linux/cma.h>
 11 #include <linux/list.h>
 12 #include <linux/kernel.h>
 13 #include <linux/slab.h>
 14 #include <linux/mm_types.h>
 15 
 16 #include "cma.h"
 17 
 18 struct cma_mem {
 19         struct hlist_node node;
 20         struct page *p;
 21         unsigned long n;
 22 };
 23 
 24 static int cma_debugfs_get(void *data, u64 *val)
 25 {
 26         unsigned long *p = data;
 27 
 28         *val = *p;
 29 
 30         return 0;
 31 }
 32 DEFINE_DEBUGFS_ATTRIBUTE(cma_debugfs_fops, cma_debugfs_get, NULL, "%llu\n");
 33 
 34 static int cma_used_get(void *data, u64 *val)
 35 {
 36         struct cma *cma = data;
 37         unsigned long used;
 38 
 39         spin_lock_irq(&cma->lock);
 40         /* pages counter is smaller than sizeof(int) */
 41         used = bitmap_weight(cma->bitmap, (int)cma_bitmap_maxno(cma));
 42         spin_unlock_irq(&cma->lock);
 43         *val = (u64)used << cma->order_per_bit;
 44 
 45         return 0;
 46 }
 47 DEFINE_DEBUGFS_ATTRIBUTE(cma_used_fops, cma_used_get, NULL, "%llu\n");
 48 
 49 static int cma_maxchunk_get(void *data, u64 *val)
 50 {
 51         struct cma *cma = data;
 52         unsigned long maxchunk = 0;
 53         unsigned long start, end = 0;
 54         unsigned long bitmap_maxno = cma_bitmap_maxno(cma);
 55 
 56         spin_lock_irq(&cma->lock);
 57         for (;;) {
 58                 start = find_next_zero_bit(cma->bitmap, bitmap_maxno, end);
 59                 if (start >= bitmap_maxno)
 60                         break;
 61                 end = find_next_bit(cma->bitmap, bitmap_maxno, start);
 62                 maxchunk = max(end - start, maxchunk);
 63         }
 64         spin_unlock_irq(&cma->lock);
 65         *val = (u64)maxchunk << cma->order_per_bit;
 66 
 67         return 0;
 68 }
 69 DEFINE_DEBUGFS_ATTRIBUTE(cma_maxchunk_fops, cma_maxchunk_get, NULL, "%llu\n");
 70 
 71 static void cma_add_to_cma_mem_list(struct cma *cma, struct cma_mem *mem)
 72 {
 73         spin_lock(&cma->mem_head_lock);
 74         hlist_add_head(&mem->node, &cma->mem_head);
 75         spin_unlock(&cma->mem_head_lock);
 76 }
 77 
 78 static struct cma_mem *cma_get_entry_from_list(struct cma *cma)
 79 {
 80         struct cma_mem *mem = NULL;
 81 
 82         spin_lock(&cma->mem_head_lock);
 83         if (!hlist_empty(&cma->mem_head)) {
 84                 mem = hlist_entry(cma->mem_head.first, struct cma_mem, node);
 85                 hlist_del_init(&mem->node);
 86         }
 87         spin_unlock(&cma->mem_head_lock);
 88 
 89         return mem;
 90 }
 91 
 92 static int cma_free_mem(struct cma *cma, int count)
 93 {
 94         struct cma_mem *mem = NULL;
 95 
 96         while (count) {
 97                 mem = cma_get_entry_from_list(cma);
 98                 if (mem == NULL)
 99                         return 0;
100 
101                 if (mem->n <= count) {
102                         cma_release(cma, mem->p, mem->n);
103                         count -= mem->n;
104                         kfree(mem);
105                 } else if (cma->order_per_bit == 0) {
106                         cma_release(cma, mem->p, count);
107                         mem->p += count;
108                         mem->n -= count;
109                         count = 0;
110                         cma_add_to_cma_mem_list(cma, mem);
111                 } else {
112                         pr_debug("cma: cannot release partial block when order_per_bit != 0\n");
113                         cma_add_to_cma_mem_list(cma, mem);
114                         break;
115                 }
116         }
117 
118         return 0;
119 
120 }
121 
122 static int cma_free_write(void *data, u64 val)
123 {
124         int pages = val;
125         struct cma *cma = data;
126 
127         return cma_free_mem(cma, pages);
128 }
129 DEFINE_DEBUGFS_ATTRIBUTE(cma_free_fops, NULL, cma_free_write, "%llu\n");
130 
131 static int cma_alloc_mem(struct cma *cma, int count)
132 {
133         struct cma_mem *mem;
134         struct page *p;
135 
136         mem = kzalloc(sizeof(*mem), GFP_KERNEL);
137         if (!mem)
138                 return -ENOMEM;
139 
140         p = cma_alloc(cma, count, 0, false);
141         if (!p) {
142                 kfree(mem);
143                 return -ENOMEM;
144         }
145 
146         mem->p = p;
147         mem->n = count;
148 
149         cma_add_to_cma_mem_list(cma, mem);
150 
151         return 0;
152 }
153 
154 static int cma_alloc_write(void *data, u64 val)
155 {
156         int pages = val;
157         struct cma *cma = data;
158 
159         return cma_alloc_mem(cma, pages);
160 }
161 DEFINE_DEBUGFS_ATTRIBUTE(cma_alloc_fops, NULL, cma_alloc_write, "%llu\n");
162 
163 static void cma_debugfs_add_one(struct cma *cma, struct dentry *root_dentry)
164 {
165         struct dentry *tmp;
166 
167         tmp = debugfs_create_dir(cma->name, root_dentry);
168 
169         debugfs_create_file("alloc", 0200, tmp, cma, &cma_alloc_fops);
170         debugfs_create_file("free", 0200, tmp, cma, &cma_free_fops);
171         debugfs_create_file("base_pfn", 0444, tmp,
172                             &cma->base_pfn, &cma_debugfs_fops);
173         debugfs_create_file("count", 0444, tmp, &cma->count, &cma_debugfs_fops);
174         debugfs_create_file("order_per_bit", 0444, tmp,
175                             &cma->order_per_bit, &cma_debugfs_fops);
176         debugfs_create_file("used", 0444, tmp, cma, &cma_used_fops);
177         debugfs_create_file("maxchunk", 0444, tmp, cma, &cma_maxchunk_fops);
178 
179         cma->dfs_bitmap.array = (u32 *)cma->bitmap;
180         cma->dfs_bitmap.n_elements = DIV_ROUND_UP(cma_bitmap_maxno(cma),
181                                                   BITS_PER_BYTE * sizeof(u32));
182         debugfs_create_u32_array("bitmap", 0444, tmp, &cma->dfs_bitmap);
183 }
184 
185 static int __init cma_debugfs_init(void)
186 {
187         struct dentry *cma_debugfs_root;
188         int i;
189 
190         cma_debugfs_root = debugfs_create_dir("cma", NULL);
191 
192         for (i = 0; i < cma_area_count; i++)
193                 cma_debugfs_add_one(&cma_areas[i], cma_debugfs_root);
194 
195         return 0;
196 }
197 late_initcall(cma_debugfs_init);
198 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php