root/mm/cma_debug.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cma_debugfs_get
  2. cma_used_get
  3. cma_maxchunk_get
  4. cma_add_to_cma_mem_list
  5. cma_get_entry_from_list
  6. cma_free_mem
  7. cma_free_write
  8. cma_alloc_mem
  9. cma_alloc_write
  10. cma_debugfs_add_one
  11. cma_debugfs_init

   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_SIMPLE_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         mutex_lock(&cma->lock);
  40         /* pages counter is smaller than sizeof(int) */
  41         used = bitmap_weight(cma->bitmap, (int)cma_bitmap_maxno(cma));
  42         mutex_unlock(&cma->lock);
  43         *val = (u64)used << cma->order_per_bit;
  44 
  45         return 0;
  46 }
  47 DEFINE_SIMPLE_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         mutex_lock(&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         mutex_unlock(&cma->lock);
  65         *val = (u64)maxchunk << cma->order_per_bit;
  66 
  67         return 0;
  68 }
  69 DEFINE_SIMPLE_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_SIMPLE_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_SIMPLE_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         char name[16];
 167         int u32s;
 168 
 169         scnprintf(name, sizeof(name), "cma-%s", cma->name);
 170 
 171         tmp = debugfs_create_dir(name, root_dentry);
 172 
 173         debugfs_create_file("alloc", 0200, tmp, cma, &cma_alloc_fops);
 174         debugfs_create_file("free", 0200, tmp, cma, &cma_free_fops);
 175         debugfs_create_file("base_pfn", 0444, tmp,
 176                             &cma->base_pfn, &cma_debugfs_fops);
 177         debugfs_create_file("count", 0444, tmp, &cma->count, &cma_debugfs_fops);
 178         debugfs_create_file("order_per_bit", 0444, tmp,
 179                             &cma->order_per_bit, &cma_debugfs_fops);
 180         debugfs_create_file("used", 0444, tmp, cma, &cma_used_fops);
 181         debugfs_create_file("maxchunk", 0444, tmp, cma, &cma_maxchunk_fops);
 182 
 183         u32s = DIV_ROUND_UP(cma_bitmap_maxno(cma), BITS_PER_BYTE * sizeof(u32));
 184         debugfs_create_u32_array("bitmap", 0444, tmp, (u32 *)cma->bitmap, u32s);
 185 }
 186 
 187 static int __init cma_debugfs_init(void)
 188 {
 189         struct dentry *cma_debugfs_root;
 190         int i;
 191 
 192         cma_debugfs_root = debugfs_create_dir("cma", NULL);
 193 
 194         for (i = 0; i < cma_area_count; i++)
 195                 cma_debugfs_add_one(&cma_areas[i], cma_debugfs_root);
 196 
 197         return 0;
 198 }
 199 late_initcall(cma_debugfs_init);

/* [<][>][^][v][top][bottom][index][help] */