linux-bk/sound/core/memory.c
<<
>>
Prefs
   1/*
   2 *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
   3 * 
   4 *  Memory allocation helpers.
   5 *
   6 *
   7 *   This program is free software; you can redistribute it and/or modify
   8 *   it under the terms of the GNU General Public License as published by
   9 *   the Free Software Foundation; either version 2 of the License, or
  10 *   (at your option) any later version.
  11 *
  12 *   This program is distributed in the hope that it will be useful,
  13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 *   GNU General Public License for more details.
  16 *
  17 *   You should have received a copy of the GNU General Public License
  18 *   along with this program; if not, write to the Free Software
  19 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  20 *
  21 */
  22
  23#include <sound/driver.h>
  24#include <asm/io.h>
  25#include <asm/uaccess.h>
  26#include <linux/init.h>
  27#include <linux/slab.h>
  28#include <linux/time.h>
  29#include <linux/pci.h>
  30#include <sound/core.h>
  31#include <sound/info.h>
  32
  33/*
  34 *  memory allocation helpers and debug routines
  35 */
  36
  37#ifdef CONFIG_SND_DEBUG_MEMORY
  38
  39struct snd_alloc_track {
  40        unsigned long magic;
  41        void *caller;
  42        size_t size;
  43        struct list_head list;
  44        long data[0];
  45};
  46
  47#define snd_alloc_track_entry(obj) (struct snd_alloc_track *)((char*)obj - (unsigned long)((struct snd_alloc_track *)0)->data)
  48
  49static long snd_alloc_kmalloc;
  50static long snd_alloc_vmalloc;
  51static LIST_HEAD(snd_alloc_kmalloc_list);
  52static LIST_HEAD(snd_alloc_vmalloc_list);
  53static spinlock_t snd_alloc_kmalloc_lock = SPIN_LOCK_UNLOCKED;
  54static spinlock_t snd_alloc_vmalloc_lock = SPIN_LOCK_UNLOCKED;
  55#define KMALLOC_MAGIC 0x87654321
  56#define VMALLOC_MAGIC 0x87654320
  57static snd_info_entry_t *snd_memory_info_entry;
  58
  59void snd_memory_init(void)
  60{
  61        snd_alloc_kmalloc = 0;
  62        snd_alloc_vmalloc = 0;
  63}
  64
  65void snd_memory_done(void)
  66{
  67        struct list_head *head;
  68        struct snd_alloc_track *t;
  69
  70        if (snd_alloc_kmalloc > 0)
  71                snd_printk(KERN_ERR "Not freed snd_alloc_kmalloc = %li\n", snd_alloc_kmalloc);
  72        if (snd_alloc_vmalloc > 0)
  73                snd_printk(KERN_ERR "Not freed snd_alloc_vmalloc = %li\n", snd_alloc_vmalloc);
  74        list_for_each_prev(head, &snd_alloc_kmalloc_list) {
  75                t = list_entry(head, struct snd_alloc_track, list);
  76                if (t->magic != KMALLOC_MAGIC) {
  77                        snd_printk(KERN_ERR "Corrupted kmalloc\n");
  78                        break;
  79                }
  80                snd_printk(KERN_ERR "kmalloc(%ld) from %p not freed\n", (long) t->size, t->caller);
  81        }
  82        list_for_each_prev(head, &snd_alloc_vmalloc_list) {
  83                t = list_entry(head, struct snd_alloc_track, list);
  84                if (t->magic != VMALLOC_MAGIC) {
  85                        snd_printk(KERN_ERR "Corrupted vmalloc\n");
  86                        break;
  87                }
  88                snd_printk(KERN_ERR "vmalloc(%ld) from %p not freed\n", (long) t->size, t->caller);
  89        }
  90}
  91
  92static void *__snd_kmalloc(size_t size, int flags, void *caller)
  93{
  94        unsigned long cpu_flags;
  95        struct snd_alloc_track *t;
  96        void *ptr;
  97        
  98        ptr = snd_wrapper_kmalloc(size + sizeof(struct snd_alloc_track), flags);
  99        if (ptr != NULL) {
 100                t = (struct snd_alloc_track *)ptr;
 101                t->magic = KMALLOC_MAGIC;
 102                t->caller = caller;
 103                spin_lock_irqsave(&snd_alloc_kmalloc_lock, cpu_flags);
 104                list_add_tail(&t->list, &snd_alloc_kmalloc_list);
 105                spin_unlock_irqrestore(&snd_alloc_kmalloc_lock, cpu_flags);
 106                t->size = size;
 107                snd_alloc_kmalloc += size;
 108                ptr = t->data;
 109        }
 110        return ptr;
 111}
 112
 113#define _snd_kmalloc(size, flags) __snd_kmalloc((size), (flags), __builtin_return_address(0));
 114void *snd_hidden_kmalloc(size_t size, int flags)
 115{
 116        return _snd_kmalloc(size, flags);
 117}
 118
 119void *snd_hidden_kcalloc(size_t n, size_t size, int flags)
 120{
 121        void *ret = NULL;
 122        if (n != 0 && size > INT_MAX / n)
 123                return ret;
 124        ret = _snd_kmalloc(n * size, flags);
 125        if (ret)
 126                memset(ret, 0, n * size);
 127        return ret;
 128}
 129
 130void snd_hidden_kfree(const void *obj)
 131{
 132        unsigned long flags;
 133        struct snd_alloc_track *t;
 134        if (obj == NULL)
 135                return;
 136        t = snd_alloc_track_entry(obj);
 137        if (t->magic != KMALLOC_MAGIC) {
 138                snd_printk(KERN_WARNING "bad kfree (called from %p)\n", __builtin_return_address(0));
 139                return;
 140        }
 141        spin_lock_irqsave(&snd_alloc_kmalloc_lock, flags);
 142        list_del(&t->list);
 143        spin_unlock_irqrestore(&snd_alloc_kmalloc_lock, flags);
 144        t->magic = 0;
 145        snd_alloc_kmalloc -= t->size;
 146        obj = t;
 147        snd_wrapper_kfree(obj);
 148}
 149
 150void *snd_hidden_vmalloc(unsigned long size)
 151{
 152        void *ptr;
 153        ptr = snd_wrapper_vmalloc(size + sizeof(struct snd_alloc_track));
 154        if (ptr) {
 155                struct snd_alloc_track *t = (struct snd_alloc_track *)ptr;
 156                t->magic = VMALLOC_MAGIC;
 157                t->caller = __builtin_return_address(0);
 158                spin_lock(&snd_alloc_vmalloc_lock);
 159                list_add_tail(&t->list, &snd_alloc_vmalloc_list);
 160                spin_unlock(&snd_alloc_vmalloc_lock);
 161                t->size = size;
 162                snd_alloc_vmalloc += size;
 163                ptr = t->data;
 164        }
 165        return ptr;
 166}
 167
 168void snd_hidden_vfree(void *obj)
 169{
 170        struct snd_alloc_track *t;
 171        if (obj == NULL)
 172                return;
 173        t = snd_alloc_track_entry(obj);
 174        if (t->magic != VMALLOC_MAGIC) {
 175                snd_printk(KERN_ERR "bad vfree (called from %p)\n", __builtin_return_address(0));
 176                return;
 177        }
 178        spin_lock(&snd_alloc_vmalloc_lock);
 179        list_del(&t->list);
 180        spin_unlock(&snd_alloc_vmalloc_lock);
 181        t->magic = 0;
 182        snd_alloc_vmalloc -= t->size;
 183        obj = t;
 184        snd_wrapper_vfree(obj);
 185}
 186
 187static void snd_memory_info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
 188{
 189        snd_iprintf(buffer, "kmalloc: %li bytes\n", snd_alloc_kmalloc);
 190        snd_iprintf(buffer, "vmalloc: %li bytes\n", snd_alloc_vmalloc);
 191}
 192
 193int __init snd_memory_info_init(void)
 194{
 195        snd_info_entry_t *entry;
 196
 197        entry = snd_info_create_module_entry(THIS_MODULE, "meminfo", NULL);
 198        if (entry) {
 199                entry->c.text.read_size = 256;
 200                entry->c.text.read = snd_memory_info_read;
 201                if (snd_info_register(entry) < 0) {
 202                        snd_info_free_entry(entry);
 203                        entry = NULL;
 204                }
 205        }
 206        snd_memory_info_entry = entry;
 207        return 0;
 208}
 209
 210int __exit snd_memory_info_done(void)
 211{
 212        if (snd_memory_info_entry)
 213                snd_info_unregister(snd_memory_info_entry);
 214        return 0;
 215}
 216
 217#else
 218
 219#define _snd_kmalloc kmalloc
 220
 221#endif /* CONFIG_SND_DEBUG_MEMORY */
 222
 223/**
 224 * snd_kmalloc_strdup - copy the string
 225 * @string: the original string
 226 * @flags: allocation conditions, GFP_XXX
 227 *
 228 * Allocates a memory chunk via kmalloc() and copies the string to it.
 229 *
 230 * Returns the pointer, or NULL if no enoguh memory.
 231 */
 232char *snd_kmalloc_strdup(const char *string, int flags)
 233{
 234        size_t len;
 235        char *ptr;
 236
 237        if (!string)
 238                return NULL;
 239        len = strlen(string) + 1;
 240        ptr = _snd_kmalloc(len, flags);
 241        if (ptr)
 242                memcpy(ptr, string, len);
 243        return ptr;
 244}
 245
 246/**
 247 * copy_to_user_fromio - copy data from mmio-space to user-space
 248 * @dst: the destination pointer on user-space
 249 * @src: the source pointer on mmio
 250 * @count: the data size to copy in bytes
 251 *
 252 * Copies the data from mmio-space to user-space.
 253 *
 254 * Returns zero if successful, or non-zero on failure.
 255 */
 256int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size_t count)
 257{
 258#if defined(__i386__) || defined(CONFIG_SPARC32)
 259        return copy_to_user(dst, (const void*)src, count) ? -EFAULT : 0;
 260#else
 261        char buf[256];
 262        while (count) {
 263                size_t c = count;
 264                if (c > sizeof(buf))
 265                        c = sizeof(buf);
 266                memcpy_fromio(buf, (void __iomem *)src, c);
 267                if (copy_to_user(dst, buf, c))
 268                        return -EFAULT;
 269                count -= c;
 270                dst += c;
 271                src += c;
 272        }
 273        return 0;
 274#endif
 275}
 276
 277/**
 278 * copy_from_user_toio - copy data from user-space to mmio-space
 279 * @dst: the destination pointer on mmio-space
 280 * @src: the source pointer on user-space
 281 * @count: the data size to copy in bytes
 282 *
 283 * Copies the data from user-space to mmio-space.
 284 *
 285 * Returns zero if successful, or non-zero on failure.
 286 */
 287int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size_t count)
 288{
 289#if defined(__i386__) || defined(CONFIG_SPARC32)
 290        return copy_from_user((void*)dst, src, count) ? -EFAULT : 0;
 291#else
 292        char buf[256];
 293        while (count) {
 294                size_t c = count;
 295                if (c > sizeof(buf))
 296                        c = sizeof(buf);
 297                if (copy_from_user(buf, src, c))
 298                        return -EFAULT;
 299                memcpy_toio(dst, buf, c);
 300                count -= c;
 301                dst += c;
 302                src += c;
 303        }
 304        return 0;
 305#endif
 306}
 307
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.