00001 #include <linux/aquosa/rres_config.h>
00002 #define QOS_DEBUG_LEVEL QOS_LEVEL_INFO
00003 #include "qos_debug.h"
00004
00005 #if defined(QOS_KS)
00006
00007 # include <linux/kernel.h>
00008 # include <linux/version.h>
00009 # include <linux/module.h>
00010 # include <linux/sched.h>
00011 # include <linux/list.h>
00012 # include <linux/slab.h>
00013 # include <linux/aquosa/kal_sched.h>
00014 # include <linux/string.h>
00015 #else
00016 # include <stdlib.h>
00017 # include <string.h>
00018 #endif
00019
00020 #include "qos_memory.h"
00021
00022 #ifdef QOS_MEMORY_CHECK
00023
00024 #define MAX_CHUNK_NUMBER 1024
00025 #define CHUNK_NAME_MAX_LEN 16
00026
00031 static struct chunk {
00032 void * ptr;
00033 unsigned long size;
00034 char name[CHUNK_NAME_MAX_LEN];
00035 } chunks[MAX_CHUNK_NUMBER];
00036 static int num_chunks = 0;
00037 static int mem_failure = 0;
00038 static int chunks_inited = 0;
00039 #ifdef QOS_KS
00040 kal_lock_define(chunks_spin_lock);
00041 #endif
00042
00044 static void chunks_init(void) {
00045 int i;
00046 if (! chunks_inited) {
00047 for (i=0; i<MAX_CHUNK_NUMBER; i++)
00048 chunks[i].ptr = NULL;
00049 chunks_inited = 1;
00050 }
00051 }
00052
00057 int find_chunk(void *ptr) {
00058 int i;
00059 for (i=0; i<MAX_CHUNK_NUMBER; ++i)
00060 if (chunks[i].ptr == ptr)
00061 break;
00062 return i;
00063 }
00064
00067 void add_chunk(void *ptr, unsigned long size, const char *name) {
00068 int i = find_chunk(NULL);
00069 qos_chk_do(i < MAX_CHUNK_NUMBER, return);
00070 chunks[i].ptr = ptr;
00071 chunks[i].size = size;
00072 strncpy(chunks[i].name, name, sizeof(chunks[i].name) - 1);
00073 chunks[i].name[sizeof(chunks[i].name) - 1] = '\0';
00074 qos_log_debug("Adding chunk: ptr=%p, size=%lu, name='%s'",
00075 chunks[i].ptr, chunks[i].size, chunks[i].name);
00076 num_chunks++;
00077 }
00078
00081 int rem_chunk(void *ptr) {
00082 int i = find_chunk(ptr);
00083 qos_chk_do(i < MAX_CHUNK_NUMBER, return 0);
00084 qos_log_debug("Freeing chunk: ptr=%p, size=%lu, name='%s'",
00085 chunks[i].ptr, chunks[i].size, chunks[i].name);
00086 chunks[i].ptr = NULL;
00087 num_chunks--;
00088 return 1;
00089 }
00090
00091 #ifdef QOS_KS
00092 # define chunks_vars unsigned long _chunks_flags
00093 # define chunks_lock kal_spin_lock_irqsave(&chunks_spin_lock, &_chunks_flags)
00094 # define chunks_unlock kal_spin_unlock_irqrestore(&chunks_spin_lock, &_chunks_flags)
00095 #else
00096 # define chunks_vars
00097 # define chunks_lock
00098 # define chunks_unlock
00099 #endif
00100
00104 int qos_mem_valid(void *ptr) {
00105 int i;
00106 int valid = 0;
00107 chunks_vars;
00108
00109 chunks_lock;
00110 chunks_init();
00111 for (i = 0; i < MAX_CHUNK_NUMBER; ++i)
00112 if (ptr >= chunks[i].ptr && ptr < chunks[i].ptr + chunks[i].size) {
00113 valid = 1;
00114 break;
00115 }
00116 chunks_unlock;
00117 return valid;
00118 }
00119
00120 #else
00121
00125 int qos_mem_valid(void *ptr) {
00126 return 1;
00127 }
00128
00129 #endif
00130
00131 static inline void *qos_ll_malloc(long size) {
00132 #if defined(QOS_KS)
00133 return kmalloc(size, GFP_ATOMIC);
00134 #else
00135 return malloc(size);
00136 #endif
00137 }
00138
00139 static inline void qos_ll_free(void *ptr) {
00140 #if defined(QOS_KS)
00141 kfree(ptr);
00142 #else
00143 free(ptr);
00144 #endif
00145 }
00146
00147 void *qos_malloc(long size) {
00148 return qos_malloc_named(size, "Unknown");
00149 }
00150
00151 void *qos_malloc_named(long size, const char *name) {
00152 void *ptr;
00153 #ifdef QOS_MEMORY_CHECK
00154 chunks_vars;
00155 #endif
00156 ptr = qos_ll_malloc(size);
00157 if (ptr == NULL)
00158 return NULL;
00159 #ifdef QOS_MEMORY_CHECK
00160 chunks_lock;
00161 chunks_init();
00162 if (num_chunks == MAX_CHUNK_NUMBER) {
00163 qos_log_crit("Chunks exhausted: cannot debug memory allocation");
00164 qos_ll_free(ptr);
00165 ptr = NULL;
00166 mem_failure = 1;
00167 } else {
00168 add_chunk(ptr, size, name);
00169 }
00170 qos_log_debug("Current number of chunks: %d", num_chunks);
00171 chunks_unlock;
00172 #endif
00173 return ptr;
00174 }
00175
00176 void qos_free(void *ptr) {
00177 #ifdef QOS_MEMORY_CHECK
00178 chunks_vars;
00179 #endif
00180 if (ptr == NULL) {
00181 qos_log_crit("Trying to free a NULL pointer");
00182 return;
00183 }
00184 #ifdef QOS_MEMORY_CHECK
00185 chunks_lock;
00186 chunks_init();
00187 if (! rem_chunk(ptr)) {
00188 qos_log_crit("Freeing a non-allocated or already freed memory chunk");
00189 chunks_unlock;
00190 return;
00191 }
00192 qos_log_debug("Current number of chunks: %d", num_chunks);
00193 chunks_unlock;
00194 #endif
00195 qos_ll_free(ptr);
00196 }
00197
00198 int qos_mem_clean() {
00199 #ifdef QOS_MEMORY_CHECK
00200 int ret;
00201 chunks_vars;
00202 chunks_lock;
00203 chunks_init();
00204 if (num_chunks > 0) {
00205 int i = 0;
00206 qos_log_debug("Residual chunks:");
00207 for (i = 0; i < MAX_CHUNK_NUMBER; ++i)
00208 if (chunks[i].ptr != NULL)
00209 qos_log_debug(" ptr=%p, size=%lu, name='%s'",
00210 chunks[i].ptr, chunks[i].size, chunks[i].name);
00211 }
00212 ret = ((num_chunks == 0) && (mem_failure == 0));
00213 chunks_unlock;
00214 return ret;
00215 #else
00216 return 1;
00217 #endif
00218 }
00219
00220 #ifdef QOS_KS
00221 EXPORT_SYMBOL(qos_malloc);
00222 EXPORT_SYMBOL_GPL(qos_malloc_named);
00223 EXPORT_SYMBOL_GPL(qos_free);
00224 EXPORT_SYMBOL_GPL(qos_mem_clean);
00225 EXPORT_SYMBOL_GPL(qos_mem_valid);
00226 #endif